Rework memory management, use per-thread arenas

This commit is contained in:
kamkow1
2025-06-28 01:29:49 +02:00
parent 2badc915d6
commit 2988a5b3d6
9 changed files with 202 additions and 195 deletions

View File

@ -7,4 +7,6 @@
# define CONFIG_LISTEN_URL "http://localhost:5000"
#endif
#define BUNDLE_ZIP_COMPRESSION 10
#endif // CONFIG_H_

View File

@ -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
View File

@ -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"

View File

@ -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

Submodule gebs updated: 596bb1ef76...db8389f7d5

View File

@ -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
View File

@ -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
View File

@ -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);
}
}

View File

@ -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_