Compare commits
10 Commits
7a9d5aa371
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| e88dc0426a | |||
| 5ee7e02f7a | |||
| e1f0d04409 | |||
| 48f4a73b0a | |||
| 2e70abd0de | |||
| b3a5860beb | |||
| 486952dcbf | |||
| 2988a5b3d6 | |||
| 2badc915d6 | |||
| 447362c74d |
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,3 +4,5 @@ build
|
||||
gpp1
|
||||
watcher
|
||||
commit.h
|
||||
compile_flags.txt
|
||||
bundle.zip
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -16,3 +16,6 @@
|
||||
[submodule "md5-c"]
|
||||
path = md5-c
|
||||
url = https://github.com/Zunawe/md5-c.git
|
||||
[submodule "zip"]
|
||||
path = zip
|
||||
url = https://github.com/kuba--/zip.git
|
||||
|
||||
@ -3,3 +3,6 @@
|
||||
./gpp1
|
||||
./watcher
|
||||
./mongoose.o
|
||||
./bundle.zip
|
||||
./compile_flags.txt
|
||||
./commit.h
|
||||
|
||||
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_
|
||||
|
||||
96
baked.c
96
baked.c
@ -3,47 +3,16 @@
|
||||
#include "gebs/gebs.h"
|
||||
#include "incbin/incbin.h"
|
||||
#include "stb/stb_ds.h"
|
||||
#include "zip.h"
|
||||
|
||||
#include "baked.h"
|
||||
#include "locked.h"
|
||||
#include "CONFIG.h"
|
||||
|
||||
INCBIN(gpp1, "./gpp1");
|
||||
|
||||
INCBIN(home_html, "./tmpls/home.html");
|
||||
INCBIN(page_missing_html, "./tmpls/page-missing.html");
|
||||
INCBIN(template_blog_html, "./tmpls/template-blog.html");
|
||||
INCBIN(blog_html, "./tmpls/blog.html");
|
||||
|
||||
INCBIN(simple_css, "./etc/simple.css");
|
||||
INCBIN(favicon_ico, "./etc/favicon.ico");
|
||||
#if MY_DEBUG
|
||||
INCBIN(hotreload_js, "./etc/hotreload.js");
|
||||
#endif
|
||||
INCBIN(theme_js, "./etc/theme.js");
|
||||
INCBIN(highlight_js, "./etc/highlight.js");
|
||||
INCBIN(hljs_rainbow_css, "./etc/hljs-rainbow.css");
|
||||
INCBIN(marked_js, "./etc/marked.js");
|
||||
INCBIN(me_jpg, "./etc/me.jpg");
|
||||
INCBIN(tmoa_engine_jpg, "./etc/tmoa-engine.jpg");
|
||||
INCBIN(tmoa_garbage_jpg, "./etc/tmoa-garbage.jpg");
|
||||
|
||||
INCBIN(blog_welcome_md, "./blog/welcome.md");
|
||||
INCBIN(blog_weird_page_md, "./blog/weird-page.md");
|
||||
INCBIN(blog_curious_case_of_gebs_md, "./blog/curious-case-of-gebs.md");
|
||||
INCBIN(blog_the_making_of_aboba_md, "./blog/the-making-of-aboba.md");
|
||||
INCBIN(bundle_zip, "./bundle.zip");
|
||||
|
||||
static locked(Baked_Resource *) baked_resources = locked_init(nil);
|
||||
|
||||
void lock_baked_resources(void)
|
||||
{
|
||||
lockx(&baked_resources);
|
||||
}
|
||||
|
||||
void unlock_baked_resources(void)
|
||||
{
|
||||
unlockx(&baked_resources);
|
||||
}
|
||||
|
||||
void add_baked_resource(char *key, const uchar *data, size_t size)
|
||||
{
|
||||
int fd = memfd_create(key, 0);
|
||||
@ -52,54 +21,55 @@ void add_baked_resource(char *key, const uchar *data, size_t size)
|
||||
abort();
|
||||
}
|
||||
write(fd, data, size);
|
||||
shput(baked_resources.value, key, fd);
|
||||
shput(baked_resources.value, key, ((Baked_Resource_Value){ .memfd = fd, .bufptr = (void *)data }));
|
||||
LOGI("Added baked resource: %s\n", key);
|
||||
}
|
||||
|
||||
void init_baked_resources(void)
|
||||
{
|
||||
lockx(&baked_resources);
|
||||
add_baked_resource("home.html", home_html_data, home_html_size);
|
||||
add_baked_resource("page-missing.html", page_missing_html_data, page_missing_html_size);
|
||||
add_baked_resource("template-blog.html", template_blog_html_data, template_blog_html_size);
|
||||
add_baked_resource("blog.html", blog_html_data, blog_html_size);
|
||||
add_baked_resource("gpp1", gpp1_data, gpp1_size);
|
||||
add_baked_resource("simple.css", simple_css_data, simple_css_size);
|
||||
add_baked_resource("favicon.ico", favicon_ico_data, favicon_ico_size);
|
||||
#if MY_DEBUG
|
||||
add_baked_resource("hotreload.js", hotreload_js_data, hotreload_js_size);
|
||||
#endif
|
||||
add_baked_resource("theme.js", theme_js_data, theme_js_size);
|
||||
add_baked_resource("highlight.js", highlight_js_data, highlight_js_size);
|
||||
add_baked_resource("hljs-rainbow.css", hljs_rainbow_css_data, hljs_rainbow_css_size);
|
||||
add_baked_resource("marked.js", marked_js_data, marked_js_size);
|
||||
add_baked_resource("me.jpg", me_jpg_data, me_jpg_size);
|
||||
add_baked_resource("tmoa-engine.jpg", tmoa_engine_jpg_data, tmoa_engine_jpg_size);
|
||||
add_baked_resource("tmoa-garbage.jpg", tmoa_garbage_jpg_data, tmoa_garbage_jpg_size);
|
||||
add_baked_resource("blog-welcome.md", blog_welcome_md_data, blog_welcome_md_size);
|
||||
add_baked_resource("blog-weird-page.md", blog_weird_page_md_data, blog_weird_page_md_size);
|
||||
add_baked_resource("blog-curious-case-of-gebs.md", blog_curious_case_of_gebs_md_data, blog_curious_case_of_gebs_md_size);
|
||||
add_baked_resource("blog-the-making-of-aboba.md", blog_the_making_of_aboba_md_data, blog_the_making_of_aboba_md_size);
|
||||
unlockx(&baked_resources);
|
||||
LOGI("Initializing baked resources...\n");
|
||||
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);
|
||||
|
||||
const char *name = strdup(zip_entry_name(zip));
|
||||
size_t size = zip_entry_size(zip);
|
||||
char *buf = malloc(size);
|
||||
zip_entry_noallocread(zip, buf, size);
|
||||
|
||||
add_baked_resource((char *)name, buf, size);
|
||||
|
||||
zip_entry_close(zip);
|
||||
}
|
||||
zip_stream_close(zip);
|
||||
LOGI("baked resources done\n");
|
||||
}
|
||||
|
||||
void free_baked_resources(void)
|
||||
{
|
||||
lockx(&baked_resources);
|
||||
LOGI("freeing baked resouces\n");
|
||||
for (size_t i = 0; i < shlen(baked_resources.value); i++) {
|
||||
close(baked_resources.value[i].value);
|
||||
close(baked_resources.value[i].value.memfd);
|
||||
free(baked_resources.value[i].key);
|
||||
free(baked_resources.value[i].value.bufptr);
|
||||
}
|
||||
shfree(baked_resources.value);
|
||||
unlockx(&baked_resources);
|
||||
LOGI("baked resources done\n");
|
||||
}
|
||||
|
||||
bool get_baked_resource_path(char *key, char *buf, size_t size)
|
||||
{
|
||||
LOGI("Request for baked resource path: %s\n", key);
|
||||
lockx(&baked_resources);
|
||||
if (shgeti(baked_resources.value, key) != -1) {
|
||||
int fd = shget(baked_resources.value, key);
|
||||
snprintf(buf, size, "/proc/%d/fd/%d", getpid(), fd);
|
||||
Baked_Resource_Value brv = shget(baked_resources.value, key);
|
||||
snprintf(buf, size, "/proc/%d/fd/%d", getpid(), brv.memfd);
|
||||
LOGI("Memfd path %s\n", buf);
|
||||
unlockx(&baked_resources);
|
||||
return true;
|
||||
}
|
||||
unlockx(&baked_resources);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
34
baked.h
34
baked.h
@ -1,43 +1,19 @@
|
||||
#ifndef BAKED_H_
|
||||
#define BAKED_H_
|
||||
|
||||
#include "incbin/incbin.h"
|
||||
|
||||
INCBIN_EXTERN(gpp1);
|
||||
|
||||
INCBIN_EXTERN(home_html);
|
||||
INCBIN_EXTERN(page_missing_html);
|
||||
INCBIN_EXTERN(template_blog_html);
|
||||
INCBIN_EXTERN(blog_html);
|
||||
|
||||
INCBIN_EXTERN(simple_css);
|
||||
INCBIN_EXTERN(favicon_ico);
|
||||
#if MY_DEBUG
|
||||
INCBIN_EXTERN(hotreload_js);
|
||||
#endif
|
||||
INCBIN_EXTERN(theme_js);
|
||||
INCBIN_EXTERN(highlight_js);
|
||||
INCBIN_EXTERN(hljs_rainbow_css);
|
||||
INCBIN_EXTERN(marked_js);
|
||||
INCBIN_EXTERN(me_jpg);
|
||||
INCBIN_EXTERN(tmoa_engine_jpg);
|
||||
INCBIN_EXTERN(tmoa_garbage_jpg);
|
||||
|
||||
INCBIN_EXTERN(blog_welcome_md);
|
||||
INCBIN_EXTERN(blog_weird_page_md);
|
||||
INCBIN_EXTERN(blog_curious_case_of_gebs_md);
|
||||
INCBIN_EXTERN(blog_the_making_of_aboba_md);
|
||||
typedef struct {
|
||||
int memfd;
|
||||
void *bufptr;
|
||||
} Baked_Resource_Value;
|
||||
|
||||
typedef struct {
|
||||
char *key; // path
|
||||
int value; // memfd
|
||||
Baked_Resource_Value value;
|
||||
} Baked_Resource;
|
||||
|
||||
void init_baked_resources(void);
|
||||
void free_baked_resources(void);
|
||||
bool get_baked_resource_path(char *key, char *buf, size_t size);
|
||||
void baked_resource_each(void (*f)(Baked_Resource *resource, void *udata), void *udata);
|
||||
void lock_baked_resources(void);
|
||||
void unlock_baked_resources(void);
|
||||
|
||||
#endif // BAKED_H_
|
||||
|
||||
273
blog/blog-asset-packing-with-zip.c.md
Normal file
273
blog/blog-asset-packing-with-zip.c.md
Normal file
@ -0,0 +1,273 @@
|
||||
# Asset packing with [zip.c](https://raw.githubusercontent.com/kuba--/zip/refs/heads/master/src/zip.c)
|
||||
|
||||
One of the technical decisions that I had to make when writing this website is the way that I'm going to
|
||||
distribute the assets (images, GPP, page templates, etc.). I've decided to go with packing or baking-in
|
||||
the assets into the main binary, so that I don't have to worry about updating an asset folder alongside
|
||||
the application.
|
||||
|
||||
One flaw of this approach is that as the website gets bigger, the binary will too. Fortunately I don't
|
||||
have to worry about this too much right now, since I've reimplemented asset packing with the excellent
|
||||
zip library by \`kuba--\` (Polska GUROM!!!111!!). In this article I'd like to demonstrate how I've
|
||||
minimised the size of our assets using \`zip\` and \`incbin\`.
|
||||
|
||||

|
||||
|
||||
## References
|
||||
|
||||
- zip: https://raw.githubusercontent.com/kuba--/zip/refs/heads/master/src/zip.c
|
||||
- incbin: https://github.com/graphitemaster/incbin
|
||||
- zip format: https://en.wikipedia.org/wiki/ZIP_(file_format)
|
||||
- the source code: https://git.kamkow1lair.pl/kamkow1/aboba
|
||||
|
||||
## Generating the bundle - \`bundle.zip\`
|
||||
|
||||
To compress our assets, first we need to generate a bundle file. I've decided to call it bundle.zip - simple
|
||||
and descriptive.
|
||||
|
||||
Generating the bundle requires some changes to our build program. See https://git.kamkow1lair.pl/kamkow1/aboba/src/branch/master/build.c for reference.
|
||||
|
||||
\`\`\`
|
||||
#define BUNDLED_FILES \\
|
||||
"./gpp1", \\
|
||||
"./tmpls/home.html", \\
|
||||
"./tmpls/page-missing.html", \\
|
||||
"./tmpls/template-blog.html", \\
|
||||
"./tmpls/blog.html", \\
|
||||
"./etc/hotreload.js", \\
|
||||
"./etc/theme.js", \\
|
||||
"./etc/simple.css", \\
|
||||
"./etc/highlight.js", \\
|
||||
"./etc/hljs-rainbow.css", \\
|
||||
"./etc/marked.js", \\
|
||||
"./etc/favicon.ico", \\
|
||||
"./etc/me.jpg", \\
|
||||
"./etc/tmoa-engine.jpg", \\
|
||||
"./etc/tmoa-garbage.jpg", \\
|
||||
"./blog/blog-welcome.md", \\
|
||||
"./blog/blog-weird-page.md", \\
|
||||
"./blog/blog-curious-case-of-gebs.md", \\
|
||||
"./blog/blog-the-making-of-aboba.md", \\
|
||||
"./blog/blog-asset-packing-with-zip.c.md"
|
||||
|
||||
const char *bundle_zip_deps[] = { BUNDLED_FILES };
|
||||
|
||||
RULE_ARRAY("./bundle.zip", bundle_zip_deps) {
|
||||
RULE("./gpp1", "./gpp/gpp.c") {
|
||||
CMD("cc", "-DHAVE_STRDUP", "-DHAVE_FNMATCH_H", "-o", "gpp1", "gpp/gpp.c");
|
||||
}
|
||||
|
||||
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++) {
|
||||
char *copy = strdup(bundle_zip_deps[i]);
|
||||
defer { free(copy); }
|
||||
char *name = basename(copy);
|
||||
|
||||
String_Builder sb = {0};
|
||||
defer { sb_free(&sb); }
|
||||
sb_read_file(&sb, bundle_zip_deps[i]);
|
||||
|
||||
zip_entry_open(zip, name);
|
||||
zip_entry_write(zip, sb.items, sb.count);
|
||||
zip_entry_close(zip);
|
||||
}
|
||||
LOGI("Generated bundle.zip\\n");
|
||||
}
|
||||
|
||||
RULE("./aboba",
|
||||
"./main.c",
|
||||
"./routes.c",
|
||||
"./routes.h",
|
||||
"./baked.c",
|
||||
"./baked.h",
|
||||
"./commit.h",
|
||||
"./timer.c",
|
||||
"./timer.h",
|
||||
"./CONFIG.h",
|
||||
"./locked.h",
|
||||
|
||||
"./mongoose.o",
|
||||
|
||||
"./bundle.zip",
|
||||
BUNDLED_FILES
|
||||
) {
|
||||
// build mongoose.o - skipped
|
||||
|
||||
// Generate commit.h - skipped
|
||||
|
||||
#define CC "cc"
|
||||
#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", \\
|
||||
"-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", \\
|
||||
"-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"
|
||||
#define OBJECTS "./mongoose.o"
|
||||
#define LINK_FLAGS "-Wl,-z,execstack", "-lpthread"
|
||||
#define INC_FLAGS "-I.", "-I./zip/src"
|
||||
|
||||
CMD(CC, TARGET, CFLAGS, DEFINES, INC_FLAGS, SOURCES, OBJECTS, EXTRA_SOURCES, LINK_FLAGS);
|
||||
|
||||
// generate compile_flags.txt - skipped
|
||||
|
||||
// #undef macros - skipped
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
If you go through the commit history, you'll see that apart from just generating the bundle file, I've also cleaned up the
|
||||
build commands a bit with \`#define\`s. Let's take a closer look at the bundle generation code.
|
||||
|
||||
\`\`\`
|
||||
const char *bundle_zip_deps[] = { BUNDLED_FILES };
|
||||
|
||||
RULE_ARRAY("./bundle.zip", bundle_zip_deps) {
|
||||
RULE("./gpp1", "./gpp/gpp.c") {
|
||||
CMD("cc", "-DHAVE_STRDUP", "-DHAVE_FNMATCH_H", "-o", "gpp1", "gpp/gpp.c");
|
||||
}
|
||||
|
||||
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++) {
|
||||
char *copy = strdup(bundle_zip_deps[i]);
|
||||
defer { free(copy); }
|
||||
char *name = basename(copy);
|
||||
|
||||
String_Builder sb = {0};
|
||||
defer { sb_free(&sb); }
|
||||
sb_read_file(&sb, bundle_zip_deps[i]);
|
||||
|
||||
zip_entry_open(zip, name);
|
||||
zip_entry_write(zip, sb.items, sb.count);
|
||||
zip_entry_close(zip);
|
||||
}
|
||||
LOGI("Generated bundle.zip\\n");
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
We declare a dependency (using \`RULE\*()\` macro), which says that \`./bundle.zip\` depends on files defined by \`BUNDLED_FILES\`.
|
||||
To generate the bundle we use \`zip_open()\` \`zip_close()\`. To call \`zip_open()\`, we have to provide a so called "compression level".
|
||||
The zip library provides us only with \`ZIP_DEFAULT_COMPRESSION_LEVEL\`, which is a macro that evaluates to 6. I wasn't satisfied with
|
||||
it, so after looking at \`miniz.h\` (a backing library that zip uses), I've found that zip uses \`MZ_DEFAULT_COMPRESSION_LEVEL\`, which
|
||||
is 6, but we can use the value of \`MZ_UBER_COMPRESSION\`, which is 10. This way we can achieve the most size-efficient compression.
|
||||
|
||||
I've decided to \`#define\` the compression level to avoid using arbitrary magic numbers and we can also use that definition both in
|
||||
the application and in the build program. Here's how \`CONFIG.h\` looks like now:
|
||||
|
||||
\`\`\`
|
||||
#ifndef CONFIG_H_
|
||||
#define CONFIG_H_
|
||||
|
||||
#if MY_DEBUG
|
||||
# define CONFIG_LISTEN_URL "http://localhost:8080"
|
||||
#else
|
||||
# define CONFIG_LISTEN_URL "http://localhost:5000"
|
||||
#endif
|
||||
|
||||
#define BUNDLE_ZIP_COMPRESSION 10
|
||||
|
||||
#endif // CONFIG_H_
|
||||
\`\`\`
|
||||
|
||||
The only "downside" here is that, since we're compressing so hard, it's going to take more time to generate the bundle. I've put "downside"
|
||||
in quotes for purpose, because this does not apply in our case. The files that we're packing are quite small already and there aren't
|
||||
many of them. We're just doing this to sqeeze out *extra* spacial performance.
|
||||
|
||||
Previously we were baking-in the assets like so:
|
||||
|
||||
from https://git.kamkow1lair.pl/kamkow1/aboba/src/commit/447362c74dda85838d37d6ee3cb218697abf6106/baked.c
|
||||
|
||||
\`\`\`
|
||||
INCBIN(gpp1, "./gpp1");
|
||||
|
||||
INCBIN(home_html, "./tmpls/home.html");
|
||||
INCBIN(page_missing_html, "./tmpls/page-missing.html");
|
||||
INCBIN(template_blog_html, "./tmpls/template-blog.html");
|
||||
INCBIN(blog_html, "./tmpls/blog.html");
|
||||
|
||||
INCBIN(simple_css, "./etc/simple.css");
|
||||
INCBIN(favicon_ico, "./etc/favicon.ico");
|
||||
#if MY_DEBUG
|
||||
INCBIN(hotreload_js, "./etc/hotreload.js");
|
||||
#endif
|
||||
INCBIN(theme_js, "./etc/theme.js");
|
||||
INCBIN(highlight_js, "./etc/highlight.js");
|
||||
INCBIN(hljs_rainbow_css, "./etc/hljs-rainbow.css");
|
||||
INCBIN(marked_js, "./etc/marked.js");
|
||||
INCBIN(me_jpg, "./etc/me.jpg");
|
||||
INCBIN(tmoa_engine_jpg, "./etc/tmoa-engine.jpg");
|
||||
INCBIN(tmoa_garbage_jpg, "./etc/tmoa-garbage.jpg");
|
||||
|
||||
INCBIN(blog_welcome_md, "./blog/welcome.md");
|
||||
INCBIN(blog_weird_page_md, "./blog/weird-page.md");
|
||||
INCBIN(blog_curious_case_of_gebs_md, "./blog/curious-case-of-gebs.md");
|
||||
INCBIN(blog_the_making_of_aboba_md, "./blog/the-making-of-aboba.md");
|
||||
\`\`\`
|
||||
|
||||
Now that we have our \`bundle.zip\`, we do it like this:
|
||||
|
||||
\`\`\`
|
||||
INCBIN(bundle_zip, "./bundle.zip");
|
||||
\`\`\`
|
||||
|
||||
And there we go, we have our bundle!
|
||||
|
||||
I've also had to slightly change the way we add the assets to the resource hash table:
|
||||
|
||||
\`\`\`
|
||||
void add_baked_resource(char *key, const uchar *data, size_t size)
|
||||
{
|
||||
int fd = memfd_create(key, 0);
|
||||
if (fd < 0) {
|
||||
LOGE("Could not create resource %s. Aborting...\n", key);
|
||||
abort();
|
||||
}
|
||||
write(fd, data, size);
|
||||
shput(baked_resources.value, key, ((Baked_Resource_Value){ .memfd = fd, .bufptr = (void *)data }));
|
||||
}
|
||||
|
||||
void init_baked_resources(void)
|
||||
{
|
||||
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);
|
||||
|
||||
const char *name = strdup(zip_entry_name(zip));
|
||||
size_t size = zip_entry_size(zip);
|
||||
char *buf = malloc(size);
|
||||
zip_entry_noallocread(zip, buf, size);
|
||||
|
||||
add_baked_resource((char *)name, buf, size);
|
||||
|
||||
zip_entry_close(zip);
|
||||
}
|
||||
zip_stream_close(zip);
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
\`add_baked_resource()\` hasn't changed here, but \`init_baked_resources()\` has. Here we use one of zip's abilities,
|
||||
which is unpacking an in-memory .zip file. We iterate each entry in the bundle, get the name and size, preallocate
|
||||
a buffer and read said entry into the buffer. We can then add the resource to the hash table as we did previously.
|
||||
|
||||
## Conclusion
|
||||
|
||||

|
||||
|
||||
One question you may ask is, how much space are we saving? I don't remeber the exact sizes of the binary, but
|
||||
I remember that before compression it was \`~1.2M\` and now after compression is implemented, it's \`~1.6M\`. How is
|
||||
that an improvement if the binary gained weight? That \`~.4M\` is likely due to zip format overhead - metadata, file and
|
||||
directory headers and so on. What we gain here is that the binary hasn't changed in size much despite adding more files,
|
||||
like for eg. this article that I'm writing right now. It has stayed at \`~1.6M\` so far and the size doesn't go up.
|
||||
*(So far)* We aren't even making byte-sized gains, which can be checked with \`stat --printf "%s" ./aboba\`. What
|
||||
we're gaining here is slowed down size increase. Previously if I wanted to add a 30K jpeg, the binary would literally
|
||||
go up by 30K.
|
||||
|
||||
123
build.c
123
build.c
@ -1,6 +1,9 @@
|
||||
#include <libgen.h>
|
||||
#define GEBS_NO_PREFIX
|
||||
#define GEBS_IMPLEMENTATION
|
||||
#include "gebs/gebs.h"
|
||||
#include "./zip/src/zip.c"
|
||||
#include "CONFIG.h"
|
||||
|
||||
char *prog = NULL;
|
||||
|
||||
@ -15,13 +18,62 @@ int main(int argc, char ** argv)
|
||||
prog = SHIFT(&argc, &argv);
|
||||
char *cmd = SHIFT(&argc, &argv);
|
||||
if (strcmp(cmd, "make") == 0) {
|
||||
#define BUNDLED_FILES \
|
||||
"./gpp1", \
|
||||
"./tmpls/home.html", \
|
||||
"./tmpls/page-missing.html", \
|
||||
"./tmpls/template-blog.html", \
|
||||
"./tmpls/blog.html", \
|
||||
"./etc/hotreload.js", \
|
||||
"./etc/theme.js", \
|
||||
"./etc/simple.css", \
|
||||
"./etc/highlight.js", \
|
||||
"./etc/hljs-rainbow.css", \
|
||||
"./etc/marked.js", \
|
||||
"./etc/favicon.ico", \
|
||||
"./etc/me.jpg", \
|
||||
"./etc/tmoa-engine.jpg", \
|
||||
"./etc/tmoa-garbage.jpg", \
|
||||
"./etc/apwz-zip-icon.png", \
|
||||
"./etc/apwz-xkcd1.png", \
|
||||
"./blog/blog-welcome.md", \
|
||||
"./blog/blog-weird-page.md", \
|
||||
"./blog/blog-curious-case-of-gebs.md", \
|
||||
"./blog/blog-the-making-of-aboba.md", \
|
||||
"./blog/blog-asset-packing-with-zip.c.md"
|
||||
|
||||
const char *bundle_zip_deps[] = { BUNDLED_FILES };
|
||||
|
||||
RULE_ARRAY("./bundle.zip", bundle_zip_deps) {
|
||||
RULE("./gpp1", "./gpp/gpp.c") {
|
||||
CMD("cc", "-DHAVE_STRDUP", "-DHAVE_FNMATCH_H", "-o", "gpp1", "gpp/gpp.c");
|
||||
}
|
||||
|
||||
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++) {
|
||||
char *copy = strdup(bundle_zip_deps[i]);
|
||||
defer { free(copy); }
|
||||
char *name = basename(copy);
|
||||
|
||||
String_Builder sb = {0};
|
||||
defer { sb_free(&sb); }
|
||||
sb_read_file(&sb, bundle_zip_deps[i]);
|
||||
|
||||
zip_entry_open(zip, name);
|
||||
zip_entry_write(zip, sb.items, sb.count);
|
||||
zip_entry_close(zip);
|
||||
}
|
||||
LOGI("Generated bundle.zip\n");
|
||||
}
|
||||
|
||||
RULE("./aboba",
|
||||
"./main.c",
|
||||
"./routes.c",
|
||||
"./routes.h",
|
||||
"./baked.c",
|
||||
"./baked.h",
|
||||
"./clonestr.h",
|
||||
"./commit.h",
|
||||
"./timer.c",
|
||||
"./timer.h",
|
||||
@ -29,28 +81,9 @@ int main(int argc, char ** argv)
|
||||
"./locked.h",
|
||||
|
||||
"./mongoose.o",
|
||||
"./gpp1",
|
||||
|
||||
"./tmpls/home.html",
|
||||
"./tmpls/page-missing.html",
|
||||
"./tmpls/template-blog.html",
|
||||
"./tmpls/blog.html",
|
||||
|
||||
"./etc/hotreload.js",
|
||||
"./etc/theme.js",
|
||||
"./etc/simple.css",
|
||||
"./etc/highlight.js",
|
||||
"./etc/hljs-rainbow.css",
|
||||
"./etc/marked.js",
|
||||
"./etc/favicon.ico",
|
||||
"./etc/me.jpg",
|
||||
"./etc/tmoa-engine.jpg",
|
||||
"./etc/tmoa-garbage.jpg",
|
||||
|
||||
"./blog/welcome.md",
|
||||
"./blog/weird-page.md",
|
||||
"./blog/curious-case-of-gebs.md",
|
||||
"./blog/the-making-of-aboba.md"
|
||||
"./bundle.zip",
|
||||
BUNDLED_FILES
|
||||
) {
|
||||
|
||||
RULE("./mongoose.o", "./mongoose/mongoose.c") {
|
||||
@ -63,10 +96,6 @@ int main(int argc, char ** argv)
|
||||
#endif
|
||||
}
|
||||
|
||||
RULE("./gpp1", "./gpp/gpp.c") {
|
||||
CMD("cc", "-DHAVE_STRDUP", "-DHAVE_FNMATCH_H", "-o", "gpp1", "gpp/gpp.c");
|
||||
}
|
||||
|
||||
RULE("./commit.h") {
|
||||
String_Builder commit = {0};
|
||||
defer { sb_free(&commit); }
|
||||
@ -95,18 +124,39 @@ int main(int argc, char ** argv)
|
||||
}
|
||||
}
|
||||
|
||||
#define CC "cc"
|
||||
#define TARGET "-o", "aboba"
|
||||
#if MY_DEBUG
|
||||
CMD("cc", "-fsanitize=address", "-fPIC", "-ggdb", "-I.", "-DMY_DEBUG=1", "-D_GNU_SOURCE", "-DGEBS_NO_PREFIX",
|
||||
"-DINCBIN_PREFIX=", "-DINCBIN_STYLE=INCBIN_STYLE_SNAKE", "-Wl,-z,execstack", "-o", "./aboba",
|
||||
"./main.c", "./routes.c", "./baked.c", "./timer.c", "./mongoose.o", "./cJSON/cJSON.c",
|
||||
"./md5-c/md5.c",
|
||||
"-lpthread");
|
||||
#define CFLAGS "-fsanitize=address", "-fPIC", "-ggdb"
|
||||
#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
|
||||
CMD("cc", "-fPIC", "-I.", "-DMY_DEBUG=0", "-D_GNU_SOURCE", "-DGEBS_NO_PREFIX",
|
||||
"-DINCBIN_PREFIX=", "-DINCBIN_STYLE=INCBIN_STYLE_SNAKE", "-Wl,-z,execstack", "-o", "./aboba",
|
||||
"./main.c", "./routes.c", "./baked.c", "./timer.c", "./mongoose.o", "./cJSON/cJSON.c",
|
||||
"-lpthread");
|
||||
#define CFLAGS "-fPIC"
|
||||
#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"
|
||||
#define OBJECTS "./mongoose.o"
|
||||
#define LINK_FLAGS "-Wl,-z,execstack", "-lpthread"
|
||||
#define INC_FLAGS "-I.", "-I./zip/src"
|
||||
|
||||
CMD(CC, TARGET, CFLAGS, DEFINES, INC_FLAGS, SOURCES, OBJECTS, EXTRA_SOURCES, LINK_FLAGS);
|
||||
|
||||
RULE("./compile_flags.txt") {
|
||||
make_compile_flags(TARGET, CFLAGS, DEFINES, INC_FLAGS, SOURCES, OBJECTS, EXTRA_SOURCES, LINK_FLAGS);
|
||||
}
|
||||
|
||||
#undef CC
|
||||
#undef TARGET
|
||||
#undef CFLAGS
|
||||
#undef DEFINES
|
||||
#undef EXTRA_SOURCES
|
||||
#undef SOURCES
|
||||
#undef OBJECTS
|
||||
#undef LINK_FLAGS
|
||||
#undef INC_FLAGS
|
||||
}
|
||||
} else if (strcmp(cmd, "clean") == 0) {
|
||||
remove1("./build");
|
||||
@ -114,6 +164,9 @@ int main(int argc, char ** argv)
|
||||
remove1("./mongoose.o");
|
||||
remove1("./gpp1");
|
||||
remove1("./watcher");
|
||||
remove1("./compile_flags.txt");
|
||||
remove1("./bundle.zip");
|
||||
remove1("./commit.h");
|
||||
} else if (strcmp(cmd, "make-watcher") == 0) {
|
||||
CMD("cc", "-o", "watcher", "watcher.c");
|
||||
} else if (strcmp(cmd, "watch") == 0) {
|
||||
|
||||
@ -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_
|
||||
|
||||
BIN
etc/apwz-xkcd1.png
Normal file
BIN
etc/apwz-xkcd1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
BIN
etc/apwz-zip-icon.png
Normal file
BIN
etc/apwz-zip-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
740
etc/simple.css
740
etc/simple.css
File diff suppressed because one or more lines are too long
17
etc/theme.js
17
etc/theme.js
@ -82,12 +82,29 @@ function neon_cyber()
|
||||
document.documentElement.style.setProperty("--disabled", "#333333");
|
||||
}
|
||||
|
||||
function dark_easy()
|
||||
{
|
||||
document.documentElement.style.setProperty("--bg", "#1A1A1A");
|
||||
document.documentElement.style.setProperty("--accent-bg", "#2E2E2E");
|
||||
document.documentElement.style.setProperty("--text", "#DCDCDC");
|
||||
document.documentElement.style.setProperty("--text-light", "#A3A3A3");
|
||||
document.documentElement.style.setProperty("--border", "#585858");
|
||||
document.documentElement.style.setProperty("--accent", "#FF5722");
|
||||
document.documentElement.style.setProperty("--accent-hover", "#F4511E");
|
||||
document.documentElement.style.setProperty("--accent-text", "#1A1A1A");
|
||||
document.documentElement.style.setProperty("--code", "#8BC34A");
|
||||
document.documentElement.style.setProperty("--preformatted", "#A3A3A3");
|
||||
document.documentElement.style.setProperty("--marked", "#FF7043");
|
||||
document.documentElement.style.setProperty("--disabled", "#383838");
|
||||
}
|
||||
|
||||
const themes = {
|
||||
"light-breeze": light_breeze,
|
||||
"plan9-acme": plan9_acme,
|
||||
"bold-navy": bold_navy,
|
||||
"soft-lavander": soft_lavander,
|
||||
"neon-cyber": neon_cyber,
|
||||
"dark-easy": dark_easy,
|
||||
};
|
||||
|
||||
|
||||
|
||||
2
gebs
2
gebs
Submodule gebs updated: 6db36114d5...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)
|
||||
|
||||
166
main.c
166
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,91 +49,91 @@ 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;
|
||||
}
|
||||
|
||||
void event_handler(struct mg_connection *conn, int ev, void *ev_data)
|
||||
{
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
LOGI("HTTP EVENT\n");
|
||||
struct mg_http_message *msg = (struct mg_http_message *)ev_data;
|
||||
LOGI("Route: %.*s\n", msg->uri.len, msg->uri.buf);
|
||||
|
||||
Route_Thread_Data *data = calloc(1, sizeof(*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();
|
||||
LOGI("starting handler thread...\n");
|
||||
run_in_thread(&route_thread_function, data);
|
||||
} else if (ev == MG_EV_WAKEUP) {
|
||||
LOGI("WAKEUP EVENT\n");
|
||||
struct mg_str *data = (struct mg_str *)ev_data;
|
||||
Route_Result *result = (Route_Result *)data->buf;
|
||||
defer {
|
||||
for (size_t i = 0; i < result->headers.count; i++) {
|
||||
free(result->headers.items[i]);
|
||||
}
|
||||
list_free(&result->headers);
|
||||
sb_free(&result->body);
|
||||
}
|
||||
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);
|
||||
@ -125,6 +141,11 @@ void event_handler(struct mg_connection *conn, int ev, void *ev_data)
|
||||
char *path = result->body.items;
|
||||
mg_http_serve_file(conn, ev_data, path, &(struct mg_http_serve_opts){0});
|
||||
}
|
||||
|
||||
arena_destroy(arena);
|
||||
free(arena);
|
||||
|
||||
LOGI("WAKEUP done, arena cleaned\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,27 +163,23 @@ void route_hashtable_put_blogs(Baked_Resource *resource, void *udata)
|
||||
|
||||
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);
|
||||
unlockx(&route_hashtable);
|
||||
}
|
||||
|
||||
void free_route_hashtable(void)
|
||||
{
|
||||
lockx(&route_hashtable);
|
||||
for (size_t i = 0; i < shlen(route_hashtable.value); i++) {
|
||||
free(route_hashtable.value[i].key);
|
||||
}
|
||||
shfree(route_hashtable.value);
|
||||
unlockx(&route_hashtable);
|
||||
}
|
||||
|
||||
char *init_baked_dump(void)
|
||||
@ -246,27 +263,28 @@ void copy_baked_resources_to_baked_dump(Baked_Resource *resource, void *udata)
|
||||
|
||||
void populate_baked_dump(char *baked_dump)
|
||||
{
|
||||
lock_baked_resources();
|
||||
baked_resource_each(©_baked_resources_to_baked_dump, 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();
|
||||
lockx(&baked_dump_path);
|
||||
if ((baked_dump_path.value = init_baked_dump()) == nil) {
|
||||
return 1;
|
||||
}
|
||||
populate_baked_dump(baked_dump_path.value);
|
||||
unlockx(&baked_dump_path);
|
||||
|
||||
mg_log_set(MG_LL_DEBUG);
|
||||
struct mg_mgr mgr;
|
||||
@ -284,9 +302,7 @@ int main(int argc, char ** argv)
|
||||
|
||||
mg_mgr_free(&mgr);
|
||||
|
||||
lockx(&baked_dump_path);
|
||||
free_baked_dump(baked_dump_path.value);
|
||||
unlockx(&baked_dump_path);
|
||||
free_baked_resources();
|
||||
|
||||
return 0;
|
||||
|
||||
226
routes.c
226
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,65 @@
|
||||
"<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_alloc(alloc, &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;
|
||||
bool ok = cmd_run_collect_alloc(alloc, &cmd, out) == 0;
|
||||
size_t len = out->count > 100 ? 100 : out->count;
|
||||
LOGI("Output (first 100): \n-------------------------------\n%.*s\n-------------------------------\n", len, out->items);
|
||||
return ok;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
LOGI("handler build_id (%.*s)\n", msg->uri.len, msg->uri.buf);
|
||||
// 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 +86,217 @@ 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);
|
||||
LOGI("handler build_id done\n");
|
||||
}
|
||||
#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(); }
|
||||
LOGI("handler page not found (%.*s)\n", msg->uri.len, msg->uri.buf);
|
||||
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);
|
||||
LOGE("Failed to get baked resource page-missing.html\n");
|
||||
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);
|
||||
}
|
||||
LOGI("handler page not found done\n");
|
||||
}
|
||||
|
||||
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(); }
|
||||
LOGI("handler home (%.*s)\n", msg->uri.len, msg->uri.buf);
|
||||
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);
|
||||
LOGE("Failed to get baked resource home.html\n");
|
||||
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);
|
||||
}
|
||||
LOGI("handler home done\n");
|
||||
}
|
||||
|
||||
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(); }
|
||||
LOGI("handler generic blog (%.*s)\n", msg->uri.len, msg->uri.buf);
|
||||
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);
|
||||
LOGE("Failed to get baked resource %s\n", resource->key);
|
||||
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);
|
||||
if (!sb_read_file_alloc(alloc, &md, md_path)) {
|
||||
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);
|
||||
}
|
||||
LOGI("handler generic blog done\n");
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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_
|
||||
|
||||
1
zip
Submodule
1
zip
Submodule
Submodule zip added at 649a16c5ea
Reference in New Issue
Block a user