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
|
Logger.root
|
||||||
..level = Level.ALL
|
..level = Level.ALL
|
||||||
..onRecord.listen(prettyLog);
|
..onRecord.listen(prettyLog);
|
||||||
|
|
||||||
var app = Angel(logger: Logger('angel_shelf_demo'));
|
var app = Angel(logger: Logger('angel_shelf_demo'));
|
||||||
var http = AngelHttp(app);
|
var http = AngelHttp(app);
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
export 'src/convert.dart';
|
export 'src/convert.dart';
|
||||||
export 'src/embed_shelf.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,
|
class AngelShelf extends Driver<shelf.Request, ShelfResponseContext,
|
||||||
Stream<shelf.Request>, ShelfRequestContext, ShelfResponseContext> {
|
Stream<shelf.Request>, ShelfRequestContext, ShelfResponseContext> {
|
||||||
AngelShelf.custom(Angel app, {bool useZone = true})
|
final StreamController<shelf.Request> incomingRequests = StreamController();
|
||||||
: super(app, (_, __) => throw _unsupported(), useZone: useZone);
|
|
||||||
|
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(
|
static UnsupportedError _unsupported() => UnsupportedError(
|
||||||
'AngelShelf cannot mount a standalone server, or return a URI.');
|
'AngelShelf cannot mount a standalone server, or return a URI.');
|
||||||
|
|
||||||
Future<shelf.Response> handler(shelf.Request request) async {
|
Future<shelf.Response> handler(shelf.Request request) async {
|
||||||
var response = ShelfResponseContext(app);
|
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;
|
return response.shelfResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +91,7 @@ class AngelShelf extends Driver<shelf.Request, ShelfResponseContext,
|
||||||
@override
|
@override
|
||||||
Future<ShelfRequestContext> createRequestContext(
|
Future<ShelfRequestContext> createRequestContext(
|
||||||
shelf.Request request, ShelfResponseContext response) {
|
shelf.Request request, ShelfResponseContext response) {
|
||||||
var path = uri.path.replaceAll(_straySlashes, '');
|
var path = request.url.path.replaceAll(_straySlashes, '');
|
||||||
if (path.isEmpty) path = '/';
|
if (path.isEmpty) path = '/';
|
||||||
var rq =
|
var rq =
|
||||||
ShelfRequestContext(app, app.container.createChild(), request, path);
|
ShelfRequestContext(app, app.container.createChild(), request, path);
|
||||||
|
|
|
@ -8,12 +8,19 @@ import 'shelf_request.dart';
|
||||||
class ShelfResponseContext extends ResponseContext<ShelfResponseContext> {
|
class ShelfResponseContext extends ResponseContext<ShelfResponseContext> {
|
||||||
final Angel app;
|
final Angel app;
|
||||||
final StreamController<List<int>> _ctrl = StreamController();
|
final StreamController<List<int>> _ctrl = StreamController();
|
||||||
bool _isOpen = true, _isDetached = false;
|
bool _isOpen = true,
|
||||||
|
_isDetached = false,
|
||||||
|
_wasClosedByHandler = false,
|
||||||
|
_handlersAreDone = false;
|
||||||
|
|
||||||
ShelfResponseContext(this.app);
|
ShelfResponseContext(this.app);
|
||||||
|
|
||||||
ShelfRequestContext _correspondingRequest;
|
ShelfRequestContext _correspondingRequest;
|
||||||
|
|
||||||
|
bool get wasClosedByHandler => _wasClosedByHandler;
|
||||||
|
|
||||||
|
void closeSilently() => _handlersAreDone = true;
|
||||||
|
|
||||||
ShelfRequestContext get correspondingRequest => _correspondingRequest;
|
ShelfRequestContext get correspondingRequest => _correspondingRequest;
|
||||||
|
|
||||||
set correspondingRequest(ShelfRequestContext value) {
|
set correspondingRequest(ShelfRequestContext value) {
|
||||||
|
@ -30,7 +37,9 @@ class ShelfResponseContext extends ResponseContext<ShelfResponseContext> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> close() {
|
Future<void> close() {
|
||||||
_isOpen = false;
|
if (!_handlersAreDone) {
|
||||||
|
_isOpen = false;
|
||||||
|
}
|
||||||
_ctrl.close();
|
_ctrl.close();
|
||||||
return super.close();
|
return super.close();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue