Chromium Code Reviews| Index: bin/src/examples/http_proxy_repository.dart |
| diff --git a/bin/src/examples/http_proxy_repository.dart b/bin/src/examples/http_proxy_repository.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..6e8e0884bf7bc19797c1244edc1c91f26b925258 |
| --- /dev/null |
| +++ b/bin/src/examples/http_proxy_repository.dart |
| @@ -0,0 +1,126 @@ |
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +library appengine_pub.http_proxy_repository; |
| + |
| +import 'dart:async'; |
| +import 'dart:convert'; |
| + |
| +import 'package:http/http.dart' as http; |
| +import 'package:logging/logging.dart'; |
| +import 'package:pub_server/repository.dart'; |
| + |
| +final Logger _logger = new Logger('pub_server.http_proxy_repository'); |
| + |
| +/// Implements the [PackageRepository] by talking to a remote HTTP server via |
| +/// the pub HTTP API. |
| +/// |
| +/// This [PackageRepository] does not support uploading so far. |
| +class HttpProxyRepository extends PackageRepository { |
| + final http.Client client; |
| + final Uri baseUrl; |
| + |
| + HttpProxyRepository(this.client, this.baseUrl); |
| + |
| + Stream<PackageVersion> versions(String package) { |
| + Uri versionUrl = baseUrl.resolve( |
| + '/api/packages/${Uri.encodeComponent(package)}'); |
| + |
| + bool done = false; |
| + |
| + Future<List<PackageVersion>> nextPage() async { |
| + if (done) return null; |
| + |
| + done = true; |
| + http.Response response = await client.get(versionUrl); |
| + var json = JSON.decode(response.body); |
| + var versions = json['versions']; |
| + if (versions != null) { |
| + return versions.map((Map item) { |
| + var pubspec = item['pubspec']; |
| + var pubspecString = JSON.encode(pubspec); |
| + return new PackageVersion( |
| + pubspec['name'], pubspec['version'], pubspecString); |
| + }).toList(); |
| + } |
| + return const []; |
| + } |
| + return _streamViaPaging(nextPage); |
|
Søren Gjesse
2015/02/16 10:23:54
Why are you using _streamViaPaging? There is alway
kustermann
2015/02/16 11:42:10
Good point.
This was old code from when I had the
|
| + } |
| + |
| + // TODO: Could be optimized, since we don't need to list all versions and can |
| + // just talk to the HTTP endpoint which gives us a specific package/version |
| + // combination. |
| + Future<PackageVersion> lookupVersion(String package, String version) { |
| + return versions(package) |
| + .where((v) => v.packageName == package && v.versionString == version) |
| + .toList().then((List<PackageVersion> versions) { |
| + if (versions.length >= 1) return versions.first; |
| + return null; |
| + }); |
| + } |
| + |
| + bool get supportsUpload => false; |
| + |
| + bool get supportsAsyncUpload => false; |
| + |
| + bool get supportsDownloadUrl => true; |
| + |
| + Future<Uri> downloadUrl(String package, String version) async { |
| + package = Uri.encodeComponent(package); |
| + version = Uri.encodeComponent(version); |
| + return baseUrl.resolve('/packages/$package/versions/$version.tar.gz'); |
| + } |
| + |
| + Future<Stream> download(String package, String version) async { |
| + _logger.info('Downloading package $package/$version.'); |
| + |
| + var url = await downloadUrl(package, version); |
| + var response = await client.send(new http.Request('GET', url)); |
| + return response.stream; |
| + } |
| +} |
| + |
| +Stream _streamViaPaging(Future nextPage()) { |
| + var controller; |
| + |
| + bool fetching = false; |
| + bool paused = false; |
| + bool canceled = false; |
| + |
| + fetch() async { |
| + if (!fetching && !paused && !canceled) { |
| + fetching = true; |
| + var items = await nextPage(); |
| + if (items == null) { |
| + controller.close(); |
| + } else { |
| + for (var item in items) { |
| + controller.add(item); |
| + } |
| + fetching = false; |
| + fetch(); |
| + } |
| + } |
| + } |
| + |
| + onListen() => fetch(); |
| + onPause() { |
| + paused = true; |
| + } |
| + onResume() { |
| + paused = false; |
| + fetch(); |
| + } |
| + onCancel() { |
| + canceled = true; |
| + controller.close(); |
| + } |
| + |
| + controller = new StreamController(onListen: onListen, |
| + onPause: onPause, |
| + onResume: onResume, |
| + onCancel: onCancel); |
| + return controller.stream; |
| +} |