]> gitweb.ps.run Git - chirp/commitdiff
posts, following
authorPatrick <patrick.schoenberger@posteo.de>
Sat, 26 Aug 2023 20:34:01 +0000 (22:34 +0200)
committerPatrick <patrick.schoenberger@posteo.de>
Sat, 26 Aug 2023 20:34:01 +0000 (22:34 +0200)
src/main.c

index d26da8ac7f38f29e58a39e22941fcf3dcd96e9b2..fb7ef338f6c5e8084c9194c5aabeeec605c1f7cc 100644 (file)
-#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