+#include <stdint.h>\r
#include <mongoose.h>\r
#define STB_DS_IMPLEMENTATION\r
#include <stb_ds.h>\r
#define CONTENT_LEN 1024\r
#define HTML_LEN 1024*8\r
\r
-typedef struct post Post;\r
-typedef struct user User;\r
+typedef struct Post Post;\r
+typedef struct User User;\r
\r
User * UsersFind(struct mg_str name);\r
\r
-// Post\r
+// Post / User\r
\r
-struct post {\r
+struct Post {\r
time_t timestamp;\r
User * user;\r
char content[CONTENT_LEN];\r
+ int likes;\r
+ Post * comments;\r
+ Post * parent;\r
};\r
\r
-\r
-\r
-// User\r
-\r
-struct user {\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
+}\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
+}\r
+\r
User\r
UserNew(const char * name) {\r
User result;\r
+ memset(&result, 0, sizeof(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
+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
- 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
+ PostWrite(&user->posts[i], 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
+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
- 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
+ Post post = PostNew();\r
+ PostRead(&post, f);\r
+ arrput(user->posts, post);\r
}\r
- fclose(f);\r
}\r
\r
\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
// HTML\r
\r
void\r
-http_redirect_home(struct mg_connection * c, struct mg_http_message * hm, User * user) {\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
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
+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
- return html;\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>"\r
"<body>"\r
"<form action=\"/api/post/%s\" method=\"post\">"\r
- "<input type=\"text\" name=\"content\"><br>"\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
- snprintf(html+strlen(html), HTML_LEN-strlen(html),\r
- html_post(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
"<html>"\r
"<body>"\r
"<form action=\"/api/post/%s\" method=\"post\">"\r
- "<input type=\"text\" name=\"content\"><br>"\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
- snprintf(html+strlen(html), HTML_LEN-strlen(html),\r
- html_post(&user->posts[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
// hm->message.len, hm->message.ptr);\r
\r
\r
- struct mg_str caps[2];\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.parent = 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
- // UserWrite(user);\r
-\r
- http_redirect_home(c, hm, user);\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.parent = parent;\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