X-Git-Url: https://gitweb.ps.run/chirp/blobdiff_plain/5baef6aec75ac5ca18222150a538a5c8c6c01931..0b2f4de9c1db5ec1059f6cd9b8c44e07f3af0b51:/src/main.c diff --git a/src/main.c b/src/main.c index d26da8a..055fcca 100644 --- a/src/main.c +++ b/src/main.c @@ -1,59 +1,451 @@ -#include "mongoose.h" +#include +#include +#define STB_DS_IMPLEMENTATION +#include + + +#define NAME_LEN 32 +#define CONTENT_LEN 1024 +#define HTML_LEN 1024*8 + +typedef struct Post Post; +typedef struct User User; + +User * UsersFind(struct mg_str name); + +// Post / User + +struct Post { + time_t timestamp; + User * user; + char content[CONTENT_LEN]; + uint32_t likes; + Post * comments; + //Post * parent; +}; + +struct User { + char name[NAME_LEN]; + Post * posts; + User ** following; +}; + +Post +PostNew() { + Post result; + memset(&result, 0, sizeof(result)); + return result; +} + +void +PostWrite(Post * post, FILE * f) { + fwrite(&post->timestamp, 8, 1, f); + fwrite(post->user->name, 1, sizeof(post->user->name), f); + fwrite(post->content, 1, sizeof(post->content), f); + fwrite(&post->likes, 4, 1, f); + uint32_t numComments = arrlen(post->comments); + fwrite(&numComments, 4, 1, f); + for (int i = 0; i < numComments; i++) { + PostWrite(&post->comments[i], f); + } +} + +void +PostRead(Post * post, FILE * f) { + fread(&post->timestamp, 8, 1, f); + char name[NAME_LEN]; + fread(name, 1, sizeof(name), f); + post->user = UsersFind(mg_str(name)); + fread(post->content, 1, sizeof(post->content), f); + fread(&post->likes, 4, 1, f); + uint32_t numComments; + fread(&numComments, 4, 1, f); + post->comments = NULL; + for (int i = 0; i < numComments; i++) { + Post newComment = PostNew(); + PostRead(&newComment, f); + arrput(post->comments, newComment); + } +} + +User +UserNew(const char * name) { + User result; + memset(&result, 0, sizeof(result)); + strcpy(result.name, name); + return result; +} + +void +UserWrite(User * user, FILE * f) { + fwrite(user->name, 1, sizeof(user->name), f); + + uint32_t numFollowing = arrlen(user->following); + uint32_t numPosts = arrlen(user->posts); + fwrite(&numFollowing, 4, 1, f); + fwrite(&numPosts, 4, 1, f); + + for (int i = 0; i < numFollowing; i++) { + fwrite(user->following[i]->name, 1, sizeof(user->following[i]->name), f); + } + + for (int i = 0; i < numPosts; i++) { + PostWrite(&user->posts[i], f); + } +} + +void +UserRead(User * user, FILE * f) { + fread(user->name, 1, sizeof(user->name), f); + + uint32_t numFollowing; + uint32_t numPosts; + fread(&numFollowing, 1, 4, f); + fread(&numPosts, 1, 4, f); + + user->following = NULL; + for (int i = 0; i < numFollowing; i++) { + char name[NAME_LEN]; + fread(name, 1, sizeof(name), f); + arrput(user->following, UsersFind(mg_str(name))); + } + + user->posts = NULL; + for (int i = 0; i < numPosts; i++) { + Post post = PostNew(); + PostRead(&post, f); + arrput(user->posts, post); + } +} + + + +// Users + +User ** g_users; +static User pat, yas, tof; + +void +UsersSetup() { + pat = UserNew("pat"); + yas = UserNew("yas"); + tof = UserNew("tof"); + + arrput(pat.following, &yas); + arrput(yas.following, &pat); + arrput(tof.following, &yas); + arrput(tof.following, &pat); + + arrput(g_users, &pat); + arrput(g_users, &yas); + arrput(g_users, &tof); +} + +User * +UsersFind(struct mg_str name) { + for (int i = 0; i < arrlen(g_users); i++) { + User * user = g_users[i]; + if (strncmp(user->name, name.ptr, name.len) == 0) + return user; + } + return NULL; +} + // HTML +void +http_redirect(struct mg_connection * c, struct mg_http_message * hm) { + struct mg_str *referer = mg_http_get_header(hm, "Referer"); + + static char redirectHeaders[128]; + snprintf(redirectHeaders, 128, + "Location: %.*s\r\n", + referer->len, referer->ptr); + mg_http_reply(c, 303, redirectHeaders, ""); +} + char * -html_user_post(struct mg_str user) { - static char html[1024]; - snprintf(html, 1024, - "" - "" - "" - "
" - "
" - " " - "
" - "" - "", - user.len, user.ptr); - return html; +html_404() +{ + static char html[1024]; + snprintf(html, 1024, + "" + "" + "" + "

