mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-18 20:57:56 +00:00
Add restful API for feed activity
This commit is contained in:
parent
bfbd2ddccd
commit
be9c138559
1
httpd.h
1
httpd.h
@ -220,6 +220,7 @@ typedef struct httpd_request
|
||||
|
||||
struct {
|
||||
rhizome_bid_t bundle_id;
|
||||
struct meshmb_activity_iterator *iterator;
|
||||
struct meshmb_session *session;
|
||||
uint8_t generation;
|
||||
enum list_phase phase;
|
||||
|
131
meshmb_restful.c
131
meshmb_restful.c
@ -595,6 +595,10 @@ static void feedlist_on_rhizome_add(httpd_request *r, rhizome_manifest *m)
|
||||
|
||||
static void feedlist_finalise(httpd_request *r)
|
||||
{
|
||||
if (r->u.meshmb_feeds.iterator){
|
||||
meshmb_activity_close(r->u.meshmb_feeds.iterator);
|
||||
r->u.meshmb_feeds.iterator = NULL;
|
||||
}
|
||||
close_session(r->u.meshmb_feeds.session);
|
||||
}
|
||||
|
||||
@ -621,6 +625,129 @@ static int restful_meshmb_feedlist(httpd_request *r, const char *remainder)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int restful_meshmb_activity_json_content_chunk(struct http_request *hr, strbuf b)
|
||||
{
|
||||
httpd_request *r = (httpd_request *) hr;
|
||||
const char *headers[] = {
|
||||
"token",
|
||||
"id",
|
||||
"author",
|
||||
"name",
|
||||
"timestamp",
|
||||
"offset",
|
||||
"message"
|
||||
};
|
||||
|
||||
DEBUGF(httpd, "Phase %d", r->u.meshmb_feeds.phase);
|
||||
|
||||
struct meshmb_activity_iterator *iterator = r->u.meshmb_feeds.iterator;
|
||||
|
||||
switch (r->u.meshmb_feeds.phase) {
|
||||
case LIST_HEADER:
|
||||
strbuf_puts(b, "{\n\"header\":[");
|
||||
unsigned i;
|
||||
for (i = 0; i != NELS(headers); ++i) {
|
||||
if (i)
|
||||
strbuf_putc(b, ',');
|
||||
strbuf_json_string(b, headers[i]);
|
||||
}
|
||||
strbuf_puts(b, "],\n\"rows\":[");
|
||||
if (strbuf_overrun(b))
|
||||
return 1;
|
||||
|
||||
if(meshmb_activity_next(iterator)==1)
|
||||
r->u.meshmb_feeds.phase = LIST_ROWS;
|
||||
else{
|
||||
r->u.meshmb_feeds.phase = LIST_END;
|
||||
return 1;
|
||||
}
|
||||
// fallthrough
|
||||
case LIST_ROWS:
|
||||
case LIST_FIRST:
|
||||
{
|
||||
size_t checkpoint = strbuf_len(b);
|
||||
|
||||
while(r->u.meshmb_feeds.phase == LIST_ROWS){
|
||||
switch(iterator->msg_reader.type){
|
||||
case MESSAGE_BLOCK_TYPE_MESSAGE:
|
||||
if (r->u.meshmb_feeds.rowcount!=0)
|
||||
strbuf_putc(b, ',');
|
||||
strbuf_puts(b, "\n[");
|
||||
strbuf_sprintf(b, "%zu", r->u.meshmb_feeds.rowcount);
|
||||
strbuf_puts(b, ",");
|
||||
strbuf_json_hex(b, iterator->msg_reader.bundle_id.binary, sizeof iterator->msg_reader.bundle_id.binary);
|
||||
strbuf_puts(b, ",");
|
||||
strbuf_json_hex(b, iterator->msg_reader.author.binary, sizeof iterator->msg_reader.author.binary);
|
||||
strbuf_puts(b, ",");
|
||||
strbuf_json_string(b, iterator->msg_reader.name);
|
||||
strbuf_puts(b, ",");
|
||||
strbuf_sprintf(b, "%d", iterator->ack_timestamp);
|
||||
strbuf_puts(b, ",");
|
||||
strbuf_sprintf(b, "%lu", iterator->msg_reader.record_end_offset);
|
||||
strbuf_puts(b, ",");
|
||||
strbuf_json_string(b, (const char *)iterator->msg_reader.record);
|
||||
strbuf_puts(b, "]");
|
||||
if (strbuf_overrun(b)){
|
||||
strbuf_trunc(b, checkpoint);
|
||||
return 1;
|
||||
}
|
||||
checkpoint = strbuf_len(b);
|
||||
r->u.meshmb_feeds.rowcount++;
|
||||
}
|
||||
if(meshmb_activity_next(iterator)==1)
|
||||
r->u.meshmb_feeds.phase = LIST_ROWS;
|
||||
else
|
||||
r->u.meshmb_feeds.phase = LIST_END;
|
||||
}
|
||||
}
|
||||
|
||||
// fallthrough
|
||||
case LIST_END:
|
||||
strbuf_puts(b, "\n]\n}\n");
|
||||
if (!strbuf_overrun(b))
|
||||
r->u.plylist.phase = LIST_DONE;
|
||||
|
||||
// fall through...
|
||||
case LIST_DONE:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int restful_meshmb_activity_json_content(struct http_request *hr, unsigned char *buf, size_t bufsz, struct http_content_generator_result *result)
|
||||
{
|
||||
return generate_http_content_from_strbuf_chunks(hr, (char *)buf, bufsz, result, restful_meshmb_activity_json_content_chunk);
|
||||
}
|
||||
|
||||
static int restful_meshmb_activity(httpd_request *r, const char *remainder)
|
||||
{
|
||||
if (*remainder)
|
||||
return 404;
|
||||
|
||||
struct meshmb_session *session = open_session(&r->bid);
|
||||
if (!session){
|
||||
http_request_simple_response(&r->http, 500, "TODO, detailed response");
|
||||
return 500;
|
||||
}
|
||||
struct meshmb_activity_iterator *iterator = meshmb_activity_open(session->feeds);
|
||||
if (!iterator){
|
||||
close_session(session);
|
||||
http_request_simple_response(&r->http, 500, "TODO, detailed response");
|
||||
return 500;
|
||||
}
|
||||
assert(r->finalise_union == NULL);
|
||||
r->finalise_union = feedlist_finalise;
|
||||
r->trigger_rhizome_bundle_added = feedlist_on_rhizome_add;
|
||||
r->u.meshmb_feeds.phase = LIST_HEADER;
|
||||
r->u.meshmb_feeds.session = session;
|
||||
r->u.meshmb_feeds.iterator = iterator;
|
||||
r->u.meshmb_feeds.generation = meshmb_flush(session->feeds);
|
||||
bzero(&r->u.meshmb_feeds.bundle_id, sizeof r->u.meshmb_feeds.bundle_id);
|
||||
|
||||
http_request_response_generated(&r->http, 200, CONTENT_TYPE_JSON, restful_meshmb_activity_json_content);
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
DECLARE_HANDLER("/restful/meshmb/", restful_meshmb_);
|
||||
static int restful_meshmb_(httpd_request *r, const char *remainder)
|
||||
{
|
||||
@ -649,6 +776,10 @@ static int restful_meshmb_(httpd_request *r, const char *remainder)
|
||||
handler = restful_meshmb_feedlist;
|
||||
remainder = "";
|
||||
r->ui64 = 0;
|
||||
} else if (strcmp(remainder, "/activity.json") == 0) {
|
||||
handler = restful_meshmb_activity;
|
||||
remainder = "";
|
||||
r->ui64 = 0;
|
||||
} else if ( str_startswith(remainder, "/newsince/", &end)
|
||||
&& strn_to_position_token(end, &r->ui64, &end)
|
||||
&& strcmp(end, "messagelist.json") == 0) {
|
||||
|
@ -174,5 +174,58 @@ test_MeshMBRestFeeds() {
|
||||
])"
|
||||
}
|
||||
|
||||
doc_MeshMBRestActivity="Restful thread incoming activity"
|
||||
setup_MeshMBRestActivity() {
|
||||
IDENTITY_COUNT=5
|
||||
setup
|
||||
executeOk_servald keyring set did $SIDA1 "" "Feed A"
|
||||
executeOk_servald keyring set did $SIDA2 "" "Feed B"
|
||||
executeOk_servald keyring set did $SIDA3 "" "Feed C"
|
||||
executeOk_servald keyring set did $SIDA4 "" "Feed D"
|
||||
executeOk_servald keyring set did $SIDA5 "" "Feed E"
|
||||
executeOk_servald meshmb send $IDA2 "Message 2"
|
||||
executeOk_servald meshmb send $IDA3 "Message 3"
|
||||
executeOk_servald meshmb follow $IDA1 $IDA2
|
||||
executeOk_servald meshmb follow $IDA1 $IDA3
|
||||
executeOk_servald meshmb send $IDA4 "Message 4"
|
||||
executeOk_servald meshmb follow $IDA1 $IDA4
|
||||
executeOk_servald meshmb send $IDA4 "Message 5"
|
||||
executeOk_servald meshmb activity $IDA1
|
||||
executeOk_servald meshmb send $IDA5 "Message 6"
|
||||
executeOk_servald meshmb follow $IDA1 $IDA5
|
||||
executeOk_servald meshmb send $IDA2 "Message 7"
|
||||
executeOk_servald meshmb activity $IDA1
|
||||
executeOk_servald meshmb send $IDA3 "Message 8"
|
||||
executeOk_servald meshmb activity $IDA1
|
||||
executeOk_servald meshmb send $IDA4 "Message 9"
|
||||
executeOk_servald meshmb activity $IDA1
|
||||
executeOk_servald meshmb send $IDA5 "Message 10"
|
||||
executeOk_servald meshmb activity $IDA1
|
||||
}
|
||||
test_MeshMBRestActivity() {
|
||||
executeOk curl \
|
||||
-H "Expect:" \
|
||||
--silent --fail --show-error \
|
||||
--output activity.json \
|
||||
--dump-header http.headers \
|
||||
--basic --user harry:potter \
|
||||
"http://$addr_localhost:$PORTA/restful/meshmb/$IDA1/activity.json"
|
||||
tfw_cat http.headers activity.json
|
||||
tfw_preserve activity.json
|
||||
assert [ "$(jq '.rows | length' activity.json)" = 9 ]
|
||||
transform_list_json activity.json list.json
|
||||
tfw_preserve list.json
|
||||
|
||||
assertJq list.json "contains([{ __index: 0, id: \"$IDA5\", author: \"$SIDA5\", name: \"Feed E\", message: \"Message 10\"}])"
|
||||
assertJq list.json "contains([{ __index: 1, id: \"$IDA4\", author: \"$SIDA4\", name: \"Feed D\", message: \"Message 9\"}])"
|
||||
assertJq list.json "contains([{ __index: 2, id: \"$IDA3\", author: \"$SIDA3\", name: \"Feed C\", message: \"Message 8\"}])"
|
||||
assertJq list.json "contains([{ __index: 3, id: \"$IDA2\", author: \"$SIDA2\", name: \"Feed B\", message: \"Message 7\"}])"
|
||||
assertJq list.json "contains([{ __index: 4, id: \"$IDA5\", author: \"$SIDA5\", name: \"Feed E\", message: \"Message 6\"}])"
|
||||
assertJq list.json "contains([{ __index: 5, id: \"$IDA4\", author: \"$SIDA4\", name: \"Feed D\", message: \"Message 5\"}])"
|
||||
assertJq list.json "contains([{ __index: 6, id: \"$IDA4\", author: \"$SIDA4\", name: \"Feed D\", message: \"Message 4\"}])"
|
||||
assertJq list.json "contains([{ __index: 7, id: \"$IDA3\", author: \"$SIDA3\", name: \"Feed C\", message: \"Message 3\"}])"
|
||||
assertJq list.json "contains([{ __index: 8, id: \"$IDA2\", author: \"$SIDA2\", name: \"Feed B\", message: \"Message 2\"}])"
|
||||
}
|
||||
|
||||
runTests "$@"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user