-#include "mongoose.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\r
+\r
+struct post {\r
+ time_t timestamp;\r
+ User * user;\r
+ char content[CONTENT_LEN];\r
+};\r
+\r
+\r
+\r
+// User\r
+\r
+struct user {\r
+ char name[NAME_LEN];\r
+ Post * posts;\r
+ User ** following;\r
+};\r
+\r
+User\r
+UserNew(const char * name) {\r
+ User result;\r
+ strcpy(result.name, name);\r
+ result.posts = NULL;\r
+ result.following = NULL;\r
+ return result;\r
+}\r
+\r
+void\r
+UserWrite(User * user) {\r
+ char filename[128];\r
+ snprintf(filename, 128, "data/users/%s", user->name);\r
+ FILE * f = fopen(filename, "w");\r
+\r
+ int numFollowing = arrlen(user->following);\r
+ int numPosts = arrlen(user->posts);\r
+ fwrite(&numFollowing, sizeof(int), 1, f);\r
+ fwrite(&numPosts, sizeof(int), 1, f);\r
+ for (int i = 0; i < numFollowing; i++) {\r
+ fwrite(user->following[i]->name, 1, sizeof(user->following[i]->name), f);\r
+ }\r
+ for (int i = 0; i < numPosts; i++) {\r
+ fwrite(&user->posts[i].timestamp, sizeof(user->posts[i].timestamp), 1, f);\r
+ fwrite(user->posts[i].user->name, 1, sizeof(user->posts[i].user->name), f);\r
+ fwrite(user->posts[i].content, 1, sizeof(user->posts[i].content), f);\r
+ }\r
+ fclose(f);\r
+}\r
+\r
+void\r
+UserRead(User * user) {\r
+ char filename[128];\r
+ snprintf(filename, 128, "data/users/%s", user->name);\r
+ FILE * f = fopen(filename, "r");\r
+\r
+ int numFollowing;\r
+ int numPosts;\r
+ fread(&numFollowing, sizeof(int), 1, f);\r
+ fread(&numPosts, sizeof(int), 1, f);\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
+ for (int i = 0; i < numPosts; i++) {\r
+ char name[NAME_LEN];\r
+ Post post;\r
+ fread(&post.timestamp, sizeof(post.timestamp), 1, f);\r
+ fread(name, 1, sizeof(name), f);\r
+ post.user = UsersFind(mg_str(name));\r
+ fread(post.content, 1, sizeof(post.content), f);\r
+ }\r
+ fclose(f);\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
+ UserRead(&pat);\r
+ UserRead(&yas);\r
+ UserRead(&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_home(struct mg_connection * c, struct mg_http_message * hm, User * user) {\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_user_post(struct mg_str user) {\r
- static char html[1024];\r
- snprintf(html, 1024,\r
- "<!DOCTYPE html>"\r
- "<html>"\r
- "<body>"\r
- "<form action=\"/user/%.*s/post\" method=\"post\">"\r
- " <input type=\"text\" id=\"content\" name=\"content\"><br>"\r
- " <input type=\"submit\" value=\"Chirp!\">"\r
- "</form>"\r
- "</body>"\r
- "</html>",\r
- user.len, user.ptr);\r
- return html;\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
-// Post\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
+char *\r
+html_post(Post * post) {\r
+ static char html[2048];\r
+ snprintf(html, 2048,\r
+ "<p>[%s] <a href=\"/user/%s\">%s</a>: %s</p>",\r
+ ctime(&post->timestamp),\r
+ post->user->name,\r
+ post->user->name,\r
+ post->content);\r
+ return html;\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\"><br>"\r
+ "<input type=\"submit\" value=\"Chirp!\">"\r
+ "</form>",\r
+ user->name);\r
+ for (int i = 0; i < arrlen(posts); i++) {\r
+ snprintf(html+strlen(html), HTML_LEN-strlen(html),\r
+ html_post(posts[i]));\r
+ }\r
+ snprintf(html+strlen(html), HTML_LEN-strlen(html),\r
+ "</body>"\r
+ "</html>");\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\"><br>"\r
+ "<input type=\"submit\" value=\"Chirp!\">"\r
+ "</form>",\r
+ user->name);\r
+ for (int i = arrlen(user->posts) - 1; i >= 0; i--) {\r
+ snprintf(html+strlen(html), HTML_LEN-strlen(html),\r
+ html_post(&user->posts[i]));\r
+ }\r
+ snprintf(html+strlen(html), HTML_LEN-strlen(html),\r
+ "</body>"\r
+ "</html>");\r
+ return html;\r
+}\r
\r
-// User\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
+ struct mg_str caps[2];\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.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
-static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {\r
- if (ev == MG_EV_HTTP_MSG) {\r
- struct mg_http_message *hm = (struct mg_http_message *) ev_data;\r
- if (mg_strcmp(hm->method, mg_str("post"))) {\r
- printf("POST: %.*s\n", hm->body.len, hm->body.ptr);\r
+ UserWrite(user);\r
+\r
+ http_redirect_home(c, hm, user);\r
+ }\r
+ }\r
}\r
- if (mg_http_match_uri(hm, "/user/*/post")) {\r
- struct mg_str caps[2];\r
- printf("uri: %.*s\n", hm->uri.len, hm->uri.ptr);\r
- mg_match(hm->uri, mg_str("/user/*/post"), caps);\r
- mg_http_reply(c, 200, "", html_user_post(caps[0]));\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, "", "Not found :/");\r
+ mg_http_reply(c, 404, "", "Unknown");\r
}\r
}\r
}\r
\r
-int main(int argc, char *argv[]) {\r
+int main(int argc, char *argv[])\r
+{\r
+ UsersSetup();\r
+\r
struct mg_mgr mgr;\r
- mg_mgr_init(&mgr); // Init manager\r
- mg_http_listen(&mgr, "http://0.0.0.0:8000", fn, &mgr); // Setup listener\r
- for (;;) mg_mgr_poll(&mgr, 1000); // Event loop\r
- mg_mgr_free(&mgr); // Cleanup\r
+ mg_mgr_init(&mgr);\r
+ mg_http_listen(&mgr, "http://0.0.0.0:8000", fn, &mgr);\r
+ while (1)\r
+ mg_mgr_poll(&mgr, 1000);\r
+ mg_mgr_free(&mgr);\r
return 0;\r
}\r