mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-18 10:46:23 +00:00
Restful meshmb list subscribed feeds
This commit is contained in:
parent
e7ca268dbc
commit
d2dfe71f26
3
httpd.h
3
httpd.h
@ -43,6 +43,7 @@ struct form_buf_malloc {
|
||||
};
|
||||
|
||||
struct httpd_request;
|
||||
struct meshmb_session;
|
||||
|
||||
int form_buf_malloc_init(struct form_buf_malloc *, size_t size_limit);
|
||||
int form_buf_malloc_accumulate(struct httpd_request *, const char *partname, struct form_buf_malloc *, const char *, size_t);
|
||||
@ -219,6 +220,8 @@ typedef struct httpd_request
|
||||
|
||||
struct {
|
||||
rhizome_bid_t bundle_id;
|
||||
struct meshmb_session *session;
|
||||
uint8_t generation;
|
||||
enum list_phase phase;
|
||||
size_t rowcount;
|
||||
} meshmb_feeds;
|
||||
|
7
meshmb.c
7
meshmb.c
@ -27,6 +27,7 @@ struct meshmb_feeds{
|
||||
keyring_identity *id;
|
||||
sign_keypair_t bundle_keypair;
|
||||
bool_t dirty;
|
||||
uint8_t generation;
|
||||
};
|
||||
|
||||
// only remember this many bytes of ply names & last messages
|
||||
@ -175,7 +176,7 @@ int meshmb_flush(struct meshmb_feeds *feeds)
|
||||
{
|
||||
if (!feeds->dirty){
|
||||
DEBUGF(meshmb, "Ignoring flush, not dirty");
|
||||
return 0;
|
||||
return feeds->generation;
|
||||
}
|
||||
|
||||
rhizome_manifest *mout = NULL;
|
||||
@ -210,14 +211,14 @@ int meshmb_flush(struct meshmb_feeds *feeds)
|
||||
rhizome_manifest_set_filesize(m, write.file_length);
|
||||
struct rhizome_bundle_result result = rhizome_manifest_finalise(m, &mout, 1);
|
||||
if (result.status == RHIZOME_BUNDLE_STATUS_NEW){
|
||||
ret = 0;
|
||||
ret = ++feeds->generation;
|
||||
feeds->dirty = 0;
|
||||
}
|
||||
rhizome_bundle_result_free(&result);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret!=0)
|
||||
if (ret==-1)
|
||||
rhizome_fail_write(&write);
|
||||
break;
|
||||
}
|
||||
|
1
meshmb.h
1
meshmb.h
@ -25,6 +25,7 @@ int meshmb_open(keyring_identity *id, struct meshmb_feeds **feeds);
|
||||
void meshmb_close(struct meshmb_feeds *feeds);
|
||||
|
||||
// re-write metadata if required
|
||||
// returns -1 on failure, or a generation number that is incremented only if something has changed.
|
||||
int meshmb_flush(struct meshmb_feeds *feeds);
|
||||
|
||||
// set / clear follow flag for this feed
|
||||
|
129
meshmb_restful.c
129
meshmb_restful.c
@ -494,6 +494,131 @@ static int restful_meshmb_ignore(httpd_request *r, const char *remainder)
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct enum_state{
|
||||
httpd_request *request;
|
||||
strbuf buffer;
|
||||
};
|
||||
|
||||
static int restful_feedlist_enum(struct meshmb_feed_details *details, void *context){
|
||||
struct enum_state *state = context;
|
||||
size_t checkpoint = strbuf_len(state->buffer);
|
||||
|
||||
if (state->request->u.meshmb_feeds.rowcount!=0)
|
||||
strbuf_putc(state->buffer, ',');
|
||||
strbuf_puts(state->buffer, "\n[");
|
||||
strbuf_json_hex(state->buffer, details->bundle_id.binary, sizeof details->bundle_id.binary);
|
||||
strbuf_puts(state->buffer, ",");
|
||||
strbuf_json_string(state->buffer, details->name);
|
||||
strbuf_puts(state->buffer, ",");
|
||||
strbuf_sprintf(state->buffer, "%d", details->timestamp);
|
||||
strbuf_puts(state->buffer, ",");
|
||||
strbuf_json_string(state->buffer, details->last_message);
|
||||
strbuf_puts(state->buffer, "]");
|
||||
|
||||
if (strbuf_overrun(state->buffer)){
|
||||
strbuf_trunc(state->buffer, checkpoint);
|
||||
return 1;
|
||||
}else{
|
||||
++state->request->u.meshmb_feeds.rowcount;
|
||||
state->request->u.meshmb_feeds.bundle_id = details->bundle_id;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int restful_meshmb_feedlist_json_content_chunk(struct http_request *hr, strbuf b)
|
||||
{
|
||||
httpd_request *r = (httpd_request *) hr;
|
||||
const char *headers[] = {
|
||||
"id",
|
||||
"name",
|
||||
"timestamp",
|
||||
"last_message"
|
||||
};
|
||||
|
||||
DEBUGF(httpd, "Phase %d", r->u.meshmb_feeds.phase);
|
||||
|
||||
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))
|
||||
r->u.meshmb_feeds.phase = LIST_ROWS;
|
||||
return 1;
|
||||
|
||||
case LIST_ROWS:
|
||||
case LIST_FIRST:
|
||||
{
|
||||
struct enum_state state={
|
||||
.request = r,
|
||||
.buffer = b
|
||||
};
|
||||
if (meshmb_enum(r->u.meshmb_feeds.session->feeds, &r->u.meshmb_feeds.bundle_id, restful_feedlist_enum, &state)!=0)
|
||||
return 0;
|
||||
}
|
||||
// fallthrough
|
||||
r->u.meshmb_feeds.phase = LIST_END;
|
||||
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_feedlist_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_feedlist_json_content_chunk);
|
||||
}
|
||||
|
||||
static void feedlist_on_rhizome_add(httpd_request *r, rhizome_manifest *m)
|
||||
{
|
||||
struct message_ply_read reader;
|
||||
bzero(&reader, sizeof(reader));
|
||||
meshmb_bundle_update(r->u.meshmb_feeds.session->feeds, m, &reader);
|
||||
message_ply_read_close(&reader);
|
||||
|
||||
int gen = meshmb_flush(r->u.meshmb_feeds.session->feeds);
|
||||
if (gen>=0 && gen != r->u.meshmb_feeds.generation)
|
||||
http_request_resume_response(&r->http);
|
||||
}
|
||||
|
||||
static void feedlist_finalise(httpd_request *r)
|
||||
{
|
||||
close_session(r->u.meshmb_feeds.session);
|
||||
}
|
||||
|
||||
static int restful_meshmb_feedlist(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;
|
||||
}
|
||||
|
||||
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.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_feedlist_json_content);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DECLARE_HANDLER("/restful/meshmb/", restful_meshmb_);
|
||||
static int restful_meshmb_(httpd_request *r, const char *remainder)
|
||||
{
|
||||
@ -518,6 +643,10 @@ static int restful_meshmb_(httpd_request *r, const char *remainder)
|
||||
handler = restful_meshmb_list;
|
||||
remainder = "";
|
||||
r->ui64 = 0;
|
||||
} else if (strcmp(remainder, "/feedlist.json") == 0) {
|
||||
handler = restful_meshmb_feedlist;
|
||||
remainder = "";
|
||||
r->ui64 = 0;
|
||||
} else if ( str_startswith(remainder, "/newsince/", &end)
|
||||
&& strn_to_position_token(end, &r->ui64, &end)
|
||||
&& strcmp(end, "messagelist.json") == 0) {
|
||||
|
@ -137,5 +137,42 @@ test_MeshMBRestFollow() {
|
||||
assertStdoutGrep --matches=1 ":$IDA3::[0-9]\+:Message 3\$"
|
||||
}
|
||||
|
||||
doc_MeshMBRestFeeds="Restful list subscribed feeds"
|
||||
setup_MeshMBRestFeeds() {
|
||||
IDENTITY_COUNT=3
|
||||
setup
|
||||
executeOk_servald meshmb send $IDA1 "Message 1"
|
||||
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
|
||||
}
|
||||
test_MeshMBRestFeeds() {
|
||||
executeOk curl \
|
||||
-H "Expect:" \
|
||||
--silent --fail --show-error \
|
||||
--output feedlist.json \
|
||||
--dump-header http.headers \
|
||||
--basic --user harry:potter \
|
||||
"http://$addr_localhost:$PORTA/restful/meshmb/$IDA1/feedlist.json"
|
||||
tfw_cat http.headers feedlist.json
|
||||
tfw_preserve feedlist.json
|
||||
assert [ "$(jq '.rows | length' feedlist.json)" = 2 ]
|
||||
transform_list_json feedlist.json list.json
|
||||
tfw_preserve list.json
|
||||
assertJq list.json \
|
||||
"contains([
|
||||
{ id: \"$IDA2\",
|
||||
last_message: \"Message 2\"
|
||||
}
|
||||
])"
|
||||
assertJq list.json \
|
||||
"contains([
|
||||
{ id: \"$IDA3\",
|
||||
last_message: \"Message 3\"
|
||||
}
|
||||
])"
|
||||
}
|
||||
|
||||
runTests "$@"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user