commit c00e3af

default  ·  2022-12-02 18:14:59 +0000 UTC
parent 450d5a3
Big data storage change.
5 files changed,  +131, -108
M data.c
M html.c
M main.c
M snac.h
+3, -3
 1@@ -879,7 +879,7 @@ int process_message(snac *snac, char *msg, char *req)
 2         if (xs_type(object) == XSTYPE_DICT)
 3             object = xs_dict_get(object, "id");
 4 
 5-        timeline_admire(snac, object, actor, 1);
 6+        timeline_admire(snac, msg, object, actor, 1);
 7         snac_log(snac, xs_fmt("new 'Like' %s %s", actor, object));
 8         do_notify = 1;
 9     }
10@@ -900,7 +900,7 @@ int process_message(snac *snac, char *msg, char *req)
11                 xs *who_o = NULL;
12 
13                 if (valid_status(actor_request(snac, who, &who_o))) {
14-                    timeline_admire(snac, object, actor, 0);
15+                    timeline_admire(snac, msg, object, actor, 0);
16                     snac_log(snac, xs_fmt("new 'Announce' %s %s", actor, object));
17                     do_notify = 1;
18                 }
19@@ -1094,7 +1094,7 @@ int activitypub_get_handler(d_char *req, char *q_path,
20     else
21     if (strcmp(p_path, "outbox") == 0) {
22         xs *id = xs_fmt("%s/outbox", snac.actor);
23-        xs *elems = local_list(&snac, 20);
24+        xs *elems = timeline_list(&snac, "public", 20);
25         xs *list = xs_list_new();
26         msg = msg_collection(&snac, id);
27         char *p, *v;
M data.c
+43, -34
  1@@ -116,6 +116,7 @@ void user_free(snac *snac)
  2     xs_free(snac->config);
  3     xs_free(snac->key);
  4     xs_free(snac->actor);
  5+    xs_free(snac->md5);
  6 }
  7 
  8 
  9@@ -154,6 +155,7 @@ int user_open(snac *snac, char *uid)
 10 
 11                     if ((snac->key = xs_json_loads(key_data)) != NULL) {
 12                         snac->actor = xs_fmt("%s/%s", srv_baseurl, uid);
 13+                        snac->md5   = xs_md5_hex(snac->actor, strlen(snac->actor));
 14                         ret = 1;
 15                     }
 16                     else
 17@@ -566,14 +568,31 @@ int object_del_if_unref(const char *id)
 18 }
 19 
 20 
 21+d_char *_object_metadata(const char *id, const char *idxsfx)
 22+/* returns the content of a metadata index */
 23+{
 24+    xs *fn = _object_fn(id);
 25+    fn = xs_replace_i(fn, ".json", idxsfx);
 26+    return index_list(fn, XS_ALL);
 27+}
 28+
 29+
 30 d_char *object_children(const char *id)
 31 /* returns the list of an object's children */
 32 {
 33-    xs *fn = _object_fn(id);
 34+    return _object_metadata(id, "_c.idx");
 35+}
 36 
 37-    fn = xs_replace_i(fn, ".json", "_c.idx");
 38 
 39-    return index_list(fn, XS_ALL);
 40+d_char *object_likes(const char *id)
 41+{
 42+    return _object_metadata(id, "_l.idx");
 43+}
 44+
 45+
 46+d_char *object_announces(const char *id)
 47+{
 48+    return _object_metadata(id, "_a.idx");
 49 }
 50 
 51 
 52@@ -818,35 +837,6 @@ d_char *timeline_get(snac *snac, char *fn)
 53 }
 54 
 55 
 56-d_char *_timeline_list(snac *snac, char *directory, int max)
 57-/* returns a list of the timeline filenames */
 58-{
 59-    xs *spec = xs_fmt("%s/%s/" "*.json", snac->basedir, directory);
 60-    int c_max;
 61-
 62-    /* maximum number of items in the timeline */
 63-    c_max = xs_number_get(xs_dict_get(srv_config, "max_timeline_entries"));
 64-
 65-    /* never more timeline entries than the configured maximum */
 66-    if (max > c_max)
 67-        max = c_max;
 68-
 69-    return xs_glob_n(spec, 0, 1, max);
 70-}
 71-
 72-
 73-d_char *timeline_list(snac *snac, int max)
 74-{
 75-    return _timeline_list(snac, "timeline", max);
 76-}
 77-
 78-
 79-d_char *local_list(snac *snac, int max)
 80-{
 81-    return _timeline_list(snac, "local", max);
 82-}
 83-
 84-
 85 d_char *_timeline_new_fn(snac *snac, char *id)
 86 /* creates a new filename */
 87 {
 88@@ -1050,7 +1040,7 @@ int timeline_add(snac *snac, char *id, char *o_msg, char *parent, char *referrer
 89 }
 90 
 91 
 92-d_char *timeline_top_level(snac *snac, d_char *list)
 93+d_char *timeline_top_level(d_char *list)
 94 /* returns the top level md5 entries from this index */
 95 {
 96     d_char *tl = xs_list_new();
 97@@ -1094,7 +1084,26 @@ d_char *timeline_top_level(snac *snac, d_char *list)
 98 }
 99 
100 
101-void timeline_admire(snac *snac, char *id, char *admirer, int like)
102+d_char *timeline_list(snac *snac, const char *idx_name, int max)
103+/* returns a timeline */
104+{
105+    int c_max;
106+
107+    /* maximum number of items in the timeline */
108+    c_max = xs_number_get(xs_dict_get(srv_config, "max_timeline_entries"));
109+
110+    /* never more timeline entries than the configured maximum */
111+    if (max > c_max)
112+        max = c_max;
113+
114+    xs *idx  = xs_fmt("%s/%s.idx", snac->basedir, idx_name);
115+    xs *list = index_list_desc(idx, max);
116+
117+    return timeline_top_level(list);
118+}
119+
120+
121+void timeline_admire(snac *snac, char *o_msg, char *id, char *admirer, int like)
122 /* updates a timeline entry with a new admiration */
123 {
124     xs *ofn = _timeline_find_fn(snac, id);
M html.c
+75, -67
  1@@ -386,7 +386,8 @@ d_char *html_entry_controls(snac *snac, d_char *os, char *msg, int num)
  2 {
  3     char *id    = xs_dict_get(msg, "id");
  4     char *actor = xs_dict_get(msg, "attributedTo");
  5-    char *meta  = xs_dict_get(msg, "_snac");
  6+    xs *likes   = object_likes(id);
  7+    xs *boosts  = object_announces(id);
  8 
  9     xs *s   = xs_str_new(NULL);
 10     xs *md5 = xs_md5_hex(id, strlen(id));
 11@@ -407,20 +408,14 @@ d_char *html_entry_controls(snac *snac, d_char *os, char *msg, int num)
 12         s = xs_str_cat(s, s1);
 13     }
 14 
 15-    {
 16-        char *l;
 17-
 18-        l = xs_dict_get(meta, "liked_by");
 19-        if (xs_list_in(l, snac->actor) == -1) {
 20-            /* not already liked; add button */
 21-            s = html_button(s, "like", L("Like"));
 22-        }
 23+    if (xs_list_in(likes, snac->md5) == -1) {
 24+        /* not already liked; add button */
 25+        s = html_button(s, "like", L("Like"));
 26+    }
 27 
 28-        l = xs_dict_get(meta, "announced_by");
 29-        if (strcmp(actor, snac->actor) == 0 || xs_list_in(l, snac->actor) == -1) {
 30-            /* not already boosted or us; add button */
 31-            s = html_button(s, "boost", L("Boost"));
 32-        }
 33+    if (strcmp(actor, snac->actor) == 0 || xs_list_in(boosts, snac->md5) == -1) {
 34+        /* not already boosted or us; add button */
 35+        s = html_button(s, "boost", L("Boost"));
 36     }
 37 
 38     if (strcmp(actor, snac->actor) != 0) {
 39@@ -477,23 +472,20 @@ d_char *html_entry_controls(snac *snac, d_char *os, char *msg, int num)
 40 }
 41 
 42 
 43-d_char *html_entry(snac *snac, d_char *os, char *msg, xs_set *seen, int local, int level, int *num)
 44+d_char *html_entry(snac *snac, d_char *os, char *msg, int local, int level, int *num)
 45 {
 46     char *id    = xs_dict_get(msg, "id");
 47     char *type  = xs_dict_get(msg, "type");
 48-    char *meta  = xs_dict_get(msg, "_snac");
 49     char *actor;
 50     int sensitive = 0;
 51     char *v;
 52+    xs *likes  = NULL;
 53+    xs *boosts = NULL;
 54 
 55     /* do not show non-public messages in the public timeline */
 56     if (local && !is_msg_public(snac, msg))
 57         return os;
 58 
 59-    /* return if already seen */
 60-    if (xs_set_add(seen, id) == 0)
 61-        return os;
 62-
 63     xs *s = xs_str_new(NULL);
 64 
 65     /* top wrap */
 66@@ -522,6 +514,14 @@ d_char *html_entry(snac *snac, d_char *os, char *msg, xs_set *seen, int local, i
 67 
 68         return xs_str_cat(os, s);
 69     }
 70+    else
 71+    if (strcmp(type, "Note") != 0) {
 72+        s = xs_str_cat(s, "<div class=\"snac-post\">\n");
 73+
 74+        xs *s1 = xs_fmt("<p>%s</p>\n", type);
 75+
 76+        return xs_str_cat(os, s);
 77+    }
 78 
 79     /* bring the main actor */
 80     if ((actor = xs_dict_get(msg, "attributedTo")) == NULL)
 81@@ -536,14 +536,14 @@ d_char *html_entry(snac *snac, d_char *os, char *msg, xs_set *seen, int local, i
 82 
 83     /* if this is our post, add the score */
 84     if (xs_startswith(id, snac->actor)) {
 85-        int likes  = xs_list_len(xs_dict_get(meta, "liked_by"));
 86-        int boosts = xs_list_len(xs_dict_get(meta, "announced_by"));
 87+        likes  = object_likes(id);
 88+        boosts = object_announces(id);
 89 
 90         /* alternate emojis: %d &#128077; %d &#128257; */
 91 
 92         xs *s1 = xs_fmt(
 93             "<div class=\"snac-score\">%d &#9733; %d &#8634;</div>\n",
 94-            likes, boosts);
 95+            xs_list_len(likes), xs_list_len(boosts));
 96 
 97         s = xs_str_cat(s, s1);
 98     }
 99@@ -553,28 +553,46 @@ d_char *html_entry(snac *snac, d_char *os, char *msg, xs_set *seen, int local, i
100 
101         s = xs_str_cat(s, "<div class=\"snac-post\">\n");
102 
103-        /* print the origin of the post, if any */
104-        if (!xs_is_null(p = xs_dict_get(meta, "referrer"))) {
105+        if (boosts == NULL)
106+            boosts = object_announces(id);
107+
108+        if (xs_list_len(boosts)) {
109+            /* if somebody boosted this, show as origin */
110+            p = xs_list_get(boosts, 0);
111             xs *actor_r = NULL;
112 
113-            if (valid_status(actor_get(snac, p, &actor_r))) {
114+            if (xs_list_in(boosts, snac->md5) != -1) {
115+                /* we boosted this */
116+                xs *s1 = xs_fmt(
117+                    "<div class=\"snac-origin\">"
118+                    "<a href=\"%s\">%s</a> %s</a></div>",
119+                    snac->actor, xs_dict_get(snac->config, "name"), L("boosted")
120+                );
121+
122+                s = xs_str_cat(s, s1);
123+            }
124+            else
125+            if (valid_status(object_get_by_md5(p, &actor_r, NULL))) {
126                 char *name;
127 
128                 if ((name = xs_dict_get(actor_r, "name")) == NULL)
129                     name = xs_dict_get(actor_r, "preferredUsername");
130 
131-                xs *s1 = xs_fmt(
132-                    "<div class=\"snac-origin\">"
133-                    "<a href=\"%s\">%s</a> %s</div>\n",
134-                    xs_dict_get(actor_r, "id"),
135-                    name,
136-                    L("boosted")
137-                );
138+                if (!xs_is_null(name)) {
139+                    xs *s1 = xs_fmt(
140+                        "<div class=\"snac-origin\">"
141+                        "<a href=\"%s\">%s</a> %s</div>\n",
142+                        xs_dict_get(actor_r, "id"),
143+                        name,
144+                        L("boosted")
145+                    );
146 
147-                s = xs_str_cat(s, s1);
148+                    s = xs_str_cat(s, s1);
149+                }
150             }
151         }
152-        else
153+
154+#if 0
155         if (!xs_is_null((p = xs_dict_get(meta, "parent"))) && *p) {
156             /* this may happen if any of the autor or the parent aren't here */
157             xs *s1 = xs_fmt(
158@@ -586,18 +604,6 @@ d_char *html_entry(snac *snac, d_char *os, char *msg, xs_set *seen, int local, i
159             s = xs_str_cat(s, s1);
160         }
161         else
162-        if (!xs_is_null((p = xs_dict_get(meta, "announced_by"))) &&
163-            xs_list_in(p, snac->actor) != -1) {
164-            /* we boosted this */
165-            xs *s1 = xs_fmt(
166-                "<div class=\"snac-origin\">"
167-                "<a href=\"%s\">%s</a> %s</a></div>",
168-                snac->actor, xs_dict_get(snac->config, "name"), L("boosted")
169-            );
170-
171-            s = xs_str_cat(s, s1);
172-        }
173-        else
174         if (!xs_is_null((p = xs_dict_get(meta, "liked_by"))) &&
175             xs_list_in(p, snac->actor) != -1) {
176             /* we liked this */
177@@ -609,6 +615,7 @@ d_char *html_entry(snac *snac, d_char *os, char *msg, xs_set *seen, int local, i
178 
179             s = xs_str_cat(s, s1);
180         }
181+#endif
182     }
183     else
184         s = xs_str_cat(s, "<div class=\"snac-child\">\n");
185@@ -717,12 +724,11 @@ d_char *html_entry(snac *snac, d_char *os, char *msg, xs_set *seen, int local, i
186         s = html_entry_controls(snac, s, msg, *num);
187 
188     /** children **/
189-
190-    char *children = xs_dict_get(meta, "children");
191-    int left       = xs_list_len(children);
192+    xs *children = object_children(id);
193+    int left     = xs_list_len(children);
194 
195     if (left) {
196-        char *id;
197+        char *p, *cmd5;
198 
199         if (level < 4)
200             s = xs_str_cat(s, "<div class=\"snac-children\">\n");
201@@ -732,16 +738,18 @@ d_char *html_entry(snac *snac, d_char *os, char *msg, xs_set *seen, int local, i
202         if (left > 3)
203             s = xs_str_cat(s, "<details><summary>...</summary>\n");
204 
205-        while (xs_list_iter(&children, &id)) {
206-            xs *chd = timeline_find(snac, id);
207+        p = children;
208+        while (xs_list_iter(&p, &cmd5)) {
209+            xs *chd = NULL;
210+            object_get_by_md5(cmd5, &chd, NULL);
211 
212             if (left == 3)
213                 s = xs_str_cat(s, "</details>\n");
214 
215             if (chd != NULL)
216-                s = html_entry(snac, s, chd, seen, local, level + 1, num);
217+                s = html_entry(snac, s, chd, local, level + 1, num);
218             else
219-                snac_debug(snac, 2, xs_fmt("cannot read from timeline child %s", id));
220+                snac_debug(snac, 2, xs_fmt("cannot read from timeline child %s", cmd5));
221 
222             left--;
223         }
224@@ -773,13 +781,10 @@ d_char *html_timeline(snac *snac, char *list, int local)
225 /* returns the HTML for the timeline */
226 {
227     d_char *s = xs_str_new(NULL);
228-    xs_set seen;
229     char *v;
230     double t = ftime();
231     int num = 0;
232 
233-    xs_set_init(&seen);
234-
235     s = html_user_header(snac, s, local);
236 
237     if (!local)
238@@ -789,9 +794,12 @@ d_char *html_timeline(snac *snac, char *list, int local)
239     s = xs_str_cat(s, "<div class=\"snac-posts\">\n");
240 
241     while (xs_list_iter(&list, &v)) {
242-        xs *msg = timeline_get(snac, v);
243+        xs *msg = NULL;
244+
245+        if (!valid_status(object_get_by_md5(v, &msg, NULL)))
246+            continue;
247 
248-        s = html_entry(snac, s, msg, &seen, local, 0, &num);
249+        s = html_entry(snac, s, msg, local, 0, &num);
250     }
251 
252     s = xs_str_cat(s, "</div>\n");
253@@ -830,8 +838,6 @@ d_char *html_timeline(snac *snac, char *list, int local)
254 
255     s = xs_str_cat(s, "</body>\n</html>\n");
256 
257-    xs_set_free(&seen);
258-
259     return s;
260 }
261 
262@@ -1007,7 +1013,7 @@ int html_get_handler(d_char *req, char *q_path, char **body, int *b_size, char *
263             status  = 200;
264         }
265         else {
266-            xs *list = local_list(&snac, XS_ALL);
267+            xs *list = timeline_list(&snac, "public", XS_ALL);
268 
269             *body   = html_timeline(&snac, list, 1);
270             *b_size = strlen(*body);
271@@ -1033,7 +1039,9 @@ int html_get_handler(d_char *req, char *q_path, char **body, int *b_size, char *
272             else {
273                 snac_debug(&snac, 1, xs_fmt("building timeline"));
274 
275-                xs *list = timeline_list(&snac, XS_ALL);
276+                xs *list = timeline_list(&snac, "private", XS_ALL);
277+
278+                printf("--> %d\n", xs_list_len(list));
279 
280                 *body   = html_timeline(&snac, list, 0);
281                 *b_size = strlen(*body);
282@@ -1098,7 +1106,7 @@ int html_get_handler(d_char *req, char *q_path, char **body, int *b_size, char *
283     if (strcmp(p_path, ".rss") == 0) {
284         /* public timeline in RSS format */
285         d_char *rss;
286-        xs *elems = local_list(&snac, 20);
287+        xs *elems = timeline_list(&snac, "public", 20);
288         xs *bio   = not_really_markdown(xs_dict_get(snac.config, "bio"));
289         char *p, *v;
290 
291@@ -1281,13 +1289,13 @@ int html_post_handler(d_char *req, char *q_path, d_char *payload, int p_size,
292         if (strcmp(action, L("Like")) == 0) {
293             xs *msg = msg_admiration(&snac, id, "Like");
294             post(&snac, msg);
295-            timeline_admire(&snac, id, snac.actor, 1);
296+            timeline_admire(&snac, msg, id, snac.actor, 1);
297         }
298         else
299         if (strcmp(action, L("Boost")) == 0) {
300             xs *msg = msg_admiration(&snac, id, "Announce");
301             post(&snac, msg);
302-            timeline_admire(&snac, id, snac.actor, 0);
303+            timeline_admire(&snac, msg, id, snac.actor, 0);
304         }
305         else
306         if (strcmp(action, L("MUTE")) == 0) {
M main.c
+1, -1
1@@ -167,7 +167,7 @@ int main(int argc, char *argv[])
2 
3         xs *idx  = xs_fmt("%s/private.idx", snac.basedir);
4         xs *list = index_list_desc(idx, 256);
5-        xs *tl   = timeline_top_level(&snac, list);
6+        xs *tl   = timeline_top_level(list);
7 
8         xs *j    = xs_json_dumps_pp(tl, 4);
9         printf("%s\n", j);
M snac.h
+9, -3
 1@@ -33,6 +33,7 @@ typedef struct _snac {
 2     d_char *config;     /* user configuration */
 3     d_char *key;        /* keypair */
 4     d_char *actor;      /* actor url */
 5+    d_char *md5;        /* actor url md5 */
 6 } snac;
 7 
 8 int user_open(snac *snac, char *uid);
 9@@ -59,9 +60,14 @@ int index_first(const char *fn, char *buf, int size);
10 d_char *index_list(const char *fn, int max);
11 d_char *index_list_desc(const char *fn, int max);
12 
13+int object_get_by_md5(const char *md5, d_char **obj, const char *type);
14 int object_del(const char *id);
15 int object_del_if_unref(const char *id);
16 
17+d_char *object_children(const char *id);
18+d_char *object_likes(const char *id);
19+d_char *object_announces(const char *id);
20+
21 int follower_add(snac *snac, const char *actor);
22 int follower_del(snac *snac, const char *actor);
23 int follower_check(snac *snac, const char *actor);
24@@ -73,11 +79,11 @@ d_char *_timeline_find_fn(snac *snac, char *id);
25 d_char *timeline_find(snac *snac, char *id);
26 int timeline_del(snac *snac, char *id);
27 d_char *timeline_get(snac *snac, char *fn);
28-d_char *timeline_list(snac *snac, int max);
29+d_char *timeline_list(snac *snac, const char *idx_name, int max);
30 int timeline_add(snac *snac, char *id, char *o_msg, char *parent, char *referrer);
31-void timeline_admire(snac *snac, char *id, char *admirer, int like);
32+void timeline_admire(snac *snac, char *o_msg, char *id, char *admirer, int like);
33 
34-d_char *timeline_top_level(snac *snac, d_char *list);
35+d_char *timeline_top_level(d_char *list);
36 
37 d_char *local_list(snac *snac, int max);
38