Rework memory management, use per-thread arenas
This commit is contained in:
2
CONFIG.h
2
CONFIG.h
@ -7,4 +7,6 @@
|
||||
# define CONFIG_LISTEN_URL "http://localhost:5000"
|
||||
#endif
|
||||
|
||||
#define BUNDLE_ZIP_COMPRESSION 10
|
||||
|
||||
#endif // CONFIG_H_
|
||||
|
6
baked.c
6
baked.c
@ -3,10 +3,11 @@
|
||||
#include "gebs/gebs.h"
|
||||
#include "incbin/incbin.h"
|
||||
#include "stb/stb_ds.h"
|
||||
#include "zip.h"
|
||||
|
||||
#include "baked.h"
|
||||
#include "locked.h"
|
||||
#include "zip.h"
|
||||
#include "CONFIG.h"
|
||||
|
||||
INCBIN(bundle_zip, "./bundle.zip");
|
||||
|
||||
@ -37,7 +38,7 @@ void init_baked_resources(void)
|
||||
{
|
||||
lockx(&baked_resources);
|
||||
|
||||
struct zip_t *zip = zip_stream_open(bundle_zip_data, bundle_zip_size, ZIP_DEFAULT_COMPRESSION_LEVEL, 'r');
|
||||
struct zip_t *zip = zip_stream_open(bundle_zip_data, bundle_zip_size, BUNDLE_ZIP_COMPRESSION, 'r');
|
||||
size_t n = zip_entries_total(zip);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
zip_entry_openbyindex(zip, i);
|
||||
@ -73,7 +74,6 @@ bool get_baked_resource_path(char *key, char *buf, size_t size)
|
||||
if (shgeti(baked_resources.value, key) != -1) {
|
||||
Baked_Resource_Value brv = shget(baked_resources.value, key);
|
||||
snprintf(buf, size, "/proc/%d/fd/%d", getpid(), brv.memfd);
|
||||
unlockx(&baked_resources);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
10
build.c
10
build.c
@ -3,6 +3,7 @@
|
||||
#define GEBS_IMPLEMENTATION
|
||||
#include "gebs/gebs.h"
|
||||
#include "./zip/src/zip.c"
|
||||
#include "CONFIG.h"
|
||||
|
||||
char *prog = NULL;
|
||||
|
||||
@ -44,7 +45,6 @@ int main(int argc, char ** argv)
|
||||
"./routes.h",
|
||||
"./baked.c",
|
||||
"./baked.h",
|
||||
"./clonestr.h",
|
||||
"./commit.h",
|
||||
"./timer.c",
|
||||
"./timer.h",
|
||||
@ -102,7 +102,7 @@ int main(int argc, char ** argv)
|
||||
CMD("cc", "-DHAVE_STRDUP", "-DHAVE_FNMATCH_H", "-o", "gpp1", "gpp/gpp.c");
|
||||
}
|
||||
|
||||
struct zip_t *zip = zip_open("./bundle.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||
struct zip_t *zip = zip_open("./bundle.zip", BUNDLE_ZIP_COMPRESSION, 'w');
|
||||
defer { zip_close(zip); }
|
||||
|
||||
for (size_t i = 0; i < sizeof(bundle_zip_deps)/sizeof(bundle_zip_deps[0]); i++) {
|
||||
@ -125,11 +125,13 @@ int main(int argc, char ** argv)
|
||||
#define TARGET "-o", "aboba"
|
||||
#if MY_DEBUG
|
||||
#define CFLAGS "-fsanitize=address", "-fPIC", "-ggdb"
|
||||
#define DEFINES "-DMY_DEBUG=1", "-D_GNU_SOURCE", "-DGEBS_NO_PREFIX", "-DINCBIN_PREFIX=", "-DINCBIN_STYLE=INCBIN_STYLE_SNAKE"
|
||||
#define DEFINES "-DMY_DEBUG=1", "-D_GNU_SOURCE", "-DGEBS_NO_PREFIX", "-DINCBIN_PREFIX=", "-DINCBIN_STYLE=INCBIN_STYLE_SNAKE", \
|
||||
"-DGEBS_ENABLE_PTHREAD_FEATURES"
|
||||
#define EXTRA_SOURCES "./cJSON/cJSON.c", "./zip/src/zip.c", "./md5-c/md5.c"
|
||||
#else
|
||||
#define CFLAGS "-fPIC"
|
||||
#define DEFINES "-DMY_DEBUG=0", "-D_GNU_SOURCE", "-DGEBS_NO_PREFIX", "-DINCBIN_PREFIX=", "-DINCBIN_STYLE=INCBIN_STYLE_SNAKE"
|
||||
#define DEFINES "-DMY_DEBUG=0", "-D_GNU_SOURCE", "-DGEBS_NO_PREFIX", "-DINCBIN_PREFIX=", "-DINCBIN_STYLE=INCBIN_STYLE_SNAKE", \
|
||||
"-DGEBS_ENABLE_PTHREAD_FEATURES"
|
||||
#define EXTRA_SOURCES "./cJSON/cJSON.c", "./zip/src/zip.c"
|
||||
#endif
|
||||
#define SOURCES "./main.c", "./routes.c", "./baked.c", "./timer.c"
|
||||
|
@ -1,11 +1,5 @@
|
||||
#ifndef CLONESTR_H_
|
||||
#define CLONESTR_H_
|
||||
|
||||
#define clonestr(str) \
|
||||
({ \
|
||||
char *__p = malloc(strlen((str))+1); \
|
||||
strcpy(__p, (str)); \
|
||||
(__p); \
|
||||
})
|
||||
|
||||
#endif // CLONESTR_H_
|
||||
|
2
gebs
2
gebs
Submodule gebs updated: 596bb1ef76...db8389f7d5
2
locked.h
2
locked.h
@ -3,7 +3,7 @@
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#define locked_init(x) { .value = (x), .lock = PTHREAD_MUTEX_INITIALIZER }
|
||||
#define locked_init(x) { .value = x, .lock = PTHREAD_MUTEX_INITIALIZER }
|
||||
#define locked(T) struct { T value; pthread_mutex_t lock; }
|
||||
|
||||
#define lockx(x) pthread_mutex_lock(&(x)->lock)
|
||||
|
149
main.c
149
main.c
@ -9,23 +9,39 @@
|
||||
#include "mongoose/mongoose.h"
|
||||
#define STB_DS_IMPLEMENTATION
|
||||
#include "stb/stb_ds.h"
|
||||
#include "md5-c/md5.h"
|
||||
|
||||
#include "routes.h"
|
||||
#include "baked.h"
|
||||
#include "timer.h"
|
||||
#include "CONFIG.h"
|
||||
#include "clonestr.h"
|
||||
#include "locked.h"
|
||||
|
||||
static locked(Route *) route_hashtable = locked_init(nil);
|
||||
static locked(char *) baked_dump_path = locked_init(nil);
|
||||
|
||||
char *clonestr_alloc(Allocator *alloc, char *s)
|
||||
{
|
||||
char *p = gebs_malloc(alloc, strlen(s)+1);
|
||||
strcpy(p, s);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *zmalloc_alloc(Allocator *alloc, size_t size)
|
||||
{
|
||||
void *p = gebs_malloc(alloc, size);
|
||||
memset(p, 0, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
void run_in_thread(void *(*f)(void *), void *p)
|
||||
{
|
||||
pthread_t tid = 0;
|
||||
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
pthread_create(&tid, &attr, f, p);
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
@ -33,60 +49,61 @@ void run_in_thread(void *(*f)(void *), void *p)
|
||||
void *route_thread_function(void *param)
|
||||
{
|
||||
Route_Thread_Data *data = (Route_Thread_Data *)param;
|
||||
Arena *arena = data->arena;
|
||||
|
||||
struct mg_http_message http_msg = {0};
|
||||
int r = mg_http_parse(data->message.buf, data->message.len, &http_msg);
|
||||
if (r <= 0) {
|
||||
Route_Result result = {0};
|
||||
result.status_code = 400;
|
||||
result.type = ROUTE_RESULT_DYNAMIC;
|
||||
/* list_append(&result.headers, clonestr("Content-Type: text/plain")); */
|
||||
sb_append_nstr(&result.body, "Could not parse HTTP request");
|
||||
sb_finish(&result.body);
|
||||
Route_Result *result = zmalloc_alloc((Allocator *)arena, sizeof(*result));
|
||||
result->arena = arena;
|
||||
result->status_code = 400;
|
||||
result->type = ROUTE_RESULT_DYNAMIC;
|
||||
sb_append_nstr_alloc(arena, &result->body, "Could not parse HTTP request");
|
||||
sb_finish_alloc(arena, &result->body);
|
||||
mg_wakeup(data->mgr, data->conn_id, &result, sizeof(result));
|
||||
free(data->message.buf);
|
||||
free(data);
|
||||
return nil;
|
||||
pthread_exit(nil);
|
||||
} else {
|
||||
if (mg_match(http_msg.uri, mg_str("/bakedres/*"), nil)) {
|
||||
Route_Result *result = zmalloc_alloc((Allocator *)arena, sizeof(*result));
|
||||
result->arena = arena;
|
||||
result->type = ROUTE_RESULT_STATIC;
|
||||
|
||||
char *p = gebs_malloc(arena, http_msg.uri.len+1);
|
||||
strncpy(p, http_msg.uri.buf, http_msg.uri.len);
|
||||
p[http_msg.uri.len] = 0;
|
||||
|
||||
char *file = basename(p);
|
||||
char *full_path = gebs_malloc(arena, PATH_MAX);
|
||||
|
||||
lockx(&baked_dump_path);
|
||||
snprintf(full_path, PATH_MAX, "%s/%s", baked_dump_path.value, file);
|
||||
unlockx(&baked_dump_path);
|
||||
|
||||
sb_append_nstr_alloc(arena, &result->body, full_path);
|
||||
sb_finish_alloc(arena, &result->body);
|
||||
mg_wakeup(data->mgr, data->conn_id, &result, sizeof(result));
|
||||
free(data->message.buf);
|
||||
free(data);
|
||||
pthread_exit(nil);
|
||||
} else {
|
||||
char key[MG_PATH_MAX] = {0};
|
||||
strncpy(key, http_msg.uri.buf, http_msg.uri.len);
|
||||
lockx(&route_hashtable);
|
||||
ssize_t idx = shgeti(route_hashtable.value, key);
|
||||
|
||||
Route_Result *result = zmalloc_alloc((Allocator *)arena, sizeof(*result));
|
||||
result->arena = arena;
|
||||
route_hashtable.value[idx].value((Allocator *)arena, &http_msg, result, route_hashtable.value[idx].context_data);
|
||||
unlockx(&route_hashtable);
|
||||
mg_wakeup(data->mgr, data->conn_id, &result, sizeof(result));
|
||||
|
||||
free(data->message.buf);
|
||||
free(data);
|
||||
pthread_exit(nil);
|
||||
}
|
||||
}
|
||||
|
||||
if (mg_match(http_msg.uri, mg_str("/bakedres/*"), nil)) {
|
||||
Route_Result result = {0};
|
||||
result.type = ROUTE_RESULT_STATIC;
|
||||
|
||||
char *p = malloc(http_msg.uri.len+1);
|
||||
strncpy(p, http_msg.uri.buf, http_msg.uri.len);
|
||||
p[http_msg.uri.len] = 0;
|
||||
|
||||
char *file = basename(p);
|
||||
char *full_path = malloc(PATH_MAX);
|
||||
|
||||
lockx(&baked_dump_path);
|
||||
snprintf(full_path, PATH_MAX, "%s/%s", baked_dump_path.value, file);
|
||||
unlockx(&baked_dump_path);
|
||||
|
||||
sb_append_nstr(&result.body, full_path);
|
||||
sb_finish(&result.body);
|
||||
free(full_path);
|
||||
free(p);
|
||||
mg_wakeup(data->mgr, data->conn_id, &result, sizeof(result));
|
||||
free(data->message.buf);
|
||||
free(data);
|
||||
return nil;
|
||||
}
|
||||
|
||||
char key[MG_PATH_MAX] = {0};
|
||||
strncpy(key, http_msg.uri.buf, http_msg.uri.len);
|
||||
lockx(&route_hashtable);
|
||||
ssize_t idx = shgeti(route_hashtable.value, key);
|
||||
|
||||
Route_Result result = {0};
|
||||
route_hashtable.value[idx].value(&http_msg, &result, route_hashtable.value[idx].context_data);
|
||||
unlockx(&route_hashtable);
|
||||
mg_wakeup(data->mgr, data->conn_id, &result, sizeof(result));
|
||||
|
||||
free(data->message.buf);
|
||||
free(data);
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@ -99,18 +116,20 @@ void event_handler(struct mg_connection *conn, int ev, void *ev_data)
|
||||
data->message = mg_strdup(msg->message);
|
||||
data->conn_id = conn->id;
|
||||
data->mgr = conn->mgr;
|
||||
data->arena = malloc(sizeof(*data->arena));
|
||||
*data->arena = arena_get();
|
||||
run_in_thread(&route_thread_function, data);
|
||||
} else if (ev == MG_EV_WAKEUP) {
|
||||
struct mg_str *data = (struct mg_str *)ev_data;
|
||||
Route_Result *result = (Route_Result *)data->buf;
|
||||
|
||||
Route_Result *result = *(Route_Result **)data->buf;
|
||||
Arena *arena = result->arena;
|
||||
|
||||
Gebs_String_Builder sb = {0};
|
||||
defer { sb_free(&sb); }
|
||||
nsl_join(&result->headers, &sb, "\r\n");
|
||||
nsl_join_alloc(arena, &result->headers, &sb, "\r\n");
|
||||
if (result->headers.count > 0) {
|
||||
sb_append_nstr(&sb, "\r\n");
|
||||
sb_append_nstr_alloc(arena, &sb, "\r\n");
|
||||
}
|
||||
sb_finish(&sb);
|
||||
sb_finish_alloc(arena, &sb);
|
||||
|
||||
if (result->type == ROUTE_RESULT_DYNAMIC) {
|
||||
mg_http_reply(conn, result->status_code, sb.items, "%s", result->body.items);
|
||||
@ -119,11 +138,8 @@ void event_handler(struct mg_connection *conn, int ev, void *ev_data)
|
||||
mg_http_serve_file(conn, ev_data, path, &(struct mg_http_serve_opts){0});
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < result->headers.count; i++) {
|
||||
free(result->headers.items[i]);
|
||||
}
|
||||
list_free(&result->headers);
|
||||
sb_free(&result->body);
|
||||
arena_destroy(arena);
|
||||
free(arena);
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,11 +159,11 @@ void init_route_hashtable(void)
|
||||
{
|
||||
lockx(&route_hashtable);
|
||||
shdefault(route_hashtable.value, &route_page_not_found);
|
||||
shput(route_hashtable.value, clonestr("/"), &route_home);
|
||||
shput(route_hashtable.value, clonestr("/page-missing"), &route_page_not_found);
|
||||
shput(route_hashtable.value, clonestr("/blog"), &route_blog);
|
||||
shput(route_hashtable.value, clonestr_alloc(&default_allocator, "/"), &route_home);
|
||||
shput(route_hashtable.value, clonestr_alloc(&default_allocator, "/page-missing"), &route_page_not_found);
|
||||
shput(route_hashtable.value, clonestr_alloc(&default_allocator, "/blog"), &route_blog);
|
||||
#if MY_DEBUG
|
||||
shput(route_hashtable.value, clonestr("/build-id"), &route_build_id);
|
||||
shput(route_hashtable.value, clonestr_alloc(&default_allocator, "/build-id"), &route_build_id);
|
||||
#endif
|
||||
|
||||
baked_resource_each(&route_hashtable_put_blogs, nil);
|
||||
@ -250,13 +266,18 @@ void populate_baked_dump(char *baked_dump)
|
||||
unlock_baked_resources();
|
||||
}
|
||||
|
||||
volatile bool alive = true;
|
||||
volatile sig_atomic_t alive = true;
|
||||
|
||||
void graceful_shutdown(int no) { alive = false; }
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
signal(SIGINT, &graceful_shutdown);
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = &graceful_shutdown;
|
||||
sa.sa_flags = 0;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigaction(SIGINT, &sa, nil);
|
||||
|
||||
start_timer();
|
||||
|
||||
init_baked_resources();
|
||||
|
206
routes.c
206
routes.c
@ -7,10 +7,11 @@
|
||||
|
||||
#include "routes.h"
|
||||
#include "baked.h"
|
||||
#include "clonestr.h"
|
||||
#include "commit.h"
|
||||
#include "timer.h"
|
||||
|
||||
extern char *clonestr_alloc(Allocator *alloc, char *s);
|
||||
|
||||
#define INTERNAL_SERVER_ERROR_MSG "Internal server error ;(. Try again later..."
|
||||
|
||||
#define META_TAGS \
|
||||
@ -19,65 +20,61 @@
|
||||
"<meta name=\"author\" content=\"kamkow1\">" \
|
||||
"<meta name=\"application-name\" content=\"aboba\">"
|
||||
|
||||
void make_internal_server_error(Route_Result *result)
|
||||
void make_application_json(Allocator *alloc, Route_Result *result, int code, cJSON *root)
|
||||
{
|
||||
result->status_code = 500;
|
||||
result->type = ROUTE_RESULT_DYNAMIC;
|
||||
list_append(&result->headers, "Content-Type: text/plain");
|
||||
sb_append_nstr(&result->body, INTERNAL_SERVER_ERROR_MSG);
|
||||
sb_finish(&result->body);
|
||||
}
|
||||
size_t buf_size = 512;
|
||||
char *buf = gebs_malloc(alloc, buf_size);
|
||||
|
||||
void make_application_json(Route_Result *result, int code, cJSON *root)
|
||||
{
|
||||
char *root_text = cJSON_PrintUnformatted(root);
|
||||
defer { free(root_text); }
|
||||
cJSON_PrintPreallocated(root, buf, buf_size, false);
|
||||
|
||||
result->status_code = code;
|
||||
result->type = ROUTE_RESULT_DYNAMIC;
|
||||
list_append(&result->headers, clonestr("Content-Type: application/json"));
|
||||
sb_append_nstr(&result->body, root_text);
|
||||
sb_finish(&result->body);
|
||||
list_append(&result->headers, clonestr_alloc(alloc, "Content-Type: application/json"));
|
||||
sb_append_nstr_alloc(alloc, &result->body, buf);
|
||||
sb_finish_alloc(alloc, &result->body);
|
||||
}
|
||||
|
||||
void make_text(Route_Result *result, char *subtype, int code, char *in)
|
||||
void make_text(Allocator *alloc, Route_Result *result, char *subtype, int code, char *in)
|
||||
{
|
||||
char type[100];
|
||||
snprintf(type, sizeof(type), "Content-Type: text/%s", subtype);
|
||||
|
||||
result->status_code = code;
|
||||
result->type = ROUTE_RESULT_DYNAMIC;
|
||||
list_append(&result->headers, clonestr(type));
|
||||
sb_append_nstr(&result->body, in);
|
||||
list_append_alloc(alloc, &result->headers,
|
||||
clonestr_alloc(alloc, fmt("Content-Type: text/%s", subtype)));
|
||||
sb_append_nstr_alloc(alloc, &result->body, in);
|
||||
sb_finish(&result->body);
|
||||
}
|
||||
|
||||
bool gpp_run(char *path, NString_List *env, String_Builder *out)
|
||||
void make_internal_server_error(Allocator *alloc, Route_Result *result)
|
||||
{
|
||||
make_text(alloc, result, "plain", 500, INTERNAL_SERVER_ERROR_MSG);
|
||||
}
|
||||
|
||||
bool gpp_run(Allocator *alloc, char *path, NString_List *env, String_Builder *out)
|
||||
{
|
||||
Cmd cmd = {0};
|
||||
defer { cmd_free(&cmd); }
|
||||
|
||||
char gpp1[PATH_MAX];
|
||||
if (!get_baked_resource_path("gpp1", gpp1, sizeof(gpp1))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cmd_append(&cmd, gpp1);
|
||||
cmd_append(&cmd, "-H");
|
||||
cmd_append(&cmd, "-x");
|
||||
cmd_append(&cmd, "--nostdinc");
|
||||
cmd_append(&cmd, path);
|
||||
cmd_append_alloc(alloc, &cmd, gpp1);
|
||||
cmd_append_alloc(alloc, &cmd, "-H");
|
||||
cmd_append_alloc(alloc, &cmd, "-x");
|
||||
cmd_append_alloc(alloc, &cmd, "--nostdinc");
|
||||
cmd_append_alloc(alloc, &cmd, path);
|
||||
|
||||
for (size_t i = 0; i < env->count; i++) {
|
||||
cmd_append(&cmd, env->items[i]);
|
||||
cmd_append_alloc(alloc, &cmd, env->items[i]);
|
||||
}
|
||||
|
||||
return cmd_run_collect(&cmd, out) == 0;
|
||||
return cmd_run_collect_alloc(alloc, &cmd, out) == 0;
|
||||
}
|
||||
|
||||
#if MY_DEBUG
|
||||
void route_build_id(struct mg_http_message *msg, Route_Result *result, void *context_data)
|
||||
void route_build_id(Allocator *alloc, struct mg_http_message *msg, Route_Result *result, void *context_data)
|
||||
{
|
||||
// TODO: Somehow use our arena in here. This will require a slight rework of the way cJSON works.
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
defer { cJSON_Delete(root); }
|
||||
|
||||
@ -85,226 +82,215 @@ void route_build_id(struct mg_http_message *msg, Route_Result *result, void *con
|
||||
uchar md5_buf[16];
|
||||
md5String(time, md5_buf);
|
||||
String_Builder sb = {0};
|
||||
defer { sb_free(&sb); }
|
||||
for (size_t i = 0; i < 16; i++) {
|
||||
sb_append_nstr(&sb, fmt("%02x", md5_buf[i]));
|
||||
sb_append_nstr_alloc(alloc, &sb, clonestr_alloc(alloc, fmt("%02x", md5_buf[i])));
|
||||
}
|
||||
sb_finish(&sb);
|
||||
sb_finish_alloc(alloc, &sb);
|
||||
|
||||
cJSON_AddItemToObject(root, "build_id", cJSON_CreateString(sb.items));
|
||||
|
||||
make_application_json(result, 200, root);
|
||||
make_application_json(alloc, result, 200, root);
|
||||
}
|
||||
#endif
|
||||
|
||||
void route_page_not_found(struct mg_http_message *msg, Route_Result *result, void *context_data)
|
||||
void route_page_not_found(Allocator *alloc, struct mg_http_message *msg, Route_Result *result, void *context_data)
|
||||
{
|
||||
lock_baked_resources();
|
||||
defer { unlock_baked_resources(); }
|
||||
NString_List env = {0};
|
||||
defer { list_free(&env); }
|
||||
|
||||
list_append(&env, fmt("-DURL=%.*s", msg->uri.len, msg->uri.buf));
|
||||
list_append_alloc(alloc, &env, clonestr_alloc(alloc, fmt("-DURL=%.*s", msg->uri.len, msg->uri.buf)));
|
||||
|
||||
String_Builder out = {0};
|
||||
defer { sb_free(&out); }
|
||||
|
||||
char path[PATH_MAX] = {0};
|
||||
if (!get_baked_resource_path("page-missing.html", path, sizeof(path))) {
|
||||
make_internal_server_error(result);
|
||||
make_internal_server_error(alloc, result);
|
||||
return;
|
||||
}
|
||||
|
||||
list_append(&env, fmt("-DCOMMIT=%s", COMMIT_STRING));
|
||||
list_append_alloc(alloc, &env, clonestr_alloc(alloc, fmt("-DCOMMIT=%s", COMMIT_STRING)));
|
||||
char timer[100];
|
||||
get_timer_string(timer, sizeof(timer));
|
||||
list_append(&env, fmt("-DRUNNING_SINCE=%s", timer));
|
||||
list_append_alloc(alloc, &env, clonestr_alloc(alloc, fmt("-DRUNNING_SINCE=%s", timer)));
|
||||
|
||||
list_append(&env, fmt("-DMETA_TAGS=%s", META_TAGS));
|
||||
list_append_alloc(alloc, &env, clonestr_alloc(alloc, fmt("-DMETA_TAGS=%s", META_TAGS)));
|
||||
|
||||
#if MY_DEBUG
|
||||
list_append(&env, "-DHOTRELOAD");
|
||||
list_append_alloc(alloc, &env, "-DHOTRELOAD");
|
||||
#endif
|
||||
|
||||
bool ok = gpp_run(path, &env, &out);
|
||||
sb_finish(&out);
|
||||
bool ok = gpp_run(alloc, path, &env, &out);
|
||||
sb_finish_alloc(alloc, &out);
|
||||
|
||||
if (!ok) {
|
||||
make_internal_server_error(result);
|
||||
make_internal_server_error(alloc, result);
|
||||
} else {
|
||||
make_text(result, "html", 200, out.items);
|
||||
make_text(alloc, result, "html", 200, out.items);
|
||||
}
|
||||
}
|
||||
|
||||
void route_home(struct mg_http_message *msg, Route_Result *result, void *context_data)
|
||||
void route_home(Allocator *alloc, struct mg_http_message *msg, Route_Result *result, void *context_data)
|
||||
{
|
||||
lock_baked_resources();
|
||||
defer { unlock_baked_resources(); }
|
||||
NString_List env = {0};
|
||||
defer { list_free(&env); }
|
||||
|
||||
String_Builder out = {0};
|
||||
defer { sb_free(&out); }
|
||||
|
||||
char path[PATH_MAX] = {0};
|
||||
if (!get_baked_resource_path("home.html", path, sizeof(path))) {
|
||||
make_internal_server_error(result);
|
||||
make_internal_server_error(alloc, result);
|
||||
return;
|
||||
}
|
||||
|
||||
list_append(&env, fmt("-DCOMMIT=%s", COMMIT_STRING));
|
||||
list_append_alloc(alloc, &env, clonestr_alloc(alloc, fmt("-DCOMMIT=%s", COMMIT_STRING)));
|
||||
char timer[100];
|
||||
get_timer_string(timer, sizeof(timer));
|
||||
list_append(&env, fmt("-DRUNNING_SINCE=%s", timer));
|
||||
list_append_alloc(alloc, &env, clonestr_alloc(alloc, fmt("-DRUNNING_SINCE=%s", timer)));
|
||||
|
||||
list_append(&env, fmt("-DMETA_TAGS=%s", META_TAGS));
|
||||
list_append_alloc(alloc, &env, clonestr_alloc(alloc, fmt("-DMETA_TAGS=%s", META_TAGS)));
|
||||
|
||||
#if MY_DEBUG
|
||||
list_append(&env, "-DHOTRELOAD");
|
||||
list_append_alloc(alloc, &env, "-DHOTRELOAD");
|
||||
#endif
|
||||
|
||||
bool ok = gpp_run(path, &env, &out);
|
||||
sb_finish(&out);
|
||||
bool ok = gpp_run(alloc, path, &env, &out);
|
||||
sb_finish_alloc(alloc, &out);
|
||||
|
||||
if (!ok) {
|
||||
make_internal_server_error(result);
|
||||
make_internal_server_error(alloc, result);
|
||||
} else {
|
||||
make_text(result, "html", 200, out.items);
|
||||
make_text(alloc, result, "html", 200, out.items);
|
||||
}
|
||||
}
|
||||
|
||||
void route_generic_blog(struct mg_http_message *msg, Route_Result *result, void *context_data)
|
||||
void route_generic_blog(Allocator *alloc, struct mg_http_message *msg, Route_Result *result, void *context_data)
|
||||
{
|
||||
lock_baked_resources();
|
||||
defer { unlock_baked_resources(); }
|
||||
NString_List env = {0};
|
||||
defer { list_free(&env); }
|
||||
|
||||
String_Builder out = {0};
|
||||
defer { sb_free(&out); }
|
||||
|
||||
Baked_Resource *resource = (Baked_Resource *)context_data;
|
||||
|
||||
char md_path[PATH_MAX] = {0};
|
||||
if (!get_baked_resource_path(resource->key, md_path, sizeof(md_path))) {
|
||||
make_internal_server_error(result);
|
||||
make_internal_server_error(alloc, result);
|
||||
return;
|
||||
}
|
||||
|
||||
list_append(&env, fmt("-DCOMMIT=%s", COMMIT_STRING));
|
||||
list_append_alloc(alloc, &env, clonestr_alloc(alloc, fmt("-DCOMMIT=%s", COMMIT_STRING)));
|
||||
char timer[100];
|
||||
get_timer_string(timer, sizeof(timer));
|
||||
list_append(&env, fmt("-DRUNNING_SINCE=%s", timer));
|
||||
list_append_alloc(alloc, &env, clonestr_alloc(alloc, fmt("-DRUNNING_SINCE=%s", timer)));
|
||||
|
||||
list_append(&env, fmt("-DMETA_TAGS=%s", META_TAGS));
|
||||
list_append_alloc(alloc, &env, clonestr_alloc(alloc, fmt("-DMETA_TAGS=%s", META_TAGS)));
|
||||
|
||||
#if MY_DEBUG
|
||||
list_append(&env, "-DHOTRELOAD");
|
||||
list_append_alloc(alloc, &env, "-DHOTRELOAD");
|
||||
#endif
|
||||
|
||||
String_Builder md = {0};
|
||||
defer { sb_free(&md); }
|
||||
if (!sb_read_file(&md, md_path)) {
|
||||
make_internal_server_error(result);
|
||||
make_internal_server_error(alloc, result);
|
||||
return;
|
||||
}
|
||||
|
||||
String_Builder md_prepared = {0};
|
||||
defer { sb_free(&md_prepared); }
|
||||
for (size_t i = 0; i < md.count; i++) {
|
||||
char c = md.items[i];
|
||||
switch (c) {
|
||||
case '\"': sb_append_nstr(&md_prepared, "\\\""); break;
|
||||
case '\'': sb_append_nstr(&md_prepared, "\\\'"); break;
|
||||
case '\\': sb_append_nstr(&md_prepared, "\\\\"); break;
|
||||
case '\a': sb_append_nstr(&md_prepared, "\\a"); break;
|
||||
case '\b': sb_append_nstr(&md_prepared, "\\b"); break;
|
||||
case '\r': sb_append_nstr(&md_prepared, "\\r"); break;
|
||||
case '\n': sb_append_nstr(&md_prepared, "\\n"); break;
|
||||
case '\t': sb_append_nstr(&md_prepared, "\\t"); break;
|
||||
case '\"': sb_append_nstr_alloc(alloc, &md_prepared, "\\\""); break;
|
||||
case '\'': sb_append_nstr_alloc(alloc, &md_prepared, "\\\'"); break;
|
||||
case '\\': sb_append_nstr_alloc(alloc, &md_prepared, "\\\\"); break;
|
||||
case '\a': sb_append_nstr_alloc(alloc, &md_prepared, "\\a"); break;
|
||||
case '\b': sb_append_nstr_alloc(alloc, &md_prepared, "\\b"); break;
|
||||
case '\r': sb_append_nstr_alloc(alloc, &md_prepared, "\\r"); break;
|
||||
case '\n': sb_append_nstr_alloc(alloc, &md_prepared, "\\n"); break;
|
||||
case '\t': sb_append_nstr_alloc(alloc, &md_prepared, "\\t"); break;
|
||||
default:
|
||||
if (iscntrl(md.items[i])) {
|
||||
sb_append_nstr(&md_prepared, fmt("\\%03o", c));
|
||||
sb_append_nstr_alloc(alloc, &md_prepared, clonestr_alloc(alloc, fmt("\\%03o", c)));
|
||||
} else {
|
||||
sb_append_char(&md_prepared, c);
|
||||
sb_append_char_alloc(alloc, &md_prepared, c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
sb_finish(&md_prepared);
|
||||
sb_finish_alloc(alloc, &md_prepared);
|
||||
|
||||
list_append(&env, fmt("-DBLOG_POST_TITLE=%s", resource->key));
|
||||
list_append(&env, fmt("-DBLOG_POST_MARKDOWN=%s", md_prepared.items));
|
||||
list_append_alloc(alloc, &env, clonestr_alloc(alloc, fmt("-DBLOG_POST_TITLE=%s", resource->key)));
|
||||
list_append_alloc(alloc, &env, clonestr_alloc(alloc, fmt("-DBLOG_POST_MARKDOWN=%s", md_prepared.items)));
|
||||
|
||||
char tmpl_file[PATH_MAX] = {0};
|
||||
if (!get_baked_resource_path("template-blog.html", tmpl_file, sizeof(tmpl_file))) {
|
||||
make_internal_server_error(result);
|
||||
make_internal_server_error(alloc, result);
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok = gpp_run(tmpl_file, &env, &out);
|
||||
sb_finish(&out);
|
||||
bool ok = gpp_run(alloc, tmpl_file, &env, &out);
|
||||
sb_finish_alloc(alloc, &out);
|
||||
|
||||
if (!ok) {
|
||||
make_internal_server_error(result);
|
||||
make_internal_server_error(alloc, result);
|
||||
} else {
|
||||
make_text(result, "html", 200, out.items);
|
||||
make_text(alloc, result, "html", 200, out.items);
|
||||
}
|
||||
}
|
||||
|
||||
void collect_blogs(Baked_Resource *resource, void *udata)
|
||||
{
|
||||
struct { Arena *tmp; String_Builder *sb; } *ud = udata;
|
||||
struct { Allocator *alloc; String_Builder *sb; } *ud = udata;
|
||||
if ((strlen(resource->key) >= strlen("blog-"))
|
||||
&& strncmp(resource->key, "blog-", strlen("blog-")) == 0) {
|
||||
sb_append_nstr_alloc(ud->tmp, ud->sb, fmt("<li><a href=\"/%s\">%s</a></li>", resource->key, resource->key));
|
||||
sb_append_nstr_alloc(ud->alloc, ud->sb,
|
||||
clonestr_alloc(ud->alloc, fmt("<li><a href=\"/%s\">%s</a></li>", resource->key, resource->key)));
|
||||
}
|
||||
}
|
||||
|
||||
void route_blog(struct mg_http_message *msg, Route_Result *result, void *context_data)
|
||||
void route_blog(Allocator *alloc, struct mg_http_message *msg, Route_Result *result, void *context_data)
|
||||
{
|
||||
lock_baked_resources();
|
||||
defer { unlock_baked_resources(); }
|
||||
NString_List env = {0};
|
||||
defer { list_free(&env); }
|
||||
|
||||
String_Builder out = {0};
|
||||
defer { sb_free(&out); }
|
||||
|
||||
Arena tmp = arena_get();
|
||||
defer { arena_destroy(&tmp); }
|
||||
|
||||
String_Builder sb = {0};
|
||||
struct { Arena *tmp; String_Builder *sb; } collect_blogs_data = {
|
||||
.tmp = &tmp,
|
||||
struct { Allocator *alloc; String_Builder *sb; } collect_blogs_data = {
|
||||
.alloc = alloc,
|
||||
.sb = &sb,
|
||||
};
|
||||
baked_resource_each(&collect_blogs, &collect_blogs_data);
|
||||
sb_finish_alloc(&tmp, &sb);
|
||||
list_append(&env, fmt("-DBLOG_POSTS=%s", sb.items));
|
||||
sb_finish_alloc(alloc, &sb);
|
||||
list_append_alloc(alloc, &env, clonestr_alloc(alloc, fmt("-DBLOG_POSTS=%s", sb.items)));
|
||||
|
||||
char path[PATH_MAX] = {0};
|
||||
if (!get_baked_resource_path("blog.html", path, sizeof(path))) {
|
||||
make_internal_server_error(result);
|
||||
make_internal_server_error(alloc, result);
|
||||
return;
|
||||
}
|
||||
|
||||
list_append(&env, fmt("-DCOMMIT=%s", COMMIT_STRING));
|
||||
list_append_alloc(alloc, &env, clonestr_alloc(alloc, fmt("-DCOMMIT=%s", COMMIT_STRING)));
|
||||
char timer[100];
|
||||
get_timer_string(timer, sizeof(timer));
|
||||
list_append(&env, fmt("-DRUNNING_SINCE=%s", timer));
|
||||
list_append_alloc(alloc, &env, clonestr_alloc(alloc, fmt("-DRUNNING_SINCE=%s", timer)));
|
||||
|
||||
list_append(&env, fmt("-DMETA_TAGS=%s", META_TAGS));
|
||||
list_append_alloc(alloc, &env, clonestr_alloc(alloc, fmt("-DMETA_TAGS=%s", META_TAGS)));
|
||||
|
||||
#if MY_DEBUG
|
||||
list_append(&env, "-DHOTRELOAD");
|
||||
list_append_alloc(alloc, &env, "-DHOTRELOAD");
|
||||
#endif
|
||||
|
||||
bool ok = gpp_run(path, &env, &out);
|
||||
sb_finish(&out);
|
||||
bool ok = gpp_run(alloc, path, &env, &out);
|
||||
sb_finish_alloc(alloc, &out);
|
||||
|
||||
if (!ok) {
|
||||
make_internal_server_error(result);
|
||||
make_internal_server_error(alloc, result);
|
||||
} else {
|
||||
make_text(result, "html", 200, out.items);
|
||||
make_text(alloc, result, "html", 200, out.items);
|
||||
}
|
||||
}
|
||||
|
||||
|
14
routes.h
14
routes.h
@ -12,15 +12,17 @@ typedef struct {
|
||||
int status_code;
|
||||
NString_List headers;
|
||||
String_Builder body;
|
||||
Arena *arena;
|
||||
} Route_Result;
|
||||
|
||||
typedef struct {
|
||||
struct mg_mgr *mgr;
|
||||
ulong conn_id;
|
||||
struct mg_str message;
|
||||
Arena *arena;
|
||||
} Route_Thread_Data;
|
||||
|
||||
typedef void (*Route_Handler)(struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
typedef void (*Route_Handler)(Allocator *alloc, struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
|
||||
typedef struct {
|
||||
char *key; // path
|
||||
@ -29,11 +31,11 @@ typedef struct {
|
||||
} Route;
|
||||
|
||||
#if MY_DEBUG
|
||||
void route_build_id(struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
void route_build_id(Allocator *alloc, struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
#endif
|
||||
void route_page_not_found(struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
void route_home(struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
void route_generic_blog(struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
void route_blog(struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
void route_page_not_found(Allocator *alloc, struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
void route_home(Allocator *alloc, struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
void route_generic_blog(Allocator *alloc, struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
void route_blog(Allocator *alloc, struct mg_http_message *msg, Route_Result *result, void *context_data);
|
||||
|
||||
#endif // ROUTES_H_
|
||||
|
Reference in New Issue
Block a user