commit c00e3af
default
·
2022-12-02 18:14:59 +0000 UTC
parent 450d5a3
Big data storage change.
5 files changed,
+131,
-108
+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 👍 %d 🔁 */
91
92 xs *s1 = xs_fmt(
93 "<div class=\"snac-score\">%d ★ %d ↺</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