|
1 | | -part of 'core.dart'; |
| 1 | +import 'dart:async'; |
| 2 | +import 'dart:io'; |
2 | 3 |
|
3 | | -class $PharaohImpl extends RouterContract |
| 4 | +import 'package:collection/collection.dart'; |
| 5 | +import 'package:http_parser/http_parser.dart'; |
| 6 | +import 'package:meta/meta.dart'; |
| 7 | +import 'package:spanner/spanner.dart'; |
| 8 | +import 'package:spanner/src/tree/tree.dart' show BASE_PATH; |
| 9 | + |
| 10 | +import '../middleware/body_parser.dart'; |
| 11 | +import '../middleware/session_mw.dart'; |
| 12 | +import '../shelf_interop/shelf.dart' as shelf; |
| 13 | +import '../utils/exceptions.dart'; |
| 14 | +import '../view/view.dart'; |
| 15 | + |
| 16 | +import 'request.dart'; |
| 17 | +import 'response.dart'; |
| 18 | + |
| 19 | +part 'router/router_contract.dart'; |
| 20 | +part 'router/router_handler.dart'; |
| 21 | + |
| 22 | +typedef PharaohError = ({Object exception, StackTrace trace}); |
| 23 | + |
| 24 | +typedef OnErrorCallback = FutureOr<Response> Function( |
| 25 | + PharaohError error, |
| 26 | + Request req, |
| 27 | + Response res, |
| 28 | +); |
| 29 | + |
| 30 | +abstract class Pharaoh implements RouterContract { |
| 31 | + static _$GroupRouter get router => _$GroupRouter(); |
| 32 | + |
| 33 | + factory Pharaoh() => _$PharaohImpl(); |
| 34 | + |
| 35 | + static ViewEngine? viewEngine; |
| 36 | + |
| 37 | + void onError(OnErrorCallback onError); |
| 38 | + |
| 39 | + void useSpanner(Spanner spanner); |
| 40 | + |
| 41 | + void useRequestHook(RequestHook hook); |
| 42 | + |
| 43 | + void group(String path, _$GroupRouter router); |
| 44 | + |
| 45 | + Uri get uri; |
| 46 | + |
| 47 | + Future<Pharaoh> listen({int port = 3000}); |
| 48 | + |
| 49 | + @visibleForTesting |
| 50 | + void handleRequest(HttpRequest httpReq); |
| 51 | + |
| 52 | + Future<void> shutdown(); |
| 53 | +} |
| 54 | + |
| 55 | +class _$PharaohImpl extends RouterContract |
4 | 56 | with RouteDefinitionMixin |
5 | 57 | implements Pharaoh { |
6 | 58 | late final HttpServer _server; |
7 | 59 |
|
8 | 60 | OnErrorCallback? _onErrorCb; |
9 | 61 |
|
10 | | - static ViewEngine? viewEngine_; |
11 | | - |
12 | | - final List<ReqResHook> _preResponseHooks = [ |
| 62 | + final List<RequestHook> _requestHooks = [ |
13 | 63 | sessionPreResponseHook, |
14 | 64 | viewRenderHook, |
15 | 65 | ]; |
16 | 66 |
|
17 | | - $PharaohImpl() { |
| 67 | + _$PharaohImpl() { |
18 | 68 | useSpanner(Spanner()); |
19 | 69 | use(bodyParser); |
20 | 70 | } |
@@ -42,15 +92,6 @@ class $PharaohImpl extends RouterContract |
42 | 92 | ); |
43 | 93 | } |
44 | 94 |
|
45 | | - @override |
46 | | - Pharaoh group(final String path, final RouterContract router) { |
47 | | - if (router is! GroupRouter) { |
48 | | - throw PharaohException.value('Router is not an instance of GroupRouter'); |
49 | | - } |
50 | | - router.commit(path, spanner); |
51 | | - return this; |
52 | | - } |
53 | | - |
54 | 95 | @override |
55 | 96 | Future<Pharaoh> listen({int port = 3000}) async { |
56 | 97 | _server = await HttpServer.bind(InternetAddress.anyIPv4, port, shared: true) |
@@ -114,21 +155,22 @@ class $PharaohImpl extends RouterContract |
114 | 155 | req.params.addAll(routeResult.params); |
115 | 156 | } |
116 | 157 |
|
117 | | - reqRes = await executeHandlers(resolvedHandlers, reqRes); |
118 | | - |
119 | | - for (final job in _preResponseHooks) { |
120 | | - reqRes = await Future.microtask(() => job(reqRes)); |
| 158 | + for (final hook in _requestHooks.whereNot((e) => e.onBefore == null)) { |
| 159 | + reqRes = await hook.onBefore!.call(req, reqRes.res); |
121 | 160 | } |
122 | 161 |
|
123 | | - if (!reqRes.res.ended) { |
124 | | - return reqRes.merge(routeNotFound()); |
| 162 | + reqRes = await executeHandlers(resolvedHandlers, reqRes); |
| 163 | + if (!reqRes.res.ended) reqRes = reqRes.merge(routeNotFound()); |
| 164 | + |
| 165 | + for (final hook in _requestHooks.whereNot((e) => e.onAfter == null)) { |
| 166 | + reqRes = await hook.onAfter!.call(reqRes.req, reqRes.res); |
125 | 167 | } |
126 | 168 |
|
127 | 169 | return reqRes; |
128 | 170 | } |
129 | 171 |
|
130 | 172 | Future<void> forward(HttpRequest request, Response res_) async { |
131 | | - var coding = res_.headers['transfer-encoding']; |
| 173 | + var coding = res_.headers[HttpHeaders.transferEncodingHeader]; |
132 | 174 |
|
133 | 175 | final statusCode = res_.statusCode; |
134 | 176 | request.response.statusCode = statusCode; |
@@ -187,14 +229,21 @@ class $PharaohImpl extends RouterContract |
187 | 229 | Future<void> shutdown() async => _server.close(); |
188 | 230 |
|
189 | 231 | @override |
190 | | - ViewEngine? get viewEngine => viewEngine_; |
| 232 | + void onError(OnErrorCallback errorCb) => _onErrorCb = errorCb; |
191 | 233 |
|
192 | 234 | @override |
193 | | - set viewEngine(ViewEngine? engine) => viewEngine_ = engine; |
| 235 | + void useRequestHook(RequestHook hook) => _requestHooks.add(hook); |
194 | 236 |
|
195 | 237 | @override |
196 | | - void onError(OnErrorCallback errorCb) => _onErrorCb = errorCb; |
| 238 | + void group(String path, _$GroupRouter router) { |
| 239 | + spanner.attachNode(path, router.spanner.root); |
| 240 | + } |
197 | 241 | } |
198 | 242 |
|
199 | | -// ignore: constant_identifier_names |
200 | 243 | const _XPoweredByHeader = 'X-Powered-By'; |
| 244 | + |
| 245 | +class _$GroupRouter extends RouterContract with RouteDefinitionMixin { |
| 246 | + _$GroupRouter() { |
| 247 | + useSpanner(Spanner()); |
| 248 | + } |
| 249 | +} |
0 commit comments