1 #include <mongoose.h>
\r
2 #define STB_DS_IMPLEMENTATION
\r
7 #define CONTENT_LEN 1024
\r
8 #define HTML_LEN 1024*8
\r
10 typedef struct post Post;
\r
11 typedef struct user User;
\r
13 User * UsersFind(struct mg_str name);
\r
20 char content[CONTENT_LEN];
\r
28 char name[NAME_LEN];
\r
34 UserNew(const char * name) {
\r
36 strcpy(result.name, name);
\r
37 result.posts = NULL;
\r
38 result.following = NULL;
\r
43 UserWrite(User * user) {
\r
45 snprintf(filename, 128, "data/users/%s", user->name);
\r
46 FILE * f = fopen(filename, "w");
\r
48 int numFollowing = arrlen(user->following);
\r
49 int numPosts = arrlen(user->posts);
\r
50 fwrite(&numFollowing, sizeof(int), 1, f);
\r
51 fwrite(&numPosts, sizeof(int), 1, f);
\r
52 for (int i = 0; i < numFollowing; i++) {
\r
53 fwrite(user->following[i]->name, 1, sizeof(user->following[i]->name), f);
\r
55 for (int i = 0; i < numPosts; i++) {
\r
56 fwrite(&user->posts[i].timestamp, sizeof(user->posts[i].timestamp), 1, f);
\r
57 fwrite(user->posts[i].user->name, 1, sizeof(user->posts[i].user->name), f);
\r
58 fwrite(user->posts[i].content, 1, sizeof(user->posts[i].content), f);
\r
64 UserRead(User * user) {
\r
66 snprintf(filename, 128, "data/users/%s", user->name);
\r
67 FILE * f = fopen(filename, "r");
\r
71 fread(&numFollowing, sizeof(int), 1, f);
\r
72 fread(&numPosts, sizeof(int), 1, f);
\r
73 for (int i = 0; i < numFollowing; i++) {
\r
74 char name[NAME_LEN];
\r
75 fread(name, 1, sizeof(name), f);
\r
76 arrput(user->following, UsersFind(mg_str(name)));
\r
78 for (int i = 0; i < numPosts; i++) {
\r
79 char name[NAME_LEN];
\r
81 fread(&post.timestamp, sizeof(post.timestamp), 1, f);
\r
82 fread(name, 1, sizeof(name), f);
\r
83 post.user = UsersFind(mg_str(name));
\r
84 fread(post.content, 1, sizeof(post.content), f);
\r
94 static User pat, yas, tof;
\r
98 pat = UserNew("pat");
\r
99 yas = UserNew("yas");
\r
100 tof = UserNew("tof");
\r
106 arrput(pat.following, &yas);
\r
107 arrput(yas.following, &pat);
\r
108 arrput(tof.following, &yas);
\r
109 arrput(tof.following, &pat);
\r
111 arrput(g_users, &pat);
\r
112 arrput(g_users, &yas);
\r
113 arrput(g_users, &tof);
\r
117 UsersFind(struct mg_str name) {
\r
118 for (int i = 0; i < arrlen(g_users); i++) {
\r
119 User * user = g_users[i];
\r
120 if (strncmp(user->name, name.ptr, name.len) == 0)
\r
131 http_redirect_home(struct mg_connection * c, struct mg_http_message * hm, User * user) {
\r
132 struct mg_str *referer = mg_http_get_header(hm, "Referer");
\r
134 static char redirectHeaders[128];
\r
135 snprintf(redirectHeaders, 128,
\r
136 "Location: %.*s\r\n",
\r
137 referer->len, referer->ptr);
\r
138 mg_http_reply(c, 303, redirectHeaders, "");
\r
144 static char html[1024];
\r
145 snprintf(html, 1024,
\r
149 "<p><i>Eeeeeeh?</i> <b>The Website's Under Construction</b></p>"
\r
156 html_user_not_found()
\r
158 static char html[1024];
\r
159 snprintf(html, 1024,
\r
163 "<p>User was not found :/</p>"
\r
170 html_post(Post * post) {
\r
171 static char html[2048];
\r
172 snprintf(html, 2048,
\r
173 "<p>[%s] <a href=\"/user/%s\">%s</a>: %s</p>",
\r
174 ctime(&post->timestamp),
\r
182 html_home(User * user)
\r
184 Post ** posts = NULL;
\r
185 for (int i = 0; i < arrlen(user->following); i++) {
\r
186 User * userF = user->following[i];
\r
187 for (int j = 0; j < arrlen(userF->posts); j++) {
\r
188 Post * post = &userF->posts[j];
\r
189 bool inserted = false;
\r
190 for (int k = 0; k < arrlen(posts); k++) {
\r
191 if (post->timestamp > posts[k]->timestamp) {
\r
192 arrins(posts, k, post);
\r
198 arrput(posts, post);
\r
202 static char html[HTML_LEN];
\r
203 snprintf(html, HTML_LEN,
\r
207 "<form action=\"/api/post/%s\" method=\"post\">"
\r
208 "<input type=\"text\" name=\"content\"><br>"
\r
209 "<input type=\"submit\" value=\"Chirp!\">"
\r
212 for (int i = 0; i < arrlen(posts); i++) {
\r
213 snprintf(html+strlen(html), HTML_LEN-strlen(html),
\r
214 html_post(posts[i]));
\r
216 snprintf(html+strlen(html), HTML_LEN-strlen(html),
\r
223 html_user(User * user)
\r
225 static char html[HTML_LEN];
\r
226 snprintf(html, HTML_LEN,
\r
230 "<form action=\"/api/post/%s\" method=\"post\">"
\r
231 "<input type=\"text\" name=\"content\"><br>"
\r
232 "<input type=\"submit\" value=\"Chirp!\">"
\r
235 for (int i = arrlen(user->posts) - 1; i >= 0; i--) {
\r
236 snprintf(html+strlen(html), HTML_LEN-strlen(html),
\r
237 html_post(&user->posts[i]));
\r
239 snprintf(html+strlen(html), HTML_LEN-strlen(html),
\r
247 static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data)
\r
249 if (ev == MG_EV_HTTP_MSG)
\r
251 struct mg_http_message *hm = (struct mg_http_message *)ev_data;
\r
254 if (mg_strcmp(hm->method, mg_str("POST")) == 0)
\r
256 // printf("POST: %.*s %.*s\n",
\r
257 // hm->uri.len, hm->uri.ptr,
\r
258 // hm->body.len, hm->body.ptr);
\r
259 // printf("Message: %.*s\n",
\r
260 // hm->message.len, hm->message.ptr);
\r
263 struct mg_str caps[2];
\r
265 if (mg_match(hm->uri, mg_str("/api/post/*"), caps)) {
\r
266 User * user = UsersFind(caps[0]);
\r
268 if (user != NULL) {
\r
270 newPost.timestamp = time(NULL);
\r
271 newPost.user = user;
\r
272 mg_http_get_var(&hm->body, "content", newPost.content, sizeof(newPost.content)-1);
\r
273 arrput(user->posts, newPost);
\r
275 // UserWrite(user);
\r
277 http_redirect_home(c, hm, user);
\r
282 else if (mg_strcmp(hm->method, mg_str("GET")) == 0)
\r
284 struct mg_str caps[2];
\r
286 if (mg_match(hm->uri, mg_str("/home/*"), caps)) {
\r
287 User * user = UsersFind(caps[0]);
\r
290 mg_http_reply(c, 200, "", html_user_not_found());
\r
292 mg_http_reply(c, 200, "", html_home(user));
\r
294 else if (mg_match(hm->uri, mg_str("/user/*"), caps)) {
\r
295 User * user = UsersFind(caps[0]);
\r
298 mg_http_reply(c, 200, "", html_user_not_found());
\r
300 mg_http_reply(c, 200, "", html_user(user));
\r
303 mg_http_reply(c, 404, "", html_404());
\r
307 mg_http_reply(c, 404, "", "Unknown");
\r
312 int main(int argc, char *argv[])
\r
318 mg_http_listen(&mgr, "http://0.0.0.0:8000", fn, &mgr);
\r
320 mg_mgr_poll(&mgr, 1000);
\r