Eeeeeeh? The Website's Under Construction

" + "" + ""); + return html; } -// Post +char * +html_user_not_found() +{ + static char html[1024]; + snprintf(html, 1024, + "" + "" + "" + "

User was not found :/

" + "" + ""); + return html; +} +int +html_post(Post * post, char * buffer, int bufferLen) { + int result = 0; + int printed = 0; + printed = snprintf(buffer, bufferLen, + "
[%s] %s: %s
", + ctime(&post->timestamp), + post->user->name, + post->user->name, + post->content); + buffer += printed; bufferLen -= printed; result += printed; + if (post->likes > 0) { + printed = snprintf(buffer, bufferLen, + "Likes: %d
", post->likes); + buffer += printed; bufferLen -= printed; result += printed; + } -// User + printed = snprintf(buffer, bufferLen, + "
" + "" + "
", + post->user->name, + (size_t)post); + buffer += printed; bufferLen -= printed; result += printed; + + if (arrlen(post->comments) > 0) { + printed = snprintf(buffer, bufferLen, + "Comments:
"); + buffer += printed; bufferLen -= printed; result += printed; + for (int i = 0; i < arrlen(post->comments); i++) { + printed = html_post(&post->comments[i], buffer, bufferLen); + buffer += printed; bufferLen -= printed; result += printed; + } + } + printed = snprintf(buffer, bufferLen, + "
" + "" + "" + "
" + "
", + post->user->name, + (size_t)post); + buffer += printed; bufferLen -= printed; result += printed; + return result; +} +char * +html_home(User * user) +{ + Post ** posts = NULL; + for (int i = 0; i < arrlen(user->following); i++) { + User * userF = user->following[i]; + for (int j = 0; j < arrlen(userF->posts); j++) { + Post * post = &userF->posts[j]; + bool inserted = false; + for (int k = 0; k < arrlen(posts); k++) { + if (post->timestamp > posts[k]->timestamp) { + arrins(posts, k, post); + inserted = true; + break; + } + } + if (! inserted) + arrput(posts, post); + } + } + + static char html[HTML_LEN]; + snprintf(html, HTML_LEN, + "" + "" + "" + "
" + "
" + "" + "
", + user->name); + snprintf(html+strlen(html), HTML_LEN-strlen(html), + "
" + "" + "
" + "
" + "" + "
", + user->name, + user->name); + for (int i = 0; i < arrlen(posts); i++) { + html_post(posts[i], html+strlen(html), HTML_LEN-strlen(html)); + } + snprintf(html+strlen(html), HTML_LEN-strlen(html), + "" + ""); + arrfree(posts); + return html; +} + +char * +html_user(User * user) +{ + static char html[HTML_LEN]; + snprintf(html, HTML_LEN, + "" + "" + "" + "
" + "
" + "" + "
", + user->name); + snprintf(html+strlen(html), HTML_LEN-strlen(html), + "
" + "" + "
" + "
" + "" + "
", + user->name, + user->name); + for (int i = arrlen(user->posts) - 1; i >= 0; i--) { + html_post(&user->posts[i], html+strlen(html), HTML_LEN-strlen(html)); + } + snprintf(html+strlen(html), HTML_LEN-strlen(html), + "" + ""); + return html; +} -static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { - if (ev == MG_EV_HTTP_MSG) { - struct mg_http_message *hm = (struct mg_http_message *) ev_data; - if (mg_strcmp(hm->method, mg_str("post"))) { - printf("POST: %.*s\n", hm->body.len, hm->body.ptr); + + +static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) +{ + if (ev == MG_EV_HTTP_MSG) + { + struct mg_http_message *hm = (struct mg_http_message *)ev_data; + + // POST + if (mg_strcmp(hm->method, mg_str("POST")) == 0) + { + // printf("POST: %.*s %.*s\n", + // hm->uri.len, hm->uri.ptr, + // hm->body.len, hm->body.ptr); + // printf("Message: %.*s\n", + // hm->message.len, hm->message.ptr); + + + // TODO: make sure this diesnt error. shhhhhh! + struct mg_str caps[10]; + + if (mg_match(hm->uri, mg_str("/api/post/*"), caps)) { + User * user = UsersFind(caps[0]); + + if (user != NULL) { + Post newPost; + newPost.likes = 0; + newPost.comments = NULL; + newPost.timestamp = time(NULL); + newPost.user = user; + mg_http_get_var(&hm->body, "content", newPost.content, sizeof(newPost.content)-1); + arrput(user->posts, newPost); + } + } + else if (mg_match(hm->uri, mg_str("/api/comment/*/*"), caps)) { + User * user = UsersFind(caps[0]); + + if (user != NULL) { + Post * parent = (Post *)atoll(caps[1].ptr); + if (parent != NULL) { + Post newComment; + newComment.likes = 0; + newComment.comments = NULL; + newComment.timestamp = time(NULL); + newComment.user = user; + mg_http_get_var(&hm->body, "content", newComment.content, sizeof(newComment.content)-1); + arrput(parent->comments, newComment); + } + } + } + else if (mg_match(hm->uri, mg_str("/api/like/*/*"), caps)) { + User * user = UsersFind(caps[0]); + if (user != NULL) { + Post * post = (Post *)atoll(caps[1].ptr); + if (post != NULL) + post->likes++; + } + } + else if (mg_match(hm->uri, mg_str("/api/write/*"), caps)) { + User * user = UsersFind(caps[0]); + if (user != NULL) { + char filename[128]; + snprintf(filename, 128, "data/users/%s", user->name); + FILE * f = fopen(filename, "w"); + UserWrite(user, f); + fclose(f); + } + } + else if (mg_match(hm->uri, mg_str("/api/read/*"), caps)) { + User * user = UsersFind(caps[0]); + if (user != NULL) { + char filename[128]; + snprintf(filename, 128, "data/users/%s", user->name); + FILE * f = fopen(filename, "r"); + UserRead(user, f); + fclose(f); + } + } + http_redirect(c, hm); } - if (mg_http_match_uri(hm, "/user/*/post")) { - struct mg_str caps[2]; - printf("uri: %.*s\n", hm->uri.len, hm->uri.ptr); - mg_match(hm->uri, mg_str("/user/*/post"), caps); - mg_http_reply(c, 200, "", html_user_post(caps[0])); + // GET + else if (mg_strcmp(hm->method, mg_str("GET")) == 0) + { + struct mg_str caps[2]; + + if (mg_match(hm->uri, mg_str("/home/*"), caps)) { + User * user = UsersFind(caps[0]); + + if (user == NULL) + mg_http_reply(c, 200, "", html_user_not_found()); + else + mg_http_reply(c, 200, "", html_home(user)); + } + else if (mg_match(hm->uri, mg_str("/user/*"), caps)) { + User * user = UsersFind(caps[0]); + + if (user == NULL) + mg_http_reply(c, 200, "", html_user_not_found()); + else + mg_http_reply(c, 200, "", html_user(user)); + } + else { + mg_http_reply(c, 404, "", html_404()); + } } else { - mg_http_reply(c, 404, "", "Not found :/"); + mg_http_reply(c, 404, "", "Unknown"); } } } -int main(int argc, char *argv[]) { +int main(int argc, char *argv[]) +{ + UsersSetup(); + struct mg_mgr mgr; - mg_mgr_init(&mgr); // Init manager - mg_http_listen(&mgr, "http://0.0.0.0:8000", fn, &mgr); // Setup listener - for (;;) mg_mgr_poll(&mgr, 1000); // Event loop - mg_mgr_free(&mgr); // Cleanup + mg_mgr_init(&mgr); + mg_http_listen(&mgr, "http://[::]:8000", fn, &mgr); + while (1) + mg_mgr_poll(&mgr, 1000); + mg_mgr_free(&mgr); return 0; }