Embed Angel within shelf
This commit is contained in:
parent
b84da76815
commit
071129902a
5 changed files with 121 additions and 7 deletions
49
example/angel_in_shelf.dart
Normal file
49
example/angel_in_shelf.dart
Normal file
|
@ -0,0 +1,49 @@
|
|||
import 'dart:io';
|
||||
import 'package:angel_container/mirrors.dart';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_shelf/angel_shelf.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:pretty_logging/pretty_logging.dart';
|
||||
import 'package:shelf/shelf.dart' as shelf;
|
||||
import 'package:shelf/shelf_io.dart' as shelf_io;
|
||||
import 'package:shelf_static/shelf_static.dart';
|
||||
|
||||
main() async {
|
||||
Logger.root
|
||||
..level = Level.ALL
|
||||
..onRecord.listen(prettyLog);
|
||||
|
||||
// Create a basic Angel server, with some routes.
|
||||
var app = Angel(
|
||||
logger: Logger('angel_shelf_demo'),
|
||||
reflector: MirrorsReflector(),
|
||||
);
|
||||
|
||||
app.get('/angel', (req, res) {
|
||||
res.write('Angel embedded within shelf!');
|
||||
return false;
|
||||
});
|
||||
|
||||
app.get('/hello', ioc((@Query('name') String name) {
|
||||
return {'hello': name};
|
||||
}));
|
||||
|
||||
// Next, create an AngelShelf driver.
|
||||
// If we have startup hooks we want to run, we need to call
|
||||
// `startServer`. Otherwise, it can be omitted.
|
||||
var angelShelf = AngelShelf(app);
|
||||
await angelShelf.startServer();
|
||||
|
||||
// Create, and mount, a shelf pipeline...
|
||||
// You can also embed Angel as a middleware...
|
||||
var mwHandler = shelf.Pipeline()
|
||||
.addMiddleware(angelShelf.middleware)
|
||||
.addHandler(createStaticHandler('.',
|
||||
defaultDocument: 'index.html', listDirectories: true));
|
||||
|
||||
// Run the servers.
|
||||
await shelf_io.serve(mwHandler, InternetAddress.loopbackIPv4, 8080);
|
||||
await shelf_io.serve(angelShelf.handler, InternetAddress.loopbackIPv4, 8081);
|
||||
print('Angel as middleware: http://localhost:8080');
|
||||
print('Angel as only handler: http://localhost:8081');
|
||||
}
|
|
@ -10,7 +10,7 @@ main() async {
|
|||
Logger.root
|
||||
..level = Level.ALL
|
||||
..onRecord.listen(prettyLog);
|
||||
|
||||
|
||||
var app = Angel(logger: Logger('angel_shelf_demo'));
|
||||
var http = AngelHttp(app);
|
||||
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
export 'src/convert.dart';
|
||||
export 'src/embed_shelf.dart';
|
||||
export 'src/shelf_driver.dart';
|
||||
export 'src/shelf_request.dart';
|
||||
export 'src/shelf_response.dart';
|
||||
|
|
|
@ -7,15 +7,68 @@ import 'shelf_response.dart';
|
|||
|
||||
class AngelShelf extends Driver<shelf.Request, ShelfResponseContext,
|
||||
Stream<shelf.Request>, ShelfRequestContext, ShelfResponseContext> {
|
||||
AngelShelf.custom(Angel app, {bool useZone = true})
|
||||
: super(app, (_, __) => throw _unsupported(), useZone: useZone);
|
||||
final StreamController<shelf.Request> incomingRequests = StreamController();
|
||||
|
||||
final FutureOr<shelf.Response> Function() notFound;
|
||||
|
||||
AngelShelf(Angel app, {FutureOr<shelf.Response> Function() notFound})
|
||||
: this.notFound =
|
||||
notFound ?? (() => shelf.Response.notFound('Not Found')),
|
||||
super(app, null, useZone: false) {
|
||||
// Inject a final handler that will keep responses open, if we are using the
|
||||
// driver as a middleware.
|
||||
app.fallback((req, res) {
|
||||
if (res is ShelfResponseContext) {
|
||||
res.closeSilently();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
Future<Stream<shelf.Request>> Function(dynamic, int) get serverGenerator =>
|
||||
(_, __) async => incomingRequests.stream;
|
||||
|
||||
static UnsupportedError _unsupported() => UnsupportedError(
|
||||
'AngelShelf cannot mount a standalone server, or return a URI.');
|
||||
|
||||
Future<shelf.Response> handler(shelf.Request request) async {
|
||||
var response = ShelfResponseContext(app);
|
||||
await handleRawRequest(request, response);
|
||||
var result = await handleRawRequest(request, response);
|
||||
if (result is shelf.Response) {
|
||||
return result;
|
||||
} else if (!response.isOpen) {
|
||||
return response.shelfResponse;
|
||||
} else {
|
||||
// return await handler(request);
|
||||
return notFound();
|
||||
}
|
||||
}
|
||||
|
||||
shelf.Handler middleware(shelf.Handler handler) {
|
||||
return (request) async {
|
||||
var response = ShelfResponseContext(app);
|
||||
var result = await handleRawRequest(request, response);
|
||||
if (result is shelf.Response) {
|
||||
return result;
|
||||
} else if (!response.isOpen) {
|
||||
return response.shelfResponse;
|
||||
} else {
|
||||
return await handler(request);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Future<shelf.Response> handleAngelHttpException(
|
||||
AngelHttpException e,
|
||||
StackTrace st,
|
||||
RequestContext req,
|
||||
ResponseContext res,
|
||||
shelf.Request request,
|
||||
ShelfResponseContext response,
|
||||
{bool ignoreFinalizers = false}) async {
|
||||
await super.handleAngelHttpException(e, st, req, res, request, response,
|
||||
ignoreFinalizers: ignoreFinalizers);
|
||||
return response.shelfResponse;
|
||||
}
|
||||
|
||||
|
@ -38,7 +91,7 @@ class AngelShelf extends Driver<shelf.Request, ShelfResponseContext,
|
|||
@override
|
||||
Future<ShelfRequestContext> createRequestContext(
|
||||
shelf.Request request, ShelfResponseContext response) {
|
||||
var path = uri.path.replaceAll(_straySlashes, '');
|
||||
var path = request.url.path.replaceAll(_straySlashes, '');
|
||||
if (path.isEmpty) path = '/';
|
||||
var rq =
|
||||
ShelfRequestContext(app, app.container.createChild(), request, path);
|
||||
|
|
|
@ -8,12 +8,19 @@ import 'shelf_request.dart';
|
|||
class ShelfResponseContext extends ResponseContext<ShelfResponseContext> {
|
||||
final Angel app;
|
||||
final StreamController<List<int>> _ctrl = StreamController();
|
||||
bool _isOpen = true, _isDetached = false;
|
||||
bool _isOpen = true,
|
||||
_isDetached = false,
|
||||
_wasClosedByHandler = false,
|
||||
_handlersAreDone = false;
|
||||
|
||||
ShelfResponseContext(this.app);
|
||||
|
||||
ShelfRequestContext _correspondingRequest;
|
||||
|
||||
bool get wasClosedByHandler => _wasClosedByHandler;
|
||||
|
||||
void closeSilently() => _handlersAreDone = true;
|
||||
|
||||
ShelfRequestContext get correspondingRequest => _correspondingRequest;
|
||||
|
||||
set correspondingRequest(ShelfRequestContext value) {
|
||||
|
@ -30,7 +37,9 @@ class ShelfResponseContext extends ResponseContext<ShelfResponseContext> {
|
|||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_isOpen = false;
|
||||
if (!_handlersAreDone) {
|
||||
_isOpen = false;
|
||||
}
|
||||
_ctrl.close();
|
||||
return super.close();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue