Skip to content

Commit

Permalink
chore: Rework req res hook (#138)
Browse files Browse the repository at this point in the history
* rework request :onBefore and :onAfter hook

* _

* _

* _

* _

* improvements to spanner

* fix implementation for re-attaching nodes back into pharaoh tree

* rework pharaoh exports

* _
  • Loading branch information
codekeyz authored Jan 22, 2025
1 parent 0be851e commit f21d4db
Show file tree
Hide file tree
Showing 30 changed files with 319 additions and 381 deletions.
12 changes: 7 additions & 5 deletions packages/pharaoh/lib/pharaoh.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
library;

export 'src/core.dart' hide $PharaohImpl;
export 'src/view/view.dart';
export 'src/http/cookie.dart';
export 'src/http/request.dart';
export 'src/http/response.dart';
export 'src/http/router.dart';

export 'src/shelf_interop/adapter.dart';
export 'src/shelf_interop/shelf.dart' show ShelfBody;

export 'src/utils/utils.dart';
export 'src/utils/exceptions.dart';
export 'src/router/router_handler.dart';

export 'src/middleware/session_mw.dart';
export 'src/middleware/body_parser.dart';
export 'src/middleware/cookie_parser.dart';
export 'src/middleware/request_logger.dart';

// shelf
export 'src/shelf_interop/adapter.dart';
export 'src/shelf_interop/shelf.dart' show ShelfBody;
export 'package:spanner/spanner.dart' show HTTPMethod;
11 changes: 3 additions & 8 deletions packages/pharaoh/lib/pharaoh_next.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
export 'src/_next/validation.dart';
export 'src/_next/router.dart';
export 'pharaoh.dart';
export 'src/_next/core.dart';
export 'src/_next/http.dart';
export 'src/core.dart';

export 'src/http/response.dart';
export 'src/http/request.dart';
export 'src/router/router_handler.dart';
export 'package:spanner/spanner.dart' show HTTPMethod;
export 'src/_next/router.dart';
export 'src/_next/validation.dart';
6 changes: 3 additions & 3 deletions packages/pharaoh/lib/src/_next/_core/core_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ class _PharaohNextImpl implements Application {
int get port => config.port;

Pharaoh _createPharaohInstance({OnErrorCallback? onException}) {
final pharaoh = Pharaoh()
..useSpanner(_spanner)
..viewEngine = _viewEngine;
final pharaoh = Pharaoh()..useSpanner(_spanner);
Pharaoh.viewEngine = _viewEngine;

if (onException != null) pharaoh.onError(onException);
return pharaoh;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/pharaoh/lib/src/_next/http.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import 'dart:io';
import '../http/request.dart';
import '../http/response.dart';
import '../middleware/session_mw.dart';
import '../router/router_handler.dart';
import '../http/router.dart';
import 'core.dart';

@inject
Expand Down
2 changes: 1 addition & 1 deletion packages/pharaoh/lib/src/_next/router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'package:grammer/grammer.dart';
import 'package:meta/meta.dart';
import '../http/request.dart';
import '../http/response.dart';
import '../router/router_handler.dart';
import '../http/router.dart';
import 'validation.dart';
import 'core.dart';

Expand Down
55 changes: 0 additions & 55 deletions packages/pharaoh/lib/src/core.dart

This file was deleted.

4 changes: 1 addition & 3 deletions packages/pharaoh/lib/src/http/request.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import 'dart:io';

import 'package:http_parser/http_parser.dart';
import 'package:pharaoh/pharaoh.dart';
import 'package:spanner/spanner.dart';

import 'message.dart';

Expand All @@ -15,8 +14,7 @@ class RequestContext {
/// cookies & session
static const String cookies = '$phar.cookies';
static const String signedCookies = '$phar.signedcookies';
static const String session = '$phar.session.cookie';
static const String sessionId = '$phar.session.id';
static const String session = '$phar.session';
}

HTTPMethod getHttpMethod(HttpRequest req) => switch (req.method) {
Expand Down
2 changes: 1 addition & 1 deletion packages/pharaoh/lib/src/http/request_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class _$RequestImpl extends Request {
Session? get session => _context[RequestContext.session];

@override
String? get sessionId => _context[RequestContext.sessionId];
String? get sessionId => session?.id;

@override
Object? operator [](String name) => _context[name];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,70 @@
part of 'core.dart';
import 'dart:async';
import 'dart:io';

class $PharaohImpl extends RouterContract
import 'package:collection/collection.dart';
import 'package:http_parser/http_parser.dart';
import 'package:meta/meta.dart';
import 'package:spanner/spanner.dart';
import 'package:spanner/src/tree/tree.dart' show BASE_PATH;

import '../middleware/body_parser.dart';
import '../middleware/session_mw.dart';
import '../shelf_interop/shelf.dart' as shelf;
import '../utils/exceptions.dart';
import '../view/view.dart';

import 'request.dart';
import 'response.dart';

part 'router/router_contract.dart';
part 'router/router_handler.dart';

typedef PharaohError = ({Object exception, StackTrace trace});

typedef OnErrorCallback = FutureOr<Response> Function(
PharaohError error,
Request req,
Response res,
);

abstract class Pharaoh implements RouterContract {
static _$GroupRouter get router => _$GroupRouter();

factory Pharaoh() => _$PharaohImpl();

static ViewEngine? viewEngine;

void onError(OnErrorCallback onError);

void useSpanner(Spanner spanner);

void useRequestHook(RequestHook hook);

void group(String path, _$GroupRouter router);

Uri get uri;

Future<Pharaoh> listen({int port = 3000});

@visibleForTesting
void handleRequest(HttpRequest httpReq);

Future<void> shutdown();
}

class _$PharaohImpl extends RouterContract
with RouteDefinitionMixin
implements Pharaoh {
late final HttpServer _server;

OnErrorCallback? _onErrorCb;

static ViewEngine? viewEngine_;

final List<ReqResHook> _preResponseHooks = [
final List<RequestHook> _requestHooks = [
sessionPreResponseHook,
viewRenderHook,
];

$PharaohImpl() {
_$PharaohImpl() {
useSpanner(Spanner());
use(bodyParser);
}
Expand Down Expand Up @@ -42,15 +92,6 @@ class $PharaohImpl extends RouterContract
);
}

@override
Pharaoh group(final String path, final RouterContract router) {
if (router is! GroupRouter) {
throw PharaohException.value('Router is not an instance of GroupRouter');
}
router.commit(path, spanner);
return this;
}

@override
Future<Pharaoh> listen({int port = 3000}) async {
_server = await HttpServer.bind(InternetAddress.anyIPv4, port, shared: true)
Expand Down Expand Up @@ -114,21 +155,22 @@ class $PharaohImpl extends RouterContract
req.params.addAll(routeResult.params);
}

reqRes = await executeHandlers(resolvedHandlers, reqRes);

for (final job in _preResponseHooks) {
reqRes = await Future.microtask(() => job(reqRes));
for (final hook in _requestHooks.whereNot((e) => e.onBefore == null)) {
reqRes = await hook.onBefore!.call(req, reqRes.res);
}

if (!reqRes.res.ended) {
return reqRes.merge(routeNotFound());
reqRes = await executeHandlers(resolvedHandlers, reqRes);
if (!reqRes.res.ended) reqRes = reqRes.merge(routeNotFound());

for (final hook in _requestHooks.whereNot((e) => e.onAfter == null)) {
reqRes = await hook.onAfter!.call(reqRes.req, reqRes.res);
}

return reqRes;
}

Future<void> forward(HttpRequest request, Response res_) async {
var coding = res_.headers['transfer-encoding'];
var coding = res_.headers[HttpHeaders.transferEncodingHeader];

final statusCode = res_.statusCode;
request.response.statusCode = statusCode;
Expand Down Expand Up @@ -187,14 +229,21 @@ class $PharaohImpl extends RouterContract
Future<void> shutdown() async => _server.close();

@override
ViewEngine? get viewEngine => viewEngine_;
void onError(OnErrorCallback errorCb) => _onErrorCb = errorCb;

@override
set viewEngine(ViewEngine? engine) => viewEngine_ = engine;
void useRequestHook(RequestHook hook) => _requestHooks.add(hook);

@override
void onError(OnErrorCallback errorCb) => _onErrorCb = errorCb;
void group(String path, _$GroupRouter router) {
spanner.attachNode(path, router.spanner.root);
}
}

// ignore: constant_identifier_names
const _XPoweredByHeader = 'X-Powered-By';

class _$GroupRouter extends RouterContract with RouteDefinitionMixin {
_$GroupRouter() {
useSpanner(Spanner());
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
import 'package:spanner/spanner.dart';
import 'package:spanner/src/tree/tree.dart' show BASE_PATH;
part of '../router.dart';

import 'router_contract.dart';
import 'router_handler.dart';
sealed class RouterContract {
void get(String path, RequestHandler hdler);

void post(String path, RequestHandler hdler);

void put(String path, RequestHandler hdler);

void delete(String path, RequestHandler hdler);

void head(String path, RequestHandler hdler);

void patch(String path, RequestHandler hdler);

void options(String path, RequestHandler hdler);

void trace(String path, RequestHandler hdler);

void use(Middleware middleware);

void on(String path, Middleware hdler, {HTTPMethod method = HTTPMethod.ALL});
}

mixin RouteDefinitionMixin on RouterContract {
late Spanner spanner;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import 'dart:async';

import '../http/request.dart';
import '../http/response.dart';
import '../utils/exceptions.dart';
part of '../router.dart';

typedef ReqRes = ({Request req, Response res});

typedef ReqResHook = FutureOr<ReqRes> Function(ReqRes reqRes);
final class RequestHook {
final FutureOr<ReqRes> Function(Request req, Response res)? onBefore;
final FutureOr<ReqRes> Function(Request req, Response res)? onAfter;
const RequestHook({this.onAfter, this.onBefore});
}

typedef NextFunction<Next> = dynamic Function([dynamic result, Next? chain]);

Expand All @@ -19,13 +19,13 @@ typedef Middleware = FutureOr<void> Function(
);

extension ReqResExtension on ReqRes {
ReqRes merge(dynamic val) {
if (val == null) return this;
if (val is Request) return (req: val, res: this.res);
if (val is Response) return (req: this.req, res: val);
if (val is ReqRes) return val;
throw PharaohException.value('Invalid Type used on merge', val);
}
ReqRes merge(dynamic val) => switch (val) {
ReqRes() => val,
Response() => (req: this.req, res: val),
Request() => (req: val, res: this.res),
null => this,
_ => throw PharaohException.value('Invalid Type used on merge', val)
};
}

extension MiddlewareChainExtension on Middleware {
Expand Down
2 changes: 1 addition & 1 deletion packages/pharaoh/lib/src/middleware/body_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import 'package:mime/mime.dart';

import '../http/request.dart';
import '../http/response.dart';
import '../router/router_handler.dart';
import '../http/router.dart';

sealed class MimeType {
static const String multiPartForm = 'multipart/form-data';
Expand Down
2 changes: 1 addition & 1 deletion packages/pharaoh/lib/src/middleware/cookie_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'package:pharaoh/src/utils/utils.dart';

import '../http/cookie.dart';
import '../http/request.dart';
import '../router/router_handler.dart';
import '../http/router.dart';

Middleware cookieParser({CookieOpts opts = const CookieOpts()}) {
opts.validate();
Expand Down
Loading

0 comments on commit f21d4db

Please sign in to comment.