+++ /dev/null
-#include <stdint.h>\r
-#include <mongoose.h>\r
-#define STB_DS_IMPLEMENTATION\r
-#include <stb_ds.h>\r
-\r
-\r
-#define NAME_LEN 32\r
-#define CONTENT_LEN 1024\r
-#define HTML_LEN 1024*8\r
-\r
-typedef struct Post Post;\r
-typedef struct User User;\r
-\r
-User * UsersFind(struct mg_str name);\r
-\r
-// Post / User\r
-\r
-struct Post {\r
- time_t timestamp;\r
- User * user;\r
- char content[CONTENT_LEN];\r
- uint32_t likes;\r
- Post * comments;\r
- //Post * parent;\r
-};\r
-\r
-struct User {\r
- char name[NAME_LEN];\r
- Post * posts;\r
- User ** following;\r
-};\r
-\r
-Post\r
-PostNew() {\r
- Post result;\r
- memset(&result, 0, sizeof(result));\r
- return result;\r
-}\r
-\r
-void\r
-PostWrite(Post * post, FILE * f) {\r
- fwrite(&post->timestamp, 8, 1, f);\r
- fwrite(post->user->name, 1, sizeof(post->user->name), f);\r
- fwrite(post->content, 1, sizeof(post->content), f);\r
- fwrite(&post->likes, 4, 1, f);\r
- uint32_t numComments = arrlen(post->comments);\r
- fwrite(&numComments, 4, 1, f);\r
- for (int i = 0; i < numComments; i++) {\r
- PostWrite(&post->comments[i], f);\r
- }\r
-}\r
-\r
-void\r
-PostRead(Post * post, FILE * f) {\r
- fread(&post->timestamp, 8, 1, f);\r
- char name[NAME_LEN];\r
- fread(name, 1, sizeof(name), f);\r
- post->user = UsersFind(mg_str(name));\r
- fread(post->content, 1, sizeof(post->content), f);\r
- fread(&post->likes, 4, 1, f);\r
- uint32_t numComments;\r
- fread(&numComments, 4, 1, f);\r
- post->comments = NULL;\r
- for (int i = 0; i < numComments; i++) {\r
- Post newComment = PostNew();\r
- PostRead(&newComment, f);\r
- arrput(post->comments, newComment);\r
- }\r
-}\r
-\r
-User\r
-UserNew(const char * name) {\r
- User result;\r
- memset(&result, 0, sizeof(result));\r
- strcpy(result.name, name);\r
- return result;\r
-}\r
-\r
-void\r
-UserWrite(User * user, FILE * f) {\r
- fwrite(user->name, 1, sizeof(user->name), f);\r
-\r
- uint32_t numFollowing = arrlen(user->following);\r
- uint32_t numPosts = arrlen(user->posts);\r
- fwrite(&numFollowing, 4, 1, f);\r
- fwrite(&numPosts, 4, 1, f);\r
-\r
- for (int i = 0; i < numFollowing; i++) {\r
- fwrite(user->following[i]->name, 1, sizeof(user->following[i]->name), f);\r
- }\r
-\r
- for (int i = 0; i < numPosts; i++) {\r
- PostWrite(&user->posts[i], f);\r
- }\r
-}\r
-\r
-void\r
-UserRead(User * user, FILE * f) {\r
- fread(user->name, 1, sizeof(user->name), f);\r
-\r
- uint32_t numFollowing;\r
- uint32_t numPosts;\r
- fread(&numFollowing, 1, 4, f);\r
- fread(&numPosts, 1, 4, f);\r
-\r
- user->following = NULL;\r
- for (int i = 0; i < numFollowing; i++) {\r
- char name[NAME_LEN];\r
- fread(name, 1, sizeof(name), f);\r
- arrput(user->following, UsersFind(mg_str(name)));\r
- }\r
-\r
- user->posts = NULL;\r
- for (int i = 0; i < numPosts; i++) {\r
- Post post = PostNew();\r
- PostRead(&post, f);\r
- arrput(user->posts, post);\r
- }\r
-}\r
-\r
-\r
-\r
-// Users\r
-\r
-User ** g_users;\r
-static User pat, yas, tof;\r
-\r
-void\r
-UsersSetup() {\r
- pat = UserNew("pat");\r
- yas = UserNew("yas");\r
- tof = UserNew("tof");\r
-\r
- arrput(pat.following, &yas);\r
- arrput(yas.following, &pat);\r
- arrput(tof.following, &yas);\r
- arrput(tof.following, &pat);\r
-\r
- arrput(g_users, &pat);\r
- arrput(g_users, &yas);\r
- arrput(g_users, &tof);\r
-}\r
-\r
-User *\r
-UsersFind(struct mg_str name) {\r
- for (int i = 0; i < arrlen(g_users); i++) {\r
- User * user = g_users[i];\r
- if (strncmp(user->name, name.ptr, name.len) == 0)\r
- return user;\r
- }\r
- return NULL;\r
-}\r
-\r
-\r
-\r
-// HTML\r
-\r
-void\r
-http_redirect(struct mg_connection * c, struct mg_http_message * hm) {\r
- struct mg_str *referer = mg_http_get_header(hm, "Referer");\r
-\r
- static char redirectHeaders[128];\r
- snprintf(redirectHeaders, 128,\r
- "Location: %.*s\r\n",\r
- referer->len, referer->ptr);\r
- mg_http_reply(c, 303, redirectHeaders, "");\r
-}\r
-\r
-char *\r
-html_404()\r
-{\r
- static char html[1024];\r
- snprintf(html, 1024,\r
- "<!DOCTYPE html>"\r
- "<html>"\r
- "<body>"\r
- "<p><i>Eeeeeeh?</i> <b>The Website's Under Construction</b></p>"\r
- "</body>"\r
- "</html>");\r
- return html;\r
-}\r
-\r
-char *\r
-html_user_not_found()\r
-{\r
- static char html[1024];\r
- snprintf(html, 1024,\r
- "<!DOCTYPE html>"\r
- "<html>"\r
- "<body>"\r
- "<p>User was not found :/</p>"\r
- "</body>"\r
- "</html>");\r
- return html;\r
-}\r
-\r
-int\r
-html_post(Post * post, char * buffer, int bufferLen) {\r
- int result = 0;\r
- int printed = 0;\r
-\r
- printed = snprintf(buffer, bufferLen,\r
- "<div style=\"border: 2px solid black; margin: 2px; padding: 2px;\">[%s] <a href=\"/user/%s\">%s</a>: %s <br />",\r
- ctime(&post->timestamp),\r
- post->user->name,\r
- post->user->name,\r
- post->content);\r
- buffer += printed; bufferLen -= printed; result += printed;\r
-\r
- if (post->likes > 0) {\r
- printed = snprintf(buffer, bufferLen,\r
- "Likes: %d<br />", post->likes);\r
- buffer += printed; bufferLen -= printed; result += printed;\r
- }\r
-\r
- printed = snprintf(buffer, bufferLen,\r
- "<form action=\"/api/like/%s/%llu\" method=\"post\">"\r
- "<input type=\"submit\" value=\"Like!\">"\r
- "</form>",\r
- post->user->name,\r
- (size_t)post);\r
- buffer += printed; bufferLen -= printed; result += printed;\r
- \r
- if (arrlen(post->comments) > 0) {\r
- printed = snprintf(buffer, bufferLen,\r
- "Comments:<br />");\r
- buffer += printed; bufferLen -= printed; result += printed;\r
-\r
- for (int i = 0; i < arrlen(post->comments); i++) {\r
- printed = html_post(&post->comments[i], buffer, bufferLen);\r
- buffer += printed; bufferLen -= printed; result += printed;\r
- }\r
- }\r
-\r
- printed = snprintf(buffer, bufferLen,\r
- "<form action=\"/api/comment/%s/%llu\" method=\"post\">"\r
- "<input type=\"text\" name=\"content\" autofocus>"\r
- "<input type=\"submit\" value=\"Comment!\">"\r
- "</form>"\r
- "</div>",\r
- post->user->name,\r
- (size_t)post);\r
- buffer += printed; bufferLen -= printed; result += printed;\r
-\r
- return result;\r
-}\r
-\r
-char *\r
-html_home(User * user)\r
-{\r
- Post ** posts = NULL;\r
- for (int i = 0; i < arrlen(user->following); i++) {\r
- User * userF = user->following[i];\r
- for (int j = 0; j < arrlen(userF->posts); j++) {\r
- Post * post = &userF->posts[j];\r
- bool inserted = false;\r
- for (int k = 0; k < arrlen(posts); k++) {\r
- if (post->timestamp > posts[k]->timestamp) {\r
- arrins(posts, k, post);\r
- inserted = true;\r
- break;\r
- }\r
- }\r
- if (! inserted)\r
- arrput(posts, post);\r
- }\r
- }\r
-\r
- static char html[HTML_LEN];\r
- snprintf(html, HTML_LEN,\r
- "<!DOCTYPE html>"\r
- "<html>"\r
- "<body>"\r
- "<form action=\"/api/post/%s\" method=\"post\">"\r
- "<input type=\"text\" name=\"content\" autofocus><br>"\r
- "<input type=\"submit\" value=\"Chirp!\">"\r
- "</form>",\r
- user->name);\r
- snprintf(html+strlen(html), HTML_LEN-strlen(html),\r
- "<form action=\"/api/write/%s\" method=\"post\">"\r
- "<input type=\"submit\" value=\"Write!\">"\r
- "</form>"\r
- "<form action=\"/api/read/%s\" method=\"post\">"\r
- "<input type=\"submit\" value=\"Read!\">"\r
- "</form>",\r
- user->name,\r
- user->name);\r
- for (int i = 0; i < arrlen(posts); i++) {\r
- html_post(posts[i], html+strlen(html), HTML_LEN-strlen(html));\r
- }\r
- snprintf(html+strlen(html), HTML_LEN-strlen(html),\r
- "</body>"\r
- "</html>");\r
- arrfree(posts);\r
- return html;\r
-}\r
-\r
-char *\r
-html_user(User * user)\r
-{\r
- static char html[HTML_LEN];\r
- snprintf(html, HTML_LEN,\r
- "<!DOCTYPE html>"\r
- "<html>"\r
- "<body>"\r
- "<form action=\"/api/post/%s\" method=\"post\">"\r
- "<input type=\"text\" name=\"content\" autofocus><br>"\r
- "<input type=\"submit\" value=\"Chirp!\">"\r
- "</form>",\r
- user->name);\r
- snprintf(html+strlen(html), HTML_LEN-strlen(html),\r
- "<form action=\"/api/write/%s\" method=\"post\">"\r
- "<input type=\"submit\" value=\"Write!\">"\r
- "</form>"\r
- "<form action=\"/api/read/%s\" method=\"post\">"\r
- "<input type=\"submit\" value=\"Read!\">"\r
- "</form>",\r
- user->name,\r
- user->name);\r
- for (int i = arrlen(user->posts) - 1; i >= 0; i--) {\r
- html_post(&user->posts[i], html+strlen(html), HTML_LEN-strlen(html));\r
- }\r
- snprintf(html+strlen(html), HTML_LEN-strlen(html),\r
- "</body>"\r
- "</html>");\r
- return html;\r
-}\r
-\r
-\r
-\r
-static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data)\r
-{\r
- if (ev == MG_EV_HTTP_MSG)\r
- {\r
- struct mg_http_message *hm = (struct mg_http_message *)ev_data;\r
- \r
- // POST\r
- if (mg_strcmp(hm->method, mg_str("POST")) == 0)\r
- {\r
- // printf("POST: %.*s %.*s\n",\r
- // hm->uri.len, hm->uri.ptr,\r
- // hm->body.len, hm->body.ptr);\r
- // printf("Message: %.*s\n",\r
- // hm->message.len, hm->message.ptr);\r
- \r
-\r
- // TODO: make sure this diesnt error. shhhhhh!\r
- struct mg_str caps[10];\r
-\r
- if (mg_match(hm->uri, mg_str("/api/post/*"), caps)) {\r
- User * user = UsersFind(caps[0]);\r
- \r
- if (user != NULL) {\r
- Post newPost;\r
- newPost.likes = 0;\r
- newPost.comments = NULL;\r
- newPost.timestamp = time(NULL);\r
- newPost.user = user;\r
- mg_http_get_var(&hm->body, "content", newPost.content, sizeof(newPost.content)-1);\r
- arrput(user->posts, newPost);\r
- }\r
- }\r
- else if (mg_match(hm->uri, mg_str("/api/comment/*/*"), caps)) {\r
- User * user = UsersFind(caps[0]);\r
- \r
- if (user != NULL) {\r
- Post * parent = (Post *)atoll(caps[1].ptr);\r
- if (parent != NULL) {\r
- Post newComment;\r
- newComment.likes = 0;\r
- newComment.comments = NULL;\r
- newComment.timestamp = time(NULL);\r
- newComment.user = user;\r
- mg_http_get_var(&hm->body, "content", newComment.content, sizeof(newComment.content)-1);\r
- arrput(parent->comments, newComment);\r
- }\r
- }\r
- }\r
- else if (mg_match(hm->uri, mg_str("/api/like/*/*"), caps)) {\r
- User * user = UsersFind(caps[0]);\r
- if (user != NULL) {\r
- Post * post = (Post *)atoll(caps[1].ptr);\r
- if (post != NULL)\r
- post->likes++;\r
- }\r
- }\r
- else if (mg_match(hm->uri, mg_str("/api/write/*"), caps)) {\r
- User * user = UsersFind(caps[0]);\r
- if (user != NULL) {\r
- char filename[128];\r
- snprintf(filename, 128, "data/users/%s", user->name);\r
- FILE * f = fopen(filename, "w");\r
- UserWrite(user, f);\r
- fclose(f);\r
- }\r
- }\r
- else if (mg_match(hm->uri, mg_str("/api/read/*"), caps)) {\r
- User * user = UsersFind(caps[0]);\r
- if (user != NULL) {\r
- char filename[128];\r
- snprintf(filename, 128, "data/users/%s", user->name);\r
- FILE * f = fopen(filename, "r");\r
- UserRead(user, f);\r
- fclose(f);\r
- }\r
- }\r
- http_redirect(c, hm);\r
- }\r
- // GET\r
- else if (mg_strcmp(hm->method, mg_str("GET")) == 0)\r
- {\r
- struct mg_str caps[2];\r
-\r
- if (mg_match(hm->uri, mg_str("/home/*"), caps)) {\r
- User * user = UsersFind(caps[0]);\r
-\r
- if (user == NULL)\r
- mg_http_reply(c, 200, "", html_user_not_found());\r
- else\r
- mg_http_reply(c, 200, "", html_home(user));\r
- }\r
- else if (mg_match(hm->uri, mg_str("/user/*"), caps)) {\r
- User * user = UsersFind(caps[0]);\r
-\r
- if (user == NULL)\r
- mg_http_reply(c, 200, "", html_user_not_found());\r
- else\r
- mg_http_reply(c, 200, "", html_user(user));\r
- }\r
- else {\r
- mg_http_reply(c, 404, "", html_404());\r
- }\r
- }\r
- else {\r
- mg_http_reply(c, 404, "", "Unknown");\r
- }\r
- }\r
-}\r
-\r
-int main(int argc, char *argv[])\r
-{\r
- UsersSetup();\r
-\r
- struct mg_mgr mgr;\r
- mg_mgr_init(&mgr);\r
- mg_http_listen(&mgr, "http://[::]:8000", fn, &mgr);\r
- while (1)\r
- mg_mgr_poll(&mgr, 1000);\r
- mg_mgr_free(&mgr);\r
- return 0;\r
-}\r