OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library shelf.server_handler; | |
6 | |
7 import 'dart:async'; | |
8 | |
9 import 'package:async/async.dart'; | |
10 | |
11 import 'request.dart'; | |
12 import 'handler.dart'; | |
13 import 'server.dart'; | |
14 | |
15 /// A connected pair of a [Server] and a [Handler]. | |
16 /// | |
17 /// Requests to the handler are sent to the server's mounted handler once it's | |
18 /// available. This is used to expose a virtual [Server] that's actually one | |
19 /// part of a larger URL-space. | |
20 class ServerHandler { | |
21 /// The server. | |
22 /// | |
23 /// Once this has a handler mounted, it's passed all requests to [handler] | |
24 /// until this server is closed. | |
25 Server get server => _server; | |
26 final _HandlerServer _server; | |
27 | |
28 /// The handler. | |
29 /// | |
30 /// This passes requests to [server]'s handler. If that handler isn't mounted | |
31 /// yet, the requests are handled once it is. | |
32 Handler get handler => _onRequest; | |
33 | |
34 /// Creates a new connected pair of a [Server] with the given [url] and a | |
35 /// [Handler]. | |
36 /// | |
37 /// The caller is responsible for ensuring that requests to [url] or any URL | |
38 /// beneath it are handled by [handler]. | |
39 /// | |
40 /// If [onClose] is passed, it's called when [server] is closed. It may return | |
41 /// a [Future] or `null`; its return value is returned by [Server.close]. | |
42 ServerHandler(Uri url, {onClose()}) | |
43 : _server = new _HandlerServer(url, onClose); | |
44 | |
45 /// Pipes requests to [server]'s handler. | |
46 _onRequest(Request request) { | |
47 if (_server._closeMemo.hasRun) { | |
48 throw new StateError("Request received after the server was closed."); | |
49 } | |
50 | |
51 if (_server._handler != null) return _server._handler(request); | |
52 | |
53 // Avoid async/await so that the common case of a handler already being | |
54 // mounted doesn't involve any extra asynchronous delays. | |
55 return _server._onMounted.then((_) => _server._handler(request)); | |
kevmoo
2015/10/22 00:44:26
Why don't you use awa...oh.
| |
56 } | |
57 } | |
58 | |
59 /// The [Server] returned by [ServerHandler]. | |
60 class _HandlerServer implements Server { | |
61 final Uri url; | |
62 | |
63 /// The callback to call when [close] is called, or `null`. | |
64 final ZoneCallback _onClose; | |
65 | |
66 /// The mounted handler. | |
67 /// | |
68 /// This is `null` until [mount] is called. | |
69 Handler _handler; | |
70 | |
71 /// A future that fires once [mount] has been called. | |
72 Future get _onMounted => _onMountedCompleter.future; | |
73 final _onMountedCompleter = new Completer(); | |
74 | |
75 _HandlerServer(this.url, this._onClose); | |
76 | |
77 void mount(Handler handler) { | |
78 if (_handler != null) { | |
79 throw new StateError("Can't mount two handlers for the same server."); | |
80 } | |
81 | |
82 _handler = handler; | |
83 _onMountedCompleter.complete(); | |
84 } | |
85 | |
86 Future close() => _closeMemo.runOnce(() { | |
87 return _onClose == null ? null : _onClose(); | |
88 }); | |
89 final _closeMemo = new AsyncMemoizer(); | |
90 } | |
OLD | NEW |