From d52b2643b978d6d9c4550f7890969fd8cc0c9641 Mon Sep 17 00:00:00 2001 From: teknomunk Date: Mon, 12 Dec 2022 19:30:06 -0600 Subject: [PATCH] Implement queuing inbox (save to disk for processing non-realtime processing) --- src/controller/inbox.c | 81 +++++++++++++++++++++++++++ src/controller/inbox.h | 8 +++ src/controller/main.c | 3 + src/view/inbox_envelope.json.template | 5 ++ 4 files changed, 97 insertions(+) create mode 100644 src/controller/inbox.c create mode 100644 src/controller/inbox.h create mode 100644 src/view/inbox_envelope.json.template diff --git a/src/controller/inbox.c b/src/controller/inbox.c new file mode 100644 index 0000000..78577d0 --- /dev/null +++ b/src/controller/inbox.c @@ -0,0 +1,81 @@ +#include "inbox.h" + +#include "http_server/http_request.h" + +#include +#include +#include +#include + +static void write_json_escaped( FILE* f, const char* str ) +{ + while( *str ) { + switch( *str ) { + case '\"': + fprintf( f, "\\\"" ); + break; + case '\n': + fprintf( f, "\\\n" ); + break; + case '\t': + fprintf( f, "\\\t" ); + break; + default: + fputc( *str, f ); + } + ++str; + } +} + +static void io_copy( FILE* in, FILE* out ) +{ + char buffer[512]; + for(;;) { + int count = fread( buffer, 1, 512, in ); + if( count == 0 ) { return; } + fwrite( buffer, 1, count, out ); + } +} + +bool route_inbox( struct http_request* req ) +{ + // No subroutes + if( !http_request_route_term( req, "" ) ) { return false; } + if( !http_request_route_method( req, "POST" ) ) { return false; } + + printf( "Queue inbox items for later processing\n" ); + + const char* signature = http_request_get_header(req,"Signature"); + const char* date = http_request_get_header(req,"Date"); + + printf( "Signature: %s\nDate: %s", signature, date ); + + FILE* body = http_request_get_request_data(req); + + uint64_t time_ns; + struct timespec ts; + clock_gettime( CLOCK_REALTIME, &ts ); + time_ns = (uint64_t)ts.tv_sec * 1000000000 + (uint64_t)ts.tv_nsec; + + char filename[512]; + snprintf( filename, 512, "data/inbox/%llu.json", time_ns ); + char tmp_filename[512+32]; + snprintf( tmp_filename, 512+32, "%s.tmp-%d", filename, rand() ); + + FILE* f = fopen( tmp_filename, "w" ); + if( !f ) { + printf( "Failed to open %s\n", tmp_filename ); + return false; + } + #define RENDER + #include "src/view/inbox_envelope.json.inc" + #undef RENDER + fclose(f); + + rename( tmp_filename, filename ); + + http_request_send_headers( req, 200, "text/plain", true ); + + return true; +} + diff --git a/src/controller/inbox.h b/src/controller/inbox.h new file mode 100644 index 0000000..454a78a --- /dev/null +++ b/src/controller/inbox.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +struct http_request; + +bool route_inbox( struct http_request* req ); + diff --git a/src/controller/main.c b/src/controller/main.c index a574281..4760fa9 100644 --- a/src/controller/main.c +++ b/src/controller/main.c @@ -5,6 +5,7 @@ #include "controller/webfinger.h" #include "controller/nodeinfo.h" #include "controller/owner.h" +#include "controller/inbox.h" bool route_asset( struct http_request* req ) { @@ -37,6 +38,8 @@ bool route_request( struct http_request* req ) return route_oauth( req ); } else if( http_request_route( req, "/owner" ) ) { return route_owner( req ); + } else if( http_request_route( req, "/inbox" ) ) { + return route_inbox( req ); } else if( http_request_route( req, "/.well-known" ) ) { if( http_request_route( req, "/webfinger?" ) ) { return route_wellknown_webfinger( req ); diff --git a/src/view/inbox_envelope.json.template b/src/view/inbox_envelope.json.template new file mode 100644 index 0000000..5b25c89 --- /dev/null +++ b/src/view/inbox_envelope.json.template @@ -0,0 +1,5 @@ +{ + "signature": "%( write_json_escaped( f, signature ); )", + "date": "%( write_json_escaped( f, signature ); )", + "body": %( io_copy( body, f ); ) +}