| // Copyright (c) 2016, 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. | |
| import 'dart:async'; | |
| import 'dart:isolate'; | |
| import 'package:path/path.dart' as p; | |
| import 'package:shelf/shelf.dart'; | |
| import 'package:shelf_static/shelf_static.dart'; | |
| /// A shelf handler that serves a virtual packages directory based on a package | |
| /// config. | |
| class PackageConfigHandler { | |
| /// The static handlers for serving entries in the package config, indexed by | |
| /// name. | |
| final _packageHandlers = <String, Future<Handler>>{}; | |
| /// Optional, a map of package names to base uri for resolving `package:` | |
| /// uris for that package. | |
| final Map<String, Uri>? _packageMap; | |
| PackageConfigHandler({Map<String, Uri>? packageMap}) | |
| : _packageMap = packageMap; | |
| /// The callback for handling a single request. | |
| Future<Response> handleRequest(Request request) async { | |
| final segments = request.url.pathSegments; | |
| final handler = await _handlerFor(segments.first); | |
| return handler(request.change(path: segments.first)); | |
| } | |
| /// Creates a handler for [packageName] based on the package map in | |
| /// [_packageMap] or the current isolate resolver. | |
| Future<Handler> _handlerFor(String packageName) => | |
| _packageHandlers.putIfAbsent(packageName, () async { | |
| Uri? packageUri; | |
| if (_packageMap != null) { | |
| packageUri = _packageMap![packageName]; | |
| } else { | |
| final fakeResolvedUri = await Isolate.resolvePackageUri( | |
| Uri(scheme: 'package', path: '$packageName/')); | |
| packageUri = fakeResolvedUri; | |
| } | |
| final handler = packageUri == null | |
| ? (_) => Response.notFound('Package $packageName not found.') | |
| : createStaticHandler(p.fromUri(packageUri), | |
| serveFilesOutsidePath: true); | |
| return handler; | |
| }); | |
| } |