forked from cory/tildefriends
ssb: Add support for registering for blob added notifications similarly to messages. I want to use this to load images on the fly.
This commit is contained in:
67
src/ssb.c
67
src/ssb.c
@@ -133,6 +133,15 @@ typedef struct _tf_ssb_message_added_callback_node_t
|
|||||||
tf_ssb_message_added_callback_node_t* next;
|
tf_ssb_message_added_callback_node_t* next;
|
||||||
} tf_ssb_message_added_callback_node_t;
|
} tf_ssb_message_added_callback_node_t;
|
||||||
|
|
||||||
|
typedef struct _tf_ssb_blob_stored_callback_node_t tf_ssb_blob_stored_callback_node_t;
|
||||||
|
typedef struct _tf_ssb_blob_stored_callback_node_t
|
||||||
|
{
|
||||||
|
tf_ssb_blob_stored_callback_t* callback;
|
||||||
|
tf_ssb_callback_cleanup_t* cleanup;
|
||||||
|
void* user_data;
|
||||||
|
tf_ssb_blob_stored_callback_node_t* next;
|
||||||
|
} tf_ssb_blob_stored_callback_node_t;
|
||||||
|
|
||||||
typedef struct _tf_ssb_blob_want_added_callback_node_t tf_ssb_blob_want_added_callback_node_t;
|
typedef struct _tf_ssb_blob_want_added_callback_node_t tf_ssb_blob_want_added_callback_node_t;
|
||||||
typedef struct _tf_ssb_blob_want_added_callback_node_t
|
typedef struct _tf_ssb_blob_want_added_callback_node_t
|
||||||
{
|
{
|
||||||
@@ -235,6 +244,9 @@ typedef struct _tf_ssb_t
|
|||||||
tf_ssb_message_added_callback_node_t* message_added;
|
tf_ssb_message_added_callback_node_t* message_added;
|
||||||
int message_added_count;
|
int message_added_count;
|
||||||
|
|
||||||
|
tf_ssb_blob_stored_callback_node_t* blob_stored;
|
||||||
|
int blob_stored_count;
|
||||||
|
|
||||||
tf_ssb_blob_want_added_callback_node_t* blob_want_added;
|
tf_ssb_blob_want_added_callback_node_t* blob_want_added;
|
||||||
int blob_want_added_count;
|
int blob_want_added_count;
|
||||||
|
|
||||||
@@ -2741,6 +2753,17 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
|
|||||||
}
|
}
|
||||||
tf_free(node);
|
tf_free(node);
|
||||||
}
|
}
|
||||||
|
while (ssb->blob_stored)
|
||||||
|
{
|
||||||
|
tf_ssb_blob_stored_callback_node_t* node = ssb->blob_stored;
|
||||||
|
ssb->blob_stored = node->next;
|
||||||
|
ssb->blob_stored_count--;
|
||||||
|
if (node->cleanup)
|
||||||
|
{
|
||||||
|
node->cleanup(ssb, node->user_data);
|
||||||
|
}
|
||||||
|
tf_free(node);
|
||||||
|
}
|
||||||
while (ssb->blob_want_added)
|
while (ssb->blob_want_added)
|
||||||
{
|
{
|
||||||
tf_ssb_blob_want_added_callback_node_t* node = ssb->blob_want_added;
|
tf_ssb_blob_want_added_callback_node_t* node = ssb->blob_want_added;
|
||||||
@@ -3960,9 +3983,53 @@ void tf_ssb_remove_message_added_callback(tf_ssb_t* ssb, tf_ssb_message_added_ca
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tf_ssb_add_blob_stored_callback(tf_ssb_t* ssb, tf_ssb_blob_stored_callback_t* callback, void (*cleanup)(tf_ssb_t* ssb, void* user_data), void* user_data)
|
||||||
|
{
|
||||||
|
tf_ssb_blob_stored_callback_node_t* node = tf_malloc(sizeof(tf_ssb_blob_stored_callback_node_t));
|
||||||
|
*node = (tf_ssb_blob_stored_callback_node_t) {
|
||||||
|
.callback = callback,
|
||||||
|
.cleanup = cleanup,
|
||||||
|
.user_data = user_data,
|
||||||
|
.next = ssb->blob_stored,
|
||||||
|
};
|
||||||
|
ssb->blob_stored = node;
|
||||||
|
ssb->blob_stored_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tf_ssb_remove_blob_stored_callback(tf_ssb_t* ssb, tf_ssb_blob_stored_callback_t* callback, void* user_data)
|
||||||
|
{
|
||||||
|
tf_ssb_blob_stored_callback_node_t** it = &ssb->blob_stored;
|
||||||
|
while (*it)
|
||||||
|
{
|
||||||
|
if ((*it)->callback == callback && (*it)->user_data == user_data)
|
||||||
|
{
|
||||||
|
tf_ssb_blob_stored_callback_node_t* node = *it;
|
||||||
|
*it = node->next;
|
||||||
|
ssb->blob_stored_count--;
|
||||||
|
if (node->cleanup)
|
||||||
|
{
|
||||||
|
node->cleanup(ssb, node->user_data);
|
||||||
|
}
|
||||||
|
tf_free(node);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
it = &(*it)->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void tf_ssb_notify_blob_stored(tf_ssb_t* ssb, const char* id)
|
void tf_ssb_notify_blob_stored(tf_ssb_t* ssb, const char* id)
|
||||||
{
|
{
|
||||||
|
tf_ssb_blob_stored_callback_node_t* next = NULL;
|
||||||
ssb->blobs_stored++;
|
ssb->blobs_stored++;
|
||||||
|
for (tf_ssb_blob_stored_callback_node_t* node = ssb->blob_stored; node; node = next)
|
||||||
|
{
|
||||||
|
next = node->next;
|
||||||
|
tf_trace_begin(ssb->trace, "blob stored callback");
|
||||||
|
node->callback(ssb, id, node->user_data);
|
||||||
|
tf_trace_end(ssb->trace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* author, int32_t sequence, const char* id, JSValue message_keys)
|
void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* author, int32_t sequence, const char* id, JSValue message_keys)
|
||||||
|
25
src/ssb.h
25
src/ssb.h
@@ -680,6 +680,31 @@ void tf_ssb_remove_message_added_callback(tf_ssb_t* ssb, tf_ssb_message_added_ca
|
|||||||
*/
|
*/
|
||||||
void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* author, int32_t sequence, const char* id, JSValue message_with_keys);
|
void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* author, int32_t sequence, const char* id, JSValue message_with_keys);
|
||||||
|
|
||||||
|
/**
|
||||||
|
** A callback called when a blob is added to the database.
|
||||||
|
** @param ssb The SSB instance.
|
||||||
|
** @param id The blob identifier.
|
||||||
|
** @param user_data The user data.
|
||||||
|
*/
|
||||||
|
typedef void(tf_ssb_blob_stored_callback_t)(tf_ssb_t* ssb, const char* id, void* user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Register a callback called when a blob is added to the database.
|
||||||
|
** @param ssb The SSB instance.
|
||||||
|
** @param callback The callback function.
|
||||||
|
** @param cleanup A function to call when the callback is removed.
|
||||||
|
** @param user_data User data to pass to the callback.
|
||||||
|
*/
|
||||||
|
void tf_ssb_add_blob_stored_callback(tf_ssb_t* ssb, tf_ssb_blob_stored_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Remove a callback registered for when a blob is added to the database.
|
||||||
|
** @param ssb The SSB instance.
|
||||||
|
** @param callback The callback function.
|
||||||
|
** @param user_data User data registered with the callback.
|
||||||
|
*/
|
||||||
|
void tf_ssb_remove_blob_stored_callback(tf_ssb_t* ssb, tf_ssb_blob_stored_callback_t* callback, void* user_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Record that a new blob was stored.
|
** Record that a new blob was stored.
|
||||||
** @param ssb The SSB instance.
|
** @param ssb The SSB instance.
|
||||||
|
24
src/ssb.js.c
24
src/ssb.js.c
@@ -1627,6 +1627,20 @@ static void _tf_ssb_on_message_added_callback(tf_ssb_t* ssb, const char* author,
|
|||||||
JS_FreeValue(context, string);
|
JS_FreeValue(context, string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _tf_ssb_on_blob_stored_callback(tf_ssb_t* ssb, const char* id, void* user_data)
|
||||||
|
{
|
||||||
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
|
JSValue callback = JS_MKPTR(JS_TAG_OBJECT, user_data);
|
||||||
|
JSValue string = JS_NewString(context, id);
|
||||||
|
JSValue response = JS_Call(context, callback, JS_UNDEFINED, 1, &string);
|
||||||
|
if (tf_util_report_error(context, response))
|
||||||
|
{
|
||||||
|
tf_ssb_remove_blob_stored_callback(ssb, _tf_ssb_on_blob_stored_callback, user_data);
|
||||||
|
}
|
||||||
|
JS_FreeValue(context, response);
|
||||||
|
JS_FreeValue(context, string);
|
||||||
|
}
|
||||||
|
|
||||||
static void _tf_ssb_on_blob_want_added_callback(tf_ssb_t* ssb, const char* id, void* user_data)
|
static void _tf_ssb_on_blob_want_added_callback(tf_ssb_t* ssb, const char* id, void* user_data)
|
||||||
{
|
{
|
||||||
JSContext* context = tf_ssb_get_context(ssb);
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
@@ -1747,6 +1761,11 @@ static JSValue _tf_ssb_add_event_listener(JSContext* context, JSValueConst this_
|
|||||||
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
||||||
tf_ssb_add_message_added_callback(ssb, _tf_ssb_on_message_added_callback, _tf_ssb_cleanup_value, ptr);
|
tf_ssb_add_message_added_callback(ssb, _tf_ssb_on_message_added_callback, _tf_ssb_cleanup_value, ptr);
|
||||||
}
|
}
|
||||||
|
else if (strcmp(event_name, "blob") == 0)
|
||||||
|
{
|
||||||
|
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
||||||
|
tf_ssb_add_blob_stored_callback(ssb, _tf_ssb_on_blob_stored_callback, _tf_ssb_cleanup_value, ptr);
|
||||||
|
}
|
||||||
else if (strcmp(event_name, "blob_want_added") == 0)
|
else if (strcmp(event_name, "blob_want_added") == 0)
|
||||||
{
|
{
|
||||||
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
||||||
@@ -1790,6 +1809,11 @@ static JSValue _tf_ssb_remove_event_listener(JSContext* context, JSValueConst th
|
|||||||
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
||||||
tf_ssb_remove_message_added_callback(ssb, _tf_ssb_on_message_added_callback, ptr);
|
tf_ssb_remove_message_added_callback(ssb, _tf_ssb_on_message_added_callback, ptr);
|
||||||
}
|
}
|
||||||
|
else if (strcmp(event_name, "blob") == 0)
|
||||||
|
{
|
||||||
|
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
||||||
|
tf_ssb_remove_blob_stored_callback(ssb, _tf_ssb_on_blob_stored_callback, ptr);
|
||||||
|
}
|
||||||
else if (strcmp(event_name, "blob_want_added") == 0)
|
else if (strcmp(event_name, "blob_want_added") == 0)
|
||||||
{
|
{
|
||||||
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
||||||
|
@@ -152,6 +152,12 @@ static void _wait_stored(tf_ssb_t* ssb, bool* stored)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _blob_stored(tf_ssb_t* ssb, const char* id, void* user_data)
|
||||||
|
{
|
||||||
|
tf_printf("blob stored %s\n", id);
|
||||||
|
*(bool*)user_data = true;
|
||||||
|
}
|
||||||
|
|
||||||
void tf_ssb_test_ssb(const tf_test_options_t* options)
|
void tf_ssb_test_ssb(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
tf_printf("Testing SSB.\n");
|
tf_printf("Testing SSB.\n");
|
||||||
@@ -224,8 +230,13 @@ void tf_ssb_test_ssb(const tf_test_options_t* options)
|
|||||||
|
|
||||||
char blob_id[k_id_base64_len] = { 0 };
|
char blob_id[k_id_base64_len] = { 0 };
|
||||||
const char* k_blob = "Hello, blob!";
|
const char* k_blob = "Hello, blob!";
|
||||||
|
bool blob_stored = false;
|
||||||
|
tf_ssb_add_blob_stored_callback(ssb0, _blob_stored, NULL, &blob_stored);
|
||||||
b = tf_ssb_db_blob_store(ssb0, (const uint8_t*)k_blob, strlen(k_blob), blob_id, sizeof(blob_id), NULL);
|
b = tf_ssb_db_blob_store(ssb0, (const uint8_t*)k_blob, strlen(k_blob), blob_id, sizeof(blob_id), NULL);
|
||||||
|
tf_ssb_notify_blob_stored(ssb0, blob_id);
|
||||||
|
tf_ssb_remove_blob_stored_callback(ssb0, _blob_stored, &blob_stored);
|
||||||
assert(b);
|
assert(b);
|
||||||
|
assert(blob_stored);
|
||||||
|
|
||||||
JSContext* context0 = tf_ssb_get_context(ssb0);
|
JSContext* context0 = tf_ssb_get_context(ssb0);
|
||||||
JSValue obj = JS_NewObject(context0);
|
JSValue obj = JS_NewObject(context0);
|
||||||
|
Reference in New Issue
Block a user