Add API's for marking a feed as blocked

This commit is contained in:
Jeremy Lakeman 2017-06-05 12:39:07 +09:30
parent f83b15d251
commit 508e95436a
11 changed files with 192 additions and 116 deletions

View File

@ -85,6 +85,10 @@ public abstract class AbstractId {
this.binary = binary; this.binary = binary;
} }
protected boolean isEquivalent(Object other){
return other.getClass() == this.getClass();
}
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
// must be the exact same type with the same binary contents to be considered equal // must be the exact same type with the same binary contents to be considered equal
@ -92,7 +96,7 @@ public abstract class AbstractId {
return false; return false;
if (other==this) if (other==this)
return true; return true;
if (other.getClass() == this.getClass()) { if (isEquivalent(other)) {
AbstractId oBinary = (AbstractId) other; AbstractId oBinary = (AbstractId) other;
for (int i = 0; i < this.binary.length; i++) for (int i = 0; i < this.binary.length; i++)
if (this.binary[i] != oBinary.binary[i]) if (this.binary[i] != oBinary.binary[i])

View File

@ -220,12 +220,8 @@ public class ServalDClient implements ServalDHttpConnectionFactory {
return list; return list;
} }
public int meshmbFollow(Subscriber id, SigningKey peer) throws ServalDInterfaceException, IOException { public int meshmbAlterSubscription(Subscriber id, MeshMBCommon.SubscriptionAction action, SigningKey peer) throws ServalDInterfaceException, IOException {
return MeshMBCommon.follow(this, id, peer); return MeshMBCommon.alterSubscription(this, id, action, peer);
}
public int meshmbIgnore(Subscriber id, SigningKey peer) throws ServalDInterfaceException, IOException {
return MeshMBCommon.ignore(this, id, peer);
} }
public MeshMBSubscriptionList meshmbSubscriptions(Subscriber identity) throws IOException, ServalDInterfaceException { public MeshMBSubscriptionList meshmbSubscriptions(Subscriber identity) throws IOException, ServalDInterfaceException {

View File

@ -29,4 +29,9 @@ public class SigningKey extends AbstractId {
public String getMimeType() { public String getMimeType() {
return "serval-mesh/id"; return "serval-mesh/id";
} }
@Override
protected boolean isEquivalent(Object other){
return SigningKey.class.isInstance(other);
}
} }

View File

@ -17,6 +17,12 @@ public class MeshMBCommon {
public static final String SERVICE = "MeshMB1"; public static final String SERVICE = "MeshMB1";
public enum SubscriptionAction{
Follow,
Ignore,
Block
}
public static int sendMessage(ServalDHttpConnectionFactory connector, SigningKey id, String text) throws IOException, ServalDInterfaceException { public static int sendMessage(ServalDHttpConnectionFactory connector, SigningKey id, String text) throws IOException, ServalDInterfaceException {
HttpURLConnection conn = connector.newServalDHttpConnection("/restful/meshmb/" + id.toHex() + "/sendmessage"); HttpURLConnection conn = connector.newServalDHttpConnection("/restful/meshmb/" + id.toHex() + "/sendmessage");
PostHelper helper = new PostHelper(conn); PostHelper helper = new PostHelper(conn);
@ -28,15 +34,8 @@ public class MeshMBCommon {
return conn.getResponseCode(); return conn.getResponseCode();
} }
public static int ignore(ServalDHttpConnectionFactory connector, Subscriber id, SigningKey peer) throws ServalDInterfaceException, IOException { public static int alterSubscription(ServalDHttpConnectionFactory connector, Subscriber id, SubscriptionAction action, SigningKey peer) throws ServalDInterfaceException, IOException {
HttpURLConnection conn = connector.newServalDHttpConnection("/restful/meshmb/" + id.signingKey.toHex() + "/ignore/" + peer.toHex()); HttpURLConnection conn = connector.newServalDHttpConnection("/restful/meshmb/" + id.signingKey.toHex() + "/"+action.toString().toLowerCase()+"/" + peer.toHex());
conn.setRequestMethod("POST");
conn.connect();
return conn.getResponseCode();
}
public static int follow(ServalDHttpConnectionFactory connector, Subscriber id, SigningKey peer) throws ServalDInterfaceException, IOException {
HttpURLConnection conn = connector.newServalDHttpConnection("/restful/meshmb/" + id.signingKey.toHex() + "/follow/" + peer.toHex());
conn.setRequestMethod("POST"); conn.setRequestMethod("POST");
conn.connect(); conn.connect();
return conn.getResponseCode(); return conn.getResponseCode();

View File

@ -1,6 +1,7 @@
package org.servalproject.servaldna.meshmb; package org.servalproject.servaldna.meshmb;
import org.servalproject.json.JSONTableScanner; import org.servalproject.json.JSONTableScanner;
import org.servalproject.json.JSONTokeniser;
import org.servalproject.servaldna.AbstractJsonList; import org.servalproject.servaldna.AbstractJsonList;
import org.servalproject.servaldna.ServalDHttpConnectionFactory; import org.servalproject.servaldna.ServalDHttpConnectionFactory;
import org.servalproject.servaldna.ServalDInterfaceException; import org.servalproject.servaldna.ServalDInterfaceException;
@ -23,9 +24,10 @@ public class MeshMBSubscriptionList extends AbstractJsonList<MeshMBSubscription,
super(httpConnector, new JSONTableScanner() super(httpConnector, new JSONTableScanner()
.addColumn("id", SigningKey.class) .addColumn("id", SigningKey.class)
.addColumn("author", SubscriberId.class) .addColumn("author", SubscriberId.class)
.addColumn("name", String.class) .addColumn("blocked", Boolean.class)
.addColumn("name", String.class, JSONTokeniser.Narrow.ALLOW_NULL)
.addColumn("timestamp", Long.class) .addColumn("timestamp", Long.class)
.addColumn("last_message", String.class) .addColumn("last_message", String.class, JSONTokeniser.Narrow.ALLOW_NULL)
); );
this.identity = identity; this.identity = identity;
} }
@ -40,7 +42,7 @@ public class MeshMBSubscriptionList extends AbstractJsonList<MeshMBSubscription,
new Subscriber((SubscriberId)row.get("author"), new Subscriber((SubscriberId)row.get("author"),
(SigningKey) row.get("id"), (SigningKey) row.get("id"),
true), true),
false, (Boolean) row.get("blocked"),
(String) row.get("name"), (String) row.get("name"),
(Long) row.get("timestamp"), (Long) row.get("timestamp"),
(String) row.get("last_message") (String) row.get("last_message")

View File

@ -22,6 +22,8 @@ struct feed_metadata{
uint64_t size; uint64_t size;
}; };
#define FLAG_BLOCKED (1<<0)
struct meshmb_feeds{ struct meshmb_feeds{
struct tree_root root; struct tree_root root;
keyring_identity *id; keyring_identity *id;
@ -29,8 +31,8 @@ struct meshmb_feeds{
sign_keypair_t ack_bundle_keypair; sign_keypair_t ack_bundle_keypair;
rhizome_manifest *ack_manifest; rhizome_manifest *ack_manifest;
struct rhizome_write ack_writer; struct rhizome_write ack_writer;
bool_t dirty;
uint8_t generation; uint8_t generation;
bool_t dirty:1;
}; };
struct meshmb_activity_iterator *meshmb_activity_open(struct meshmb_feeds *feeds){ struct meshmb_activity_iterator *meshmb_activity_open(struct meshmb_feeds *feeds){
@ -74,6 +76,8 @@ static int activity_next_ack(struct meshmb_activity_iterator *i){
}else{ }else{
struct feed_metadata *metadata; struct feed_metadata *metadata;
if (tree_find(&i->feeds->root, (void**)&metadata, ack.binary, ack.binary_length, NULL, NULL)==TREE_FOUND){ if (tree_find(&i->feeds->root, (void**)&metadata, ack.binary, ack.binary_length, NULL, NULL)==TREE_FOUND){
if (metadata->details.blocked)
continue;
bundle_id = &metadata->bundle_id; bundle_id = &metadata->bundle_id;
i->metadata = metadata; i->metadata = metadata;
}else{ }else{
@ -240,6 +244,8 @@ static int activity_ack(struct meshmb_feeds *feeds, struct message_ply_ack *ack)
static int update_stats(struct meshmb_feeds *feeds, struct feed_metadata *metadata, struct message_ply_read *reader) static int update_stats(struct meshmb_feeds *feeds, struct feed_metadata *metadata, struct message_ply_read *reader)
{ {
if (metadata->details.blocked)
return 0;
if (!metadata->details.ply.found){ if (!metadata->details.ply.found){
// get the current size from the db // get the current size from the db
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
@ -329,7 +335,7 @@ static int update_stats(struct meshmb_feeds *feeds, struct feed_metadata *metada
return 1; return 1;
} }
// TODO, might be quicker to fetch all meshmb bundles and test if they are in the feed list // TODO, might sometimes be quicker to fetch all meshmb bundles and test if they are in the feed list
static int update_stats_tree(void **record, void *context) static int update_stats_tree(void **record, void *context)
{ {
struct feed_metadata *metadata = (struct feed_metadata *)*record; struct feed_metadata *metadata = (struct feed_metadata *)*record;
@ -346,7 +352,8 @@ int meshmb_bundle_update(struct meshmb_feeds *feeds, rhizome_manifest *m, struct
{ {
struct feed_metadata *metadata; struct feed_metadata *metadata;
if (strcmp(m->service, RHIZOME_SERVICE_MESHMB) == 0 if (strcmp(m->service, RHIZOME_SERVICE_MESHMB) == 0
&& tree_find(&feeds->root, (void**)&metadata, m->keypair.public_key.binary, sizeof m->keypair.public_key.binary, NULL, NULL)==TREE_FOUND){ && tree_find(&feeds->root, (void**)&metadata, m->keypair.public_key.binary, sizeof m->keypair.public_key.binary, NULL, NULL)==TREE_FOUND
&& !metadata->details.blocked){
metadata->details.ply.found = 1; metadata->details.ply.found = 1;
if (metadata->details.ply.size != m->filesize){ if (metadata->details.ply.size != m->filesize){
@ -384,7 +391,9 @@ static int write_metadata(void **record, void *context)
len += sizeof (rhizome_bid_t); len += sizeof (rhizome_bid_t);
bcopy(metadata->details.ply.author.binary, &buffer[len], sizeof (sid_t)); bcopy(metadata->details.ply.author.binary, &buffer[len], sizeof (sid_t));
len += sizeof (sid_t); len += sizeof (sid_t);
buffer[len++]=0;// flags? uint8_t flags = (metadata->details.blocked ? FLAG_BLOCKED : 0);
buffer[len++]=flags;
if (!metadata->details.blocked){
len+=pack_uint(&buffer[len], metadata->size); len+=pack_uint(&buffer[len], metadata->size);
len+=pack_uint(&buffer[len], metadata->size - metadata->last_message_offset); len+=pack_uint(&buffer[len], metadata->size - metadata->last_message_offset);
len+=pack_uint(&buffer[len], metadata->size - metadata->last_seen); len+=pack_uint(&buffer[len], metadata->size - metadata->last_seen);
@ -399,6 +408,7 @@ static int write_metadata(void **record, void *context)
else else
buffer[len]=0; buffer[len]=0;
len+=msg_len; len+=msg_len;
}
assert(len < sizeof buffer); assert(len < sizeof buffer);
DEBUGF(meshmb, "Write %zu bytes of metadata for %s/%s", DEBUGF(meshmb, "Write %zu bytes of metadata for %s/%s",
len, len,
@ -525,10 +535,12 @@ static int read_metadata(struct meshmb_feeds *feeds, struct rhizome_read *read)
break; break;
uint64_t delta=0; uint64_t delta=0;
uint64_t size; uint64_t size=0;
uint64_t last_message_offset; uint64_t last_message_offset=0;
uint64_t last_seen; uint64_t last_seen=0;
uint64_t timestamp; uint64_t timestamp=0;
const char *name=NULL;
const char *msg=NULL;
int unpacked; int unpacked;
const rhizome_bid_t *bid = (const rhizome_bid_t *)&buffer[0]; const rhizome_bid_t *bid = (const rhizome_bid_t *)&buffer[0];
@ -541,8 +553,9 @@ static int read_metadata(struct meshmb_feeds *feeds, struct rhizome_read *read)
if (offset >= (unsigned)bytes) if (offset >= (unsigned)bytes)
goto error; goto error;
//uint8_t flags = buffer[offset++]; uint8_t flags = buffer[offset++];
offset++;
if (!(flags & FLAG_BLOCKED)){
if (offset >= (unsigned)bytes) if (offset >= (unsigned)bytes)
goto error; goto error;
@ -564,17 +577,18 @@ static int read_metadata(struct meshmb_feeds *feeds, struct rhizome_read *read)
goto error; goto error;
offset += unpacked; offset += unpacked;
const char *name = (const char *)&buffer[offset]; name = (const char *)&buffer[offset];
while(buffer[offset++]){ while(buffer[offset++]){
if (offset >= (unsigned)bytes) if (offset >= (unsigned)bytes)
goto error; goto error;
} }
const char *msg = (const char *)&buffer[offset]; msg = (const char *)&buffer[offset];
while(buffer[offset++]){ while(buffer[offset++]){
if (offset >= (unsigned)bytes) if (offset >= (unsigned)bytes)
goto error; goto error;
} }
}
DEBUGF(meshmb, "Seeking backwards %"PRIu64", %u, %zu", read->offset, offset, bytes); DEBUGF(meshmb, "Seeking backwards %"PRIu64", %u, %zu", read->offset, offset, bytes);
read->offset = (read->offset - bytes) + offset; read->offset = (read->offset - bytes) + offset;
@ -583,6 +597,7 @@ static int read_metadata(struct meshmb_feeds *feeds, struct rhizome_read *read)
if (tree_find(&feeds->root, (void**)&result, bid->binary, sizeof *bid, alloc_feed, feeds)<0) if (tree_find(&feeds->root, (void**)&result, bid->binary, sizeof *bid, alloc_feed, feeds)<0)
return WHY("Failed to allocate metadata"); return WHY("Failed to allocate metadata");
result->details.blocked = (flags & FLAG_BLOCKED) ? 1 : 0;
result->last_message_offset = last_message_offset; result->last_message_offset = last_message_offset;
result->last_seen = last_seen; result->last_seen = last_seen;
result->size = size; result->size = size;
@ -675,8 +690,6 @@ int meshmb_follow(struct meshmb_feeds *feeds, rhizome_bid_t *bid)
struct feed_metadata *metadata; struct feed_metadata *metadata;
DEBUGF(meshmb, "Attempting to follow %s", alloca_tohex_rhizome_bid_t(*bid)); DEBUGF(meshmb, "Attempting to follow %s", alloca_tohex_rhizome_bid_t(*bid));
// TODO load the manifest and check the service!
if (tree_find(&feeds->root, (void**)&metadata, bid->binary, sizeof *bid, alloc_feed, feeds)!=TREE_FOUND) if (tree_find(&feeds->root, (void**)&metadata, bid->binary, sizeof *bid, alloc_feed, feeds)!=TREE_FOUND)
return WHYF("Failed to follow feed"); return WHYF("Failed to follow feed");
@ -687,6 +700,30 @@ int meshmb_follow(struct meshmb_feeds *feeds, rhizome_bid_t *bid)
return 0; return 0;
} }
int meshmb_block(struct meshmb_feeds *feeds, rhizome_bid_t *bid)
{
struct feed_metadata *metadata;
DEBUGF(meshmb, "Attempting to block %s", alloca_tohex_rhizome_bid_t(*bid));
if (tree_find(&feeds->root, (void**)&metadata, bid->binary, sizeof *bid, alloc_feed, feeds)!=TREE_FOUND)
return WHYF("Failed to block feed");
if (metadata->details.name){
free((void*)metadata->details.name);
metadata->details.name = NULL;
}
if (metadata->details.last_message){
free((void*)metadata->details.last_message);
metadata->details.last_message = NULL;
}
if (is_all_matching(metadata->details.ply.author.binary, sizeof metadata->details.ply.author, 0))
crypto_sign_to_sid(bid, &metadata->details.ply.author);
if (!metadata->details.blocked)
feeds->dirty = 1;
metadata->details.blocked = 1;
metadata->details.timestamp = 0;
return 0;
}
int meshmb_ignore(struct meshmb_feeds *feeds, rhizome_bid_t *bid) int meshmb_ignore(struct meshmb_feeds *feeds, rhizome_bid_t *bid)
{ {
DEBUGF(meshmb, "Attempting to ignore %s", alloca_tohex_rhizome_bid_t(*bid)); DEBUGF(meshmb, "Attempting to ignore %s", alloca_tohex_rhizome_bid_t(*bid));

View File

@ -14,6 +14,7 @@ struct meshmb_feed_details{
const char *name; const char *name;
const char *last_message; const char *last_message;
time_s_t timestamp; time_s_t timestamp;
bool_t blocked:1;
}; };
// threaded feed iterator state // threaded feed iterator state
@ -41,6 +42,7 @@ int meshmb_flush(struct meshmb_feeds *feeds);
// set / clear follow flag for this feed // set / clear follow flag for this feed
int meshmb_follow(struct meshmb_feeds *feeds, rhizome_bid_t *bid); int meshmb_follow(struct meshmb_feeds *feeds, rhizome_bid_t *bid);
int meshmb_ignore(struct meshmb_feeds *feeds, rhizome_bid_t *bid); int meshmb_ignore(struct meshmb_feeds *feeds, rhizome_bid_t *bid);
int meshmb_block(struct meshmb_feeds *feeds, rhizome_bid_t *bid);
// enumerate feeds, starting from restart_from // enumerate feeds, starting from restart_from
typedef int (*meshmb_callback) (struct meshmb_feed_details *details, void *context); typedef int (*meshmb_callback) (struct meshmb_feed_details *details, void *context);

View File

@ -212,8 +212,8 @@ static int app_meshmb_find(const struct cli_parsed *parsed, struct cli_context *
} }
DEFINE_CMD(app_meshmb_follow, 0, DEFINE_CMD(app_meshmb_follow, 0,
"Start or stop following a broadcast feed", "Follow, block or ignore a broadcast feed",
"meshmb", "follow|ignore" KEYRING_PIN_OPTIONS, "<id>", "<peer>"); "meshmb", "follow|ignore|block" KEYRING_PIN_OPTIONS, "<id>", "<peer>");
static int app_meshmb_follow(const struct cli_parsed *parsed, struct cli_context *UNUSED(context)) static int app_meshmb_follow(const struct cli_parsed *parsed, struct cli_context *UNUSED(context))
{ {
const char *peerhex; const char *peerhex;
@ -221,6 +221,7 @@ static int app_meshmb_follow(const struct cli_parsed *parsed, struct cli_context
return -1; return -1;
int follow = cli_arg(parsed, "follow", NULL, NULL, NULL) == 0; int follow = cli_arg(parsed, "follow", NULL, NULL, NULL) == 0;
int block = cli_arg(parsed, "block", NULL, NULL, NULL) == 0;
identity_t peer; identity_t peer;
if (str_to_identity_t(&peer, peerhex) == -1) if (str_to_identity_t(&peer, peerhex) == -1)
@ -230,7 +231,9 @@ static int app_meshmb_follow(const struct cli_parsed *parsed, struct cli_context
int ret = -1; int ret = -1;
if (feeds){ if (feeds){
if (follow){ if (block){
ret = meshmb_block(feeds, &peer);
}else if (follow){
ret = meshmb_follow(feeds, &peer); ret = meshmb_follow(feeds, &peer);
}else{ }else{
ret = meshmb_ignore(feeds, &peer); ret = meshmb_ignore(feeds, &peer);
@ -263,6 +266,7 @@ static int list_callback(struct meshmb_feed_details *details, void *context)
cli_put_long(enum_context->context, enum_context->rowcount, ":"); cli_put_long(enum_context->context, enum_context->rowcount, ":");
cli_put_string(enum_context->context, alloca_tohex_rhizome_bid_t(details->ply.bundle_id), ":"); cli_put_string(enum_context->context, alloca_tohex_rhizome_bid_t(details->ply.bundle_id), ":");
cli_put_string(enum_context->context, alloca_tohex_sid_t(details->ply.author), ":"); cli_put_string(enum_context->context, alloca_tohex_sid_t(details->ply.author), ":");
cli_put_string(enum_context->context, details->blocked ? "true" : "false", ":");
cli_put_string(enum_context->context, details->name, ":"); cli_put_string(enum_context->context, details->name, ":");
cli_put_long(enum_context->context, details->timestamp ? (long)(gettime() - details->timestamp) : (long)-1, ":"); cli_put_long(enum_context->context, details->timestamp ? (long)(gettime() - details->timestamp) : (long)-1, ":");
cli_put_string(enum_context->context, details->last_message, "\n"); cli_put_string(enum_context->context, details->last_message, "\n");
@ -270,7 +274,7 @@ static int list_callback(struct meshmb_feed_details *details, void *context)
} }
DEFINE_CMD(app_meshmb_list, 0, DEFINE_CMD(app_meshmb_list, 0,
"List the feeds that you are currently following", "List the feeds that you are currently following or blocking",
"meshmb", "list", "following" KEYRING_PIN_OPTIONS, "<id>"); "meshmb", "list", "following" KEYRING_PIN_OPTIONS, "<id>");
static int app_meshmb_list(const struct cli_parsed *parsed, struct cli_context *context) static int app_meshmb_list(const struct cli_parsed *parsed, struct cli_context *context)
{ {
@ -282,6 +286,7 @@ static int app_meshmb_list(const struct cli_parsed *parsed, struct cli_context *
"_id", "_id",
"id", "id",
"author", "author",
"blocked",
"name", "name",
"age", "age",
"last_message" "last_message"

View File

@ -20,6 +20,10 @@ struct meshmb_session{
struct meshmb_feeds *feeds; struct meshmb_feeds *feeds;
}; };
#define FLAG_FOLLOW (1)
#define FLAG_IGNORE (2)
#define FLAG_BLOCK (3)
static struct meshmb_session *sessions = NULL; static struct meshmb_session *sessions = NULL;
static struct meshmb_session *open_session(const identity_t *identity){ static struct meshmb_session *open_session(const identity_t *identity){
@ -484,40 +488,25 @@ static int restful_meshmb_newsince_find(httpd_request *r, const char *remainder)
*/ */
static int restful_meshmb_follow(httpd_request *r, const char *remainder) static int restful_meshmb_follow_ignore(httpd_request *r, const char *remainder)
{ {
if (*remainder) if (*remainder)
return 404; return 404;
assert(r->finalise_union == NULL); assert(r->finalise_union == NULL);
struct meshmb_session *session = open_session(&r->bid); struct meshmb_session *session = open_session(&r->bid);
int ret; int ret=-1;
if (session if (session){
&& meshmb_follow(session->feeds, &r->u.meshmb_feeds.bundle_id)!=-1 switch(r->ui64){
&& meshmb_flush(session->feeds)!=-1){ case FLAG_FOLLOW: ret = meshmb_follow(session->feeds, &r->u.meshmb_feeds.bundle_id); break;
http_request_simple_response(&r->http, 201, "TODO, detailed response"); case FLAG_IGNORE: ret = meshmb_ignore(session->feeds, &r->u.meshmb_feeds.bundle_id); break;
ret = 201; case FLAG_BLOCK: ret = meshmb_block (session->feeds, &r->u.meshmb_feeds.bundle_id); break;
}else{ default:
http_request_simple_response(&r->http, 500, "TODO, detailed response"); FATAL("Unexpected value");
ret = 500;
} }
if (session) }
close_session(session); if (ret!=-1
return ret;
}
static int restful_meshmb_ignore(httpd_request *r, const char *remainder)
{
if (*remainder)
return 404;
assert(r->finalise_union == NULL);
struct meshmb_session *session = open_session(&r->bid);
int ret;
if (session
&& meshmb_ignore(session->feeds, &r->u.meshmb_feeds.bundle_id)!=-1
&& meshmb_flush(session->feeds)!=-1){ && meshmb_flush(session->feeds)!=-1){
http_request_simple_response(&r->http, 201, "TODO, detailed response"); http_request_simple_response(&r->http, 201, "TODO, detailed response");
ret = 201; ret = 201;
@ -545,7 +534,7 @@ static int restful_feedlist_enum(struct meshmb_feed_details *details, void *cont
strbuf_json_hex(state->buffer, details->ply.bundle_id.binary, sizeof details->ply.bundle_id.binary); strbuf_json_hex(state->buffer, details->ply.bundle_id.binary, sizeof details->ply.bundle_id.binary);
strbuf_puts(state->buffer, ","); strbuf_puts(state->buffer, ",");
strbuf_json_hex(state->buffer, details->ply.author.binary, sizeof details->ply.author.binary); strbuf_json_hex(state->buffer, details->ply.author.binary, sizeof details->ply.author.binary);
strbuf_puts(state->buffer, ","); strbuf_puts(state->buffer, details->blocked ? ",true," : ",false,");
strbuf_json_string(state->buffer, details->name); strbuf_json_string(state->buffer, details->name);
strbuf_puts(state->buffer, ","); strbuf_puts(state->buffer, ",");
strbuf_sprintf(state->buffer, "%d", details->timestamp); strbuf_sprintf(state->buffer, "%d", details->timestamp);
@ -569,6 +558,7 @@ static int restful_meshmb_feedlist_json_content_chunk(struct http_request *hr, s
const char *headers[] = { const char *headers[] = {
"id", "id",
"author", "author",
"blocked",
"name", "name",
"timestamp", "timestamp",
"last_message" "last_message"
@ -918,13 +908,21 @@ static int restful_meshmb_(httpd_request *r, const char *remainder)
remainder = ""; remainder = "";
} else if(str_startswith(remainder, "/follow/", &end) } else if(str_startswith(remainder, "/follow/", &end)
&& strn_to_identity_t(&r->u.meshmb_feeds.bundle_id, end, &end) != -1) { && strn_to_identity_t(&r->u.meshmb_feeds.bundle_id, end, &end) != -1) {
handler = restful_meshmb_follow; handler = restful_meshmb_follow_ignore;
verb = HTTP_VERB_POST; verb = HTTP_VERB_POST;
r->ui64 = FLAG_FOLLOW;
remainder = ""; remainder = "";
} else if(str_startswith(remainder, "/ignore/", &end) } else if(str_startswith(remainder, "/ignore/", &end)
&& strn_to_identity_t(&r->u.meshmb_feeds.bundle_id, end, &end) != -1) { && strn_to_identity_t(&r->u.meshmb_feeds.bundle_id, end, &end) != -1) {
handler = restful_meshmb_ignore; handler = restful_meshmb_follow_ignore;
verb = HTTP_VERB_POST; verb = HTTP_VERB_POST;
r->ui64 = FLAG_IGNORE;
remainder = "";
} else if(str_startswith(remainder, "/block/", &end)
&& strn_to_identity_t(&r->u.meshmb_feeds.bundle_id, end, &end) != -1) {
handler = restful_meshmb_follow_ignore;
verb = HTTP_VERB_POST;
r->ui64 = FLAG_BLOCK;
remainder = ""; remainder = "";
} }
/* /*

View File

@ -85,16 +85,16 @@ setup_meshmbFollow() {
test_meshmbFollow() { test_meshmbFollow() {
executeOk_servald meshmb follow $IDA1 $IDA2 executeOk_servald meshmb follow $IDA1 $IDA2
executeOk_servald meshmb list following $IDA1 executeOk_servald meshmb list following $IDA1
assertStdoutGrep --matches=1 ":$IDA2:$SIDA2:Feed B:[0-9]\+:Message 2\$" assertStdoutGrep --matches=1 ":$IDA2:$SIDA2:false:Feed B:[0-9]\+:Message 2\$"
assertStdoutGrep --matches=0 ":$IDA3:$SIDA3:Feed C:[0-9]\+:Message 3\$" assertStdoutGrep --matches=0 ":$IDA3:$SIDA3:false:Feed C:[0-9]\+:Message 3\$"
executeOk_servald meshmb follow $IDA1 $IDA3 executeOk_servald meshmb follow $IDA1 $IDA3
executeOk_servald meshmb list following $IDA1 executeOk_servald meshmb list following $IDA1
assertStdoutGrep --matches=1 ":$IDA2:$SIDA2:Feed B:[0-9]\+:Message 2\$" assertStdoutGrep --matches=1 ":$IDA2:$SIDA2:false:Feed B:[0-9]\+:Message 2\$"
assertStdoutGrep --matches=1 ":$IDA3:$SIDA3:Feed C:[0-9]\+:Message 3\$" assertStdoutGrep --matches=1 ":$IDA3:$SIDA3:false:Feed C:[0-9]\+:Message 3\$"
executeOk_servald meshmb ignore $IDA1 $IDA2 executeOk_servald meshmb ignore $IDA1 $IDA2
executeOk_servald meshmb list following $IDA1 executeOk_servald meshmb list following $IDA1
assertStdoutGrep --matches=0 ":$IDA2:$SIDA2:Feed B:[0-9]\+:Message 2\$" assertStdoutGrep --matches=0 ":$IDA2:$SIDA2:false:Feed B:[0-9]\+:Message 2\$"
assertStdoutGrep --matches=1 ":$IDA3:$SIDA3:Feed C:[0-9]\+:Message 3\$" assertStdoutGrep --matches=1 ":$IDA3:$SIDA3:false:Feed C:[0-9]\+:Message 3\$"
} }
doc_meshmbThreading="Thread incoming message feeds" doc_meshmbThreading="Thread incoming message feeds"
@ -143,4 +143,32 @@ test_meshmbThreading() {
assertStdoutGrep --matches=1 "5:$IDA5:$SIDA5:Feed E:[0-9]\+:[0-9]\+:Message 6\$" assertStdoutGrep --matches=1 "5:$IDA5:$SIDA5:Feed E:[0-9]\+:[0-9]\+:Message 6\$"
} }
doc_meshmbBlock="Record blocked feeds"
setup_meshmbBlock() {
setup_identities 4
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 meshmb send $IDA2 "Message 1"
executeOk_servald meshmb send $IDA3 "Message 2"
executeOk_servald meshmb send $IDA4 "Message 3"
executeOk_servald meshmb follow $IDA1 $IDA2
executeOk_servald meshmb follow $IDA1 $IDA3
}
test_meshmbBlock() {
executeOk_servald meshmb block $IDA1 $IDA3
executeOk_servald meshmb block $IDA1 $IDA4
executeOk_servald meshmb activity $IDA1
tfw_cat --stdout
assertStdoutGrep --matches=1 "0:$IDA2:$SIDA2:Feed B:[0-9]\+:[0-9]\+:Message 1\$"
# what was followed, disappears
assertStdoutGrep --matches=0 ":$IDA3:$SIDA3:"
executeOk_servald meshmb list following $IDA1
tfw_cat --stdout
assertStdoutGrep --matches=1 ":$IDA2:$SIDA2:false:Feed B:[0-9]\+:Message 1\$"
assertStdoutGrep --matches=1 ":$IDA3:$SIDA3:true::-1:\$"
assertStdoutGrep --matches=1 ":$IDA4:$SIDA4:true::-1:\$"
}
runTests "$@" runTests "$@"

View File

@ -110,8 +110,8 @@ test_MeshMBRestFollow() {
--request POST \ --request POST \
"http://$addr_localhost:$PORTA/restful/meshmb/$IDA1/follow/$IDA2" "http://$addr_localhost:$PORTA/restful/meshmb/$IDA1/follow/$IDA2"
executeOk_servald meshmb list following $IDA1 executeOk_servald meshmb list following $IDA1
assertStdoutGrep --matches=1 ":$IDA2:$SIDA2::[0-9]\+:Message 2\$" assertStdoutGrep --matches=1 ":$IDA2:$SIDA2:false::[0-9]\+:Message 2\$"
assertStdoutGrep --matches=0 ":$IDA3:$SIDA3::[0-9]\+:Message 3\$" assertStdoutGrep --matches=0 ":$IDA3:$SIDA3:false::[0-9]\+:Message 3\$"
executeOk curl \ executeOk curl \
--silent --fail --show-error \ --silent --fail --show-error \
--output follow.json \ --output follow.json \
@ -119,8 +119,8 @@ test_MeshMBRestFollow() {
--request POST \ --request POST \
"http://$addr_localhost:$PORTA/restful/meshmb/$IDA1/follow/$IDA3" "http://$addr_localhost:$PORTA/restful/meshmb/$IDA1/follow/$IDA3"
executeOk_servald meshmb list following $IDA1 executeOk_servald meshmb list following $IDA1
assertStdoutGrep --matches=1 ":$IDA2:$SIDA2::[0-9]\+:Message 2\$" assertStdoutGrep --matches=1 ":$IDA2:$SIDA2:false::[0-9]\+:Message 2\$"
assertStdoutGrep --matches=1 ":$IDA3:$SIDA3::[0-9]\+:Message 3\$" assertStdoutGrep --matches=1 ":$IDA3:$SIDA3:false::[0-9]\+:Message 3\$"
executeOk curl \ executeOk curl \
--silent --fail --show-error \ --silent --fail --show-error \
--output follow.json \ --output follow.json \
@ -128,8 +128,8 @@ test_MeshMBRestFollow() {
--request POST \ --request POST \
"http://$addr_localhost:$PORTA/restful/meshmb/$IDA1/ignore/$IDA2" "http://$addr_localhost:$PORTA/restful/meshmb/$IDA1/ignore/$IDA2"
executeOk_servald meshmb list following $IDA1 executeOk_servald meshmb list following $IDA1
assertStdoutGrep --matches=0 ":$IDA2:$SIDA2::[0-9]\+:Message 2\$" assertStdoutGrep --matches=0 ":$IDA2:$SIDA2:false::[0-9]\+:Message 2\$"
assertStdoutGrep --matches=1 ":$IDA3:$SIDA3::[0-9]\+:Message 3\$" assertStdoutGrep --matches=1 ":$IDA3:$SIDA3:false::[0-9]\+:Message 3\$"
} }
doc_MeshMBRestFeeds="Restful list subscribed feeds" doc_MeshMBRestFeeds="Restful list subscribed feeds"