Skip to content

Commit

Permalink
clean up
Browse files Browse the repository at this point in the history
  • Loading branch information
rawleyfowler committed Dec 11, 2023
1 parent a7b9950 commit 3df91e4
Show file tree
Hide file tree
Showing 9 changed files with 45 additions and 33 deletions.
5 changes: 0 additions & 5 deletions examples/basic/basic.raku
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,6 @@ get('/throws-error', -> $request, $response {
# Error handler
error(X::AdHoc, -> $exn, $response { $response.status(500).write("Encountered an error. <br> $exn") });

# After middleware, Response --> Response
advice(&advice-logger);

# Static content
static('/static', '/var/www/static'); # Server static content on '/static', from '/var/www/static'

Expand All @@ -138,8 +135,6 @@ post('/form', sub ($request, $response) {

# Routers
my $router = Router.new(root => '/foo');
$router.middleware(&middleware-logger); # Append this middleware to all proceeding routes
$router.advice(&advice-logger); # Append this advice to all proceeding routes
$router.get(-> $request, $response { $response.write('foo') });
$router.post(-> $request, $response { $response.write('foo post!') });
$router.get('/bar', -> $request, $response { $response.write('foo bar') }); # Registered on /foo/bar
Expand Down
1 change: 0 additions & 1 deletion lib/Humming-Bird/Advice.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@ unit module Humming-Bird::Advice;
sub advice-logger(Humming-Bird::Glue::Response:D $response --> Humming-Bird::Glue::Response:D) is export {
my $log = "{ $response.status.Int } { $response.status } | { $response.initiator.path } | ";
$log ~= $response.header('Content-Type') ?? $response.header('Content-Type') !! "no-content";

$response.log: $log;
}
39 changes: 23 additions & 16 deletions lib/Humming-Bird/Core.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,22 @@ class Route {
has &.callback is required;
has @.middlewares; # List of functions that type Request --> Request

submethod TWEAK {
@!middlewares.prepend: @MIDDLEWARE;
}

method CALL-ME(Request:D $req) {
method CALL-ME(Request:D $req --> Response:D) {
my @middlewares = [|@!middlewares, |@MIDDLEWARE, -> $a, $b, &c { &!callback($a, $b) }];
my $res = Response.new(initiator => $req, status => HTTP::Status(200));
if @!middlewares.elems {
state &composition = @!middlewares.map({ .assuming($req, $res) }).reduce(-> &a, &b { &a({ &b }) });
# Finally, the main callback is added to the end of the chain
&composition(&!callback.assuming($req, $res));
} else {
if @middlewares.elems > 1 {
# For historical purposes this code will stay here, unfortunately, it was not performant enough.
# This code was written on the first day I started working on Humming-Bird. - RF
# state &comp = @middlewares.prepend(-> $re, $rp, &n { &!callback.assuming($req, $res) }).map({ $^a.raku.say; $^a.assuming($req, $res) }).reverse.reduce(-> &a, &b { &b.assuming(&a) } );

for @middlewares -> &middleware {
my Bool:D $next = False;
&middleware($req, $res, sub { $next = True } );
last unless $next;
}
return $res;
}
else {
# If there is are no middlewares, just process the callback
&!callback($req, $res);
}
Expand All @@ -49,7 +54,7 @@ sub split_uri(Str:D $uri --> List:D) {

sub delegate-route(Route:D $route, HTTPMethod:D $meth --> Route:D) {
die 'Route cannot be empty' unless $route.path;
die "Invalid route: { $route.path }" unless $route.path.contains('/');
die "Invalid route: { $route.path }, routes must start with a '/'" unless $route.path.contains('/');

my @uri_parts = split_uri($route.path);

Expand All @@ -70,13 +75,13 @@ class Router is export {
has Str:D $.root is required;
has @.routes;
has @!middlewares;
has @!advice = { $^a }; # List of functions that type Response --> Response
has @!advice = ( { $^a } ); # List of functions that type Response --> Response

method !add-route(Route:D $route, HTTPMethod:D $method --> Route:D) {
my &advice = [o] @!advice;
my &cb = $route.callback;
my $r = $route.clone(path => $!root ~ $route.path,
middlewares => [|@!middlewares, |$route.middlewares],
middlewares => [|$route.middlewares, |@!middlewares],
callback => { &advice(&cb($^a, $^b)) });
@!routes.push: $r;
delegate-route($r, $method);
Expand Down Expand Up @@ -287,7 +292,8 @@ sub plugin(Str:D $plugin, **@args --> Array:D) is export {
}

sub handle(Humming-Bird::Glue::Request:D $request) {
return ([o] @ADVICE).(dispatch-request($request));
state &advice-handler = [o] @ADVICE;
return &advice-handler(dispatch-request($request));
}

sub listen(Int:D $port, Str:D $addr = '0.0.0.0', :$no-block, :$timeout = 3, :$backend = Humming-Bird::Backend::HTTPServer) is export {
Expand Down Expand Up @@ -325,8 +331,9 @@ sub listen(Int:D $port, Str:D $addr = '0.0.0.0', :$no-block, :$timeout = 3, :$ba
);
say '';
say(
colored('Warning', 'yellow underline'),
': Humming-Bird is currently running in DEV mode, please set HUMMING_BIRD_ENV to PROD or PRODUCTION to enable PRODUCTION mode.'
colored('Warning', 'yellow'),
': Humming-Bird is currently running in DEV mode, please set HUMMING_BIRD_ENV to PROD or PRODUCTION to enable PRODUCTION mode.',
"\n"
) without ($*ENV<HUMMING_BIRD_ENV>);
if $no-block {
start {
Expand Down
16 changes: 14 additions & 2 deletions lib/Humming-Bird/Plugin/Logger.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,19 @@ use Humming-Bird::Advice;

unit class Humming-Bird::Plugin::Logger does Humming-Bird::Plugin;

sub pre-logger($file, $request, $response, &next) {
$request.log(sprintf("%s | %s | %s | %s", $request.method.Str, $request.path, $request.version, $request.header('User-Agent') || 'Unknown Agent'), :$file);
&next();
}

sub post-logger($file, $response) {
my $log = "{ $response.status.Int } { $response.status } | { $response.initiator.path } | ";
$log ~= $response.header('Content-Type') ?? $response.header('Content-Type') !! "No Content";
$response.log: $log;
}

method register($server, %routes, @middleware, @advice, **@args) {
@middleware.unshift: &middleware-logger;
@advice.unshift: &advice-logger;
my $file = @args[0] ?? @args[0].IO !! $*OUT;
@middleware.prepend: &pre-logger.assuming($file);
@advice.prepend: &post-logger.assuming($file);
}
4 changes: 2 additions & 2 deletions lib/Humming-Bird/Plugin/Session.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ use Humming-Bird::Advice;

unit class Humming-Bird::Plugin::Session does Humming-Bird::Plugin;

method register($server, %routes, @middleware is rw, @advice is rw, **@args) {
@middleware.unshift: &middleware-session;
method register($server, %routes, @middleware, @advice, **@args) {
@middleware.push: &middleware-session;
}
2 changes: 0 additions & 2 deletions t/02-request_encoding.rakutest
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ is $simple_post_request.header('Content-Type'), 'application/json';
is $simple_post_request.header('Content-Length'), $body.chars;
is $simple_post_request.method, POST;

say $simple_post_request.body.decode.raku;
say $body.raku;
is $simple_post_request.body.decode('latin-1'), $body, 'Is post body OK?';

my $simple_post_empty_raw_request = "POST / HTTP/1.1\r\nContent-Type: application/json\r\nContent-Length: 0\r\nHost: bob.com\r\n\r\n";
Expand Down
2 changes: 1 addition & 1 deletion t/04-middleware.rakutest
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ group((
is routes{'/'}{'hello'}{GET}.middlewares[0].raku, &middleware-logger.raku, 'Is middleware of group properly assigned?';
is routes{'/'}{'hello'}{'world'}{GET}.middlewares[0].raku, &middleware-logger.raku, 'Is middleware of group properly assigned?';

middleware(-> $request, $response, &next { $response.html('Foo Bar') });
middleware(sub ($request, $response, &next) { $response.html('Foo Bar') });
get('/foobar', -> $request, $response { $response.write('YOU CANT SEE ME') });
my $simple_request = Request.decode: "GET /foobar HTTP/1.1\r\nHost: bob.com\r\n";
is routes{'/'}{'foobar'}{GET}($simple_request).body, Buf.new('Foo Bar'.encode), 'Is global middleware OK?';
Expand Down
2 changes: 1 addition & 1 deletion t/09-routers.rakutest
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ is routes{'/'}{'home'}{GET}(Request.new(path => '/home', method => GET, version
is routes{'/'}{'home'}{'abc'}{GET}(Request.new(path => '/home/abc', method => GET, version => 'HTTP/1.1')).status, HTTP::Status(200), 'Is response status OK?';
is routes{'/'}{'home'}{'abc'}{GET}(Request.new(path => '/home/abc', method => GET, version => 'HTTP/1.1')).body.decode, 'abc', 'Is response body OK?';
is routes{'/'}{'home'}{'abc'}{GET}(Request.new(path => '/home/abc', method => GET, version => 'HTTP/1.1')).header('X-Test'), 'abc', 'Is advice working?';
is routes{'/'}{'home'}{'abc'}{GET}(Request.new(path => '/home/abc', method => GET, version => 'HTTP/1.1')).header('X-Middleware'), '123', 'Is advice working?';
is routes{'/'}{'home'}{'abc'}{GET}(Request.new(path => '/home/abc', method => GET, version => 'HTTP/1.1')).header('X-Middleware'), '123', 'Is middleware working?';

done-testing;
7 changes: 4 additions & 3 deletions t/13-plugin.rakutest
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use Humming-Bird::Backend;
use Humming-Bird::Middleware;
use Humming-Bird::Advice;

plan 7;
plan 8;

class TestBackend does Humming-Bird::Backend {
method listen(&handler) {
Expand All @@ -17,13 +17,14 @@ class TestBackend does Humming-Bird::Backend {

lives-ok sub { plugin('Config', 't/static/.humming-bird.json'); }, 'Does plugin not die?';
lives-ok sub { plugin 'Logger'; }, 'Does other plugin not die?';
lives-ok sub { plugin 'Session'; }, 'Does other plugin not die?';
lives-ok sub { listen(8080, :backend(TestBackend)); }, 'Does plugin register ok?';
ok Humming-Bird::Glue::HTTPAction.^can('config'), 'Did plugin properly run?';

my $action = Humming-Bird::Glue::HTTPAction.new;

ok $action.config<database_url> eq 'foo', 'Did config parse properly?';
is middleware()[0].raku, &middleware-logger.raku, 'Did logger properly setup middleware?';
is advice()[0].raku, &advice-logger.raku, 'Did logger properly setup advice?';
is middleware().elems, 2, 'Did logger properly setup middleware?';
is advice().elems, 2, 'Did logger properly setup advice?'; # This has to be 2 because of the identity function that implicity exists

done-testing;

0 comments on commit 3df91e4

Please sign in to comment.