abouttreesummaryrefslogcommitdiff
diff options
context:
space:
mode:
authorPatrick2023-08-26 22:34:01 +0200
committerPatrick2023-08-26 22:34:01 +0200
commit46cdeacd5f0bb421055d628e21c71f4e2b7e36c4 (patch)
treed1e761e44aff35e6514fd0431e0a8e92037f9ebd
parent5baef6aec75ac5ca18222150a538a5c8c6c01931 (diff)
downloadchirp-46cdeacd5f0bb421055d628e21c71f4e2b7e36c4.tar.gz
chirp-46cdeacd5f0bb421055d628e21c71f4e2b7e36c4.zip
posts, following
-rw-r--r--src/main.c330
1 files changed, 297 insertions, 33 deletions
diff --git a/src/main.c b/src/main.c
index d26da8a..fb7ef33 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,59 +1,323 @@
-#include "mongoose.h"
+#include <mongoose.h>
+#define STB_DS_IMPLEMENTATION
+#include <stb_ds.h>
+
+
+#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
+
+struct post {
+ time_t timestamp;
+ User * user;
+ char content[CONTENT_LEN];
+};
+
+
+
+// User
+
+struct user {
+ char name[NAME_LEN];
+ Post * posts;
+ User ** following;
+};
+
+User
+UserNew(const char * name) {
+ User result;
+ strcpy(result.name, name);
+ result.posts = NULL;
+ result.following = NULL;
+ return result;
+}
+
+void
+UserWrite(User * user) {
+ char filename[128];
+ snprintf(filename, 128, "data/users/%s", user->name);
+ FILE * f = fopen(filename, "w");
+
+ int numFollowing = arrlen(user->following);
+ int numPosts = arrlen(user->posts);
+ fwrite(&numFollowing, sizeof(int), 1, f);
+ fwrite(&numPosts, sizeof(int), 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++) {
+ fwrite(&user->posts[i].timestamp, sizeof(user->posts[i].timestamp), 1, f);
+ fwrite(user->posts[i].user->name, 1, sizeof(user->posts[i].user->name), f);
+ fwrite(user->posts[i].content, 1, sizeof(user->posts[i].content), f);
+ }
+ fclose(f);
+}
+
+void
+UserRead(User * user) {
+ char filename[128];
+ snprintf(filename, 128, "data/users/%s", user->name);
+ FILE * f = fopen(filename, "r");
+
+ int numFollowing;
+ int numPosts;
+ fread(&numFollowing, sizeof(int), 1, f);
+ fread(&numPosts, sizeof(int), 1, f);
+ for (int i = 0; i < numFollowing; i++) {
+ char name[NAME_LEN];
+ fread(name, 1, sizeof(name), f);
+ arrput(user->following, UsersFind(mg_str(name)));
+ }
+ for (int i = 0; i < numPosts; i++) {
+ char name[NAME_LEN];
+ Post post;
+ fread(&post.timestamp, sizeof(post.timestamp), 1, f);
+ fread(name, 1, sizeof(name), f);
+ post.user = UsersFind(mg_str(name));
+ fread(post.content, 1, sizeof(post.content), f);
+ }
+ fclose(f);
+}
+
+
+
+// Users
+
+User ** g_users;
+static User pat, yas, tof;
+
+void
+UsersSetup() {
+ pat = UserNew("pat");
+ yas = UserNew("yas");
+ tof = UserNew("tof");
+
+ UserRead(&pat);
+ UserRead(&yas);
+ UserRead(&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_home(struct mg_connection * c, struct mg_http_message * hm, User * user) {
+ 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,
- "<!DOCTYPE html>"
- "<html>"
- "<body>"
- "<form action=\"/user/%.*s/post\" method=\"post\">"
- " <input type=\"text\" id=\"content\" name=\"content\"><br>"
- " <input type=\"submit\" value=\"Chirp!\">"
- "</form>"
- "</body>"
- "</html>",
- user.len, user.ptr);
- return html;
+html_404()
+{
+ static char html[1024];
+ snprintf(html, 1024,
+ "<!DOCTYPE html>"
+ "<html>"
+ "<body>"
+ "<p><i>Eeeeeeh?</i> <b>The Website's Under Construction</b></p>"
+ "</body>"
+ "</html>");
+ return html;
}
-// Post
+char *
+html_user_not_found()
+{
+ static char html[1024];
+ snprintf(html, 1024,
+ "<!DOCTYPE html>"
+ "<html>"
+ "<body>"
+ "<p>User was not found :/</p>"
+ "</body>"
+ "</html>");
+ return html;
+}
+
+char *
+html_post(Post * post) {
+ static char html[2048];
+ snprintf(html, 2048,
+ "<p>[%s] <a href=\"/user/%s\">%s</a>: %s</p>",
+ ctime(&post->timestamp),
+ post->user->name,
+ post->user->name,
+ post->content);
+ return html;
+}
+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,
+ "<!DOCTYPE html>"
+ "<html>"
+ "<body>"
+ "<form action=\"/api/post/%s\" method=\"post\">"
+ "<input type=\"text\" name=\"content\"><br>"
+ "<input type=\"submit\" value=\"Chirp!\">"
+ "</form>",
+ user->name);
+ for (int i = 0; i < arrlen(posts); i++) {
+ snprintf(html+strlen(html), HTML_LEN-strlen(html),
+ html_post(posts[i]));
+ }
+ snprintf(html+strlen(html), HTML_LEN-strlen(html),
+ "</body>"
+ "</html>");
+ return html;
+}
+char *
+html_user(User * user)
+{
+ static char html[HTML_LEN];
+ snprintf(html, HTML_LEN,
+ "<!DOCTYPE html>"
+ "<html>"
+ "<body>"
+ "<form action=\"/api/post/%s\" method=\"post\">"
+ "<input type=\"text\" name=\"content\"><br>"
+ "<input type=\"submit\" value=\"Chirp!\">"
+ "</form>",
+ user->name);
+ for (int i = arrlen(user->posts) - 1; i >= 0; i--) {
+ snprintf(html+strlen(html), HTML_LEN-strlen(html),
+ html_post(&user->posts[i]));
+ }
+ snprintf(html+strlen(html), HTML_LEN-strlen(html),
+ "</body>"
+ "</html>");
+ return html;
+}
-// User
+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);
+
+ struct mg_str caps[2];
+ if (mg_match(hm->uri, mg_str("/api/post/*"), caps)) {
+ User * user = UsersFind(caps[0]);
+
+ if (user != NULL) {
+ Post newPost;
+ newPost.timestamp = time(NULL);
+ newPost.user = user;
+ mg_http_get_var(&hm->body, "content", newPost.content, sizeof(newPost.content)-1);
+ arrput(user->posts, newPost);
-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);
+ UserWrite(user);
+
+ http_redirect_home(c, hm, user);
+ }
+ }
}
- 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://0.0.0.0:8000", fn, &mgr);
+ while (1)
+ mg_mgr_poll(&mgr, 1000);
+ mg_mgr_free(&mgr);
return 0;
}