forked from cory/tildefriends
clang-format the source. Not exactly how I want it, but automated is better than perfect.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4845 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
parent
c8812b1add
commit
fbc3cfeda4
@ -865,3 +865,7 @@ dist-test: dist
|
|||||||
@docker build tildefriends-$(VERSION_NUMBER)/
|
@docker build tildefriends-$(VERSION_NUMBER)/
|
||||||
@rm -rf tildefriends-$(VERSION_NUMBER)
|
@rm -rf tildefriends-$(VERSION_NUMBER)
|
||||||
.PHONY: dist-test
|
.PHONY: dist-test
|
||||||
|
|
||||||
|
format:
|
||||||
|
@clang-format -i $(wildcard src/*.c src/*.h src/*.m)
|
||||||
|
.PHONY: format
|
||||||
|
2336
src/bip39.words.c
2336
src/bip39.words.c
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
enum { k_bip39_words_count = 2048 };
|
enum
|
||||||
|
{
|
||||||
|
k_bip39_words_count = 2048
|
||||||
|
};
|
||||||
extern const char* k_bip39_words[k_bip39_words_count];
|
extern const char* k_bip39_words[k_bip39_words_count];
|
||||||
|
@ -22,7 +22,7 @@ typedef struct _database_t
|
|||||||
} database_t;
|
} database_t;
|
||||||
|
|
||||||
static JSValue _database_create(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* data);
|
static JSValue _database_create(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* data);
|
||||||
static void _database_finalizer(JSRuntime *runtime, JSValue value);
|
static void _database_finalizer(JSRuntime* runtime, JSValue value);
|
||||||
|
|
||||||
static JSValue _database_get(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
static JSValue _database_get(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
||||||
static JSValue _database_set(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
static JSValue _database_set(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
||||||
@ -35,8 +35,7 @@ static JSValue _databases_list(JSContext* context, JSValueConst this_val, int ar
|
|||||||
void tf_database_register(JSContext* context)
|
void tf_database_register(JSContext* context)
|
||||||
{
|
{
|
||||||
JS_NewClassID(&_database_class_id);
|
JS_NewClassID(&_database_class_id);
|
||||||
JSClassDef def =
|
JSClassDef def = {
|
||||||
{
|
|
||||||
.class_name = "Database",
|
.class_name = "Database",
|
||||||
.finalizer = &_database_finalizer,
|
.finalizer = &_database_finalizer,
|
||||||
};
|
};
|
||||||
@ -61,8 +60,7 @@ static JSValue _database_create(JSContext* context, JSValueConst this_val, int a
|
|||||||
JSValue object = JS_NewObjectClass(context, _database_class_id);
|
JSValue object = JS_NewObjectClass(context, _database_class_id);
|
||||||
|
|
||||||
database_t* database = tf_malloc(sizeof(database_t));
|
database_t* database = tf_malloc(sizeof(database_t));
|
||||||
*database = (database_t)
|
*database = (database_t) {
|
||||||
{
|
|
||||||
.task = JS_GetContextOpaque(context),
|
.task = JS_GetContextOpaque(context),
|
||||||
.context = context,
|
.context = context,
|
||||||
.object = object,
|
.object = object,
|
||||||
@ -82,7 +80,7 @@ static JSValue _database_create(JSContext* context, JSValueConst this_val, int a
|
|||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _database_finalizer(JSRuntime *runtime, JSValue value)
|
static void _database_finalizer(JSRuntime* runtime, JSValue value)
|
||||||
{
|
{
|
||||||
database_t* database = JS_GetOpaque(value, _database_class_id);
|
database_t* database = JS_GetOpaque(value, _database_class_id);
|
||||||
if (database)
|
if (database)
|
||||||
@ -106,8 +104,7 @@ static JSValue _database_get(JSContext* context, JSValueConst this_val, int argc
|
|||||||
{
|
{
|
||||||
size_t length;
|
size_t length;
|
||||||
const char* keyString = JS_ToCStringLen(context, &length, argv[0]);
|
const char* keyString = JS_ToCStringLen(context, &length, argv[0]);
|
||||||
if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, keyString, length, NULL) == SQLITE_OK &&
|
||||||
sqlite3_bind_text(statement, 2, keyString, length, NULL) == SQLITE_OK &&
|
|
||||||
sqlite3_step(statement) == SQLITE_ROW)
|
sqlite3_step(statement) == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
entry = JS_NewStringLen(context, (const char*)sqlite3_column_text(statement, 0), sqlite3_column_bytes(statement, 0));
|
entry = JS_NewStringLen(context, (const char*)sqlite3_column_text(statement, 0), sqlite3_column_bytes(statement, 0));
|
||||||
@ -134,10 +131,8 @@ static JSValue _database_set(JSContext* context, JSValueConst this_val, int argc
|
|||||||
const char* keyString = JS_ToCStringLen(context, &keyLength, argv[0]);
|
const char* keyString = JS_ToCStringLen(context, &keyLength, argv[0]);
|
||||||
size_t valueLength;
|
size_t valueLength;
|
||||||
const char* valueString = JS_ToCStringLen(context, &valueLength, argv[1]);
|
const char* valueString = JS_ToCStringLen(context, &valueLength, argv[1]);
|
||||||
if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, keyString, keyLength, NULL) == SQLITE_OK &&
|
||||||
sqlite3_bind_text(statement, 2, keyString, keyLength, NULL) == SQLITE_OK &&
|
sqlite3_bind_text(statement, 3, valueString, valueLength, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_OK)
|
||||||
sqlite3_bind_text(statement, 3, valueString, valueLength, NULL) == SQLITE_OK &&
|
|
||||||
sqlite3_step(statement) == SQLITE_OK)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
JS_FreeCString(context, keyString);
|
JS_FreeCString(context, keyString);
|
||||||
@ -166,10 +161,8 @@ static JSValue _database_exchange(JSContext* context, JSValueConst this_val, int
|
|||||||
size_t set_length;
|
size_t set_length;
|
||||||
const char* key = JS_ToCStringLen(context, &key_length, argv[0]);
|
const char* key = JS_ToCStringLen(context, &key_length, argv[0]);
|
||||||
const char* set = JS_ToCStringLen(context, &set_length, argv[2]);
|
const char* set = JS_ToCStringLen(context, &set_length, argv[2]);
|
||||||
if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, key, key_length, NULL) == SQLITE_OK &&
|
||||||
sqlite3_bind_text(statement, 2, key, key_length, NULL) == SQLITE_OK &&
|
sqlite3_bind_text(statement, 3, set, set_length, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_DONE)
|
||||||
sqlite3_bind_text(statement, 3, set, set_length, NULL) == SQLITE_OK &&
|
|
||||||
sqlite3_step(statement) == SQLITE_DONE)
|
|
||||||
{
|
{
|
||||||
exchanged = sqlite3_changes(db) != 0 ? JS_TRUE : JS_FALSE;
|
exchanged = sqlite3_changes(db) != 0 ? JS_TRUE : JS_FALSE;
|
||||||
}
|
}
|
||||||
@ -186,10 +179,8 @@ static JSValue _database_exchange(JSContext* context, JSValueConst this_val, int
|
|||||||
const char* key = JS_ToCStringLen(context, &key_length, argv[0]);
|
const char* key = JS_ToCStringLen(context, &key_length, argv[0]);
|
||||||
const char* expected = JS_ToCStringLen(context, &expected_length, argv[1]);
|
const char* expected = JS_ToCStringLen(context, &expected_length, argv[1]);
|
||||||
const char* set = JS_ToCStringLen(context, &set_length, argv[2]);
|
const char* set = JS_ToCStringLen(context, &set_length, argv[2]);
|
||||||
if (sqlite3_bind_text(statement, 1, set, set_length, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, set, set_length, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, database->id, -1, NULL) == SQLITE_OK &&
|
||||||
sqlite3_bind_text(statement, 2, database->id, -1, NULL) == SQLITE_OK &&
|
sqlite3_bind_text(statement, 3, key, key_length, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 4, expected, expected_length, NULL) == SQLITE_OK &&
|
||||||
sqlite3_bind_text(statement, 3, key, key_length, NULL) == SQLITE_OK &&
|
|
||||||
sqlite3_bind_text(statement, 4, expected, expected_length, NULL) == SQLITE_OK &&
|
|
||||||
sqlite3_step(statement) == SQLITE_DONE)
|
sqlite3_step(statement) == SQLITE_DONE)
|
||||||
{
|
{
|
||||||
exchanged = sqlite3_changes(db) != 0 ? JS_TRUE : JS_FALSE;
|
exchanged = sqlite3_changes(db) != 0 ? JS_TRUE : JS_FALSE;
|
||||||
@ -216,8 +207,7 @@ static JSValue _database_remove(JSContext* context, JSValueConst this_val, int a
|
|||||||
{
|
{
|
||||||
size_t keyLength;
|
size_t keyLength;
|
||||||
const char* keyString = JS_ToCStringLen(context, &keyLength, argv[0]);
|
const char* keyString = JS_ToCStringLen(context, &keyLength, argv[0]);
|
||||||
if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, keyString, keyLength, NULL) == SQLITE_OK &&
|
||||||
sqlite3_bind_text(statement, 2, keyString, keyLength, NULL) == SQLITE_OK &&
|
|
||||||
sqlite3_step(statement) == SQLITE_OK)
|
sqlite3_step(statement) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -246,7 +236,8 @@ static JSValue _database_get_all(JSContext* context, JSValueConst this_val, int
|
|||||||
uint32_t index = 0;
|
uint32_t index = 0;
|
||||||
while (sqlite3_step(statement) == SQLITE_ROW)
|
while (sqlite3_step(statement) == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
JS_SetPropertyUint32(context, array, index++, JS_NewStringLen(context, (const char*)sqlite3_column_text(statement, 0), sqlite3_column_bytes(statement, 0)));
|
JS_SetPropertyUint32(
|
||||||
|
context, array, index++, JS_NewStringLen(context, (const char*)sqlite3_column_text(statement, 0), sqlite3_column_bytes(statement, 0)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sqlite3_finalize(statement);
|
sqlite3_finalize(statement);
|
||||||
@ -268,16 +259,12 @@ static JSValue _database_get_like(JSContext* context, JSValueConst this_val, int
|
|||||||
if (sqlite3_prepare(db, "SELECT key, value FROM properties WHERE id = ? AND KEY LIKE ?", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "SELECT key, value FROM properties WHERE id = ? AND KEY LIKE ?", -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
const char* pattern = JS_ToCString(context, argv[0]);
|
const char* pattern = JS_ToCString(context, argv[0]);
|
||||||
if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, pattern, -1, NULL) == SQLITE_OK)
|
||||||
sqlite3_bind_text(statement, 2, pattern, -1, NULL) == SQLITE_OK)
|
|
||||||
{
|
{
|
||||||
result = JS_NewObject(context);
|
result = JS_NewObject(context);
|
||||||
while (sqlite3_step(statement) == SQLITE_ROW)
|
while (sqlite3_step(statement) == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
JS_SetPropertyStr(
|
JS_SetPropertyStr(context, result, (const char*)sqlite3_column_text(statement, 0),
|
||||||
context,
|
|
||||||
result,
|
|
||||||
(const char*)sqlite3_column_text(statement, 0),
|
|
||||||
JS_NewStringLen(context, (const char*)sqlite3_column_text(statement, 1), sqlite3_column_bytes(statement, 1)));
|
JS_NewStringLen(context, (const char*)sqlite3_column_text(statement, 1), sqlite3_column_bytes(statement, 1)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -305,7 +292,8 @@ static JSValue _databases_list(JSContext* context, JSValueConst this_val, int ar
|
|||||||
uint32_t index = 0;
|
uint32_t index = 0;
|
||||||
while (sqlite3_step(statement) == SQLITE_ROW)
|
while (sqlite3_step(statement) == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
JS_SetPropertyUint32(context, array, index++, JS_NewStringLen(context, (const char*)sqlite3_column_text(statement, 0), sqlite3_column_bytes(statement, 0)));
|
JS_SetPropertyUint32(
|
||||||
|
context, array, index++, JS_NewStringLen(context, (const char*)sqlite3_column_text(statement, 0), sqlite3_column_bytes(statement, 0)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
JS_FreeCString(context, pattern);
|
JS_FreeCString(context, pattern);
|
||||||
|
@ -25,14 +25,16 @@ static JSValue _file_write_file(JSContext* context, JSValueConst this_val, int a
|
|||||||
static double _time_spec_to_double(const uv_timespec_t* time_spec);
|
static double _time_spec_to_double(const uv_timespec_t* time_spec);
|
||||||
static void _file_on_stat_complete(uv_fs_t* request);
|
static void _file_on_stat_complete(uv_fs_t* request);
|
||||||
|
|
||||||
typedef struct file_stat_t {
|
typedef struct file_stat_t
|
||||||
|
{
|
||||||
void* _task;
|
void* _task;
|
||||||
JSContext* _context;
|
JSContext* _context;
|
||||||
promiseid_t _promise;
|
promiseid_t _promise;
|
||||||
uv_fs_t _request;
|
uv_fs_t _request;
|
||||||
} file_stat_t;
|
} file_stat_t;
|
||||||
|
|
||||||
typedef struct fs_req_t {
|
typedef struct fs_req_t
|
||||||
|
{
|
||||||
uv_fs_t fs;
|
uv_fs_t fs;
|
||||||
size_t size;
|
size_t size;
|
||||||
uv_file file;
|
uv_file file;
|
||||||
@ -52,7 +54,10 @@ void tf_file_register(JSContext* context)
|
|||||||
JS_FreeValue(context, global);
|
JS_FreeValue(context, global);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum { k_file_read_max = 8 * 1024 * 1024 };
|
enum
|
||||||
|
{
|
||||||
|
k_file_read_max = 8 * 1024 * 1024
|
||||||
|
};
|
||||||
|
|
||||||
static void _file_async_close_callback(uv_fs_t* req)
|
static void _file_async_close_callback(uv_fs_t* req)
|
||||||
{
|
{
|
||||||
|
81
src/http.c
81
src/http.c
@ -110,8 +110,7 @@ static void _http_tls_update(tf_http_connection_t* connection);
|
|||||||
tf_http_t* tf_http_create(uv_loop_t* loop)
|
tf_http_t* tf_http_create(uv_loop_t* loop)
|
||||||
{
|
{
|
||||||
tf_http_t* http = tf_malloc(sizeof(tf_http_t));
|
tf_http_t* http = tf_malloc(sizeof(tf_http_t));
|
||||||
*http = (tf_http_t)
|
*http = (tf_http_t) {
|
||||||
{
|
|
||||||
.loop = loop,
|
.loop = loop,
|
||||||
};
|
};
|
||||||
return http;
|
return http;
|
||||||
@ -132,10 +131,9 @@ static bool _http_find_handler(tf_http_t* http, const char* path, tf_http_callba
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < http->handlers_count; i++)
|
for (int i = 0; i < http->handlers_count; i++)
|
||||||
{
|
{
|
||||||
if (!http->handlers[i].pattern ||
|
if (!http->handlers[i].pattern || !*http->handlers[i].pattern || strcmp(path, http->handlers[i].pattern) == 0 ||
|
||||||
!*http->handlers[i].pattern ||
|
(*http->handlers[i].pattern && strncmp(path, http->handlers[i].pattern, strlen(http->handlers[i].pattern)) == 0 &&
|
||||||
strcmp(path, http->handlers[i].pattern) == 0 ||
|
path[strlen(http->handlers[i].pattern) - 1] == '/'))
|
||||||
(*http->handlers[i].pattern && strncmp(path, http->handlers[i].pattern, strlen(http->handlers[i].pattern)) == 0 && path[strlen(http->handlers[i].pattern) - 1] == '/'))
|
|
||||||
{
|
{
|
||||||
*out_callback = http->handlers[i].callback;
|
*out_callback = http->handlers[i].callback;
|
||||||
*out_trace_name = http->handlers[i].pattern;
|
*out_trace_name = http->handlers[i].pattern;
|
||||||
@ -186,10 +184,7 @@ static void _http_connection_destroy(tf_http_connection_t* connection, const cha
|
|||||||
connection->tls = NULL;
|
connection->tls = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connection->ref_count == 0 &&
|
if (connection->ref_count == 0 && !connection->tcp.data && !connection->shutdown.data && !connection->timeout.data)
|
||||||
!connection->tcp.data &&
|
|
||||||
!connection->shutdown.data &&
|
|
||||||
!connection->timeout.data)
|
|
||||||
{
|
{
|
||||||
tf_http_t* http = connection->http;
|
tf_http_t* http = connection->http;
|
||||||
for (int i = 0; i < http->connections_count; i++)
|
for (int i = 0; i < http->connections_count; i++)
|
||||||
@ -211,8 +206,7 @@ static void _http_connection_destroy(tf_http_connection_t* connection, const cha
|
|||||||
}
|
}
|
||||||
tf_free(connection);
|
tf_free(connection);
|
||||||
|
|
||||||
if (http->is_shutting_down &&
|
if (http->is_shutting_down && http->connections_count == 0)
|
||||||
http->connections_count == 0)
|
|
||||||
{
|
{
|
||||||
tf_http_destroy(http);
|
tf_http_destroy(http);
|
||||||
}
|
}
|
||||||
@ -308,10 +302,7 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d
|
|||||||
if (connection->body_length >= total_length)
|
if (connection->body_length >= total_length)
|
||||||
{
|
{
|
||||||
uint32_t mask =
|
uint32_t mask =
|
||||||
(uint32_t)p[mask_start + 0] |
|
(uint32_t)p[mask_start + 0] | (uint32_t)p[mask_start + 1] << 8 | (uint32_t)p[mask_start + 2] << 16 | (uint32_t)p[mask_start + 3] << 24;
|
||||||
(uint32_t)p[mask_start + 1] << 8 |
|
|
||||||
(uint32_t)p[mask_start + 2] << 16 |
|
|
||||||
(uint32_t)p[mask_start + 3] << 24;
|
|
||||||
uint8_t* message = p + mask_start + 4;
|
uint8_t* message = p + mask_start + 4;
|
||||||
_http_websocket_mask_in_place(message, mask, length);
|
_http_websocket_mask_in_place(message, mask, length);
|
||||||
|
|
||||||
@ -332,9 +323,7 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d
|
|||||||
if (connection->request->on_message)
|
if (connection->request->on_message)
|
||||||
{
|
{
|
||||||
tf_trace_begin(connection->http->trace, connection->trace_name ? connection->trace_name : "websocket");
|
tf_trace_begin(connection->http->trace, connection->trace_name ? connection->trace_name : "websocket");
|
||||||
connection->request->on_message(
|
connection->request->on_message(connection->request, connection->fragment_length ? connection->fragment_op_code : op_code,
|
||||||
connection->request,
|
|
||||||
connection->fragment_length ? connection->fragment_op_code : op_code,
|
|
||||||
connection->fragment_length ? connection->fragment : message,
|
connection->fragment_length ? connection->fragment : message,
|
||||||
connection->fragment_length ? connection->fragment_length : length);
|
connection->fragment_length ? connection->fragment_length : length);
|
||||||
tf_trace_end(connection->http->trace);
|
tf_trace_end(connection->http->trace);
|
||||||
@ -369,8 +358,7 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d
|
|||||||
if (connection->body_length == connection->content_length)
|
if (connection->body_length == connection->content_length)
|
||||||
{
|
{
|
||||||
tf_http_request_t* request = tf_malloc(sizeof(tf_http_request_t));
|
tf_http_request_t* request = tf_malloc(sizeof(tf_http_request_t));
|
||||||
*request = (tf_http_request_t)
|
*request = (tf_http_request_t) {
|
||||||
{
|
|
||||||
.http = connection->http,
|
.http = connection->http,
|
||||||
.connection = connection,
|
.connection = connection,
|
||||||
.is_tls = connection->tls != NULL,
|
.is_tls = connection->tls != NULL,
|
||||||
@ -408,7 +396,8 @@ static size_t _http_on_read_plain_internal(tf_http_connection_t* connection, con
|
|||||||
size_t path_length = 0;
|
size_t path_length = 0;
|
||||||
size_t header_count = sizeof(connection->headers) / sizeof(*connection->headers);
|
size_t header_count = sizeof(connection->headers) / sizeof(*connection->headers);
|
||||||
|
|
||||||
int parse_result = phr_parse_request(connection->headers_buffer, connection->headers_buffer_length, &method, &method_length, &path, &path_length, &connection->minor_version, connection->headers, &header_count, connection->parsed_length);
|
int parse_result = phr_parse_request(connection->headers_buffer, connection->headers_buffer_length, &method, &method_length, &path, &path_length,
|
||||||
|
&connection->minor_version, connection->headers, &header_count, connection->parsed_length);
|
||||||
connection->parsed_length = connection->headers_buffer_length;
|
connection->parsed_length = connection->headers_buffer_length;
|
||||||
if (parse_result > 0)
|
if (parse_result > 0)
|
||||||
{
|
{
|
||||||
@ -431,8 +420,7 @@ static size_t _http_on_read_plain_internal(tf_http_connection_t* connection, con
|
|||||||
{
|
{
|
||||||
for (size_t j = 0; j < connection->headers[i].name_len; j++)
|
for (size_t j = 0; j < connection->headers[i].name_len; j++)
|
||||||
{
|
{
|
||||||
if (connection->headers[i].name[j] >= 'A' &&
|
if (connection->headers[i].name[j] >= 'A' && connection->headers[i].name[j] <= 'Z')
|
||||||
connection->headers[i].name[j] <= 'Z')
|
|
||||||
{
|
{
|
||||||
((char*)connection->headers[i].name)[j] += 'a' - 'A';
|
((char*)connection->headers[i].name)[j] += 'a' - 'A';
|
||||||
}
|
}
|
||||||
@ -457,7 +445,8 @@ static size_t _http_on_read_plain_internal(tf_http_connection_t* connection, con
|
|||||||
connection->body = tf_malloc(connection->content_length);
|
connection->body = tf_malloc(connection->content_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_http_find_handler(connection->http, connection->path, &connection->callback, &connection->trace_name, &connection->user_data) || !connection->callback)
|
if (!_http_find_handler(connection->http, connection->path, &connection->callback, &connection->trace_name, &connection->user_data) ||
|
||||||
|
!connection->callback)
|
||||||
{
|
{
|
||||||
connection->callback = _http_builtin_404_handler;
|
connection->callback = _http_builtin_404_handler;
|
||||||
connection->trace_name = "404";
|
connection->trace_name = "404";
|
||||||
@ -619,8 +608,7 @@ static void _http_on_connection(uv_stream_t* stream, int status)
|
|||||||
int tf_http_listen(tf_http_t* http, int port, tf_tls_context_t* tls, tf_http_cleanup_t* cleanup, void* user_data)
|
int tf_http_listen(tf_http_t* http, int port, tf_tls_context_t* tls, tf_http_cleanup_t* cleanup, void* user_data)
|
||||||
{
|
{
|
||||||
tf_http_listener_t* listener = tf_malloc(sizeof(tf_http_listener_t));
|
tf_http_listener_t* listener = tf_malloc(sizeof(tf_http_listener_t));
|
||||||
*listener = (tf_http_listener_t)
|
*listener = (tf_http_listener_t) {
|
||||||
{
|
|
||||||
.http = http,
|
.http = http,
|
||||||
.tls = tls,
|
.tls = tls,
|
||||||
.tcp = { .data = listener },
|
.tcp = { .data = listener },
|
||||||
@ -635,8 +623,7 @@ int tf_http_listen(tf_http_t* http, int port, tf_tls_context_t* tls, tf_http_cle
|
|||||||
|
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
{
|
{
|
||||||
struct sockaddr_in6 addr =
|
struct sockaddr_in6 addr = {
|
||||||
{
|
|
||||||
.sin6_family = AF_INET6,
|
.sin6_family = AF_INET6,
|
||||||
.sin6_addr = IN6ADDR_ANY_INIT,
|
.sin6_addr = IN6ADDR_ANY_INIT,
|
||||||
.sin6_port = ntohs(port),
|
.sin6_port = ntohs(port),
|
||||||
@ -677,8 +664,7 @@ int tf_http_listen(tf_http_t* http, int port, tf_tls_context_t* tls, tf_http_cle
|
|||||||
void tf_http_add_handler(tf_http_t* http, const char* pattern, tf_http_callback_t* callback, tf_http_cleanup_t* cleanup, void* user_data)
|
void tf_http_add_handler(tf_http_t* http, const char* pattern, tf_http_callback_t* callback, tf_http_cleanup_t* cleanup, void* user_data)
|
||||||
{
|
{
|
||||||
http->handlers = tf_resize_vec(http->handlers, sizeof(tf_http_handler_t) * (http->handlers_count + 1));
|
http->handlers = tf_resize_vec(http->handlers, sizeof(tf_http_handler_t) * (http->handlers_count + 1));
|
||||||
http->handlers[http->handlers_count++] = (tf_http_handler_t)
|
http->handlers[http->handlers_count++] = (tf_http_handler_t) {
|
||||||
{
|
|
||||||
.pattern = tf_strdup(pattern),
|
.pattern = tf_strdup(pattern),
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
.cleanup = cleanup,
|
.cleanup = cleanup,
|
||||||
@ -760,16 +746,26 @@ const char* tf_http_status_text(int status)
|
|||||||
{
|
{
|
||||||
switch (status)
|
switch (status)
|
||||||
{
|
{
|
||||||
case 101: return "Switching Protocols";
|
case 101:
|
||||||
case 200: return "OK";
|
return "Switching Protocols";
|
||||||
case 303: return "See other";
|
case 200:
|
||||||
case 304: return "Not Modified";
|
return "OK";
|
||||||
case 400: return "Bad Request";
|
case 303:
|
||||||
case 401: return "Unauthorized";
|
return "See other";
|
||||||
case 403: return "Forbidden";
|
case 304:
|
||||||
case 404: return "File not found";
|
return "Not Modified";
|
||||||
case 500: return "Internal server error";
|
case 400:
|
||||||
default: return "Unknown";
|
return "Bad Request";
|
||||||
|
case 401:
|
||||||
|
return "Unauthorized";
|
||||||
|
case 403:
|
||||||
|
return "Forbidden";
|
||||||
|
case 404:
|
||||||
|
return "File not found";
|
||||||
|
case 500:
|
||||||
|
return "Internal server error";
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -923,8 +919,7 @@ void tf_http_respond(tf_http_request_t* request, int status, const char** header
|
|||||||
}
|
}
|
||||||
_http_timer_reset(request->connection);
|
_http_timer_reset(request->connection);
|
||||||
|
|
||||||
if (request->connection->connection_close &&
|
if (request->connection->connection_close && !request->connection->shutdown.data)
|
||||||
!request->connection->shutdown.data)
|
|
||||||
{
|
{
|
||||||
request->connection->shutdown.data = request->connection;
|
request->connection->shutdown.data = request->connection;
|
||||||
uv_shutdown(&request->connection->shutdown, (uv_stream_t*)&request->connection->tcp, _http_on_shutdown);
|
uv_shutdown(&request->connection->shutdown, (uv_stream_t*)&request->connection->tcp, _http_on_shutdown);
|
||||||
|
@ -10,8 +10,8 @@ typedef struct _tf_tls_context_t tf_tls_context_t;
|
|||||||
typedef struct _tf_trace_t tf_trace_t;
|
typedef struct _tf_trace_t tf_trace_t;
|
||||||
typedef struct uv_loop_s uv_loop_t;
|
typedef struct uv_loop_s uv_loop_t;
|
||||||
|
|
||||||
typedef void (tf_http_message_callback)(tf_http_request_t* request, int op_code, const void* data, size_t size);
|
typedef void(tf_http_message_callback)(tf_http_request_t* request, int op_code, const void* data, size_t size);
|
||||||
typedef void (tf_http_close_callback)(tf_http_request_t* request);
|
typedef void(tf_http_close_callback)(tf_http_request_t* request);
|
||||||
|
|
||||||
typedef struct _tf_http_request_t
|
typedef struct _tf_http_request_t
|
||||||
{
|
{
|
||||||
@ -32,8 +32,8 @@ typedef struct _tf_http_request_t
|
|||||||
int ref_count;
|
int ref_count;
|
||||||
} tf_http_request_t;
|
} tf_http_request_t;
|
||||||
|
|
||||||
typedef void (tf_http_callback_t)(tf_http_request_t* request);
|
typedef void(tf_http_callback_t)(tf_http_request_t* request);
|
||||||
typedef void (tf_http_cleanup_t)(void* user_data);
|
typedef void(tf_http_cleanup_t)(void* user_data);
|
||||||
|
|
||||||
tf_http_t* tf_http_create(uv_loop_t* loop);
|
tf_http_t* tf_http_create(uv_loop_t* loop);
|
||||||
void tf_http_set_trace(tf_http_t* http, tf_trace_t* trace);
|
void tf_http_set_trace(tf_http_t* http, tf_trace_t* trace);
|
||||||
|
@ -230,8 +230,7 @@ static void _httpd_callback_internal(tf_http_request_t* request, bool is_websock
|
|||||||
JS_SetPropertyStr(context, response_object, "end", JS_NewCFunction(context, _httpd_response_end, "end", 1));
|
JS_SetPropertyStr(context, response_object, "end", JS_NewCFunction(context, _httpd_response_end, "end", 1));
|
||||||
JS_SetPropertyStr(context, response_object, "send", JS_NewCFunction(context, _httpd_response_send, "send", 2));
|
JS_SetPropertyStr(context, response_object, "send", JS_NewCFunction(context, _httpd_response_send, "send", 2));
|
||||||
JS_SetPropertyStr(context, response_object, "upgrade", JS_NewCFunction(context, _httpd_websocket_upgrade, "upgrade", 2));
|
JS_SetPropertyStr(context, response_object, "upgrade", JS_NewCFunction(context, _httpd_websocket_upgrade, "upgrade", 2));
|
||||||
JSValue args[] =
|
JSValue args[] = {
|
||||||
{
|
|
||||||
request_object,
|
request_object,
|
||||||
response_object,
|
response_object,
|
||||||
};
|
};
|
||||||
@ -278,11 +277,7 @@ static JSValue _httpd_websocket_upgrade(JSContext* context, JSValueConst this_va
|
|||||||
const char* header_connection = tf_http_request_get_header(request, "connection");
|
const char* header_connection = tf_http_request_get_header(request, "connection");
|
||||||
const char* header_upgrade = tf_http_request_get_header(request, "upgrade");
|
const char* header_upgrade = tf_http_request_get_header(request, "upgrade");
|
||||||
const char* header_sec_websocket_key = tf_http_request_get_header(request, "sec-websocket-key");
|
const char* header_sec_websocket_key = tf_http_request_get_header(request, "sec-websocket-key");
|
||||||
if (header_connection &&
|
if (header_connection && header_upgrade && header_sec_websocket_key && strstr(header_connection, "Upgrade") && strcasecmp(header_upgrade, "websocket") == 0)
|
||||||
header_upgrade &&
|
|
||||||
header_sec_websocket_key &&
|
|
||||||
strstr(header_connection, "Upgrade") &&
|
|
||||||
strcasecmp(header_upgrade, "websocket") == 0)
|
|
||||||
{
|
{
|
||||||
static const char* k_magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
static const char* k_magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||||
size_t key_length = strlen(header_sec_websocket_key);
|
size_t key_length = strlen(header_sec_websocket_key);
|
||||||
@ -311,8 +306,7 @@ static JSValue _httpd_websocket_upgrade(JSContext* context, JSValueConst this_va
|
|||||||
headers_count++;
|
headers_count++;
|
||||||
|
|
||||||
bool send_version =
|
bool send_version =
|
||||||
!tf_http_request_get_header(request, "sec-websocket-version") ||
|
!tf_http_request_get_header(request, "sec-websocket-version") || strcmp(tf_http_request_get_header(request, "sec-websocket-version"), "13") != 0;
|
||||||
strcmp(tf_http_request_get_header(request, "sec-websocket-version"), "13") != 0;
|
|
||||||
if (send_version)
|
if (send_version)
|
||||||
{
|
{
|
||||||
headers[headers_count * 2 + 0] = "Sec-WebSocket-Accept";
|
headers[headers_count * 2 + 0] = "Sec-WebSocket-Accept";
|
||||||
@ -433,10 +427,11 @@ static void _httpd_endpoint_trace(tf_http_request_t* request)
|
|||||||
tf_task_t* task = request->user_data;
|
tf_task_t* task = request->user_data;
|
||||||
tf_trace_t* trace = tf_task_get_trace(task);
|
tf_trace_t* trace = tf_task_get_trace(task);
|
||||||
char* json = tf_trace_export(trace);
|
char* json = tf_trace_export(trace);
|
||||||
const char* headers[] =
|
const char* headers[] = {
|
||||||
{
|
"Content-Type",
|
||||||
"Content-Type", "application/json; charset=utf-8",
|
"application/json; charset=utf-8",
|
||||||
"Access-Control-Allow-Origin", "*",
|
"Access-Control-Allow-Origin",
|
||||||
|
"*",
|
||||||
};
|
};
|
||||||
tf_http_respond(request, 200, headers, tf_countof(headers) / 2, json, json ? strlen(json) : 0);
|
tf_http_respond(request, 200, headers, tf_countof(headers) / 2, json, json ? strlen(json) : 0);
|
||||||
tf_free(json);
|
tf_free(json);
|
||||||
@ -465,10 +460,11 @@ static void _httpd_endpoint_mem(tf_http_request_t* request)
|
|||||||
}
|
}
|
||||||
tf_free(alloc);
|
tf_free(alloc);
|
||||||
|
|
||||||
const char* headers[] =
|
const char* headers[] = {
|
||||||
{
|
"Content-Type",
|
||||||
"Content-Type", "text/plain; charset=utf-8",
|
"text/plain; charset=utf-8",
|
||||||
"Access-Control-Allow-Origin", "*",
|
"Access-Control-Allow-Origin",
|
||||||
|
"*",
|
||||||
};
|
};
|
||||||
tf_http_respond(request, 200, headers, tf_countof(headers) / 2, response, length);
|
tf_http_respond(request, 200, headers, tf_countof(headers) / 2, response, length);
|
||||||
tf_free(response);
|
tf_free(response);
|
||||||
@ -483,10 +479,11 @@ static void _httpd_endpoint_disconnections(tf_http_request_t* request)
|
|||||||
|
|
||||||
tf_task_t* task = request->user_data;
|
tf_task_t* task = request->user_data;
|
||||||
char* response = tf_task_get_disconnections(task);
|
char* response = tf_task_get_disconnections(task);
|
||||||
const char* headers[] =
|
const char* headers[] = {
|
||||||
{
|
"Content-Type",
|
||||||
"Content-Type", "application/json; charset=utf-8",
|
"application/json; charset=utf-8",
|
||||||
"Access-Control-Allow-Origin", "*",
|
"Access-Control-Allow-Origin",
|
||||||
|
"*",
|
||||||
};
|
};
|
||||||
tf_http_respond(request, 200, headers, tf_countof(headers) / 2, response, response ? strlen(response) : 0);
|
tf_http_respond(request, 200, headers, tf_countof(headers) / 2, response, response ? strlen(response) : 0);
|
||||||
tf_free(response);
|
tf_free(response);
|
||||||
@ -501,10 +498,11 @@ static void _httpd_endpoint_hitches(tf_http_request_t* request)
|
|||||||
|
|
||||||
tf_task_t* task = request->user_data;
|
tf_task_t* task = request->user_data;
|
||||||
char* response = tf_task_get_hitches(task);
|
char* response = tf_task_get_hitches(task);
|
||||||
const char* headers[] =
|
const char* headers[] = {
|
||||||
{
|
"Content-Type",
|
||||||
"Content-Type", "application/json; charset=utf-8",
|
"application/json; charset=utf-8",
|
||||||
"Access-Control-Allow-Origin", "*",
|
"Access-Control-Allow-Origin",
|
||||||
|
"*",
|
||||||
};
|
};
|
||||||
tf_http_respond(request, 200, headers, tf_countof(headers) / 2, response, response ? strlen(response) : 0);
|
tf_http_respond(request, 200, headers, tf_countof(headers) / 2, response, response ? strlen(response) : 0);
|
||||||
tf_free(response);
|
tf_free(response);
|
||||||
@ -560,21 +558,24 @@ static void _httpd_endpoint_static_read(tf_task_t* task, const char* path, int r
|
|||||||
if (strcmp(path, "core/tfrpc.js") == 0)
|
if (strcmp(path, "core/tfrpc.js") == 0)
|
||||||
{
|
{
|
||||||
const char* content_type = _ext_to_content_type(strrchr(path, '.'));
|
const char* content_type = _ext_to_content_type(strrchr(path, '.'));
|
||||||
const char* headers[] =
|
const char* headers[] = {
|
||||||
{
|
"Content-Type",
|
||||||
"Content-Type", content_type,
|
content_type,
|
||||||
"etag", file->etag,
|
"etag",
|
||||||
"Access-Control-Allow-Origin", "null",
|
file->etag,
|
||||||
|
"Access-Control-Allow-Origin",
|
||||||
|
"null",
|
||||||
};
|
};
|
||||||
tf_http_respond(request, 200, headers, tf_countof(headers) / 2, data, result);
|
tf_http_respond(request, 200, headers, tf_countof(headers) / 2, data, result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const char* content_type = _ext_to_content_type(strrchr(path, '.'));
|
const char* content_type = _ext_to_content_type(strrchr(path, '.'));
|
||||||
const char* headers[] =
|
const char* headers[] = {
|
||||||
{
|
"Content-Type",
|
||||||
"Content-Type", content_type,
|
content_type,
|
||||||
"etag", file->etag,
|
"etag",
|
||||||
|
file->etag,
|
||||||
};
|
};
|
||||||
tf_http_respond(request, 200, headers, tf_countof(headers) / 2, data, result);
|
tf_http_respond(request, 200, headers, tf_countof(headers) / 2, data, result);
|
||||||
}
|
}
|
||||||
@ -625,8 +626,7 @@ static void _httpd_endpoint_static(tf_http_request_t* request)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* k_static_files[] =
|
const char* k_static_files[] = {
|
||||||
{
|
|
||||||
"index.html",
|
"index.html",
|
||||||
"client.js",
|
"client.js",
|
||||||
"favicon.png",
|
"favicon.png",
|
||||||
@ -636,8 +636,7 @@ static void _httpd_endpoint_static(tf_http_request_t* request)
|
|||||||
"w3.css",
|
"w3.css",
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* k_map[][2] =
|
const char* k_map[][2] = {
|
||||||
{
|
|
||||||
{ "/static/", "core/" },
|
{ "/static/", "core/" },
|
||||||
{ "/lit/", "deps/lit/" },
|
{ "/lit/", "deps/lit/" },
|
||||||
{ "/codemirror/", "deps/codemirror/" },
|
{ "/codemirror/", "deps/codemirror/" },
|
||||||
@ -696,8 +695,7 @@ static void _httpd_endpoint_robots_txt(tf_http_request_t* request)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
char* response =
|
char* response = "User-Agent: *\n"
|
||||||
"User-Agent: *\n"
|
|
||||||
"Disallow: /*/*/edit\n"
|
"Disallow: /*/*/edit\n"
|
||||||
"Allow: /\n";
|
"Allow: /\n";
|
||||||
const char* headers[] = { "Content-Type", "text/plain; charset=utf-8" };
|
const char* headers[] = { "Content-Type", "text/plain; charset=utf-8" };
|
||||||
@ -713,10 +711,11 @@ static void _httpd_endpoint_debug(tf_http_request_t* request)
|
|||||||
|
|
||||||
tf_task_t* task = request->user_data;
|
tf_task_t* task = request->user_data;
|
||||||
char* response = tf_task_get_debug(task);
|
char* response = tf_task_get_debug(task);
|
||||||
const char* headers[] =
|
const char* headers[] = {
|
||||||
{
|
"Content-Type",
|
||||||
"Content-Type", "application/json; charset=utf-8",
|
"application/json; charset=utf-8",
|
||||||
"Access-Control-Allow-Origin", "*",
|
"Access-Control-Allow-Origin",
|
||||||
|
"*",
|
||||||
};
|
};
|
||||||
tf_http_respond(request, 200, headers, tf_countof(headers) / 2, response, response ? strlen(response) : 0);
|
tf_http_respond(request, 200, headers, tf_countof(headers) / 2, response, response ? strlen(response) : 0);
|
||||||
tf_free(response);
|
tf_free(response);
|
||||||
@ -726,8 +725,7 @@ void tf_httpd_register(JSContext* context)
|
|||||||
{
|
{
|
||||||
JS_NewClassID(&_httpd_class_id);
|
JS_NewClassID(&_httpd_class_id);
|
||||||
JS_NewClassID(&_httpd_request_class_id);
|
JS_NewClassID(&_httpd_request_class_id);
|
||||||
JSClassDef httpd_def =
|
JSClassDef httpd_def = {
|
||||||
{
|
|
||||||
.class_name = "Httpd",
|
.class_name = "Httpd",
|
||||||
.finalizer = &_httpd_finalizer,
|
.finalizer = &_httpd_finalizer,
|
||||||
};
|
};
|
||||||
@ -735,8 +733,7 @@ void tf_httpd_register(JSContext* context)
|
|||||||
{
|
{
|
||||||
fprintf(stderr, "Failed to register Httpd.\n");
|
fprintf(stderr, "Failed to register Httpd.\n");
|
||||||
}
|
}
|
||||||
JSClassDef request_def =
|
JSClassDef request_def = {
|
||||||
{
|
|
||||||
.class_name = "Request",
|
.class_name = "Request",
|
||||||
.finalizer = &_httpd_request_finalizer,
|
.finalizer = &_httpd_request_finalizer,
|
||||||
};
|
};
|
||||||
|
60
src/ios.m
60
src/ios.m
@ -9,8 +9,8 @@
|
|||||||
|
|
||||||
void tf_run_thread_start(const char* zip_path);
|
void tf_run_thread_start(const char* zip_path);
|
||||||
|
|
||||||
@interface ViewController : UIViewController<WKUIDelegate,WKNavigationDelegate>
|
@interface ViewController : UIViewController <WKUIDelegate, WKNavigationDelegate>
|
||||||
@property(strong, nonatomic) WKWebView* web_view;
|
@property (strong, nonatomic) WKWebView* web_view;
|
||||||
@property bool initial_load_complete;
|
@property bool initial_load_complete;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -32,12 +32,12 @@ static void _start_initial_load(WKWebView* web_view)
|
|||||||
_start_initial_load(self.web_view);
|
_start_initial_load(self.web_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
|
- (void)webView:(WKWebView*)webView didFinishNavigation:(WKNavigation*)navigation
|
||||||
{
|
{
|
||||||
self.initial_load_complete = true;
|
self.initial_load_complete = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
|
- (void)webView:(WKWebView*)webView didFailProvisionalNavigation:(WKNavigation*)navigation withError:(NSError*)error
|
||||||
{
|
{
|
||||||
if (!self.initial_load_complete)
|
if (!self.initial_load_complete)
|
||||||
{
|
{
|
||||||
@ -45,49 +45,55 @@ static void _start_initial_load(WKWebView* web_view)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler
|
- (void)webView:(WKWebView*)webView
|
||||||
|
runJavaScriptConfirmPanelWithMessage:(NSString*)message
|
||||||
|
initiatedByFrame:(WKFrameInfo*)frame
|
||||||
|
completionHandler:(void (^)(BOOL result))completionHandler
|
||||||
{
|
{
|
||||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert];
|
UIAlertController* alertController = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { completionHandler(true); }]];
|
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) { completionHandler(true); }]];
|
||||||
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { completionHandler(false); }]];
|
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction* action) { completionHandler(false); }]];
|
||||||
[self presentViewController:alertController animated:YES completion:^{}];
|
[self presentViewController:alertController animated:YES completion:^ {}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
|
- (void)webView:(WKWebView*)webView runJavaScriptAlertPanelWithMessage:(NSString*)message initiatedByFrame:(WKFrameInfo*)frame completionHandler:(void (^)(void))completionHandler
|
||||||
{
|
{
|
||||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert];
|
UIAlertController* alertController = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { completionHandler(); }]];
|
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) { completionHandler(); }]];
|
||||||
[self presentViewController:alertController animated:YES completion:^{}];
|
[self presentViewController:alertController animated:YES completion:^ {}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *))completionHandler
|
- (void)webView:(WKWebView*)webView
|
||||||
|
runJavaScriptTextInputPanelWithPrompt:(NSString*)prompt
|
||||||
|
defaultText:(NSString*)defaultText
|
||||||
|
initiatedByFrame:(WKFrameInfo*)frame
|
||||||
|
completionHandler:(void (^)(NSString*))completionHandler
|
||||||
{
|
{
|
||||||
NSString *sender = [NSString stringWithFormat:@"%@", self.web_view.URL.host];
|
NSString* sender = [NSString stringWithFormat:@"%@", self.web_view.URL.host];
|
||||||
|
|
||||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:sender preferredStyle:UIAlertControllerStyleAlert];
|
UIAlertController* alertController = [UIAlertController alertControllerWithTitle:prompt message:sender preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
|
[alertController addTextFieldWithConfigurationHandler:^(UITextField* textField) {
|
||||||
textField.placeholder = defaultText;
|
textField.placeholder = defaultText;
|
||||||
textField.text = defaultText;
|
textField.text = defaultText;
|
||||||
}];
|
}];
|
||||||
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
[alertController addAction:[UIAlertAction actionWithTitle:@"OK"
|
||||||
NSString *input = ((UITextField *)alertController.textFields.firstObject).text;
|
style:UIAlertActionStyleDefault
|
||||||
|
handler:^(UIAlertAction* action) {
|
||||||
|
NSString* input = ((UITextField*)alertController.textFields.firstObject).text;
|
||||||
completionHandler(input);
|
completionHandler(input);
|
||||||
}]];
|
}]];
|
||||||
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
|
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction* action) { completionHandler(nil); }]];
|
||||||
completionHandler(nil);
|
[self presentViewController:alertController animated:YES completion:^ {}];
|
||||||
}]];
|
|
||||||
[self presentViewController:alertController animated:YES completion:^{}];
|
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface AppDelegate : UIResponder<UIApplicationDelegate>
|
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||||
@property(strong, nonatomic) UIWindow* window;
|
@property (strong, nonatomic) UIWindow* window;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation AppDelegate
|
@implementation AppDelegate
|
||||||
- (BOOL)application:(UIApplication*)application
|
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
|
||||||
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
|
|
||||||
{
|
{
|
||||||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||||
ViewController* view_controller = [[ViewController alloc] init];
|
ViewController* view_controller = [[ViewController alloc] init];
|
||||||
|
@ -7,7 +7,13 @@
|
|||||||
#include <TargetConditionals.h>
|
#include <TargetConditionals.h>
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
#include <os/log.h>
|
#include <os/log.h>
|
||||||
#define tf_printf(...) do { char buffer ## __LINE__[2048]; snprintf(buffer ## __LINE__, sizeof(buffer ## __LINE__), __VA_ARGS__); os_log(OS_LOG_DEFAULT, "%{public}s", buffer ## __LINE__); } while (0)
|
#define tf_printf(...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
char buffer##__LINE__[2048]; \
|
||||||
|
snprintf(buffer##__LINE__, sizeof(buffer##__LINE__), __VA_ARGS__); \
|
||||||
|
os_log(OS_LOG_DEFAULT, "%{public}s", buffer##__LINE__); \
|
||||||
|
} while (0)
|
||||||
#else
|
#else
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#define tf_printf printf
|
#define tf_printf printf
|
||||||
|
82
src/main.c
82
src/main.c
@ -41,11 +41,15 @@ struct backtrace_state* g_backtrace_state;
|
|||||||
|
|
||||||
const char* k_db_path_default = "db.sqlite";
|
const char* k_db_path_default = "db.sqlite";
|
||||||
|
|
||||||
#define XOPT_PARSE(name, flags, options, config_ptr, argc, argv, extrac_ptr, extrav_ptr, err_ptr, autohelp_file, autohelp_usage, autohelp_prefix, autohelp_suffix, autohelp_spacer) do { \
|
#define XOPT_PARSE( \
|
||||||
xoptContext *_xopt_ctx; \
|
name, flags, options, config_ptr, argc, argv, extrac_ptr, extrav_ptr, err_ptr, autohelp_file, autohelp_usage, autohelp_prefix, autohelp_suffix, autohelp_spacer) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
xoptContext* _xopt_ctx; \
|
||||||
*(err_ptr) = NULL; \
|
*(err_ptr) = NULL; \
|
||||||
_xopt_ctx = xopt_context((name), (options), ((flags) ^ XOPT_CTX_POSIXMEHARDER), (err_ptr)); \
|
_xopt_ctx = xopt_context((name), (options), ((flags) ^ XOPT_CTX_POSIXMEHARDER), (err_ptr)); \
|
||||||
if (*(err_ptr)) break; \
|
if (*(err_ptr)) \
|
||||||
|
break; \
|
||||||
*extrac_ptr = xopt_parse(_xopt_ctx, (argc), (argv), (config_ptr), (extrav_ptr), (err_ptr)); \
|
*extrac_ptr = xopt_parse(_xopt_ctx, (argc), (argv), (config_ptr), (extrav_ptr), (err_ptr)); \
|
||||||
if ((config_ptr)->help) \
|
if ((config_ptr)->help) \
|
||||||
{ \
|
{ \
|
||||||
@ -55,11 +59,13 @@ const char* k_db_path_default = "db.sqlite";
|
|||||||
__xopt_autohelp_opts.suffix = (autohelp_suffix); \
|
__xopt_autohelp_opts.suffix = (autohelp_suffix); \
|
||||||
__xopt_autohelp_opts.spacer = (autohelp_spacer); \
|
__xopt_autohelp_opts.spacer = (autohelp_spacer); \
|
||||||
xopt_autohelp(_xopt_ctx, (autohelp_file), &__xopt_autohelp_opts, (err_ptr)); \
|
xopt_autohelp(_xopt_ctx, (autohelp_file), &__xopt_autohelp_opts, (err_ptr)); \
|
||||||
if (*(err_ptr)) goto __xopt_end_free_extrav; \
|
if (*(err_ptr)) \
|
||||||
|
goto __xopt_end_free_extrav; \
|
||||||
free(_xopt_ctx); \
|
free(_xopt_ctx); \
|
||||||
goto xopt_help; \
|
goto xopt_help; \
|
||||||
} \
|
} \
|
||||||
if (*(err_ptr)) goto __xopt_end_free_ctx; \
|
if (*(err_ptr)) \
|
||||||
|
goto __xopt_end_free_ctx; \
|
||||||
__xopt_end_free_ctx: \
|
__xopt_end_free_ctx: \
|
||||||
free(_xopt_ctx); \
|
free(_xopt_ctx); \
|
||||||
break; \
|
break; \
|
||||||
@ -77,7 +83,8 @@ static int _tf_command_run(const char* file, int argc, char* argv[]);
|
|||||||
static int _tf_command_sandbox(const char* file, int argc, char* argv[]);
|
static int _tf_command_sandbox(const char* file, int argc, char* argv[]);
|
||||||
static int _tf_command_usage(const char* file, int argc, char* argv[]);
|
static int _tf_command_usage(const char* file, int argc, char* argv[]);
|
||||||
|
|
||||||
typedef struct _command_t {
|
typedef struct _command_t
|
||||||
|
{
|
||||||
const char* name;
|
const char* name;
|
||||||
int (*callback)(const char* file, int argc, char* argv[]);
|
int (*callback)(const char* file, int argc, char* argv[]);
|
||||||
const char* description;
|
const char* description;
|
||||||
@ -94,7 +101,8 @@ const command_t k_commands[] = {
|
|||||||
static int _tf_command_test(const char* file, int argc, char* argv[])
|
static int _tf_command_test(const char* file, int argc, char* argv[])
|
||||||
{
|
{
|
||||||
#if !defined(__ANDROID__)
|
#if !defined(__ANDROID__)
|
||||||
typedef struct args_t {
|
typedef struct args_t
|
||||||
|
{
|
||||||
const char* tests;
|
const char* tests;
|
||||||
bool help;
|
bool help;
|
||||||
} args_t;
|
} args_t;
|
||||||
@ -108,16 +116,16 @@ static int _tf_command_test(const char* file, int argc, char* argv[])
|
|||||||
args_t args = { 0 };
|
args_t args = { 0 };
|
||||||
const char** extras = NULL;
|
const char** extras = NULL;
|
||||||
int extra_count = 0;
|
int extra_count = 0;
|
||||||
const char *err = NULL;
|
const char* err = NULL;
|
||||||
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, "test [options]", "options:", NULL, 15);
|
XOPT_PARSE(
|
||||||
|
file, XOPT_CTX_KEEPFIRST | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, "test [options]", "options:", NULL, 15);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
fprintf(stderr, "Error: %s\n", err);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
tf_test_options_t test_options =
|
tf_test_options_t test_options = {
|
||||||
{
|
|
||||||
.exe_path = file,
|
.exe_path = file,
|
||||||
.tests = args.tests,
|
.tests = args.tests,
|
||||||
};
|
};
|
||||||
@ -138,7 +146,8 @@ xopt_help:
|
|||||||
|
|
||||||
static int _tf_command_import(const char* file, int argc, char* argv[])
|
static int _tf_command_import(const char* file, int argc, char* argv[])
|
||||||
{
|
{
|
||||||
typedef struct args_t {
|
typedef struct args_t
|
||||||
|
{
|
||||||
const char* user;
|
const char* user;
|
||||||
const char* db_path;
|
const char* db_path;
|
||||||
bool help;
|
bool help;
|
||||||
@ -154,8 +163,9 @@ static int _tf_command_import(const char* file, int argc, char* argv[])
|
|||||||
args_t args = { .user = "import", .db_path = k_db_path_default };
|
args_t args = { .user = "import", .db_path = k_db_path_default };
|
||||||
const char** extras = NULL;
|
const char** extras = NULL;
|
||||||
int extra_count = 0;
|
int extra_count = 0;
|
||||||
const char *err = NULL;
|
const char* err = NULL;
|
||||||
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, "import [options] [paths] ...", "options:", NULL, 15);
|
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr,
|
||||||
|
"import [options] [paths] ...", "options:", NULL, 15);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
fprintf(stderr, "Error: %s\n", err);
|
||||||
@ -194,7 +204,8 @@ xopt_help:
|
|||||||
|
|
||||||
static int _tf_command_export(const char* file, int argc, char* argv[])
|
static int _tf_command_export(const char* file, int argc, char* argv[])
|
||||||
{
|
{
|
||||||
typedef struct args_t {
|
typedef struct args_t
|
||||||
|
{
|
||||||
const char* user;
|
const char* user;
|
||||||
const char* db_path;
|
const char* db_path;
|
||||||
bool help;
|
bool help;
|
||||||
@ -210,8 +221,9 @@ static int _tf_command_export(const char* file, int argc, char* argv[])
|
|||||||
args_t args = { .user = "core", .db_path = k_db_path_default };
|
args_t args = { .user = "core", .db_path = k_db_path_default };
|
||||||
const char** extras = NULL;
|
const char** extras = NULL;
|
||||||
int extra_count = 0;
|
int extra_count = 0;
|
||||||
const char *err = NULL;
|
const char* err = NULL;
|
||||||
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, "export [options] [paths] ...", "options:", NULL, 15);
|
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr,
|
||||||
|
"export [options] [paths] ...", "options:", NULL, 15);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
fprintf(stderr, "Error: %s\n", err);
|
||||||
@ -264,7 +276,8 @@ xopt_help:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct tf_run_args_t {
|
typedef struct tf_run_args_t
|
||||||
|
{
|
||||||
const char* script;
|
const char* script;
|
||||||
int ssb_port;
|
int ssb_port;
|
||||||
int http_port;
|
int http_port;
|
||||||
@ -401,8 +414,7 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
|
|||||||
XOPT_NULLOPTION,
|
XOPT_NULLOPTION,
|
||||||
};
|
};
|
||||||
|
|
||||||
tf_run_args_t args =
|
tf_run_args_t args = {
|
||||||
{
|
|
||||||
.count = 1,
|
.count = 1,
|
||||||
.script = "core/core.js",
|
.script = "core/core.js",
|
||||||
.http_port = 12345,
|
.http_port = 12345,
|
||||||
@ -412,8 +424,9 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
|
|||||||
};
|
};
|
||||||
const char** extras = NULL;
|
const char** extras = NULL;
|
||||||
int extra_count = 0;
|
int extra_count = 0;
|
||||||
const char *err = NULL;
|
const char* err = NULL;
|
||||||
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, "run [options] [paths] ...", "options:", NULL, 15);
|
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr,
|
||||||
|
"run [options] [paths] ...", "options:", NULL, 15);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
@ -434,10 +447,9 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
|
|||||||
{
|
{
|
||||||
uv_thread_t* threads = tf_malloc(sizeof(uv_thread_t) * args.count);
|
uv_thread_t* threads = tf_malloc(sizeof(uv_thread_t) * args.count);
|
||||||
tf_run_thread_data_t* data = tf_malloc(sizeof(tf_run_thread_data_t) * args.count);
|
tf_run_thread_data_t* data = tf_malloc(sizeof(tf_run_thread_data_t) * args.count);
|
||||||
for (int i = 0 ; i < args.count; i++)
|
for (int i = 0; i < args.count; i++)
|
||||||
{
|
|
||||||
data[i] = (tf_run_thread_data_t)
|
|
||||||
{
|
{
|
||||||
|
data[i] = (tf_run_thread_data_t) {
|
||||||
.args = args,
|
.args = args,
|
||||||
.index = i,
|
.index = i,
|
||||||
};
|
};
|
||||||
@ -471,7 +483,8 @@ xopt_help:
|
|||||||
|
|
||||||
static int _tf_command_sandbox(const char* file, int argc, char* argv[])
|
static int _tf_command_sandbox(const char* file, int argc, char* argv[])
|
||||||
{
|
{
|
||||||
typedef struct args_t {
|
typedef struct args_t
|
||||||
|
{
|
||||||
const char* script;
|
const char* script;
|
||||||
bool help;
|
bool help;
|
||||||
} args_t;
|
} args_t;
|
||||||
@ -484,8 +497,9 @@ static int _tf_command_sandbox(const char* file, int argc, char* argv[])
|
|||||||
args_t args = { 0 };
|
args_t args = { 0 };
|
||||||
const char** extras = NULL;
|
const char** extras = NULL;
|
||||||
int extra_count = 0;
|
int extra_count = 0;
|
||||||
const char *err = NULL;
|
const char* err = NULL;
|
||||||
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, "sandbox [options]", "options:", NULL, 15);
|
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER | XOPT_CTX_STRICT, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr,
|
||||||
|
"sandbox [options]", "options:", NULL, 15);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Error: %s\n", err);
|
fprintf(stderr, "Error: %s\n", err);
|
||||||
@ -560,11 +574,7 @@ static void _startup(int argc, char* argv[])
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
tf_mem_startup(tracking);
|
tf_mem_startup(tracking);
|
||||||
g_backtrace_state = backtrace_create_state(
|
g_backtrace_state = backtrace_create_state(argv[0], 0, _backtrace_error, NULL);
|
||||||
argv[0],
|
|
||||||
0,
|
|
||||||
_backtrace_error,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
||||||
@ -624,8 +634,7 @@ void tf_run_thread_start(const char* zip_path)
|
|||||||
_startup(0, NULL);
|
_startup(0, NULL);
|
||||||
uv_thread_t* thread = tf_malloc(sizeof(uv_thread_t));
|
uv_thread_t* thread = tf_malloc(sizeof(uv_thread_t));
|
||||||
tf_run_thread_data_t* data = tf_malloc(sizeof(tf_run_thread_data_t));
|
tf_run_thread_data_t* data = tf_malloc(sizeof(tf_run_thread_data_t));
|
||||||
tf_run_args_t args =
|
tf_run_args_t args = {
|
||||||
{
|
|
||||||
.count = 1,
|
.count = 1,
|
||||||
.script = "core/core.js",
|
.script = "core/core.js",
|
||||||
.http_port = 12345,
|
.http_port = 12345,
|
||||||
@ -635,8 +644,7 @@ void tf_run_thread_start(const char* zip_path)
|
|||||||
.one_proc = true,
|
.one_proc = true,
|
||||||
.zip = zip_path,
|
.zip = zip_path,
|
||||||
};
|
};
|
||||||
*data = (tf_run_thread_data_t)
|
*data = (tf_run_thread_data_t) {
|
||||||
{
|
|
||||||
.args = args,
|
.args = args,
|
||||||
};
|
};
|
||||||
uv_thread_create(thread, _tf_run_task_thread, data);
|
uv_thread_create(thread, _tf_run_task_thread, data);
|
||||||
|
22
src/mem.c
22
src/mem.c
@ -107,12 +107,7 @@ void tf_mem_walk_allocations(void (*callback)(void* ptr, size_t size, int frames
|
|||||||
memcpy(frames, node->frames, sizeof(void*) * node->frames_count);
|
memcpy(frames, node->frames, sizeof(void*) * node->frames_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
callback(
|
callback((void*)((intptr_t)node->ptr + sizeof(size_t)), size, node->frames_count, node->frames_count ? frames : NULL, user_data);
|
||||||
(void*)((intptr_t)node->ptr + sizeof(size_t)),
|
|
||||||
size,
|
|
||||||
node->frames_count,
|
|
||||||
node->frames_count ? frames : NULL,
|
|
||||||
user_data);
|
|
||||||
if (node == s_mem_tracked)
|
if (node == s_mem_tracked)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@ -161,8 +156,7 @@ static int _tf_mem_size_compare(const void* a, const void* b)
|
|||||||
static void _tf_mem_summarize(void* ptr, size_t size, int frames_count, void* const* frames, void* user_data)
|
static void _tf_mem_summarize(void* ptr, size_t size, int frames_count, void* const* frames, void* user_data)
|
||||||
{
|
{
|
||||||
summary_t* summary = user_data;
|
summary_t* summary = user_data;
|
||||||
tf_mem_allocation_t allocation =
|
tf_mem_allocation_t allocation = {
|
||||||
{
|
|
||||||
.stack_hash = fnv32a(frames, sizeof(void*) * frames_count, 0),
|
.stack_hash = fnv32a(frames, sizeof(void*) * frames_count, 0),
|
||||||
.count = 1,
|
.count = 1,
|
||||||
.size = size,
|
.size = size,
|
||||||
@ -171,9 +165,7 @@ static void _tf_mem_summarize(void* ptr, size_t size, int frames_count, void* co
|
|||||||
memcpy(allocation.frames, frames, sizeof(void*) * frames_count);
|
memcpy(allocation.frames, frames, sizeof(void*) * frames_count);
|
||||||
|
|
||||||
int index = tf_util_insert_index(&allocation, summary->allocations, summary->count, sizeof(tf_mem_allocation_t), _tf_mem_hash_stack_compare);
|
int index = tf_util_insert_index(&allocation, summary->allocations, summary->count, sizeof(tf_mem_allocation_t), _tf_mem_hash_stack_compare);
|
||||||
if (index < summary->count &&
|
if (index < summary->count && allocation.stack_hash == summary->allocations[index].stack_hash && allocation.frames_count == summary->allocations[index].frames_count &&
|
||||||
allocation.stack_hash == summary->allocations[index].stack_hash &&
|
|
||||||
allocation.frames_count == summary->allocations[index].frames_count &&
|
|
||||||
memcmp(frames, summary->allocations[index].frames, sizeof(void*) * frames_count) == 0)
|
memcmp(frames, summary->allocations[index].frames, sizeof(void*) * frames_count) == 0)
|
||||||
{
|
{
|
||||||
summary->allocations[index].count++;
|
summary->allocations[index].count++;
|
||||||
@ -457,7 +449,7 @@ char* tf_strdup(const char* string)
|
|||||||
}
|
}
|
||||||
size_t len = strlen(string);
|
size_t len = strlen(string);
|
||||||
char* buffer = tf_malloc(len + 1);
|
char* buffer = tf_malloc(len + 1);
|
||||||
if ( buffer)
|
if (buffer)
|
||||||
{
|
{
|
||||||
memcpy(buffer, string, len + 1);
|
memcpy(buffer, string, len + 1);
|
||||||
}
|
}
|
||||||
@ -543,8 +535,7 @@ static size_t _tf_js_malloc_usable_size(const void* ptr)
|
|||||||
|
|
||||||
void tf_get_js_malloc_functions(JSMallocFunctions* out)
|
void tf_get_js_malloc_functions(JSMallocFunctions* out)
|
||||||
{
|
{
|
||||||
*out = (JSMallocFunctions)
|
*out = (JSMallocFunctions) {
|
||||||
{
|
|
||||||
.js_malloc = _tf_js_malloc,
|
.js_malloc = _tf_js_malloc,
|
||||||
.js_free = _tf_js_free,
|
.js_free = _tf_js_free,
|
||||||
.js_realloc = _tf_js_realloc,
|
.js_realloc = _tf_js_realloc,
|
||||||
@ -599,8 +590,7 @@ static void _tf_sqlite_shutdown(void* user_data)
|
|||||||
|
|
||||||
void tf_mem_replace_sqlite_allocator()
|
void tf_mem_replace_sqlite_allocator()
|
||||||
{
|
{
|
||||||
sqlite3_mem_methods methods =
|
sqlite3_mem_methods methods = {
|
||||||
{
|
|
||||||
.xMalloc = _tf_sqlite_malloc,
|
.xMalloc = _tf_sqlite_malloc,
|
||||||
.xFree = _tf_sqlite_free,
|
.xFree = _tf_sqlite_free,
|
||||||
.xRealloc = _tf_sqlite_realloc,
|
.xRealloc = _tf_sqlite_realloc,
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
typedef struct _tf_packetstream_t {
|
typedef struct _tf_packetstream_t
|
||||||
|
{
|
||||||
tf_packetstream_onreceive_t* onreceive;
|
tf_packetstream_onreceive_t* onreceive;
|
||||||
void* onreceive_user_data;
|
void* onreceive_user_data;
|
||||||
uv_pipe_t stream;
|
uv_pipe_t stream;
|
||||||
|
@ -6,7 +6,7 @@ typedef struct uv_pipe_s uv_pipe_t;
|
|||||||
|
|
||||||
typedef struct _tf_packetstream_t tf_packetstream_t;
|
typedef struct _tf_packetstream_t tf_packetstream_t;
|
||||||
|
|
||||||
typedef void (tf_packetstream_onreceive_t)(int packet_type, const char* begin, size_t length, void* user_data);
|
typedef void(tf_packetstream_onreceive_t)(int packet_type, const char* begin, size_t length, void* user_data);
|
||||||
|
|
||||||
tf_packetstream_t* tf_packetstream_create();
|
tf_packetstream_t* tf_packetstream_create();
|
||||||
void tf_packetstream_destroy(tf_packetstream_t* stream);
|
void tf_packetstream_destroy(tf_packetstream_t* stream);
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
typedef enum _serialize_type_t {
|
typedef enum _serialize_type_t
|
||||||
|
{
|
||||||
kUndefined,
|
kUndefined,
|
||||||
kNull,
|
kNull,
|
||||||
kUninitialized,
|
kUninitialized,
|
||||||
@ -29,7 +30,8 @@ typedef enum _serialize_type_t {
|
|||||||
kException,
|
kException,
|
||||||
} serialize_type_t;
|
} serialize_type_t;
|
||||||
|
|
||||||
typedef struct _buffer_t {
|
typedef struct _buffer_t
|
||||||
|
{
|
||||||
char* data;
|
char* data;
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
|
@ -22,13 +22,15 @@ static tf_tls_context_t* _defaultTlsContext;
|
|||||||
static socket_t** _sockets;
|
static socket_t** _sockets;
|
||||||
static int _sockets_count;
|
static int _sockets_count;
|
||||||
|
|
||||||
typedef enum _socket_direction_t {
|
typedef enum _socket_direction_t
|
||||||
|
{
|
||||||
kUndetermined,
|
kUndetermined,
|
||||||
kAccept,
|
kAccept,
|
||||||
kConnect,
|
kConnect,
|
||||||
} socket_direction_t;
|
} socket_direction_t;
|
||||||
|
|
||||||
typedef struct _socket_t {
|
typedef struct _socket_t
|
||||||
|
{
|
||||||
tf_task_t* _task;
|
tf_task_t* _task;
|
||||||
uv_tcp_t _socket;
|
uv_tcp_t _socket;
|
||||||
uv_timer_t _timer;
|
uv_timer_t _timer;
|
||||||
@ -51,7 +53,7 @@ typedef struct _socket_t {
|
|||||||
} socket_t;
|
} socket_t;
|
||||||
|
|
||||||
static JSValue _socket_create(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
static JSValue _socket_create(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
||||||
static void _socket_finalizer(JSRuntime *runtime, JSValue value);
|
static void _socket_finalizer(JSRuntime* runtime, JSValue value);
|
||||||
|
|
||||||
static JSValue _socket_startTls(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
static JSValue _socket_startTls(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
||||||
static JSValue _socket_stopTls(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
static JSValue _socket_stopTls(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
||||||
@ -131,8 +133,7 @@ static void _socket_gc_mark(JSRuntime* runtime, JSValueConst value, JS_MarkFunc
|
|||||||
JSValue tf_socket_register(JSContext* context)
|
JSValue tf_socket_register(JSContext* context)
|
||||||
{
|
{
|
||||||
JS_NewClassID(&_classId);
|
JS_NewClassID(&_classId);
|
||||||
JSClassDef def =
|
JSClassDef def = {
|
||||||
{
|
|
||||||
.class_name = "Socket",
|
.class_name = "Socket",
|
||||||
.finalizer = &_socket_finalizer,
|
.finalizer = &_socket_finalizer,
|
||||||
.gc_mark = _socket_gc_mark,
|
.gc_mark = _socket_gc_mark,
|
||||||
@ -158,7 +159,8 @@ int tf_socket_get_open_count()
|
|||||||
return _open_count;
|
return _open_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct _socket_resolve_data_t {
|
typedef struct _socket_resolve_data_t
|
||||||
|
{
|
||||||
uv_getaddrinfo_t resolver;
|
uv_getaddrinfo_t resolver;
|
||||||
socket_t* socket;
|
socket_t* socket;
|
||||||
promiseid_t promise;
|
promiseid_t promise;
|
||||||
@ -241,20 +243,16 @@ static void _socket_close_internal(socket_t* socket)
|
|||||||
tf_tls_session_destroy(socket->_tls);
|
tf_tls_session_destroy(socket->_tls);
|
||||||
socket->_tls = NULL;
|
socket->_tls = NULL;
|
||||||
}
|
}
|
||||||
if (socket->_socket.data &&
|
if (socket->_socket.data && !uv_is_closing((uv_handle_t*)&socket->_socket))
|
||||||
!uv_is_closing((uv_handle_t*)&socket->_socket))
|
|
||||||
{
|
{
|
||||||
uv_close((uv_handle_t*)&socket->_socket, _socket_onClose);
|
uv_close((uv_handle_t*)&socket->_socket, _socket_onClose);
|
||||||
}
|
}
|
||||||
if (socket->_timer.data &&
|
if (socket->_timer.data && !uv_is_closing((uv_handle_t*)&socket->_timer))
|
||||||
!uv_is_closing((uv_handle_t*)&socket->_timer))
|
|
||||||
{
|
{
|
||||||
uv_close((uv_handle_t*)&socket->_timer, _socket_onClose);
|
uv_close((uv_handle_t*)&socket->_timer, _socket_onClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!socket->_socket.data &&
|
if (!socket->_socket.data && !socket->_timer.data && JS_IsUndefined(socket->_object))
|
||||||
!socket->_timer.data &&
|
|
||||||
JS_IsUndefined(socket->_object))
|
|
||||||
{
|
{
|
||||||
--_count;
|
--_count;
|
||||||
for (int i = 0; i < _sockets_count; i++)
|
for (int i = 0; i < _sockets_count; i++)
|
||||||
@ -282,7 +280,7 @@ static void _socket_reportError(socket_t* socket, const char* error)
|
|||||||
{
|
{
|
||||||
JSContext* context = tf_task_get_context(socket->_task);
|
JSContext* context = tf_task_get_context(socket->_task);
|
||||||
JSValue ref = JS_DupValue(context, socket->_object);
|
JSValue ref = JS_DupValue(context, socket->_object);
|
||||||
if (JS_IsFunction(context, socket-> _onError))
|
if (JS_IsFunction(context, socket->_onError))
|
||||||
{
|
{
|
||||||
JSValue exception = JS_ThrowInternalError(context, "%s", error);
|
JSValue exception = JS_ThrowInternalError(context, "%s", error);
|
||||||
JSValue cb_ref = JS_DupValue(context, socket->_onError);
|
JSValue cb_ref = JS_DupValue(context, socket->_onError);
|
||||||
@ -393,8 +391,7 @@ static bool _socket_processSomeOutgoingTls(socket_t* socket, promiseid_t promise
|
|||||||
char* rawBuffer = request_buffer + sizeof(uv_write_t);
|
char* rawBuffer = request_buffer + sizeof(uv_write_t);
|
||||||
memcpy(rawBuffer, buffer, result);
|
memcpy(rawBuffer, buffer, result);
|
||||||
|
|
||||||
uv_buf_t writeBuffer =
|
uv_buf_t writeBuffer = {
|
||||||
{
|
|
||||||
.base = rawBuffer,
|
.base = rawBuffer,
|
||||||
.len = result,
|
.len = result,
|
||||||
};
|
};
|
||||||
@ -431,8 +428,7 @@ static JSValue _socket_bind(JSContext* context, JSValueConst this_val, int argc,
|
|||||||
|
|
||||||
socket_resolve_data_t* data = tf_malloc(sizeof(socket_resolve_data_t));
|
socket_resolve_data_t* data = tf_malloc(sizeof(socket_resolve_data_t));
|
||||||
memset(data, 0, sizeof(*data));
|
memset(data, 0, sizeof(*data));
|
||||||
struct addrinfo hints =
|
struct addrinfo hints = {
|
||||||
{
|
|
||||||
.ai_family = AF_UNSPEC,
|
.ai_family = AF_UNSPEC,
|
||||||
.ai_socktype = SOCK_STREAM,
|
.ai_socktype = SOCK_STREAM,
|
||||||
.ai_protocol = IPPROTO_TCP,
|
.ai_protocol = IPPROTO_TCP,
|
||||||
@ -455,14 +451,16 @@ static void _socket_onResolvedForBind(uv_getaddrinfo_t* resolver, int status, st
|
|||||||
socket_resolve_data_t* data = (socket_resolve_data_t*)resolver->data;
|
socket_resolve_data_t* data = (socket_resolve_data_t*)resolver->data;
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
{
|
{
|
||||||
tf_task_reject_promise(data->socket->_task, data->promise, JS_ThrowInternalError(tf_task_get_context(data->socket->_task), "uv_getaddrinfo: %s", uv_strerror(status)));
|
tf_task_reject_promise(
|
||||||
|
data->socket->_task, data->promise, JS_ThrowInternalError(tf_task_get_context(data->socket->_task), "uv_getaddrinfo: %s", uv_strerror(status)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int bindResult = uv_tcp_bind(&data->socket->_socket, result->ai_addr, 0);
|
int bindResult = uv_tcp_bind(&data->socket->_socket, result->ai_addr, 0);
|
||||||
if (bindResult != 0)
|
if (bindResult != 0)
|
||||||
{
|
{
|
||||||
tf_task_reject_promise(data->socket->_task, data->promise, JS_ThrowInternalError(tf_task_get_context(data->socket->_task), "uv_tcp_bind: %s", uv_strerror(bindResult)));
|
tf_task_reject_promise(
|
||||||
|
data->socket->_task, data->promise, JS_ThrowInternalError(tf_task_get_context(data->socket->_task), "uv_tcp_bind: %s", uv_strerror(bindResult)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -642,9 +640,7 @@ static JSValue _socket_accept(JSContext* context, JSValueConst this_val, int arg
|
|||||||
static JSValue _socket_close(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
static JSValue _socket_close(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||||
{
|
{
|
||||||
socket_t* socket = JS_GetOpaque(this_val, _classId);
|
socket_t* socket = JS_GetOpaque(this_val, _classId);
|
||||||
if (socket->_closePromise == -1 &&
|
if (socket->_closePromise == -1 && socket->_socket.data && !uv_is_closing((uv_handle_t*)&socket->_socket))
|
||||||
socket->_socket.data &&
|
|
||||||
!uv_is_closing((uv_handle_t*)&socket->_socket))
|
|
||||||
{
|
{
|
||||||
JSValue result = tf_task_allocate_promise(socket->_task, &socket->_closePromise);
|
JSValue result = tf_task_allocate_promise(socket->_task, &socket->_closePromise);
|
||||||
_socket_close_internal(socket);
|
_socket_close_internal(socket);
|
||||||
@ -921,8 +917,7 @@ static int _socket_writeInternal(socket_t* socket, promiseid_t promise, const ch
|
|||||||
uv_write_t* request = (uv_write_t*)rawBuffer;
|
uv_write_t* request = (uv_write_t*)rawBuffer;
|
||||||
memcpy(rawBuffer + sizeof(uv_write_t), data, length);
|
memcpy(rawBuffer + sizeof(uv_write_t), data, length);
|
||||||
|
|
||||||
uv_buf_t buffer =
|
uv_buf_t buffer = {
|
||||||
{
|
|
||||||
.base = rawBuffer + sizeof(uv_write_t),
|
.base = rawBuffer + sizeof(uv_write_t),
|
||||||
.len = length,
|
.len = length,
|
||||||
};
|
};
|
||||||
@ -1018,11 +1013,13 @@ static JSValue _socket_setActivityTimeout(JSContext* context, JSValueConst this_
|
|||||||
{
|
{
|
||||||
socket_t* socket = JS_GetOpaque(this_val, _classId);
|
socket_t* socket = JS_GetOpaque(this_val, _classId);
|
||||||
int64_t timeout = 0;
|
int64_t timeout = 0;
|
||||||
if (JS_ToInt64(context, &timeout, argv[0]) == 0 &&
|
if (JS_ToInt64(context, &timeout, argv[0]) == 0 && socket->timeout_ms > 0)
|
||||||
socket->timeout_ms > 0) {
|
{
|
||||||
socket->timeout_ms = timeout;
|
socket->timeout_ms = timeout;
|
||||||
uv_timer_start(&socket->_timer, _socket_timeout, socket->timeout_ms, 0);
|
uv_timer_start(&socket->_timer, _socket_timeout, socket->timeout_ms, 0);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
uv_timer_stop(&socket->_timer);
|
uv_timer_stop(&socket->_timer);
|
||||||
}
|
}
|
||||||
return JS_UNDEFINED;
|
return JS_UNDEFINED;
|
||||||
|
310
src/ssb.c
310
src/ssb.c
@ -42,22 +42,18 @@ static_assert(k_id_base64_len == sodium_base64_ENCODED_LEN(9 + crypto_box_PUBLIC
|
|||||||
static_assert(k_id_bin_len == crypto_box_PUBLICKEYBYTES, "k_id_bin_len");
|
static_assert(k_id_bin_len == crypto_box_PUBLICKEYBYTES, "k_id_bin_len");
|
||||||
static_assert(k_blob_id_len == (sodium_base64_ENCODED_LEN(crypto_hash_sha256_BYTES, sodium_base64_VARIANT_ORIGINAL) + 8), "k_blob_id_len");
|
static_assert(k_blob_id_len == (sodium_base64_ENCODED_LEN(crypto_hash_sha256_BYTES, sodium_base64_VARIANT_ORIGINAL) + 8), "k_blob_id_len");
|
||||||
|
|
||||||
const uint8_t k_ssb_network[] = {
|
const uint8_t k_ssb_network[] = { 0xd4, 0xa1, 0xcb, 0x88, 0xa6, 0x6f, 0x02, 0xf8, 0xdb, 0x63, 0x5c, 0xe2, 0x64, 0x41, 0xcc, 0x5d, 0xac, 0x1b, 0x08, 0x42, 0x0c, 0xea, 0xac, 0x23,
|
||||||
0xd4, 0xa1, 0xcb, 0x88, 0xa6, 0x6f, 0x02, 0xf8,
|
0x08, 0x39, 0xb7, 0x55, 0x84, 0x5a, 0x9f, 0xfb };
|
||||||
0xdb, 0x63, 0x5c, 0xe2, 0x64, 0x41, 0xcc, 0x5d,
|
|
||||||
0xac, 0x1b, 0x08, 0x42, 0x0c, 0xea, 0xac, 0x23,
|
|
||||||
0x08, 0x39, 0xb7, 0x55, 0x84, 0x5a, 0x9f, 0xfb
|
|
||||||
};
|
|
||||||
|
|
||||||
const char* k_ssb_type_names[] =
|
const char* k_ssb_type_names[] = {
|
||||||
{
|
|
||||||
"binary",
|
"binary",
|
||||||
"utf8",
|
"utf8",
|
||||||
"json",
|
"json",
|
||||||
"unknown",
|
"unknown",
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
k_tf_ssb_state_invalid,
|
k_tf_ssb_state_invalid,
|
||||||
k_tf_ssb_state_connected,
|
k_tf_ssb_state_connected,
|
||||||
k_tf_ssb_state_sent_hello,
|
k_tf_ssb_state_sent_hello,
|
||||||
@ -71,7 +67,8 @@ typedef enum {
|
|||||||
k_tf_ssb_state_closing,
|
k_tf_ssb_state_closing,
|
||||||
} tf_ssb_state_t;
|
} tf_ssb_state_t;
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
k_connections_changed_callbacks_max = 8,
|
k_connections_changed_callbacks_max = 8,
|
||||||
k_tf_ssb_rpc_message_body_length_max = 1 * 1024 * 1024,
|
k_tf_ssb_rpc_message_body_length_max = 1 * 1024 * 1024,
|
||||||
k_debug_close_message_count = 256,
|
k_debug_close_message_count = 256,
|
||||||
@ -406,8 +403,7 @@ static void _tf_ssb_connection_add_debug_message(tf_ssb_connection_t* connection
|
|||||||
connection->debug_messages[i] = connection->debug_messages[i - 1];
|
connection->debug_messages[i] = connection->debug_messages[i - 1];
|
||||||
}
|
}
|
||||||
tf_ssb_debug_message_t* message = tf_malloc(sizeof(tf_ssb_debug_message_t) + size);
|
tf_ssb_debug_message_t* message = tf_malloc(sizeof(tf_ssb_debug_message_t) + size);
|
||||||
*message = (tf_ssb_debug_message_t)
|
*message = (tf_ssb_debug_message_t) {
|
||||||
{
|
|
||||||
.outgoing = outgoing,
|
.outgoing = outgoing,
|
||||||
.flags = flags,
|
.flags = flags,
|
||||||
.request_number = request_number,
|
.request_number = request_number,
|
||||||
@ -440,8 +436,7 @@ static void _tf_ssb_connection_close(tf_ssb_connection_t* connection, const char
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (connection->state == k_tf_ssb_state_verified ||
|
else if (connection->state == k_tf_ssb_state_verified || connection->state == k_tf_ssb_state_server_verified)
|
||||||
connection->state == k_tf_ssb_state_server_verified)
|
|
||||||
{
|
{
|
||||||
tf_printf("Connection %s %p is closing: %s.\n", connection->name, connection, reason);
|
tf_printf("Connection %s %p is closing: %s.\n", connection->name, connection, reason);
|
||||||
_tf_ssb_add_debug_close(connection->ssb, connection, reason);
|
_tf_ssb_add_debug_close(connection->ssb, connection, reason);
|
||||||
@ -488,14 +483,7 @@ static void _tf_ssb_write(tf_ssb_connection_t* connection, void* data, size_t si
|
|||||||
else if (connection->tunnel_connection)
|
else if (connection->tunnel_connection)
|
||||||
{
|
{
|
||||||
tf_ssb_connection_rpc_send(
|
tf_ssb_connection_rpc_send(
|
||||||
connection->tunnel_connection,
|
connection->tunnel_connection, k_ssb_rpc_flag_binary | k_ssb_rpc_flag_stream, -connection->tunnel_request_number, data, size, NULL, NULL, NULL);
|
||||||
k_ssb_rpc_flag_binary | k_ssb_rpc_flag_stream,
|
|
||||||
-connection->tunnel_request_number,
|
|
||||||
data,
|
|
||||||
size,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -618,8 +606,7 @@ static void _tf_ssb_connection_box_stream_send(tf_ssb_connection_t* connection,
|
|||||||
void tf_ssb_connection_schedule_idle(tf_ssb_connection_t* connection, tf_ssb_scheduled_callback_t* callback, void* user_data)
|
void tf_ssb_connection_schedule_idle(tf_ssb_connection_t* connection, tf_ssb_scheduled_callback_t* callback, void* user_data)
|
||||||
{
|
{
|
||||||
connection->scheduled = tf_resize_vec(connection->scheduled, sizeof(tf_ssb_connection_scheduled_t) * (connection->scheduled_count + 1));
|
connection->scheduled = tf_resize_vec(connection->scheduled, sizeof(tf_ssb_connection_scheduled_t) * (connection->scheduled_count + 1));
|
||||||
connection->scheduled[connection->scheduled_count++] = (tf_ssb_connection_scheduled_t)
|
connection->scheduled[connection->scheduled_count++] = (tf_ssb_connection_scheduled_t) {
|
||||||
{
|
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
.user_data = user_data,
|
.user_data = user_data,
|
||||||
};
|
};
|
||||||
@ -655,9 +642,11 @@ static bool _tf_ssb_connection_get_request_callback(tf_ssb_connection_t* connect
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t request_number, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data, tf_ssb_connection_t* dependent_connection)
|
void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t request_number, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data,
|
||||||
|
tf_ssb_connection_t* dependent_connection)
|
||||||
{
|
{
|
||||||
tf_ssb_request_t* existing = connection->requests_count ? bsearch(&request_number, connection->requests, connection->requests_count, sizeof(tf_ssb_request_t), _request_compare) : NULL;
|
tf_ssb_request_t* existing =
|
||||||
|
connection->requests_count ? bsearch(&request_number, connection->requests, connection->requests_count, sizeof(tf_ssb_request_t), _request_compare) : NULL;
|
||||||
if (existing)
|
if (existing)
|
||||||
{
|
{
|
||||||
assert(!existing->callback);
|
assert(!existing->callback);
|
||||||
@ -672,8 +661,7 @@ void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t requ
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
tf_ssb_connection_remove_request(connection, request_number);
|
tf_ssb_connection_remove_request(connection, request_number);
|
||||||
tf_ssb_request_t request =
|
tf_ssb_request_t request = {
|
||||||
{
|
|
||||||
.request_number = request_number,
|
.request_number = request_number,
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
.cleanup = cleanup,
|
.cleanup = cleanup,
|
||||||
@ -702,7 +690,8 @@ static int _message_request_compare(const void* a, const void* b)
|
|||||||
|
|
||||||
void tf_ssb_connection_add_new_message_request(tf_ssb_connection_t* connection, const char* author, int32_t request_number, bool keys)
|
void tf_ssb_connection_add_new_message_request(tf_ssb_connection_t* connection, const char* author, int32_t request_number, bool keys)
|
||||||
{
|
{
|
||||||
int index = tf_util_insert_index(author, connection->message_requests, connection->message_requests_count, sizeof(tf_ssb_connection_message_request_t), _message_request_compare);
|
int index =
|
||||||
|
tf_util_insert_index(author, connection->message_requests, connection->message_requests_count, sizeof(tf_ssb_connection_message_request_t), _message_request_compare);
|
||||||
if (index < connection->message_requests_count && strcmp(author, connection->message_requests[index].author) == 0)
|
if (index < connection->message_requests_count && strcmp(author, connection->message_requests[index].author) == 0)
|
||||||
{
|
{
|
||||||
connection->message_requests[index].request_number = request_number;
|
connection->message_requests[index].request_number = request_number;
|
||||||
@ -712,10 +701,10 @@ void tf_ssb_connection_add_new_message_request(tf_ssb_connection_t* connection,
|
|||||||
connection->message_requests = tf_resize_vec(connection->message_requests, sizeof(tf_ssb_connection_message_request_t) * (connection->message_requests_count + 1));
|
connection->message_requests = tf_resize_vec(connection->message_requests, sizeof(tf_ssb_connection_message_request_t) * (connection->message_requests_count + 1));
|
||||||
if (connection->message_requests_count - index)
|
if (connection->message_requests_count - index)
|
||||||
{
|
{
|
||||||
memmove(connection->message_requests + index + 1, connection->message_requests + index, sizeof(tf_ssb_connection_message_request_t) * (connection->message_requests_count - index));
|
memmove(connection->message_requests + index + 1, connection->message_requests + index,
|
||||||
|
sizeof(tf_ssb_connection_message_request_t) * (connection->message_requests_count - index));
|
||||||
}
|
}
|
||||||
connection->message_requests[index] = (tf_ssb_connection_message_request_t)
|
connection->message_requests[index] = (tf_ssb_connection_message_request_t) {
|
||||||
{
|
|
||||||
.request_number = request_number,
|
.request_number = request_number,
|
||||||
.keys = keys,
|
.keys = keys,
|
||||||
};
|
};
|
||||||
@ -725,19 +714,20 @@ void tf_ssb_connection_add_new_message_request(tf_ssb_connection_t* connection,
|
|||||||
|
|
||||||
void tf_ssb_connection_remove_new_message_request(tf_ssb_connection_t* connection, const char* author)
|
void tf_ssb_connection_remove_new_message_request(tf_ssb_connection_t* connection, const char* author)
|
||||||
{
|
{
|
||||||
int index = tf_util_insert_index(author, connection->message_requests, connection->message_requests_count, sizeof(tf_ssb_connection_message_request_t), _message_request_compare);
|
int index =
|
||||||
|
tf_util_insert_index(author, connection->message_requests, connection->message_requests_count, sizeof(tf_ssb_connection_message_request_t), _message_request_compare);
|
||||||
if (index < connection->message_requests_count && strcmp(author, connection->message_requests[index].author) == 0)
|
if (index < connection->message_requests_count && strcmp(author, connection->message_requests[index].author) == 0)
|
||||||
{
|
{
|
||||||
memmove(connection->message_requests + index, connection->message_requests + index + 1, sizeof(tf_ssb_connection_message_request_t) * (connection->message_requests_count - index - 1));
|
memmove(connection->message_requests + index, connection->message_requests + index + 1,
|
||||||
|
sizeof(tf_ssb_connection_message_request_t) * (connection->message_requests_count - index - 1));
|
||||||
connection->message_requests_count--;
|
connection->message_requests_count--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_ssb_connection_remove_request(tf_ssb_connection_t* connection, int32_t request_number)
|
void tf_ssb_connection_remove_request(tf_ssb_connection_t* connection, int32_t request_number)
|
||||||
{
|
{
|
||||||
tf_ssb_request_t* request = connection->requests_count ?
|
tf_ssb_request_t* request =
|
||||||
bsearch(&request_number, connection->requests, connection->requests_count, sizeof(tf_ssb_request_t), _request_compare) :
|
connection->requests_count ? bsearch(&request_number, connection->requests, connection->requests_count, sizeof(tf_ssb_request_t), _request_compare) : NULL;
|
||||||
NULL;
|
|
||||||
if (request)
|
if (request)
|
||||||
{
|
{
|
||||||
if (request->cleanup)
|
if (request->cleanup)
|
||||||
@ -752,7 +742,8 @@ void tf_ssb_connection_remove_request(tf_ssb_connection_t* connection, int32_t r
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_ssb_connection_rpc_send(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, const uint8_t* message, size_t size, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data)
|
void tf_ssb_connection_rpc_send(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, const uint8_t* message, size_t size, tf_ssb_rpc_callback_t* callback,
|
||||||
|
tf_ssb_callback_cleanup_t* cleanup, void* user_data)
|
||||||
{
|
{
|
||||||
if (!connection)
|
if (!connection)
|
||||||
{
|
{
|
||||||
@ -782,15 +773,9 @@ void tf_ssb_connection_rpc_send(tf_ssb_connection_t* connection, uint8_t flags,
|
|||||||
memcpy(combined + 1 + 2 * sizeof(uint32_t), message, size);
|
memcpy(combined + 1 + 2 * sizeof(uint32_t), message, size);
|
||||||
if (connection->ssb->verbose)
|
if (connection->ssb->verbose)
|
||||||
{
|
{
|
||||||
tf_printf(MAGENTA "%s RPC SEND" RESET " end/error=%s stream=%s type=%s RN=%d: [%zd B] %.*s\n",
|
tf_printf(MAGENTA "%s RPC SEND" RESET " end/error=%s stream=%s type=%s RN=%d: [%zd B] %.*s\n", connection->name,
|
||||||
connection->name,
|
(flags & k_ssb_rpc_flag_end_error) ? "true" : "false", (flags & k_ssb_rpc_flag_stream) ? "true" : "false", k_ssb_type_names[flags & k_ssb_rpc_mask_type],
|
||||||
(flags & k_ssb_rpc_flag_end_error) ? "true" : "false",
|
request_number, size, (flags & k_ssb_rpc_mask_type) == k_ssb_rpc_flag_binary ? 0 : (int)size, message);
|
||||||
(flags & k_ssb_rpc_flag_stream) ? "true" : "false",
|
|
||||||
k_ssb_type_names[flags & k_ssb_rpc_mask_type],
|
|
||||||
request_number,
|
|
||||||
size,
|
|
||||||
(flags & k_ssb_rpc_mask_type) == k_ssb_rpc_flag_binary ? 0 : (int)size,
|
|
||||||
message);
|
|
||||||
}
|
}
|
||||||
_tf_ssb_connection_add_debug_message(connection, true, flags & k_ssb_rpc_mask_send, request_number, message, size);
|
_tf_ssb_connection_add_debug_message(connection, true, flags & k_ssb_rpc_mask_send, request_number, message, size);
|
||||||
_tf_ssb_connection_box_stream_send(connection, combined, 1 + 2 * sizeof(uint32_t) + size);
|
_tf_ssb_connection_box_stream_send(connection, combined, 1 + 2 * sizeof(uint32_t) + size);
|
||||||
@ -806,21 +791,15 @@ void tf_ssb_connection_rpc_send(tf_ssb_connection_t* connection, uint8_t flags,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_ssb_connection_rpc_send_json(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue message, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data)
|
void tf_ssb_connection_rpc_send_json(
|
||||||
|
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue message, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data)
|
||||||
{
|
{
|
||||||
JSContext* context = connection->ssb->context;
|
JSContext* context = connection->ssb->context;
|
||||||
JSValue json = JS_JSONStringify(context, message, JS_NULL, JS_NULL);
|
JSValue json = JS_JSONStringify(context, message, JS_NULL, JS_NULL);
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
const char* json_string = JS_ToCStringLen(context, &size, json);
|
const char* json_string = JS_ToCStringLen(context, &size, json);
|
||||||
tf_ssb_connection_rpc_send(
|
tf_ssb_connection_rpc_send(
|
||||||
connection,
|
connection, k_ssb_rpc_flag_json | (flags & ~k_ssb_rpc_mask_type), request_number, (const uint8_t*)json_string, size, callback, cleanup, user_data);
|
||||||
k_ssb_rpc_flag_json | (flags & ~k_ssb_rpc_mask_type),
|
|
||||||
request_number,
|
|
||||||
(const uint8_t*)json_string,
|
|
||||||
size,
|
|
||||||
callback,
|
|
||||||
cleanup,
|
|
||||||
user_data);
|
|
||||||
JS_FreeCString(context, json_string);
|
JS_FreeCString(context, json_string);
|
||||||
JS_FreeValue(context, json);
|
JS_FreeValue(context, json);
|
||||||
}
|
}
|
||||||
@ -833,7 +812,8 @@ void tf_ssb_connection_rpc_send_error(tf_ssb_connection_t* connection, uint8_t f
|
|||||||
JS_SetPropertyStr(context, message, "name", JS_NewString(context, "Error"));
|
JS_SetPropertyStr(context, message, "name", JS_NewString(context, "Error"));
|
||||||
JS_SetPropertyStr(context, message, "stack", JS_NewString(context, stack ? stack : "stack unavailable"));
|
JS_SetPropertyStr(context, message, "stack", JS_NewString(context, stack ? stack : "stack unavailable"));
|
||||||
JS_SetPropertyStr(context, message, "message", JS_NewString(context, error));
|
JS_SetPropertyStr(context, message, "message", JS_NewString(context, error));
|
||||||
tf_ssb_connection_rpc_send_json(connection, ((flags & k_ssb_rpc_flag_stream) ? (k_ssb_rpc_flag_stream) : 0) | k_ssb_rpc_flag_end_error, request_number, message, NULL, NULL, NULL);
|
tf_ssb_connection_rpc_send_json(
|
||||||
|
connection, ((flags & k_ssb_rpc_flag_stream) ? (k_ssb_rpc_flag_stream) : 0) | k_ssb_rpc_flag_end_error, request_number, message, NULL, NULL, NULL);
|
||||||
JS_FreeValue(context, message);
|
JS_FreeValue(context, message);
|
||||||
tf_free((void*)stack);
|
tf_free((void*)stack);
|
||||||
}
|
}
|
||||||
@ -847,10 +827,7 @@ void tf_ssb_connection_rpc_send_error_method_not_allowed(tf_ssb_connection_t* co
|
|||||||
|
|
||||||
static int _utf8_len(uint8_t ch)
|
static int _utf8_len(uint8_t ch)
|
||||||
{
|
{
|
||||||
static const uint8_t k_length[] =
|
static const uint8_t k_length[] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 3, 4 };
|
||||||
{
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 3, 4
|
|
||||||
};
|
|
||||||
return k_length[(ch & 0xf0) >> 4];
|
return k_length[(ch & 0xf0) >> 4];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -859,10 +836,7 @@ static uint32_t _utf8_decode(uint32_t c)
|
|||||||
if (c > 0x7f)
|
if (c > 0x7f)
|
||||||
{
|
{
|
||||||
uint32_t mask = (c <= 0x00efbfbf) ? 0x000f0000 : 0x003f0000;
|
uint32_t mask = (c <= 0x00efbfbf) ? 0x000f0000 : 0x003f0000;
|
||||||
c = ((c & 0x07000000) >> 6) |
|
c = ((c & 0x07000000) >> 6) | ((c & mask) >> 4) | ((c & 0x00003f00) >> 2) | (c & 0x0000003f);
|
||||||
((c & mask) >> 4) |
|
|
||||||
((c & 0x00003f00) >> 2) |
|
|
||||||
(c & 0x0000003f);
|
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@ -996,7 +970,7 @@ static bool _tf_ssb_verify_and_strip_signature_internal(JSContext* context, JSVa
|
|||||||
verified = r == 0;
|
verified = r == 0;
|
||||||
if (!verified)
|
if (!verified)
|
||||||
{
|
{
|
||||||
//tf_printf("crypto_sign_verify_detached fail (r=%d)\n", r);
|
// tf_printf("crypto_sign_verify_detached fail (r=%d)\n", r);
|
||||||
if (false)
|
if (false)
|
||||||
{
|
{
|
||||||
tf_printf("val=[%.*s]\n", (int)strlen(sigstr), sigstr);
|
tf_printf("val=[%.*s]\n", (int)strlen(sigstr), sigstr);
|
||||||
@ -1031,7 +1005,8 @@ static bool _tf_ssb_verify_and_strip_signature_internal(JSContext* context, JSVa
|
|||||||
return verified;
|
return verified;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tf_ssb_verify_and_strip_signature(JSContext* context, JSValue val, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size, bool* out_sequence_before_author)
|
bool tf_ssb_verify_and_strip_signature(
|
||||||
|
JSContext* context, JSValue val, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size, bool* out_sequence_before_author)
|
||||||
{
|
{
|
||||||
if (_tf_ssb_verify_and_strip_signature_internal(context, val, out_id, out_id_size, out_signature, out_signature_size))
|
if (_tf_ssb_verify_and_strip_signature_internal(context, val, out_id, out_id_size, out_signature, out_signature_size))
|
||||||
{
|
{
|
||||||
@ -1237,9 +1212,7 @@ bool tf_ssb_connection_is_client(tf_ssb_connection_t* connection)
|
|||||||
|
|
||||||
bool tf_ssb_connection_is_connected(tf_ssb_connection_t* connection)
|
bool tf_ssb_connection_is_connected(tf_ssb_connection_t* connection)
|
||||||
{
|
{
|
||||||
return
|
return connection->state == k_tf_ssb_state_verified || connection->state == k_tf_ssb_state_server_verified;
|
||||||
connection->state == k_tf_ssb_state_verified ||
|
|
||||||
connection->state == k_tf_ssb_state_server_verified;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* tf_ssb_connection_get_host(tf_ssb_connection_t* connection)
|
const char* tf_ssb_connection_get_host(tf_ssb_connection_t* connection)
|
||||||
@ -1254,10 +1227,7 @@ int tf_ssb_connection_get_port(tf_ssb_connection_t* connection)
|
|||||||
|
|
||||||
bool tf_ssb_connection_get_id(tf_ssb_connection_t* connection, char* out_id, size_t out_id_size)
|
bool tf_ssb_connection_get_id(tf_ssb_connection_t* connection, char* out_id, size_t out_id_size)
|
||||||
{
|
{
|
||||||
return
|
return connection && memcmp(connection->serverpub, (uint8_t[k_id_bin_len]) { 0 }, k_id_bin_len) != 0 && tf_ssb_id_bin_to_str(out_id, out_id_size, connection->serverpub);
|
||||||
connection &&
|
|
||||||
memcmp(connection->serverpub, (uint8_t[k_id_bin_len]) { 0 }, k_id_bin_len) != 0 &&
|
|
||||||
tf_ssb_id_bin_to_str(out_id, out_id_size, connection->serverpub);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tf_ssb_connection_t* tf_ssb_connection_get_tunnel(tf_ssb_connection_t* connection)
|
tf_ssb_connection_t* tf_ssb_connection_get_tunnel(tf_ssb_connection_t* connection)
|
||||||
@ -1558,15 +1528,9 @@ static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t
|
|||||||
tf_ssb_id_bin_to_str(id, sizeof(id), connection->serverpub);
|
tf_ssb_id_bin_to_str(id, sizeof(id), connection->serverpub);
|
||||||
if (connection->ssb->verbose)
|
if (connection->ssb->verbose)
|
||||||
{
|
{
|
||||||
tf_printf(CYAN "%s RPC RECV" RESET " end/error=%s stream=%s type=%s RN=%d: [%zd B] %.*s\n",
|
tf_printf(CYAN "%s RPC RECV" RESET " end/error=%s stream=%s type=%s RN=%d: [%zd B] %.*s\n", connection->name,
|
||||||
connection->name,
|
(flags & k_ssb_rpc_flag_end_error) ? "true" : "false", (flags & k_ssb_rpc_flag_stream) ? "true" : "false",
|
||||||
(flags & k_ssb_rpc_flag_end_error) ? "true" : "false",
|
k_ssb_type_names[flags & k_ssb_rpc_mask_type], request_number, size, (int)size, message);
|
||||||
(flags & k_ssb_rpc_flag_stream) ? "true" : "false",
|
|
||||||
k_ssb_type_names[flags & k_ssb_rpc_mask_type],
|
|
||||||
request_number,
|
|
||||||
size,
|
|
||||||
(int)size,
|
|
||||||
message);
|
|
||||||
}
|
}
|
||||||
JSContext* context = connection->ssb->context;
|
JSContext* context = connection->ssb->context;
|
||||||
JSValue val = JS_ParseJSON(context, (const char*)message, size, NULL);
|
JSValue val = JS_ParseJSON(context, (const char*)message, size, NULL);
|
||||||
@ -1612,7 +1576,6 @@ static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t
|
|||||||
tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, buffer);
|
tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1626,13 +1589,9 @@ static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t
|
|||||||
{
|
{
|
||||||
if (connection->ssb->verbose)
|
if (connection->ssb->verbose)
|
||||||
{
|
{
|
||||||
tf_printf(CYAN "%s RPC RECV" RESET " end/error=%s stream=%s type=%s RN=%d: [%zd B]\n",
|
tf_printf(CYAN "%s RPC RECV" RESET " end/error=%s stream=%s type=%s RN=%d: [%zd B]\n", connection->name,
|
||||||
connection->name,
|
(flags & k_ssb_rpc_flag_end_error) ? "true" : "false", (flags & k_ssb_rpc_flag_stream) ? "true" : "false",
|
||||||
(flags & k_ssb_rpc_flag_end_error) ? "true" : "false",
|
k_ssb_type_names[flags & k_ssb_rpc_mask_type], request_number, size);
|
||||||
(flags & k_ssb_rpc_flag_stream) ? "true" : "false",
|
|
||||||
k_ssb_type_names[flags & k_ssb_rpc_mask_type],
|
|
||||||
request_number,
|
|
||||||
size);
|
|
||||||
}
|
}
|
||||||
tf_ssb_rpc_callback_t* callback = NULL;
|
tf_ssb_rpc_callback_t* callback = NULL;
|
||||||
void* user_data = NULL;
|
void* user_data = NULL;
|
||||||
@ -1667,7 +1626,8 @@ static void _tf_ssb_connection_rpc_recv_push(tf_ssb_connection_t* connection, co
|
|||||||
size_t size_processed = 0;
|
size_t size_processed = 0;
|
||||||
while (size_left > 0)
|
while (size_left > 0)
|
||||||
{
|
{
|
||||||
size_t copy_size = (connection->rpc_recv_size + size_left > sizeof(connection->rpc_recv_buffer)) ? sizeof(connection->rpc_recv_buffer) - connection->rpc_recv_size : size_left;
|
size_t copy_size =
|
||||||
|
(connection->rpc_recv_size + size_left > sizeof(connection->rpc_recv_buffer)) ? sizeof(connection->rpc_recv_buffer) - connection->rpc_recv_size : size_left;
|
||||||
if (copy_size == 0)
|
if (copy_size == 0)
|
||||||
{
|
{
|
||||||
_tf_ssb_connection_close(connection, "recv buffer overflow");
|
_tf_ssb_connection_close(connection, "recv buffer overflow");
|
||||||
@ -1740,7 +1700,8 @@ static bool _tf_ssb_connection_box_stream_recv(tf_ssb_connection_t* connection)
|
|||||||
memcpy(connection->box_stream_buf, connection->body_auth_tag, sizeof(connection->body_auth_tag));
|
memcpy(connection->box_stream_buf, connection->body_auth_tag, sizeof(connection->body_auth_tag));
|
||||||
if (_tf_ssb_connection_recv_pop(connection, connection->box_stream_buf + 16, connection->body_len))
|
if (_tf_ssb_connection_recv_pop(connection, connection->box_stream_buf + 16, connection->body_len))
|
||||||
{
|
{
|
||||||
if (crypto_secretbox_open_easy(connection->secretbox_buf, connection->box_stream_buf, 16 + connection->body_len, connection->nonce, connection->s_to_c_box_key) != 0)
|
if (crypto_secretbox_open_easy(
|
||||||
|
connection->secretbox_buf, connection->box_stream_buf, 16 + connection->body_len, connection->nonce, connection->s_to_c_box_key) != 0)
|
||||||
{
|
{
|
||||||
_tf_ssb_connection_close(connection, "failed to open secret box");
|
_tf_ssb_connection_close(connection, "failed to open secret box");
|
||||||
return false;
|
return false;
|
||||||
@ -1905,11 +1866,7 @@ static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const ch
|
|||||||
uv_close((uv_handle_t*)&connection->tcp, _tf_ssb_connection_on_close);
|
uv_close((uv_handle_t*)&connection->tcp, _tf_ssb_connection_on_close);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JS_IsUndefined(connection->object) &&
|
if (JS_IsUndefined(connection->object) && !connection->async.data && !connection->tcp.data && !connection->connect.data && connection->ref_count == 0)
|
||||||
!connection->async.data &&
|
|
||||||
!connection->tcp.data &&
|
|
||||||
!connection->connect.data &&
|
|
||||||
connection->ref_count == 0)
|
|
||||||
{
|
{
|
||||||
JS_FreeValue(ssb->context, connection->ebt_send_clock);
|
JS_FreeValue(ssb->context, connection->ebt_send_clock);
|
||||||
connection->ebt_send_clock = JS_UNDEFINED;
|
connection->ebt_send_clock = JS_UNDEFINED;
|
||||||
@ -1923,8 +1880,7 @@ static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const ch
|
|||||||
connection->debug_messages[i] = NULL;
|
connection->debug_messages[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (--connection->ssb->connection_ref_count == 0 &&
|
if (--connection->ssb->connection_ref_count == 0 && connection->ssb->shutting_down)
|
||||||
connection->ssb->shutting_down)
|
|
||||||
{
|
{
|
||||||
tf_ssb_destroy(connection->ssb);
|
tf_ssb_destroy(connection->ssb);
|
||||||
}
|
}
|
||||||
@ -2108,8 +2064,7 @@ static void _tf_ssb_trace_timer(uv_timer_t* timer)
|
|||||||
{
|
{
|
||||||
tf_ssb_t* ssb = timer->data;
|
tf_ssb_t* ssb = timer->data;
|
||||||
|
|
||||||
const char* names[] =
|
const char* names[] = {
|
||||||
{
|
|
||||||
"connections",
|
"connections",
|
||||||
"broadcasts",
|
"broadcasts",
|
||||||
"rpc",
|
"rpc",
|
||||||
@ -2118,8 +2073,7 @@ static void _tf_ssb_trace_timer(uv_timer_t* timer)
|
|||||||
"blob_want_added",
|
"blob_want_added",
|
||||||
"broadcasts_changed",
|
"broadcasts_changed",
|
||||||
};
|
};
|
||||||
int64_t values[] =
|
int64_t values[] = {
|
||||||
{
|
|
||||||
ssb->connections_count,
|
ssb->connections_count,
|
||||||
ssb->broadcasts_count,
|
ssb->broadcasts_count,
|
||||||
ssb->rpc_count,
|
ssb->rpc_count,
|
||||||
@ -2186,8 +2140,7 @@ tf_ssb_t* tf_ssb_create(uv_loop_t* loop, JSContext* context, const char* db_path
|
|||||||
uv_mutex_init(&ssb->db_writer_lock);
|
uv_mutex_init(&ssb->db_writer_lock);
|
||||||
|
|
||||||
JS_NewClassID(&_connection_class_id);
|
JS_NewClassID(&_connection_class_id);
|
||||||
JSClassDef def =
|
JSClassDef def = {
|
||||||
{
|
|
||||||
.class_name = "connection",
|
.class_name = "connection",
|
||||||
.finalizer = _tf_ssb_connection_finalizer,
|
.finalizer = _tf_ssb_connection_finalizer,
|
||||||
};
|
};
|
||||||
@ -2423,13 +2376,8 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
|
|||||||
|
|
||||||
tf_printf("Waiting for closes.\n");
|
tf_printf("Waiting for closes.\n");
|
||||||
|
|
||||||
while (ssb->broadcast_listener.data ||
|
while (ssb->broadcast_listener.data || ssb->broadcast_sender.data || ssb->broadcast_timer.data || ssb->broadcast_cleanup_timer.data || ssb->trace_timer.data ||
|
||||||
ssb->broadcast_sender.data ||
|
ssb->server.data || ssb->ref_count)
|
||||||
ssb->broadcast_timer.data ||
|
|
||||||
ssb->broadcast_cleanup_timer.data ||
|
|
||||||
ssb->trace_timer.data ||
|
|
||||||
ssb->server.data ||
|
|
||||||
ssb->ref_count)
|
|
||||||
{
|
{
|
||||||
uv_run(ssb->loop, UV_RUN_ONCE);
|
uv_run(ssb->loop, UV_RUN_ONCE);
|
||||||
}
|
}
|
||||||
@ -2656,26 +2604,12 @@ tf_ssb_connection_t* tf_ssb_connection_create(tf_ssb_t* ssb, const char* host, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_connection_tunnel_callback(
|
static void _tf_ssb_connection_tunnel_callback(
|
||||||
tf_ssb_connection_t* connection,
|
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
uint8_t flags,
|
|
||||||
int32_t request_number,
|
|
||||||
JSValue args,
|
|
||||||
const uint8_t* message,
|
|
||||||
size_t size,
|
|
||||||
void* user_data)
|
|
||||||
{
|
{
|
||||||
tf_ssb_connection_t* tunnel = user_data;
|
tf_ssb_connection_t* tunnel = user_data;
|
||||||
if (flags & k_ssb_rpc_flag_end_error)
|
if (flags & k_ssb_rpc_flag_end_error)
|
||||||
{
|
{
|
||||||
tf_ssb_connection_rpc_send(
|
tf_ssb_connection_rpc_send(connection, flags, -request_number, (const uint8_t*)"false", strlen("false"), NULL, NULL, NULL);
|
||||||
connection,
|
|
||||||
flags,
|
|
||||||
-request_number,
|
|
||||||
(const uint8_t*)"false",
|
|
||||||
strlen("false"),
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
tf_ssb_connection_close(tunnel);
|
tf_ssb_connection_close(tunnel);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2712,13 +2646,7 @@ tf_ssb_connection_t* tf_ssb_connection_tunnel_create(tf_ssb_t* ssb, const char*
|
|||||||
ssb->connections_count++;
|
ssb->connections_count++;
|
||||||
_tf_ssb_notify_connections_changed(ssb, k_tf_ssb_change_create, tunnel);
|
_tf_ssb_notify_connections_changed(ssb, k_tf_ssb_change_create, tunnel);
|
||||||
|
|
||||||
tf_ssb_connection_add_request(
|
tf_ssb_connection_add_request(connection, request_number, _tf_ssb_connection_tunnel_callback, NULL, tunnel, tunnel);
|
||||||
connection,
|
|
||||||
request_number,
|
|
||||||
_tf_ssb_connection_tunnel_callback,
|
|
||||||
NULL,
|
|
||||||
tunnel,
|
|
||||||
tunnel);
|
|
||||||
if (request_number > 0)
|
if (request_number > 0)
|
||||||
{
|
{
|
||||||
tunnel->state = k_tf_ssb_state_connected;
|
tunnel->state = k_tf_ssb_state_connected;
|
||||||
@ -2732,7 +2660,8 @@ tf_ssb_connection_t* tf_ssb_connection_tunnel_create(tf_ssb_t* ssb, const char*
|
|||||||
return tunnel;
|
return tunnel;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct _connect_t {
|
typedef struct _connect_t
|
||||||
|
{
|
||||||
tf_ssb_t* ssb;
|
tf_ssb_t* ssb;
|
||||||
uv_getaddrinfo_t req;
|
uv_getaddrinfo_t req;
|
||||||
char host[256];
|
char host[256];
|
||||||
@ -2760,8 +2689,7 @@ static void _tf_on_connect_getaddrinfo(uv_getaddrinfo_t* addrinfo, int result, s
|
|||||||
void tf_ssb_connect(tf_ssb_t* ssb, const char* host, int port, const uint8_t* key)
|
void tf_ssb_connect(tf_ssb_t* ssb, const char* host, int port, const uint8_t* key)
|
||||||
{
|
{
|
||||||
connect_t* connect = tf_malloc(sizeof(connect_t));
|
connect_t* connect = tf_malloc(sizeof(connect_t));
|
||||||
*connect = (connect_t)
|
*connect = (connect_t) {
|
||||||
{
|
|
||||||
.ssb = ssb,
|
.ssb = ssb,
|
||||||
.port = port,
|
.port = port,
|
||||||
.req.data = connect,
|
.req.data = connect,
|
||||||
@ -2866,9 +2794,7 @@ static void _tf_ssb_send_broadcast(tf_ssb_t* ssb, struct sockaddr_in* address, s
|
|||||||
struct sockaddr_in broadcast_addr = { 0 };
|
struct sockaddr_in broadcast_addr = { 0 };
|
||||||
broadcast_addr.sin_family = AF_INET;
|
broadcast_addr.sin_family = AF_INET;
|
||||||
broadcast_addr.sin_port = htons(8008);
|
broadcast_addr.sin_port = htons(8008);
|
||||||
broadcast_addr.sin_addr.s_addr =
|
broadcast_addr.sin_addr.s_addr = (address->sin_addr.s_addr & netmask->sin_addr.s_addr) | (INADDR_BROADCAST & ~netmask->sin_addr.s_addr);
|
||||||
(address->sin_addr.s_addr & netmask->sin_addr.s_addr) |
|
|
||||||
(INADDR_BROADCAST & ~netmask->sin_addr.s_addr);
|
|
||||||
r = uv_udp_try_send(&ssb->broadcast_sender, &buf, 1, (struct sockaddr*)&broadcast_addr);
|
r = uv_udp_try_send(&ssb->broadcast_sender, &buf, 1, (struct sockaddr*)&broadcast_addr);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
{
|
{
|
||||||
@ -2887,8 +2813,7 @@ static void _tf_ssb_broadcast_timer(uv_timer_t* timer)
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
if (!info[i].is_internal &&
|
if (!info[i].is_internal && info[i].address.address4.sin_family == AF_INET)
|
||||||
info[i].address.address4.sin_family == AF_INET)
|
|
||||||
{
|
{
|
||||||
_tf_ssb_send_broadcast(ssb, &info[i].address.address4, &info[i].netmask.netmask4);
|
_tf_ssb_send_broadcast(ssb, &info[i].address.address4, &info[i].netmask.netmask4);
|
||||||
}
|
}
|
||||||
@ -3011,8 +2936,7 @@ static void _tf_ssb_add_broadcast(tf_ssb_t* ssb, const tf_ssb_broadcast_t* broad
|
|||||||
{
|
{
|
||||||
for (tf_ssb_broadcast_t* node = ssb->broadcasts; node; node = node->next)
|
for (tf_ssb_broadcast_t* node = ssb->broadcasts; node; node = node->next)
|
||||||
{
|
{
|
||||||
if (node->tunnel_connection == broadcast->tunnel_connection &&
|
if (node->tunnel_connection == broadcast->tunnel_connection && memcmp(node->pub, broadcast->pub, sizeof(node->pub)) == 0)
|
||||||
memcmp(node->pub, broadcast->pub, sizeof(node->pub)) == 0)
|
|
||||||
{
|
{
|
||||||
node->mtime = time(NULL);
|
node->mtime = time(NULL);
|
||||||
return;
|
return;
|
||||||
@ -3023,10 +2947,8 @@ static void _tf_ssb_add_broadcast(tf_ssb_t* ssb, const tf_ssb_broadcast_t* broad
|
|||||||
{
|
{
|
||||||
for (tf_ssb_broadcast_t* node = ssb->broadcasts; node; node = node->next)
|
for (tf_ssb_broadcast_t* node = ssb->broadcasts; node; node = node->next)
|
||||||
{
|
{
|
||||||
if (node->addr.sin_family == broadcast->addr.sin_family &&
|
if (node->addr.sin_family == broadcast->addr.sin_family && node->addr.sin_port == broadcast->addr.sin_port &&
|
||||||
node->addr.sin_port == broadcast->addr.sin_port &&
|
node->addr.sin_addr.s_addr == broadcast->addr.sin_addr.s_addr && memcmp(node->pub, broadcast->pub, sizeof(node->pub)) == 0)
|
||||||
node->addr.sin_addr.s_addr == broadcast->addr.sin_addr.s_addr &&
|
|
||||||
memcmp(node->pub, broadcast->pub, sizeof(node->pub)) == 0)
|
|
||||||
{
|
{
|
||||||
node->mtime = time(NULL);
|
node->mtime = time(NULL);
|
||||||
return;
|
return;
|
||||||
@ -3077,7 +2999,8 @@ static void _tf_ssb_on_broadcast_listener_recv(uv_udp_t* handle, ssize_t nread,
|
|||||||
tf_free(buf->base);
|
tf_free(buf->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_ssb_visit_broadcasts(tf_ssb_t* ssb, void (*callback)(const char* host, const struct sockaddr_in* addr, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data), void* user_data)
|
void tf_ssb_visit_broadcasts(
|
||||||
|
tf_ssb_t* ssb, void (*callback)(const char* host, const struct sockaddr_in* addr, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data), void* user_data)
|
||||||
{
|
{
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
tf_ssb_broadcast_t* next = NULL;
|
tf_ssb_broadcast_t* next = NULL;
|
||||||
@ -3165,8 +3088,7 @@ void tf_ssb_broadcast_sender_start(tf_ssb_t* ssb)
|
|||||||
|
|
||||||
ssb->broadcast_sender.data = ssb;
|
ssb->broadcast_sender.data = ssb;
|
||||||
uv_udp_init(ssb->loop, &ssb->broadcast_sender);
|
uv_udp_init(ssb->loop, &ssb->broadcast_sender);
|
||||||
struct sockaddr_in broadcast_from =
|
struct sockaddr_in broadcast_from = {
|
||||||
{
|
|
||||||
.sin_family = AF_INET,
|
.sin_family = AF_INET,
|
||||||
.sin_addr.s_addr = INADDR_ANY,
|
.sin_addr.s_addr = INADDR_ANY,
|
||||||
};
|
};
|
||||||
@ -3231,9 +3153,7 @@ const char** tf_ssb_get_connection_ids(tf_ssb_t* ssb)
|
|||||||
int tf_ssb_get_connections(tf_ssb_t* ssb, tf_ssb_connection_t** out_connections, int out_connections_count)
|
int tf_ssb_get_connections(tf_ssb_t* ssb, tf_ssb_connection_t** out_connections, int out_connections_count)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (tf_ssb_connection_t* connection = ssb->connections;
|
for (tf_ssb_connection_t* connection = ssb->connections; connection && i < out_connections_count; connection = connection->next)
|
||||||
connection && i < out_connections_count;
|
|
||||||
connection = connection->next)
|
|
||||||
{
|
{
|
||||||
out_connections[i++] = connection;
|
out_connections[i++] = connection;
|
||||||
}
|
}
|
||||||
@ -3243,8 +3163,7 @@ int tf_ssb_get_connections(tf_ssb_t* ssb, tf_ssb_connection_t** out_connections,
|
|||||||
void tf_ssb_add_broadcasts_changed_callback(tf_ssb_t* ssb, tf_ssb_broadcasts_changed_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data)
|
void tf_ssb_add_broadcasts_changed_callback(tf_ssb_t* ssb, tf_ssb_broadcasts_changed_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data)
|
||||||
{
|
{
|
||||||
tf_ssb_broadcasts_changed_callback_node_t* node = tf_malloc(sizeof(tf_ssb_broadcasts_changed_callback_node_t));
|
tf_ssb_broadcasts_changed_callback_node_t* node = tf_malloc(sizeof(tf_ssb_broadcasts_changed_callback_node_t));
|
||||||
*node = (tf_ssb_broadcasts_changed_callback_node_t)
|
*node = (tf_ssb_broadcasts_changed_callback_node_t) {
|
||||||
{
|
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
.cleanup = cleanup,
|
.cleanup = cleanup,
|
||||||
.user_data = user_data,
|
.user_data = user_data,
|
||||||
@ -3259,8 +3178,7 @@ void tf_ssb_remove_broadcasts_changed_callback(tf_ssb_t* ssb, tf_ssb_broadcasts_
|
|||||||
tf_ssb_broadcasts_changed_callback_node_t** it = &ssb->broadcasts_changed;
|
tf_ssb_broadcasts_changed_callback_node_t** it = &ssb->broadcasts_changed;
|
||||||
while (*it)
|
while (*it)
|
||||||
{
|
{
|
||||||
if ((*it)->callback == callback &&
|
if ((*it)->callback == callback && (*it)->user_data == user_data)
|
||||||
(*it)->user_data == user_data)
|
|
||||||
{
|
{
|
||||||
tf_ssb_broadcasts_changed_callback_node_t* node = *it;
|
tf_ssb_broadcasts_changed_callback_node_t* node = *it;
|
||||||
*it = node->next;
|
*it = node->next;
|
||||||
@ -3281,8 +3199,7 @@ void tf_ssb_remove_broadcasts_changed_callback(tf_ssb_t* ssb, tf_ssb_broadcasts_
|
|||||||
void tf_ssb_add_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_connections_changed_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data)
|
void tf_ssb_add_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_connections_changed_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data)
|
||||||
{
|
{
|
||||||
tf_ssb_connections_changed_callback_node_t* node = tf_malloc(sizeof(tf_ssb_connections_changed_callback_node_t));
|
tf_ssb_connections_changed_callback_node_t* node = tf_malloc(sizeof(tf_ssb_connections_changed_callback_node_t));
|
||||||
*node = (tf_ssb_connections_changed_callback_node_t)
|
*node = (tf_ssb_connections_changed_callback_node_t) {
|
||||||
{
|
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
.cleanup = cleanup,
|
.cleanup = cleanup,
|
||||||
.user_data = user_data,
|
.user_data = user_data,
|
||||||
@ -3297,8 +3214,7 @@ void tf_ssb_remove_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_connection
|
|||||||
tf_ssb_connections_changed_callback_node_t** it = &ssb->connections_changed;
|
tf_ssb_connections_changed_callback_node_t** it = &ssb->connections_changed;
|
||||||
while (*it)
|
while (*it)
|
||||||
{
|
{
|
||||||
if ((*it)->callback == callback &&
|
if ((*it)->callback == callback && (*it)->user_data == user_data)
|
||||||
(*it)->user_data == user_data)
|
|
||||||
{
|
{
|
||||||
tf_ssb_connections_changed_callback_node_t* node = *it;
|
tf_ssb_connections_changed_callback_node_t* node = *it;
|
||||||
*it = node->next;
|
*it = node->next;
|
||||||
@ -3325,13 +3241,8 @@ void tf_ssb_add_rpc_callback(tf_ssb_t* ssb, const char** name, tf_ssb_rpc_callba
|
|||||||
name_count++;
|
name_count++;
|
||||||
name_len += strlen(name[i]) + 1;
|
name_len += strlen(name[i]) + 1;
|
||||||
}
|
}
|
||||||
tf_ssb_rpc_callback_node_t* node = tf_malloc(
|
tf_ssb_rpc_callback_node_t* node = tf_malloc(sizeof(tf_ssb_rpc_callback_node_t) + (name_count + 1) * sizeof(const char*) + name_len + name_len + 3);
|
||||||
sizeof(tf_ssb_rpc_callback_node_t) +
|
*node = (tf_ssb_rpc_callback_node_t) {
|
||||||
(name_count + 1) * sizeof(const char*) +
|
|
||||||
name_len +
|
|
||||||
name_len + 3);
|
|
||||||
*node = (tf_ssb_rpc_callback_node_t)
|
|
||||||
{
|
|
||||||
.name = (const char**)(node + 1),
|
.name = (const char**)(node + 1),
|
||||||
.flattened_name = (const char*)(node + 1) + (name_count + 1) * sizeof(const char*) + name_len,
|
.flattened_name = (const char*)(node + 1) + (name_count + 1) * sizeof(const char*) + name_len,
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
@ -3391,11 +3302,11 @@ JSValue tf_ssb_connection_get_object(tf_ssb_connection_t* connection)
|
|||||||
return connection ? connection->object : JS_UNDEFINED;
|
return connection ? connection->object : JS_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_ssb_add_message_added_callback(tf_ssb_t* ssb, void (*callback)(tf_ssb_t* ssb, const char* id, void* user_data), void (*cleanup)(tf_ssb_t* ssb, void* user_data), void* user_data)
|
void tf_ssb_add_message_added_callback(
|
||||||
|
tf_ssb_t* ssb, void (*callback)(tf_ssb_t* ssb, const char* id, void* user_data), void (*cleanup)(tf_ssb_t* ssb, void* user_data), void* user_data)
|
||||||
{
|
{
|
||||||
tf_ssb_message_added_callback_node_t* node = tf_malloc(sizeof(tf_ssb_message_added_callback_node_t));
|
tf_ssb_message_added_callback_node_t* node = tf_malloc(sizeof(tf_ssb_message_added_callback_node_t));
|
||||||
*node = (tf_ssb_message_added_callback_node_t)
|
*node = (tf_ssb_message_added_callback_node_t) {
|
||||||
{
|
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
.cleanup = cleanup,
|
.cleanup = cleanup,
|
||||||
.user_data = user_data,
|
.user_data = user_data,
|
||||||
@ -3410,8 +3321,7 @@ void tf_ssb_remove_message_added_callback(tf_ssb_t* ssb, tf_ssb_message_added_ca
|
|||||||
tf_ssb_message_added_callback_node_t** it = &ssb->message_added;
|
tf_ssb_message_added_callback_node_t** it = &ssb->message_added;
|
||||||
while (*it)
|
while (*it)
|
||||||
{
|
{
|
||||||
if ((*it)->callback == callback &&
|
if ((*it)->callback == callback && (*it)->user_data == user_data)
|
||||||
(*it)->user_data == user_data)
|
|
||||||
{
|
{
|
||||||
tf_ssb_message_added_callback_node_t* node = *it;
|
tf_ssb_message_added_callback_node_t* node = *it;
|
||||||
*it = node->next;
|
*it = node->next;
|
||||||
@ -3459,23 +3369,12 @@ void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* id, JSValue message_
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tf_ssb_connection_message_request_t* message_request =
|
tf_ssb_connection_message_request_t* message_request = bsearch(
|
||||||
bsearch(
|
author_string, connection->message_requests, connection->message_requests_count, sizeof(tf_ssb_connection_message_request_t), _message_request_compare);
|
||||||
author_string,
|
|
||||||
connection->message_requests,
|
|
||||||
connection->message_requests_count,
|
|
||||||
sizeof(tf_ssb_connection_message_request_t),
|
|
||||||
_message_request_compare);
|
|
||||||
if (message_request)
|
if (message_request)
|
||||||
{
|
{
|
||||||
tf_ssb_connection_rpc_send_json(
|
tf_ssb_connection_rpc_send_json(
|
||||||
connection,
|
connection, k_ssb_rpc_flag_stream, message_request->request_number, message_request->keys ? message_keys : message, NULL, NULL, NULL);
|
||||||
k_ssb_rpc_flag_stream,
|
|
||||||
message_request->request_number,
|
|
||||||
message_request->keys ? message_keys : message,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3485,11 +3384,11 @@ void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* id, JSValue message_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_ssb_add_blob_want_added_callback(tf_ssb_t* ssb, void (*callback)(tf_ssb_t* ssb, const char* id, void* user_data), void (*cleanup)(tf_ssb_t* ssb, void* user_data), void* user_data)
|
void tf_ssb_add_blob_want_added_callback(
|
||||||
|
tf_ssb_t* ssb, void (*callback)(tf_ssb_t* ssb, const char* id, void* user_data), void (*cleanup)(tf_ssb_t* ssb, void* user_data), void* user_data)
|
||||||
{
|
{
|
||||||
tf_ssb_blob_want_added_callback_node_t* node = tf_malloc(sizeof(tf_ssb_blob_want_added_callback_node_t));
|
tf_ssb_blob_want_added_callback_node_t* node = tf_malloc(sizeof(tf_ssb_blob_want_added_callback_node_t));
|
||||||
*node = (tf_ssb_blob_want_added_callback_node_t)
|
*node = (tf_ssb_blob_want_added_callback_node_t) {
|
||||||
{
|
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
.cleanup = cleanup,
|
.cleanup = cleanup,
|
||||||
.user_data = user_data,
|
.user_data = user_data,
|
||||||
@ -3504,8 +3403,7 @@ void tf_ssb_remove_blob_want_added_callback(tf_ssb_t* ssb, tf_ssb_blob_want_adde
|
|||||||
tf_ssb_blob_want_added_callback_node_t** it = &ssb->blob_want_added;
|
tf_ssb_blob_want_added_callback_node_t** it = &ssb->blob_want_added;
|
||||||
while (*it)
|
while (*it)
|
||||||
{
|
{
|
||||||
if ((*it)->callback == callback &&
|
if ((*it)->callback == callback && (*it)->user_data == user_data)
|
||||||
(*it)->user_data == user_data)
|
|
||||||
{
|
{
|
||||||
tf_ssb_blob_want_added_callback_node_t* node = *it;
|
tf_ssb_blob_want_added_callback_node_t* node = *it;
|
||||||
*it = node->next;
|
*it = node->next;
|
||||||
@ -3537,8 +3435,7 @@ void tf_ssb_notify_blob_want_added(tf_ssb_t* ssb, const char* id)
|
|||||||
|
|
||||||
void tf_ssb_connection_add_room_attendant(tf_ssb_connection_t* connection, const char* id)
|
void tf_ssb_connection_add_room_attendant(tf_ssb_connection_t* connection, const char* id)
|
||||||
{
|
{
|
||||||
tf_ssb_broadcast_t broadcast =
|
tf_ssb_broadcast_t broadcast = {
|
||||||
{
|
|
||||||
.tunnel_connection = connection,
|
.tunnel_connection = connection,
|
||||||
};
|
};
|
||||||
tf_ssb_id_str_to_bin(broadcast.pub, id);
|
tf_ssb_id_str_to_bin(broadcast.pub, id);
|
||||||
@ -3553,8 +3450,7 @@ void tf_ssb_connection_remove_room_attendant(tf_ssb_connection_t* connection, co
|
|||||||
int modified = 0;
|
int modified = 0;
|
||||||
for (tf_ssb_broadcast_t** it = &connection->ssb->broadcasts; *it;)
|
for (tf_ssb_broadcast_t** it = &connection->ssb->broadcasts; *it;)
|
||||||
{
|
{
|
||||||
if ((*it)->tunnel_connection == connection &&
|
if ((*it)->tunnel_connection == connection && memcmp((*it)->pub, pub, k_id_bin_len) == 0)
|
||||||
memcmp((*it)->pub, pub, k_id_bin_len) == 0)
|
|
||||||
{
|
{
|
||||||
tf_ssb_broadcast_t* node = *it;
|
tf_ssb_broadcast_t* node = *it;
|
||||||
*it = node->next;
|
*it = node->next;
|
||||||
@ -3651,8 +3547,7 @@ void tf_ssb_verify_strip_and_store_message(tf_ssb_t* ssb, JSValue value, tf_ssb_
|
|||||||
{
|
{
|
||||||
JSContext* context = tf_ssb_get_context(ssb);
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
store_t* async = tf_malloc(sizeof(store_t));
|
store_t* async = tf_malloc(sizeof(store_t));
|
||||||
*async = (store_t)
|
*async = (store_t) {
|
||||||
{
|
|
||||||
.ssb = ssb,
|
.ssb = ssb,
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
.user_data = user_data,
|
.user_data = user_data,
|
||||||
@ -3729,7 +3624,8 @@ JSValue tf_ssb_get_disconnection_debug(tf_ssb_t* ssb, JSContext* context)
|
|||||||
JS_SetPropertyStr(context, message, "flags", JS_NewInt32(context, ssb->debug_close[i].messages[j]->flags));
|
JS_SetPropertyStr(context, message, "flags", JS_NewInt32(context, ssb->debug_close[i].messages[j]->flags));
|
||||||
JS_SetPropertyStr(context, message, "request_number", JS_NewInt32(context, ssb->debug_close[i].messages[j]->request_number));
|
JS_SetPropertyStr(context, message, "request_number", JS_NewInt32(context, ssb->debug_close[i].messages[j]->request_number));
|
||||||
JS_SetPropertyStr(context, message, "timestamp", JS_NewFloat64(context, ssb->debug_close[i].messages[j]->timestamp));
|
JS_SetPropertyStr(context, message, "timestamp", JS_NewFloat64(context, ssb->debug_close[i].messages[j]->timestamp));
|
||||||
JS_SetPropertyStr(context, message, "payload", JS_NewStringLen(context, (const char*)ssb->debug_close[i].messages[j]->data, ssb->debug_close[i].messages[j]->size));
|
JS_SetPropertyStr(context, message, "payload",
|
||||||
|
JS_NewStringLen(context, (const char*)ssb->debug_close[i].messages[j]->data, ssb->debug_close[i].messages[j]->size));
|
||||||
JS_SetPropertyUint32(context, messages, j, message);
|
JS_SetPropertyUint32(context, messages, j, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3815,19 +3711,15 @@ static void _tf_ssb_connection_after_work_callback(uv_work_t* work, int status)
|
|||||||
data->after_work_callback(data->connection, status, data->user_data);
|
data->after_work_callback(data->connection, status, data->user_data);
|
||||||
}
|
}
|
||||||
data->connection->ref_count--;
|
data->connection->ref_count--;
|
||||||
if (data->connection->ref_count == 0 &&
|
if (data->connection->ref_count == 0 && data->connection->closing)
|
||||||
data->connection->closing)
|
|
||||||
{
|
{
|
||||||
_tf_ssb_connection_destroy(data->connection, "work completed");
|
_tf_ssb_connection_destroy(data->connection, "work completed");
|
||||||
}
|
}
|
||||||
tf_free(data);
|
tf_free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_ssb_connection_run_work(
|
void tf_ssb_connection_run_work(tf_ssb_connection_t* connection, void (*work_callback)(tf_ssb_connection_t* connection, void* user_data),
|
||||||
tf_ssb_connection_t* connection,
|
void (*after_work_callback)(tf_ssb_connection_t* connection, int result, void* user_data), void* user_data)
|
||||||
void (*work_callback)(tf_ssb_connection_t* connection, void* user_data),
|
|
||||||
void (*after_work_callback)(tf_ssb_connection_t* connection, int result, void* user_data),
|
|
||||||
void* user_data)
|
|
||||||
{
|
{
|
||||||
connection_work_t* work = tf_malloc(sizeof(connection_work_t));
|
connection_work_t* work = tf_malloc(sizeof(connection_work_t));
|
||||||
*work = (connection_work_t)
|
*work = (connection_work_t)
|
||||||
|
@ -27,9 +27,7 @@ static void _tf_ssb_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_change_t
|
|||||||
case k_tf_ssb_change_create:
|
case k_tf_ssb_change_create:
|
||||||
{
|
{
|
||||||
char key[k_id_base64_len];
|
char key[k_id_base64_len];
|
||||||
if (tf_ssb_connection_get_host(connection) &&
|
if (tf_ssb_connection_get_host(connection) && *tf_ssb_connection_get_host(connection) && tf_ssb_connection_get_port(connection) &&
|
||||||
*tf_ssb_connection_get_host(connection) &&
|
|
||||||
tf_ssb_connection_get_port(connection) &&
|
|
||||||
tf_ssb_connection_get_id(connection, key, sizeof(key)))
|
tf_ssb_connection_get_id(connection, key, sizeof(key)))
|
||||||
{
|
{
|
||||||
tf_ssb_connections_set_attempted(connections, tf_ssb_connection_get_host(connection), tf_ssb_connection_get_port(connection), key);
|
tf_ssb_connections_set_attempted(connections, tf_ssb_connection_get_host(connection), tf_ssb_connection_get_port(connection), key);
|
||||||
@ -55,10 +53,10 @@ static bool _tf_ssb_connections_get_next_connection(tf_ssb_connections_t* connec
|
|||||||
bool result = false;
|
bool result = false;
|
||||||
sqlite3_stmt* statement;
|
sqlite3_stmt* statement;
|
||||||
sqlite3* db = tf_ssb_acquire_db_reader(connections->ssb);
|
sqlite3* db = tf_ssb_acquire_db_reader(connections->ssb);
|
||||||
if (sqlite3_prepare(db, "SELECT host, port, key FROM connections WHERE last_attempt IS NULL OR (strftime('%s', 'now') - last_attempt > ?1) ORDER BY last_attempt LIMIT 1", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "SELECT host, port, key FROM connections WHERE last_attempt IS NULL OR (strftime('%s', 'now') - last_attempt > ?1) ORDER BY last_attempt LIMIT 1",
|
||||||
|
-1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_int(statement, 1, 60000) == SQLITE_OK &&
|
if (sqlite3_bind_int(statement, 1, 60000) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW)
|
||||||
sqlite3_step(statement) == SQLITE_ROW)
|
|
||||||
{
|
{
|
||||||
snprintf(host, host_size, "%s", sqlite3_column_text(statement, 0));
|
snprintf(host, host_size, "%s", sqlite3_column_text(statement, 0));
|
||||||
*port = sqlite3_column_int(statement, 1);
|
*port = sqlite3_column_int(statement, 1);
|
||||||
@ -181,10 +179,10 @@ static void _tf_ssb_connections_update_work(uv_work_t* work)
|
|||||||
sqlite3* db = tf_ssb_acquire_db_writer(update->ssb);
|
sqlite3* db = tf_ssb_acquire_db_writer(update->ssb);
|
||||||
if (update->attempted)
|
if (update->attempted)
|
||||||
{
|
{
|
||||||
if (sqlite3_prepare(db, "UPDATE connections SET last_attempt = strftime('%s', 'now') WHERE host = ?1 AND port = ?2 AND key = ?3", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "UPDATE connections SET last_attempt = strftime('%s', 'now') WHERE host = ?1 AND port = ?2 AND key = ?3", -1, &statement, NULL) ==
|
||||||
|
SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, update->host, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, update->host, -1, NULL) == SQLITE_OK && sqlite3_bind_int(statement, 2, update->port) == SQLITE_OK &&
|
||||||
sqlite3_bind_int(statement, 2, update->port) == SQLITE_OK &&
|
|
||||||
sqlite3_bind_text(statement, 3, update->key, -1, NULL) == SQLITE_OK)
|
sqlite3_bind_text(statement, 3, update->key, -1, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_step(statement) != SQLITE_DONE)
|
if (sqlite3_step(statement) != SQLITE_DONE)
|
||||||
@ -197,10 +195,10 @@ static void _tf_ssb_connections_update_work(uv_work_t* work)
|
|||||||
}
|
}
|
||||||
else if (update->succeeded)
|
else if (update->succeeded)
|
||||||
{
|
{
|
||||||
if (sqlite3_prepare(db, "UPDATE connections SET last_success = strftime('%s', 'now') WHERE host = ?1 AND port = ?2 AND key = ?3", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "UPDATE connections SET last_success = strftime('%s', 'now') WHERE host = ?1 AND port = ?2 AND key = ?3", -1, &statement, NULL) ==
|
||||||
|
SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, update->host, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, update->host, -1, NULL) == SQLITE_OK && sqlite3_bind_int(statement, 2, update->port) == SQLITE_OK &&
|
||||||
sqlite3_bind_int(statement, 2, update->port) == SQLITE_OK &&
|
|
||||||
sqlite3_bind_text(statement, 3, update->key, -1, NULL) == SQLITE_OK)
|
sqlite3_bind_text(statement, 3, update->key, -1, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_step(statement) != SQLITE_DONE)
|
if (sqlite3_step(statement) != SQLITE_DONE)
|
||||||
@ -215,8 +213,7 @@ static void _tf_ssb_connections_update_work(uv_work_t* work)
|
|||||||
{
|
{
|
||||||
if (sqlite3_prepare(db, "INSERT INTO connections (host, port, key) VALUES (?1, ?2, ?3) ON CONFLICT DO NOTHING", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "INSERT INTO connections (host, port, key) VALUES (?1, ?2, ?3) ON CONFLICT DO NOTHING", -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, update->host, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, update->host, -1, NULL) == SQLITE_OK && sqlite3_bind_int(statement, 2, update->port) == SQLITE_OK &&
|
||||||
sqlite3_bind_int(statement, 2, update->port) == SQLITE_OK &&
|
|
||||||
sqlite3_bind_text(statement, 3, update->key, -1, NULL) == SQLITE_OK)
|
sqlite3_bind_text(statement, 3, update->key, -1, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
int r = sqlite3_step(statement);
|
int r = sqlite3_step(statement);
|
||||||
@ -251,8 +248,7 @@ static void _tf_ssb_connections_queue_update(tf_ssb_connections_t* connections,
|
|||||||
void tf_ssb_connections_store(tf_ssb_connections_t* connections, const char* host, int port, const char* key)
|
void tf_ssb_connections_store(tf_ssb_connections_t* connections, const char* host, int port, const char* key)
|
||||||
{
|
{
|
||||||
tf_ssb_connections_update_t* update = tf_malloc(sizeof(tf_ssb_connections_update_t));
|
tf_ssb_connections_update_t* update = tf_malloc(sizeof(tf_ssb_connections_update_t));
|
||||||
*update = (tf_ssb_connections_update_t)
|
*update = (tf_ssb_connections_update_t) {
|
||||||
{
|
|
||||||
.ssb = connections->ssb,
|
.ssb = connections->ssb,
|
||||||
.port = port,
|
.port = port,
|
||||||
};
|
};
|
||||||
@ -264,8 +260,7 @@ void tf_ssb_connections_store(tf_ssb_connections_t* connections, const char* hos
|
|||||||
void tf_ssb_connections_set_attempted(tf_ssb_connections_t* connections, const char* host, int port, const char* key)
|
void tf_ssb_connections_set_attempted(tf_ssb_connections_t* connections, const char* host, int port, const char* key)
|
||||||
{
|
{
|
||||||
tf_ssb_connections_update_t* update = tf_malloc(sizeof(tf_ssb_connections_update_t));
|
tf_ssb_connections_update_t* update = tf_malloc(sizeof(tf_ssb_connections_update_t));
|
||||||
*update = (tf_ssb_connections_update_t)
|
*update = (tf_ssb_connections_update_t) {
|
||||||
{
|
|
||||||
.ssb = connections->ssb,
|
.ssb = connections->ssb,
|
||||||
.port = port,
|
.port = port,
|
||||||
.attempted = true,
|
.attempted = true,
|
||||||
@ -278,8 +273,7 @@ void tf_ssb_connections_set_attempted(tf_ssb_connections_t* connections, const c
|
|||||||
void tf_ssb_connections_set_succeeded(tf_ssb_connections_t* connections, const char* host, int port, const char* key)
|
void tf_ssb_connections_set_succeeded(tf_ssb_connections_t* connections, const char* host, int port, const char* key)
|
||||||
{
|
{
|
||||||
tf_ssb_connections_update_t* update = tf_malloc(sizeof(tf_ssb_connections_update_t));
|
tf_ssb_connections_update_t* update = tf_malloc(sizeof(tf_ssb_connections_update_t));
|
||||||
*update = (tf_ssb_connections_update_t)
|
*update = (tf_ssb_connections_update_t) {
|
||||||
{
|
|
||||||
.ssb = connections->ssb,
|
.ssb = connections->ssb,
|
||||||
.port = port,
|
.port = port,
|
||||||
.succeeded = true,
|
.succeeded = true,
|
||||||
|
158
src/ssb.db.c
158
src/ssb.db.c
@ -116,7 +116,7 @@ void tf_ssb_db_init(tf_ssb_t* ssb)
|
|||||||
" content BLOB,"
|
" content BLOB,"
|
||||||
" created INTEGER"
|
" created INTEGER"
|
||||||
")");
|
")");
|
||||||
_tf_ssb_db_exec(db,"DROP TABLE IF EXISTS blob_wants");
|
_tf_ssb_db_exec(db, "DROP TABLE IF EXISTS blob_wants");
|
||||||
_tf_ssb_db_exec(db,
|
_tf_ssb_db_exec(db,
|
||||||
"CREATE TABLE IF NOT EXISTS properties ("
|
"CREATE TABLE IF NOT EXISTS properties ("
|
||||||
" id TEXT,"
|
" id TEXT,"
|
||||||
@ -165,8 +165,11 @@ void tf_ssb_db_init(tf_ssb_t* ssb)
|
|||||||
tf_printf("Done.\n");
|
tf_printf("Done.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
_tf_ssb_db_exec(db, "CREATE TRIGGER IF NOT EXISTS messages_ai AFTER INSERT ON messages BEGIN INSERT INTO messages_fts(rowid, content) VALUES (new.rowid, new.content); END");
|
_tf_ssb_db_exec(
|
||||||
_tf_ssb_db_exec(db, "CREATE TRIGGER IF NOT EXISTS messages_ad AFTER DELETE ON messages BEGIN INSERT INTO messages_fts(messages_fts, rowid, content) VALUES ('delete', old.rowid, old.content); END");
|
db, "CREATE TRIGGER IF NOT EXISTS messages_ai AFTER INSERT ON messages BEGIN INSERT INTO messages_fts(rowid, content) VALUES (new.rowid, new.content); END");
|
||||||
|
_tf_ssb_db_exec(db,
|
||||||
|
"CREATE TRIGGER IF NOT EXISTS messages_ad AFTER DELETE ON messages BEGIN INSERT INTO messages_fts(messages_fts, rowid, content) VALUES ('delete', old.rowid, "
|
||||||
|
"old.content); END");
|
||||||
|
|
||||||
if (!_tf_ssb_db_has_rows(db, "PRAGMA table_list('messages_refs')"))
|
if (!_tf_ssb_db_has_rows(db, "PRAGMA table_list('messages_refs')"))
|
||||||
{
|
{
|
||||||
@ -177,7 +180,8 @@ void tf_ssb_db_init(tf_ssb_t* ssb)
|
|||||||
" UNIQUE(message, ref)"
|
" UNIQUE(message, ref)"
|
||||||
")");
|
")");
|
||||||
tf_printf("Populating messages_refs...\n");
|
tf_printf("Populating messages_refs...\n");
|
||||||
_tf_ssb_db_exec(db, "INSERT INTO messages_refs(message, ref) "
|
_tf_ssb_db_exec(db,
|
||||||
|
"INSERT INTO messages_refs(message, ref) "
|
||||||
"SELECT messages.id, j.value FROM messages, json_tree(messages.content) as j WHERE "
|
"SELECT messages.id, j.value FROM messages, json_tree(messages.content) as j WHERE "
|
||||||
"j.value LIKE '&%.sha256' OR "
|
"j.value LIKE '&%.sha256' OR "
|
||||||
"j.value LIKE '%%%.sha256' OR "
|
"j.value LIKE '%%%.sha256' OR "
|
||||||
@ -187,7 +191,8 @@ void tf_ssb_db_init(tf_ssb_t* ssb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_tf_ssb_db_exec(db, "DROP TRIGGER IF EXISTS messages_ai_refs");
|
_tf_ssb_db_exec(db, "DROP TRIGGER IF EXISTS messages_ai_refs");
|
||||||
_tf_ssb_db_exec(db, "CREATE TRIGGER IF NOT EXISTS messages_ai_refs AFTER INSERT ON messages BEGIN "
|
_tf_ssb_db_exec(db,
|
||||||
|
"CREATE TRIGGER IF NOT EXISTS messages_ai_refs AFTER INSERT ON messages BEGIN "
|
||||||
"INSERT INTO messages_refs(message, ref) "
|
"INSERT INTO messages_refs(message, ref) "
|
||||||
"SELECT DISTINCT new.id, j.value FROM json_tree(new.content) as j WHERE "
|
"SELECT DISTINCT new.id, j.value FROM json_tree(new.content) as j WHERE "
|
||||||
"j.value LIKE '&%.sha256' OR "
|
"j.value LIKE '&%.sha256' OR "
|
||||||
@ -264,10 +269,8 @@ static bool _tf_ssb_db_previous_message_exists(sqlite3* db, const char* author,
|
|||||||
sqlite3_stmt* statement;
|
sqlite3_stmt* statement;
|
||||||
if (sqlite3_prepare(db, "SELECT COUNT(*) FROM messages WHERE author = ?1 AND sequence = ?2 AND id = ?3", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "SELECT COUNT(*) FROM messages WHERE author = ?1 AND sequence = ?2 AND id = ?3", -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, author, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, author, -1, NULL) == SQLITE_OK && sqlite3_bind_int64(statement, 2, sequence - 1) == SQLITE_OK &&
|
||||||
sqlite3_bind_int64(statement, 2, sequence - 1) == SQLITE_OK &&
|
sqlite3_bind_text(statement, 3, previous, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW)
|
||||||
sqlite3_bind_text(statement, 3, previous, -1, NULL) == SQLITE_OK &&
|
|
||||||
sqlite3_step(statement) == SQLITE_ROW)
|
|
||||||
{
|
{
|
||||||
exists = sqlite3_column_int(statement, 0) != 0;
|
exists = sqlite3_column_int(statement, 0) != 0;
|
||||||
}
|
}
|
||||||
@ -277,35 +280,24 @@ static bool _tf_ssb_db_previous_message_exists(sqlite3* db, const char* author,
|
|||||||
return exists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t _tf_ssb_db_store_message_raw(
|
static int64_t _tf_ssb_db_store_message_raw(tf_ssb_t* ssb, const char* id, const char* previous, const char* author, int64_t sequence, double timestamp, const char* content,
|
||||||
tf_ssb_t* ssb,
|
size_t content_len, const char* signature, bool sequence_before_author)
|
||||||
const char* id,
|
|
||||||
const char* previous,
|
|
||||||
const char* author,
|
|
||||||
int64_t sequence,
|
|
||||||
double timestamp,
|
|
||||||
const char* content,
|
|
||||||
size_t content_len,
|
|
||||||
const char* signature,
|
|
||||||
bool sequence_before_author)
|
|
||||||
{
|
{
|
||||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||||
int64_t last_row_id = -1;
|
int64_t last_row_id = -1;
|
||||||
|
|
||||||
if (_tf_ssb_db_previous_message_exists(db, author, sequence, previous))
|
if (_tf_ssb_db_previous_message_exists(db, author, sequence, previous))
|
||||||
{
|
{
|
||||||
const char* query = "INSERT INTO messages (id, previous, author, sequence, timestamp, content, hash, signature, sequence_before_author) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT DO NOTHING";
|
const char* query = "INSERT INTO messages (id, previous, author, sequence, timestamp, content, hash, signature, sequence_before_author) VALUES (?, ?, ?, ?, ?, ?, "
|
||||||
|
"?, ?, ?) ON CONFLICT DO NOTHING";
|
||||||
sqlite3_stmt* statement;
|
sqlite3_stmt* statement;
|
||||||
if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK &&
|
||||||
(previous ? sqlite3_bind_text(statement, 2, previous, -1, NULL) : sqlite3_bind_null(statement, 2)) == SQLITE_OK &&
|
(previous ? sqlite3_bind_text(statement, 2, previous, -1, NULL) : sqlite3_bind_null(statement, 2)) == SQLITE_OK &&
|
||||||
sqlite3_bind_text(statement, 3, author, -1, NULL) == SQLITE_OK &&
|
sqlite3_bind_text(statement, 3, author, -1, NULL) == SQLITE_OK && sqlite3_bind_int64(statement, 4, sequence) == SQLITE_OK &&
|
||||||
sqlite3_bind_int64(statement, 4, sequence) == SQLITE_OK &&
|
sqlite3_bind_double(statement, 5, timestamp) == SQLITE_OK && sqlite3_bind_text(statement, 6, content, content_len, NULL) == SQLITE_OK &&
|
||||||
sqlite3_bind_double(statement, 5, timestamp) == SQLITE_OK &&
|
sqlite3_bind_text(statement, 7, "sha256", 6, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 8, signature, -1, NULL) == SQLITE_OK &&
|
||||||
sqlite3_bind_text(statement, 6, content, content_len, NULL) == SQLITE_OK &&
|
|
||||||
sqlite3_bind_text(statement, 7, "sha256", 6, NULL) == SQLITE_OK &&
|
|
||||||
sqlite3_bind_text(statement, 8, signature, -1, NULL) == SQLITE_OK &&
|
|
||||||
sqlite3_bind_int(statement, 9, sequence_before_author) == SQLITE_OK)
|
sqlite3_bind_int(statement, 9, sequence_before_author) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
int r = sqlite3_step(statement);
|
int r = sqlite3_step(statement);
|
||||||
@ -344,10 +336,12 @@ static char* _tf_ssb_db_get_message_blob_wants(tf_ssb_t* ssb, int64_t rowid)
|
|||||||
char* result = NULL;
|
char* result = NULL;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
|
|
||||||
if (sqlite3_prepare(db, "SELECT DISTINCT json.value FROM messages, json_tree(messages.content) AS json LEFT OUTER JOIN blobs ON json.value = blobs.id WHERE messages.rowid = ?1 AND json.value LIKE '&%%.sha256' AND length(json.value) = ?2 AND blobs.content IS NULL", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db,
|
||||||
|
"SELECT DISTINCT json.value FROM messages, json_tree(messages.content) AS json LEFT OUTER JOIN blobs ON json.value = blobs.id WHERE messages.rowid = ?1 AND "
|
||||||
|
"json.value LIKE '&%%.sha256' AND length(json.value) = ?2 AND blobs.content IS NULL",
|
||||||
|
-1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_int64(statement, 1, rowid) == SQLITE_OK &&
|
if (sqlite3_bind_int64(statement, 1, rowid) == SQLITE_OK && sqlite3_bind_int(statement, 2, k_blob_id_len - 1) == SQLITE_OK)
|
||||||
sqlite3_bind_int(statement, 2, k_blob_id_len - 1) == SQLITE_OK)
|
|
||||||
{
|
{
|
||||||
int r = SQLITE_OK;
|
int r = SQLITE_OK;
|
||||||
while ((r = sqlite3_step(statement)) == SQLITE_ROW)
|
while ((r = sqlite3_step(statement)) == SQLITE_ROW)
|
||||||
@ -409,7 +403,8 @@ static void _tf_ssb_db_store_message_work(uv_work_t* work)
|
|||||||
tf_ssb_record_thread_busy(store->ssb, true);
|
tf_ssb_record_thread_busy(store->ssb, true);
|
||||||
tf_trace_t* trace = tf_ssb_get_trace(store->ssb);
|
tf_trace_t* trace = tf_ssb_get_trace(store->ssb);
|
||||||
tf_trace_begin(trace, "message_store_work");
|
tf_trace_begin(trace, "message_store_work");
|
||||||
int64_t last_row_id = _tf_ssb_db_store_message_raw(store->ssb, store->id, *store->previous ? store->previous : NULL, store->author, store->sequence, store->timestamp, store->content, store->length, store->signature, store->sequence_before_author);
|
int64_t last_row_id = _tf_ssb_db_store_message_raw(store->ssb, store->id, *store->previous ? store->previous : NULL, store->author, store->sequence, store->timestamp,
|
||||||
|
store->content, store->length, store->signature, store->sequence_before_author);
|
||||||
if (last_row_id != -1)
|
if (last_row_id != -1)
|
||||||
{
|
{
|
||||||
store->out_stored = true;
|
store->out_stored = true;
|
||||||
@ -466,15 +461,7 @@ static void _tf_ssb_db_store_message_after_work(uv_work_t* work, int status)
|
|||||||
tf_trace_begin(trace, "notify_message_added");
|
tf_trace_begin(trace, "notify_message_added");
|
||||||
JSContext* context = tf_ssb_get_context(store->ssb);
|
JSContext* context = tf_ssb_get_context(store->ssb);
|
||||||
JSValue formatted = tf_ssb_format_message(
|
JSValue formatted = tf_ssb_format_message(
|
||||||
context,
|
context, store->previous, store->author, store->sequence, store->timestamp, "sha256", store->content, store->signature, store->sequence_before_author);
|
||||||
store->previous,
|
|
||||||
store->author,
|
|
||||||
store->sequence,
|
|
||||||
store->timestamp,
|
|
||||||
"sha256",
|
|
||||||
store->content,
|
|
||||||
store->signature,
|
|
||||||
store->sequence_before_author);
|
|
||||||
JSValue message = JS_NewObject(context);
|
JSValue message = JS_NewObject(context);
|
||||||
JS_SetPropertyStr(context, message, "key", JS_NewString(context, store->id));
|
JS_SetPropertyStr(context, message, "key", JS_NewString(context, store->id));
|
||||||
JS_SetPropertyStr(context, message, "value", formatted);
|
JS_SetPropertyStr(context, message, "value", formatted);
|
||||||
@ -499,7 +486,8 @@ static void _tf_ssb_db_store_message_after_work(uv_work_t* work, int status)
|
|||||||
tf_trace_end(trace);
|
tf_trace_end(trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, JSValue val, const char* signature, bool sequence_before_author, tf_ssb_db_store_message_callback_t* callback, void* user_data)
|
void tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, JSValue val, const char* signature, bool sequence_before_author,
|
||||||
|
tf_ssb_db_store_message_callback_t* callback, void* user_data)
|
||||||
{
|
{
|
||||||
JSValue previousval = JS_GetPropertyStr(context, val, "previous");
|
JSValue previousval = JS_GetPropertyStr(context, val, "previous");
|
||||||
const char* previous = JS_IsNull(previousval) ? NULL : JS_ToCString(context, previousval);
|
const char* previous = JS_IsNull(previousval) ? NULL : JS_ToCString(context, previousval);
|
||||||
@ -573,8 +561,7 @@ bool tf_ssb_db_message_content_get(tf_ssb_t* ssb, const char* id, uint8_t** out_
|
|||||||
const char* query = "SELECT content FROM messages WHERE id = ?";
|
const char* query = "SELECT content FROM messages WHERE id = ?";
|
||||||
if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW)
|
||||||
sqlite3_step(statement) == SQLITE_ROW)
|
|
||||||
{
|
{
|
||||||
const uint8_t* blob = sqlite3_column_blob(statement, 0);
|
const uint8_t* blob = sqlite3_column_blob(statement, 0);
|
||||||
int size = sqlite3_column_bytes(statement, 0);
|
int size = sqlite3_column_bytes(statement, 0);
|
||||||
@ -604,8 +591,7 @@ bool tf_ssb_db_blob_has(tf_ssb_t* ssb, const char* id)
|
|||||||
const char* query = "SELECT COUNT(*) FROM blobs WHERE id = ?1";
|
const char* query = "SELECT COUNT(*) FROM blobs WHERE id = ?1";
|
||||||
if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW)
|
||||||
sqlite3_step(statement) == SQLITE_ROW)
|
|
||||||
{
|
{
|
||||||
result = sqlite3_column_int64(statement, 0) != 0;
|
result = sqlite3_column_int64(statement, 0) != 0;
|
||||||
}
|
}
|
||||||
@ -623,8 +609,7 @@ bool tf_ssb_db_blob_get(tf_ssb_t* ssb, const char* id, uint8_t** out_blob, size_
|
|||||||
const char* query = "SELECT content FROM blobs WHERE id = ?1";
|
const char* query = "SELECT content FROM blobs WHERE id = ?1";
|
||||||
if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW)
|
||||||
sqlite3_step(statement) == SQLITE_ROW)
|
|
||||||
{
|
{
|
||||||
const uint8_t* blob = sqlite3_column_blob(statement, 0);
|
const uint8_t* blob = sqlite3_column_blob(statement, 0);
|
||||||
int size = sqlite3_column_bytes(statement, 0);
|
int size = sqlite3_column_bytes(statement, 0);
|
||||||
@ -737,10 +722,10 @@ bool tf_ssb_db_blob_store(tf_ssb_t* ssb, const uint8_t* blob, size_t size, char*
|
|||||||
|
|
||||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||||
sqlite3_stmt* statement;
|
sqlite3_stmt* statement;
|
||||||
if (sqlite3_prepare(db, "INSERT INTO blobs (id, content, created) VALUES (?1, ?2, CAST(strftime('%s') AS INTEGER)) ON CONFLICT DO NOTHING", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "INSERT INTO blobs (id, content, created) VALUES (?1, ?2, CAST(strftime('%s') AS INTEGER)) ON CONFLICT DO NOTHING", -1, &statement, NULL) ==
|
||||||
|
SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK && sqlite3_bind_blob(statement, 2, blob, size, NULL) == SQLITE_OK)
|
||||||
sqlite3_bind_blob(statement, 2, blob, size, NULL) == SQLITE_OK)
|
|
||||||
{
|
{
|
||||||
result = sqlite3_step(statement) == SQLITE_DONE;
|
result = sqlite3_step(statement) == SQLITE_DONE;
|
||||||
rows = sqlite3_changes(db);
|
rows = sqlite3_changes(db);
|
||||||
@ -776,7 +761,8 @@ bool tf_ssb_db_blob_store(tf_ssb_t* ssb, const uint8_t* blob, size_t size, char*
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* author, int64_t sequence, char* out_message_id, size_t out_message_id_size, double* out_timestamp, char** out_content)
|
bool tf_ssb_db_get_message_by_author_and_sequence(
|
||||||
|
tf_ssb_t* ssb, const char* author, int64_t sequence, char* out_message_id, size_t out_message_id_size, double* out_timestamp, char** out_content)
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
sqlite3_stmt* statement;
|
sqlite3_stmt* statement;
|
||||||
@ -784,8 +770,7 @@ bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* aut
|
|||||||
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
||||||
if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, author, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, author, -1, NULL) == SQLITE_OK && sqlite3_bind_int64(statement, 2, sequence) == SQLITE_OK &&
|
||||||
sqlite3_bind_int64(statement, 2, sequence) == SQLITE_OK &&
|
|
||||||
sqlite3_step(statement) == SQLITE_ROW)
|
sqlite3_step(statement) == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
if (out_message_id)
|
if (out_message_id)
|
||||||
@ -820,8 +805,7 @@ bool tf_ssb_db_get_latest_message_by_author(tf_ssb_t* ssb, const char* author, i
|
|||||||
const char* query = "SELECT id, sequence FROM messages WHERE author = ?1 AND sequence = (SELECT MAX(sequence) FROM messages WHERE author = ?1)";
|
const char* query = "SELECT id, sequence FROM messages WHERE author = ?1 AND sequence = (SELECT MAX(sequence) FROM messages WHERE author = ?1)";
|
||||||
if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, author, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, author, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW)
|
||||||
sqlite3_step(statement) == SQLITE_ROW)
|
|
||||||
{
|
{
|
||||||
if (out_sequence)
|
if (out_sequence)
|
||||||
{
|
{
|
||||||
@ -942,20 +926,12 @@ int tf_ssb_sqlite_authorizer(void* user_data, int action_code, const char* arg0,
|
|||||||
result = SQLITE_OK;
|
result = SQLITE_OK;
|
||||||
break;
|
break;
|
||||||
case SQLITE_READ:
|
case SQLITE_READ:
|
||||||
result = (
|
result = (strcmp(arg0, "blob_wants_view") == 0 || strcmp(arg0, "json_each") == 0 || strcmp(arg0, "json_tree") == 0 || strcmp(arg0, "messages") == 0 ||
|
||||||
strcmp(arg0, "blob_wants_view") == 0 ||
|
strcmp(arg0, "messages_fts") == 0 || strcmp(arg0, "messages_fts_idx") == 0 || strcmp(arg0, "messages_fts_config") == 0 ||
|
||||||
strcmp(arg0, "json_each") == 0 ||
|
strcmp(arg0, "messages_refs") == 0 || strcmp(arg0, "messages_refs_message_idx") == 0 || strcmp(arg0, "messages_refs_ref_idx") == 0 ||
|
||||||
strcmp(arg0, "json_tree") == 0 ||
|
strcmp(arg0, "sqlite_master") == 0 || false)
|
||||||
strcmp(arg0, "messages") == 0 ||
|
? SQLITE_OK
|
||||||
strcmp(arg0, "messages_fts") == 0 ||
|
: SQLITE_DENY;
|
||||||
strcmp(arg0, "messages_fts_idx") == 0 ||
|
|
||||||
strcmp(arg0, "messages_fts_config") == 0 ||
|
|
||||||
strcmp(arg0, "messages_refs") == 0 ||
|
|
||||||
strcmp(arg0, "messages_refs_message_idx") == 0 ||
|
|
||||||
strcmp(arg0, "messages_refs_ref_idx") == 0 ||
|
|
||||||
strcmp(arg0, "sqlite_master") == 0 ||
|
|
||||||
false)
|
|
||||||
? SQLITE_OK : SQLITE_DENY;
|
|
||||||
break;
|
break;
|
||||||
case SQLITE_PRAGMA:
|
case SQLITE_PRAGMA:
|
||||||
result = strcmp(arg0, "data_version") == 0 ? SQLITE_OK : SQLITE_DENY;
|
result = strcmp(arg0, "data_version") == 0 ? SQLITE_OK : SQLITE_DENY;
|
||||||
@ -1012,7 +988,8 @@ JSValue tf_ssb_db_visit_query(tf_ssb_t* ssb, const char* query, const JSValue bi
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue tf_ssb_format_message(JSContext* context, const char* previous, const char* author, int64_t sequence, double timestamp, const char* hash, const char* content, const char* signature, bool sequence_before_author)
|
JSValue tf_ssb_format_message(JSContext* context, const char* previous, const char* author, int64_t sequence, double timestamp, const char* hash, const char* content,
|
||||||
|
const char* signature, bool sequence_before_author)
|
||||||
{
|
{
|
||||||
JSValue value = JS_NewObject(context);
|
JSValue value = JS_NewObject(context);
|
||||||
JS_SetPropertyStr(context, value, "previous", (previous && *previous) ? JS_NewString(context, previous) : JS_NULL);
|
JS_SetPropertyStr(context, value, "previous", (previous && *previous) ? JS_NewString(context, previous) : JS_NULL);
|
||||||
@ -1078,13 +1055,10 @@ bool tf_ssb_db_identity_add(tf_ssb_t* ssb, const char* user, const char* public_
|
|||||||
sqlite3_stmt* statement = NULL;
|
sqlite3_stmt* statement = NULL;
|
||||||
if (sqlite3_prepare(db, "INSERT INTO identities (user, public_key, private_key) VALUES (?, ?, ?) ON CONFLICT DO NOTHING", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "INSERT INTO identities (user, public_key, private_key) VALUES (?, ?, ?) ON CONFLICT DO NOTHING", -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, public_key, -1, NULL) == SQLITE_OK &&
|
||||||
sqlite3_bind_text(statement, 2, public_key, -1, NULL) == SQLITE_OK &&
|
|
||||||
sqlite3_bind_text(statement, 3, private_key, -1, NULL) == SQLITE_OK)
|
sqlite3_bind_text(statement, 3, private_key, -1, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
added =
|
added = sqlite3_step(statement) == SQLITE_DONE && sqlite3_changes(db) != 0;
|
||||||
sqlite3_step(statement) == SQLITE_DONE &&
|
|
||||||
sqlite3_changes(db) != 0;
|
|
||||||
if (!added)
|
if (!added)
|
||||||
{
|
{
|
||||||
tf_printf("Unable to add identity: %s.\n", sqlite3_errmsg(db));
|
tf_printf("Unable to add identity: %s.\n", sqlite3_errmsg(db));
|
||||||
@ -1104,12 +1078,9 @@ bool tf_ssb_db_identity_delete(tf_ssb_t* ssb, const char* user, const char* publ
|
|||||||
tf_printf("deleting [%s] [%s]\n", user, public_key);
|
tf_printf("deleting [%s] [%s]\n", user, public_key);
|
||||||
if (sqlite3_prepare(db, "DELETE FROM identities WHERE user = ? AND public_key = ?", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "DELETE FROM identities WHERE user = ? AND public_key = ?", -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, public_key, -1, NULL) == SQLITE_OK)
|
||||||
sqlite3_bind_text(statement, 2, public_key, -1, NULL) == SQLITE_OK)
|
|
||||||
{
|
{
|
||||||
removed =
|
removed = sqlite3_step(statement) == SQLITE_DONE && sqlite3_changes(db) != 0;
|
||||||
sqlite3_step(statement) == SQLITE_DONE &&
|
|
||||||
sqlite3_changes(db) != 0;
|
|
||||||
if (!removed)
|
if (!removed)
|
||||||
{
|
{
|
||||||
tf_printf("Unable to delete identity: %s.\n", sqlite3_errmsg(db));
|
tf_printf("Unable to delete identity: %s.\n", sqlite3_errmsg(db));
|
||||||
@ -1508,29 +1479,23 @@ const char** tf_ssb_db_get_all_visible_identities(tf_ssb_t* ssb, int depth)
|
|||||||
return following;
|
return following;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue tf_ssb_db_get_message_by_id( tf_ssb_t* ssb, const char* id, bool is_keys)
|
JSValue tf_ssb_db_get_message_by_id(tf_ssb_t* ssb, const char* id, bool is_keys)
|
||||||
{
|
{
|
||||||
JSValue result = JS_UNDEFINED;
|
JSValue result = JS_UNDEFINED;
|
||||||
JSContext* context = tf_ssb_get_context(ssb);
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
||||||
sqlite3_stmt* statement;
|
sqlite3_stmt* statement;
|
||||||
if (sqlite3_prepare(db, "SELECT previous, author, id, sequence, timestamp, hash, content, signature, sequence_before_author FROM messages WHERE id = ?", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "SELECT previous, author, id, sequence, timestamp, hash, content, signature, sequence_before_author FROM messages WHERE id = ?", -1, &statement,
|
||||||
|
NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK)
|
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_step(statement) == SQLITE_ROW)
|
if (sqlite3_step(statement) == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
JSValue message = JS_UNDEFINED;
|
JSValue message = JS_UNDEFINED;
|
||||||
JSValue formatted = tf_ssb_format_message(
|
JSValue formatted = tf_ssb_format_message(context, (const char*)sqlite3_column_text(statement, 0), (const char*)sqlite3_column_text(statement, 1),
|
||||||
context,
|
sqlite3_column_int64(statement, 3), sqlite3_column_double(statement, 4), (const char*)sqlite3_column_text(statement, 5),
|
||||||
(const char*)sqlite3_column_text(statement, 0),
|
(const char*)sqlite3_column_text(statement, 6), (const char*)sqlite3_column_text(statement, 7), sqlite3_column_int(statement, 8));
|
||||||
(const char*)sqlite3_column_text(statement, 1),
|
|
||||||
sqlite3_column_int64(statement, 3),
|
|
||||||
sqlite3_column_double(statement, 4),
|
|
||||||
(const char*)sqlite3_column_text(statement, 5),
|
|
||||||
(const char*)sqlite3_column_text(statement, 6),
|
|
||||||
(const char*)sqlite3_column_text(statement, 7),
|
|
||||||
sqlite3_column_int(statement, 8));
|
|
||||||
if (is_keys)
|
if (is_keys)
|
||||||
{
|
{
|
||||||
message = JS_NewObject(context);
|
message = JS_NewObject(context);
|
||||||
@ -1563,8 +1528,7 @@ tf_ssb_db_stored_connection_t* tf_ssb_db_get_stored_connections(tf_ssb_t* ssb, i
|
|||||||
while (sqlite3_step(statement) == SQLITE_ROW)
|
while (sqlite3_step(statement) == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
result = tf_resize_vec(result, sizeof(tf_ssb_db_stored_connection_t) * (count + 1));
|
result = tf_resize_vec(result, sizeof(tf_ssb_db_stored_connection_t) * (count + 1));
|
||||||
result[count] = (tf_ssb_db_stored_connection_t)
|
result[count] = (tf_ssb_db_stored_connection_t) {
|
||||||
{
|
|
||||||
.port = sqlite3_column_int(statement, 1),
|
.port = sqlite3_column_int(statement, 1),
|
||||||
};
|
};
|
||||||
snprintf(result[count].address, sizeof(result[count].address), "%s", (const char*)sqlite3_column_text(statement, 0));
|
snprintf(result[count].address, sizeof(result[count].address), "%s", (const char*)sqlite3_column_text(statement, 0));
|
||||||
@ -1585,10 +1549,8 @@ void tf_ssb_db_forget_stored_connection(tf_ssb_t* ssb, const char* address, int
|
|||||||
sqlite3_stmt* statement;
|
sqlite3_stmt* statement;
|
||||||
if (sqlite3_prepare(db, "DELETE FROM connections WHERE host = ? AND port = ? AND key = ?", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "DELETE FROM connections WHERE host = ? AND port = ? AND key = ?", -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, address, -1, NULL) != SQLITE_OK ||
|
if (sqlite3_bind_text(statement, 1, address, -1, NULL) != SQLITE_OK || sqlite3_bind_int(statement, 2, port) != SQLITE_OK ||
|
||||||
sqlite3_bind_int(statement, 2, port) != SQLITE_OK ||
|
sqlite3_bind_text(statement, 3, pubkey, -1, NULL) != SQLITE_OK || sqlite3_step(statement) != SQLITE_DONE)
|
||||||
sqlite3_bind_text(statement, 3, pubkey, -1, NULL) != SQLITE_OK ||
|
|
||||||
sqlite3_step(statement) != SQLITE_DONE)
|
|
||||||
{
|
{
|
||||||
tf_printf("Delete stored connection: %s.\n", sqlite3_errmsg(db));
|
tf_printf("Delete stored connection: %s.\n", sqlite3_errmsg(db));
|
||||||
}
|
}
|
||||||
|
24
src/ssb.db.h
24
src/ssb.db.h
@ -14,15 +14,17 @@ bool tf_ssb_db_message_content_get(tf_ssb_t* ssb, const char* id, uint8_t** out_
|
|||||||
bool tf_ssb_db_blob_has(tf_ssb_t* ssb, const char* id);
|
bool tf_ssb_db_blob_has(tf_ssb_t* ssb, const char* id);
|
||||||
bool tf_ssb_db_blob_get(tf_ssb_t* ssb, const char* id, uint8_t** out_blob, size_t* out_size);
|
bool tf_ssb_db_blob_get(tf_ssb_t* ssb, const char* id, uint8_t** out_blob, size_t* out_size);
|
||||||
|
|
||||||
typedef void (tf_ssb_db_store_message_callback_t)(const char* id, bool stored, void* user_data);
|
typedef void(tf_ssb_db_store_message_callback_t)(const char* id, bool stored, void* user_data);
|
||||||
void tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, JSValue val, const char* signature, bool sequence_before_author, tf_ssb_db_store_message_callback_t* callback, void* user_data);
|
void tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id, JSValue val, const char* signature, bool sequence_before_author,
|
||||||
|
tf_ssb_db_store_message_callback_t* callback, void* user_data);
|
||||||
|
|
||||||
typedef void (tf_ssb_db_blob_store_callback_t)(const char* id, bool is_new, void* user_data);
|
typedef void(tf_ssb_db_blob_store_callback_t)(const char* id, bool is_new, void* user_data);
|
||||||
void tf_ssb_db_blob_store_async(tf_ssb_t* ssb, const uint8_t* blob, size_t size, tf_ssb_db_blob_store_callback_t* callback, void* user_data);
|
void tf_ssb_db_blob_store_async(tf_ssb_t* ssb, const uint8_t* blob, size_t size, tf_ssb_db_blob_store_callback_t* callback, void* user_data);
|
||||||
bool tf_ssb_db_blob_store(tf_ssb_t* ssb, const uint8_t* blob, size_t size, char* out_id, size_t out_id_size, bool* out_new);
|
bool tf_ssb_db_blob_store(tf_ssb_t* ssb, const uint8_t* blob, size_t size, char* out_id, size_t out_id_size, bool* out_new);
|
||||||
|
|
||||||
JSValue tf_ssb_db_get_message_by_id( tf_ssb_t* ssb, const char* id, bool is_keys);
|
JSValue tf_ssb_db_get_message_by_id(tf_ssb_t* ssb, const char* id, bool is_keys);
|
||||||
bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* author, int64_t sequence, char* out_message_id, size_t out_message_id_size, double* out_timestamp, char** out_content);
|
bool tf_ssb_db_get_message_by_author_and_sequence(
|
||||||
|
tf_ssb_t* ssb, const char* author, int64_t sequence, char* out_message_id, size_t out_message_id_size, double* out_timestamp, char** out_content);
|
||||||
bool tf_ssb_db_get_latest_message_by_author(tf_ssb_t* ssb, const char* author, int64_t* out_sequence, char* out_message_id, size_t out_message_id_size);
|
bool tf_ssb_db_get_latest_message_by_author(tf_ssb_t* ssb, const char* author, int64_t* out_sequence, char* out_message_id, size_t out_message_id_size);
|
||||||
JSValue tf_ssb_db_visit_query(tf_ssb_t* ssb, const char* query, const JSValue binds, void (*callback)(JSValue row, void* user_data), void* user_data);
|
JSValue tf_ssb_db_visit_query(tf_ssb_t* ssb, const char* query, const JSValue binds, void (*callback)(JSValue row, void* user_data), void* user_data);
|
||||||
|
|
||||||
@ -37,16 +39,8 @@ void tf_ssb_db_identity_visit(tf_ssb_t* ssb, const char* user, void (*callback)(
|
|||||||
void tf_ssb_db_identity_visit_all(tf_ssb_t* ssb, void (*callback)(const char* identity, void* user_data), void* user_data);
|
void tf_ssb_db_identity_visit_all(tf_ssb_t* ssb, void (*callback)(const char* identity, void* user_data), void* user_data);
|
||||||
bool tf_ssb_db_identity_get_private_key(tf_ssb_t* ssb, const char* user, const char* public_key, uint8_t* out_private_key, size_t private_key_size);
|
bool tf_ssb_db_identity_get_private_key(tf_ssb_t* ssb, const char* user, const char* public_key, uint8_t* out_private_key, size_t private_key_size);
|
||||||
|
|
||||||
JSValue tf_ssb_format_message(
|
JSValue tf_ssb_format_message(JSContext* context, const char* previous, const char* author, int64_t sequence, double timestamp, const char* hash, const char* content,
|
||||||
JSContext* context,
|
const char* signature, bool sequence_before_author);
|
||||||
const char* previous,
|
|
||||||
const char* author,
|
|
||||||
int64_t sequence,
|
|
||||||
double timestamp,
|
|
||||||
const char* hash,
|
|
||||||
const char* content,
|
|
||||||
const char* signature,
|
|
||||||
bool sequence_before_author);
|
|
||||||
|
|
||||||
typedef struct _tf_ssb_following_t
|
typedef struct _tf_ssb_following_t
|
||||||
{
|
{
|
||||||
|
@ -92,8 +92,7 @@ void tf_ssb_export(tf_ssb_t* ssb, const char* key)
|
|||||||
sqlite3_stmt* statement;
|
sqlite3_stmt* statement;
|
||||||
if (sqlite3_prepare(db, "SELECT value FROM properties WHERE id = ?1 AND key = 'path:' || ?2", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "SELECT value FROM properties WHERE id = ?1 AND key = 'path:' || ?2", -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, path, -1, NULL) == SQLITE_OK &&
|
||||||
sqlite3_bind_text(statement, 2, path, -1, NULL) == SQLITE_OK &&
|
|
||||||
sqlite3_step(statement) == SQLITE_ROW)
|
sqlite3_step(statement) == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
int len = sqlite3_column_bytes(statement, 0);
|
int len = sqlite3_column_bytes(statement, 0);
|
||||||
@ -206,4 +205,3 @@ void tf_ssb_export(tf_ssb_t* ssb, const char* key)
|
|||||||
JS_FreeValue(context, files);
|
JS_FreeValue(context, files);
|
||||||
JS_FreeValue(context, app);
|
JS_FreeValue(context, app);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
41
src/ssb.h
41
src/ssb.h
@ -39,7 +39,8 @@ typedef struct sqlite3 sqlite3;
|
|||||||
typedef struct uv_loop_s uv_loop_t;
|
typedef struct uv_loop_s uv_loop_t;
|
||||||
struct sockaddr_in;
|
struct sockaddr_in;
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
k_id_base64_len = 57,
|
k_id_base64_len = 57,
|
||||||
k_id_bin_len = 32,
|
k_id_bin_len = 32,
|
||||||
k_blob_id_len = 53,
|
k_blob_id_len = 53,
|
||||||
@ -106,7 +107,8 @@ void tf_ssb_run(tf_ssb_t* ssb);
|
|||||||
JSValue tf_ssb_sign_message(tf_ssb_t* ssb, const char* author, const uint8_t* private_key, JSValue message);
|
JSValue tf_ssb_sign_message(tf_ssb_t* ssb, const char* author, const uint8_t* private_key, JSValue message);
|
||||||
bool tf_ssb_whoami(tf_ssb_t* ssb, char* out_id, size_t out_id_size);
|
bool tf_ssb_whoami(tf_ssb_t* ssb, char* out_id, size_t out_id_size);
|
||||||
|
|
||||||
void tf_ssb_visit_broadcasts(tf_ssb_t* ssb, void (*callback)(const char* host, const struct sockaddr_in* addr, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data), void* user_data);
|
void tf_ssb_visit_broadcasts(
|
||||||
|
tf_ssb_t* ssb, void (*callback)(const char* host, const struct sockaddr_in* addr, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data), void* user_data);
|
||||||
|
|
||||||
const char** tf_ssb_get_connection_ids(tf_ssb_t* ssb);
|
const char** tf_ssb_get_connection_ids(tf_ssb_t* ssb);
|
||||||
int tf_ssb_get_connections(tf_ssb_t* ssb, tf_ssb_connection_t** out_connections, int out_connections_count);
|
int tf_ssb_get_connections(tf_ssb_t* ssb, tf_ssb_connection_t** out_connections, int out_connections_count);
|
||||||
@ -121,9 +123,10 @@ void tf_ssb_send_close(tf_ssb_t* ssb);
|
|||||||
bool tf_ssb_id_str_to_bin(uint8_t* bin, const char* str);
|
bool tf_ssb_id_str_to_bin(uint8_t* bin, const char* str);
|
||||||
bool tf_ssb_id_bin_to_str(char* str, size_t str_size, const uint8_t* bin);
|
bool tf_ssb_id_bin_to_str(char* str, size_t str_size, const uint8_t* bin);
|
||||||
|
|
||||||
bool tf_ssb_verify_and_strip_signature(JSContext* context, JSValue val, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size, bool* out_sequence_before_author);
|
bool tf_ssb_verify_and_strip_signature(
|
||||||
|
JSContext* context, JSValue val, char* out_id, size_t out_id_size, char* out_signature, size_t out_signature_size, bool* out_sequence_before_author);
|
||||||
void tf_ssb_calculate_message_id(JSContext* context, JSValue message, char* out_id, size_t out_id_size);
|
void tf_ssb_calculate_message_id(JSContext* context, JSValue message, char* out_id, size_t out_id_size);
|
||||||
typedef void (tf_ssb_verify_strip_store_callback_t)(const char* id, bool verified, bool is_new, void* user_data);
|
typedef void(tf_ssb_verify_strip_store_callback_t)(const char* id, bool verified, bool is_new, void* user_data);
|
||||||
void tf_ssb_verify_strip_and_store_message(tf_ssb_t* ssb, JSValue value, tf_ssb_verify_strip_store_callback_t* callback, void* user_data);
|
void tf_ssb_verify_strip_and_store_message(tf_ssb_t* ssb, JSValue value, tf_ssb_verify_strip_store_callback_t* callback, void* user_data);
|
||||||
|
|
||||||
bool tf_ssb_connection_is_client(tf_ssb_connection_t* connection);
|
bool tf_ssb_connection_is_client(tf_ssb_connection_t* connection);
|
||||||
@ -143,44 +146,44 @@ bool tf_ssb_connection_get_id(tf_ssb_connection_t* connection, char* out_id, siz
|
|||||||
JSValue tf_ssb_connection_get_object(tf_ssb_connection_t* connection);
|
JSValue tf_ssb_connection_get_object(tf_ssb_connection_t* connection);
|
||||||
|
|
||||||
/* Callbacks. */
|
/* Callbacks. */
|
||||||
typedef void (tf_ssb_callback_cleanup_t)(tf_ssb_t* ssb, void* user_data);
|
typedef void(tf_ssb_callback_cleanup_t)(tf_ssb_t* ssb, void* user_data);
|
||||||
typedef void (tf_ssb_connections_changed_callback_t)(tf_ssb_t* ssb, tf_ssb_change_t change, tf_ssb_connection_t* connection, void* user_data);
|
typedef void(tf_ssb_connections_changed_callback_t)(tf_ssb_t* ssb, tf_ssb_change_t change, tf_ssb_connection_t* connection, void* user_data);
|
||||||
void tf_ssb_add_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_connections_changed_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
void tf_ssb_add_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_connections_changed_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
||||||
void tf_ssb_remove_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_connections_changed_callback_t* callback, void* user_data);
|
void tf_ssb_remove_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_connections_changed_callback_t* callback, void* user_data);
|
||||||
|
|
||||||
typedef void (tf_ssb_broadcasts_changed_callback_t)(tf_ssb_t* ssb, void* user_data);
|
typedef void(tf_ssb_broadcasts_changed_callback_t)(tf_ssb_t* ssb, void* user_data);
|
||||||
void tf_ssb_add_broadcasts_changed_callback(tf_ssb_t* ssb, tf_ssb_broadcasts_changed_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
void tf_ssb_add_broadcasts_changed_callback(tf_ssb_t* ssb, tf_ssb_broadcasts_changed_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
||||||
void tf_ssb_remove_broadcasts_changed_callback(tf_ssb_t* ssb, tf_ssb_broadcasts_changed_callback_t* callback, void* user_data);
|
void tf_ssb_remove_broadcasts_changed_callback(tf_ssb_t* ssb, tf_ssb_broadcasts_changed_callback_t* callback, void* user_data);
|
||||||
|
|
||||||
typedef void (tf_ssb_message_added_callback_t)(tf_ssb_t* ssb, const char* id, void* user_data);
|
typedef void(tf_ssb_message_added_callback_t)(tf_ssb_t* ssb, const char* id, void* user_data);
|
||||||
void tf_ssb_add_message_added_callback(tf_ssb_t* ssb, tf_ssb_message_added_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
void tf_ssb_add_message_added_callback(tf_ssb_t* ssb, tf_ssb_message_added_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
||||||
void tf_ssb_remove_message_added_callback(tf_ssb_t* ssb, tf_ssb_message_added_callback_t* callback, void* user_data);
|
void tf_ssb_remove_message_added_callback(tf_ssb_t* ssb, tf_ssb_message_added_callback_t* callback, void* user_data);
|
||||||
void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* id, JSValue message_with_keys);
|
void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* id, JSValue message_with_keys);
|
||||||
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);
|
||||||
|
|
||||||
typedef void (tf_ssb_blob_want_added_callback_t)(tf_ssb_t* ssb, const char* id, void* user_data);
|
typedef void(tf_ssb_blob_want_added_callback_t)(tf_ssb_t* ssb, const char* id, void* user_data);
|
||||||
void tf_ssb_add_blob_want_added_callback(tf_ssb_t* ssb, tf_ssb_blob_want_added_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
void tf_ssb_add_blob_want_added_callback(tf_ssb_t* ssb, tf_ssb_blob_want_added_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
||||||
void tf_ssb_remove_blob_want_added_callback(tf_ssb_t* ssb, tf_ssb_blob_want_added_callback_t* callback, void* user_data);
|
void tf_ssb_remove_blob_want_added_callback(tf_ssb_t* ssb, tf_ssb_blob_want_added_callback_t* callback, void* user_data);
|
||||||
void tf_ssb_notify_blob_want_added(tf_ssb_t* ssb, const char* id);
|
void tf_ssb_notify_blob_want_added(tf_ssb_t* ssb, const char* id);
|
||||||
|
|
||||||
typedef void (tf_ssb_rpc_callback_t)(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data);
|
typedef void(tf_ssb_rpc_callback_t)(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data);
|
||||||
void tf_ssb_add_rpc_callback(tf_ssb_t* ssb, const char** name, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
void tf_ssb_add_rpc_callback(tf_ssb_t* ssb, const char** name, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
||||||
void tf_ssb_remove_rpc_callback(tf_ssb_t* ssb, const char** name, tf_ssb_rpc_callback_t* callback, void* user_data);
|
void tf_ssb_remove_rpc_callback(tf_ssb_t* ssb, const char** name, tf_ssb_rpc_callback_t* callback, void* user_data);
|
||||||
|
|
||||||
void tf_ssb_connection_rpc_send(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, const uint8_t* message, size_t size, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
void tf_ssb_connection_rpc_send(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, const uint8_t* message, size_t size, tf_ssb_rpc_callback_t* callback,
|
||||||
void tf_ssb_connection_rpc_send_json(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue message, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
||||||
|
void tf_ssb_connection_rpc_send_json(
|
||||||
|
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue message, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
||||||
void tf_ssb_connection_rpc_send_error(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, const char* error);
|
void tf_ssb_connection_rpc_send_error(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, const char* error);
|
||||||
void tf_ssb_connection_rpc_send_error_method_not_allowed(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, const char* name);
|
void tf_ssb_connection_rpc_send_error_method_not_allowed(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, const char* name);
|
||||||
void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t request_number, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data, tf_ssb_connection_t* dependent_connection);
|
void tf_ssb_connection_add_request(tf_ssb_connection_t* connection, int32_t request_number, tf_ssb_rpc_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data,
|
||||||
|
tf_ssb_connection_t* dependent_connection);
|
||||||
void tf_ssb_connection_remove_request(tf_ssb_connection_t* connection, int32_t request_number);
|
void tf_ssb_connection_remove_request(tf_ssb_connection_t* connection, int32_t request_number);
|
||||||
|
|
||||||
typedef void (tf_ssb_scheduled_callback_t)(tf_ssb_connection_t* connection, void* user_data);
|
typedef void(tf_ssb_scheduled_callback_t)(tf_ssb_connection_t* connection, void* user_data);
|
||||||
void tf_ssb_connection_schedule_idle(tf_ssb_connection_t* connection, tf_ssb_scheduled_callback_t* callback, void* user_data);
|
void tf_ssb_connection_schedule_idle(tf_ssb_connection_t* connection, tf_ssb_scheduled_callback_t* callback, void* user_data);
|
||||||
void tf_ssb_connection_run_work(
|
void tf_ssb_connection_run_work(tf_ssb_connection_t* connection, void (*work_callback)(tf_ssb_connection_t* connection, void* user_data),
|
||||||
tf_ssb_connection_t* connection,
|
void (*after_work_callback)(tf_ssb_connection_t* connection, int result, void* user_data), void* user_data);
|
||||||
void (*work_callback)(tf_ssb_connection_t* connection, void* user_data),
|
|
||||||
void (*after_work_callback)(tf_ssb_connection_t* connection, int result, void* user_data),
|
|
||||||
void* user_data);
|
|
||||||
|
|
||||||
void tf_ssb_connection_add_new_message_request(tf_ssb_connection_t* connection, const char* author, int32_t request_number, bool keys);
|
void tf_ssb_connection_add_new_message_request(tf_ssb_connection_t* connection, const char* author, int32_t request_number, bool keys);
|
||||||
void tf_ssb_connection_remove_new_message_request(tf_ssb_connection_t* connection, const char* author);
|
void tf_ssb_connection_remove_new_message_request(tf_ssb_connection_t* connection, const char* author);
|
||||||
|
@ -23,8 +23,7 @@ static void _tf_ssb_import_add_app(tf_ssb_t* ssb, const char* user, const char*
|
|||||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||||
if (sqlite3_prepare(db, "SELECT value FROM properties WHERE id = ?1 AND key = 'apps'", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "SELECT value FROM properties WHERE id = ?1 AND key = 'apps'", -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_ROW)
|
||||||
sqlite3_step(statement) == SQLITE_ROW)
|
|
||||||
{
|
{
|
||||||
const char* json = (const char*)sqlite3_column_text(statement, 0);
|
const char* json = (const char*)sqlite3_column_text(statement, 0);
|
||||||
apps = JS_ParseJSON(context, json, strlen(json), NULL);
|
apps = JS_ParseJSON(context, json, strlen(json), NULL);
|
||||||
@ -71,8 +70,7 @@ static void _tf_ssb_import_add_app(tf_ssb_t* ssb, const char* user, const char*
|
|||||||
const char* text = JS_ToCString(context, json);
|
const char* text = JS_ToCString(context, json);
|
||||||
if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES (?1, 'apps', ?2)", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES (?1, 'apps', ?2)", -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, text, -1, NULL) == SQLITE_OK &&
|
||||||
sqlite3_bind_text(statement, 2, text, -1, NULL) == SQLITE_OK &&
|
|
||||||
sqlite3_step(statement) == SQLITE_OK)
|
sqlite3_step(statement) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -166,10 +164,8 @@ static bool _tf_ssb_register_app(tf_ssb_t* ssb, const char* user, const char* ap
|
|||||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||||
if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES (?1, 'path:' || ?2, ?3)", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES (?1, 'path:' || ?2, ?3)", -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, user, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, app, -1, NULL) == SQLITE_OK &&
|
||||||
sqlite3_bind_text(statement, 2, app, -1, NULL) == SQLITE_OK &&
|
sqlite3_bind_text(statement, 3, id, -1, NULL) == SQLITE_OK && sqlite3_step(statement) == SQLITE_DONE)
|
||||||
sqlite3_bind_text(statement, 3, id, -1, NULL) == SQLITE_OK &&
|
|
||||||
sqlite3_step(statement) == SQLITE_DONE)
|
|
||||||
{
|
{
|
||||||
result = sqlite3_changes(db) != 0;
|
result = sqlite3_changes(db) != 0;
|
||||||
}
|
}
|
||||||
@ -242,8 +238,7 @@ void tf_ssb_import(tf_ssb_t* ssb, const char* user, const char* path)
|
|||||||
size_t len = strlen(path) + strlen(ent.name) + 2;
|
size_t len = strlen(path) + strlen(ent.name) + 2;
|
||||||
char* full_path = tf_malloc(len);
|
char* full_path = tf_malloc(len);
|
||||||
snprintf(full_path, len, "%s/%s", path, ent.name);
|
snprintf(full_path, len, "%s/%s", path, ent.name);
|
||||||
if (strlen(ent.name) > strlen(".json") &&
|
if (strlen(ent.name) > strlen(".json") && strcasecmp(ent.name + strlen(ent.name) - strlen(".json"), ".json") == 0)
|
||||||
strcasecmp(ent.name + strlen(ent.name) - strlen(".json"), ".json") == 0)
|
|
||||||
{
|
{
|
||||||
_tf_ssb_import_app_json(ssb, tf_ssb_get_loop(ssb), tf_ssb_get_context(ssb), user, full_path);
|
_tf_ssb_import_app_json(ssb, tf_ssb_get_loop(ssb), tf_ssb_get_context(ssb), user, full_path);
|
||||||
}
|
}
|
||||||
@ -290,8 +285,7 @@ static void _tf_ssb_import_recursive_add_files_from_zip(tf_ssb_t* ssb, unzFile z
|
|||||||
unz_file_info64 info = { 0 };
|
unz_file_info64 info = { 0 };
|
||||||
if (unzGetCurrentFileInfo64(zip, &info, file_path, sizeof(file_path), NULL, 0, NULL, 0) == UNZ_OK)
|
if (unzGetCurrentFileInfo64(zip, &info, file_path, sizeof(file_path), NULL, 0, NULL, 0) == UNZ_OK)
|
||||||
{
|
{
|
||||||
if (strncmp(file_path, root, strlen(root)) == 0 &&
|
if (strncmp(file_path, root, strlen(root)) == 0 && file_path[strlen(root)] == '/')
|
||||||
file_path[strlen(root)] == '/')
|
|
||||||
{
|
{
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
char* blob = _tf_ssb_import_read_current_file_from_zip(zip, &size);
|
char* blob = _tf_ssb_import_read_current_file_from_zip(zip, &size);
|
||||||
@ -306,8 +300,7 @@ static void _tf_ssb_import_recursive_add_files_from_zip(tf_ssb_t* ssb, unzFile z
|
|||||||
tf_free(blob);
|
tf_free(blob);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} while (unzGoToNextFile(zip) == UNZ_OK);
|
||||||
while (unzGoToNextFile(zip) == UNZ_OK);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,9 +359,7 @@ void tf_ssb_import_from_zip(tf_ssb_t* ssb, const char* zip_path, const char* use
|
|||||||
unz_file_info64 info = { 0 };
|
unz_file_info64 info = { 0 };
|
||||||
if (unzGetCurrentFileInfo64(zip, &info, file_path, sizeof(file_path), NULL, 0, NULL, 0) == UNZ_OK)
|
if (unzGetCurrentFileInfo64(zip, &info, file_path, sizeof(file_path), NULL, 0, NULL, 0) == UNZ_OK)
|
||||||
{
|
{
|
||||||
if (strncmp(file_path, path, strlen(path)) == 0 &&
|
if (strncmp(file_path, path, strlen(path)) == 0 && !strchr(file_path + strlen(path) + 1, '/') && strlen(file_path) > strlen(".json") &&
|
||||||
!strchr(file_path + strlen(path) + 1, '/') &&
|
|
||||||
strlen(file_path) > strlen(".json") &&
|
|
||||||
strcasecmp(file_path + strlen(file_path) - strlen(".json"), ".json") == 0)
|
strcasecmp(file_path + strlen(file_path) - strlen(".json"), ".json") == 0)
|
||||||
{
|
{
|
||||||
unz_file_pos pos = { 0 };
|
unz_file_pos pos = { 0 };
|
||||||
@ -377,8 +368,7 @@ void tf_ssb_import_from_zip(tf_ssb_t* ssb, const char* zip_path, const char* use
|
|||||||
unzGoToFilePos(zip, &pos);
|
unzGoToFilePos(zip, &pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} while (unzGoToNextFile(zip) == UNZ_OK);
|
||||||
while (unzGoToNextFile(zip) == UNZ_OK);
|
|
||||||
}
|
}
|
||||||
unzClose(zip);
|
unzClose(zip);
|
||||||
}
|
}
|
||||||
|
51
src/ssb.js.c
51
src/ssb.js.c
@ -94,8 +94,7 @@ static JSValue _tf_ssb_addIdentity(JSContext* context, JSValueConst this_val, in
|
|||||||
unsigned char seed[crypto_sign_SEEDBYTES];
|
unsigned char seed[crypto_sign_SEEDBYTES];
|
||||||
uint8_t secret_key[crypto_sign_SECRETKEYBYTES] = { 0 };
|
uint8_t secret_key[crypto_sign_SECRETKEYBYTES] = { 0 };
|
||||||
memcpy(secret_key, array, sizeof(secret_key) / 2);
|
memcpy(secret_key, array, sizeof(secret_key) / 2);
|
||||||
if (crypto_sign_ed25519_sk_to_seed(seed, secret_key) == 0 &&
|
if (crypto_sign_ed25519_sk_to_seed(seed, secret_key) == 0 && crypto_sign_seed_keypair(public_key, secret_key, seed) == 0)
|
||||||
crypto_sign_seed_keypair(public_key, secret_key, seed) == 0)
|
|
||||||
{
|
{
|
||||||
char public_key_b64[512];
|
char public_key_b64[512];
|
||||||
tf_base64_encode(public_key, sizeof(public_key), public_key_b64, sizeof(public_key_b64));
|
tf_base64_encode(public_key, sizeof(public_key), public_key_b64, sizeof(public_key_b64));
|
||||||
@ -170,8 +169,7 @@ static JSValue _set_server_following_internal(tf_ssb_t* ssb, JSValueConst this_v
|
|||||||
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "contact"));
|
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "contact"));
|
||||||
JS_SetPropertyStr(context, message, "contact", JS_DupValue(context, id));
|
JS_SetPropertyStr(context, message, "contact", JS_DupValue(context, id));
|
||||||
JS_SetPropertyStr(context, message, "following", JS_DupValue(context, following));
|
JS_SetPropertyStr(context, message, "following", JS_DupValue(context, following));
|
||||||
JSValue args[] =
|
JSValue args[] = {
|
||||||
{
|
|
||||||
server_user,
|
server_user,
|
||||||
server_id,
|
server_id,
|
||||||
message,
|
message,
|
||||||
@ -246,8 +244,7 @@ static JSValue _tf_ssb_getIdentities(JSContext* context, JSValueConst this_val,
|
|||||||
if (ssb)
|
if (ssb)
|
||||||
{
|
{
|
||||||
const char* user = JS_ToCString(context, argv[0]);
|
const char* user = JS_ToCString(context, argv[0]);
|
||||||
identities_visit_t state =
|
identities_visit_t state = {
|
||||||
{
|
|
||||||
.context = context,
|
.context = context,
|
||||||
.array = result,
|
.array = result,
|
||||||
};
|
};
|
||||||
@ -294,8 +291,7 @@ static JSValue _tf_ssb_getAllIdentities(JSContext* context, JSValueConst this_va
|
|||||||
tf_ssb_t* ssb = JS_GetOpaque(this_val, _tf_ssb_classId);
|
tf_ssb_t* ssb = JS_GetOpaque(this_val, _tf_ssb_classId);
|
||||||
if (ssb)
|
if (ssb)
|
||||||
{
|
{
|
||||||
identities_visit_t state =
|
identities_visit_t state = {
|
||||||
{
|
|
||||||
.context = context,
|
.context = context,
|
||||||
.array = result,
|
.array = result,
|
||||||
};
|
};
|
||||||
@ -747,8 +743,7 @@ static void _tf_ssb_sqlAsync_handle_close(uv_handle_t* handle)
|
|||||||
{
|
{
|
||||||
sql_work_t* work = handle->data;
|
sql_work_t* work = handle->data;
|
||||||
handle->data = NULL;
|
handle->data = NULL;
|
||||||
if (!work->async.data &&
|
if (!work->async.data && !work->timeout.data)
|
||||||
!work->timeout.data)
|
|
||||||
{
|
{
|
||||||
tf_free(work);
|
tf_free(work);
|
||||||
}
|
}
|
||||||
@ -1153,8 +1148,7 @@ static void _tf_ssb_on_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_change
|
|||||||
case k_tf_ssb_change_connect:
|
case k_tf_ssb_change_connect:
|
||||||
{
|
{
|
||||||
JSValue object = JS_DupValue(context, tf_ssb_connection_get_object(connection));
|
JSValue object = JS_DupValue(context, tf_ssb_connection_get_object(connection));
|
||||||
JSValue args[] =
|
JSValue args[] = {
|
||||||
{
|
|
||||||
JS_NewString(context, "add"),
|
JS_NewString(context, "add"),
|
||||||
object,
|
object,
|
||||||
};
|
};
|
||||||
@ -1170,8 +1164,7 @@ static void _tf_ssb_on_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_change
|
|||||||
case k_tf_ssb_change_remove:
|
case k_tf_ssb_change_remove:
|
||||||
{
|
{
|
||||||
JSValue object = JS_DupValue(context, tf_ssb_connection_get_object(connection));
|
JSValue object = JS_DupValue(context, tf_ssb_connection_get_object(connection));
|
||||||
JSValue args[] =
|
JSValue args[] = {
|
||||||
{
|
|
||||||
JS_NewString(context, "remove"),
|
JS_NewString(context, "remove"),
|
||||||
object,
|
object,
|
||||||
};
|
};
|
||||||
@ -1394,7 +1387,10 @@ static JSValue _tf_ssb_createTunnel(JSContext* context, JSValueConst this_val, i
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum { k_max_private_message_recipients = 8 };
|
enum
|
||||||
|
{
|
||||||
|
k_max_private_message_recipients = 8
|
||||||
|
};
|
||||||
|
|
||||||
static bool _tf_ssb_get_private_key_curve25519(sqlite3* db, const char* user, const char* identity, uint8_t out_private_key[static crypto_sign_SECRETKEYBYTES])
|
static bool _tf_ssb_get_private_key_curve25519(sqlite3* db, const char* user, const char* identity, uint8_t out_private_key[static crypto_sign_SECRETKEYBYTES])
|
||||||
{
|
{
|
||||||
@ -1414,11 +1410,8 @@ static bool _tf_ssb_get_private_key_curve25519(sqlite3* db, const char* user, co
|
|||||||
while (sqlite3_step(statement) == SQLITE_ROW)
|
while (sqlite3_step(statement) == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
uint8_t key[crypto_sign_SECRETKEYBYTES] = { 0 };
|
uint8_t key[crypto_sign_SECRETKEYBYTES] = { 0 };
|
||||||
int length = tf_base64_decode(
|
int length =
|
||||||
(const char*)sqlite3_column_text(statement, 0),
|
tf_base64_decode((const char*)sqlite3_column_text(statement, 0), sqlite3_column_bytes(statement, 0) - strlen(".ed25519"), key, sizeof(key));
|
||||||
sqlite3_column_bytes(statement, 0) - strlen(".ed25519"),
|
|
||||||
key,
|
|
||||||
sizeof(key));
|
|
||||||
if (length == crypto_sign_SECRETKEYBYTES)
|
if (length == crypto_sign_SECRETKEYBYTES)
|
||||||
{
|
{
|
||||||
success = crypto_sign_ed25519_sk_to_curve25519(out_private_key, key) == 0;
|
success = crypto_sign_ed25519_sk_to_curve25519(out_private_key, key) == 0;
|
||||||
@ -1489,10 +1482,8 @@ static JSValue _tf_ssb_private_message_encrypt(JSContext* context, JSValueConst
|
|||||||
length_and_key[0] = (uint8_t)recipient_count;
|
length_and_key[0] = (uint8_t)recipient_count;
|
||||||
memcpy(length_and_key + 1, body_key, sizeof(body_key));
|
memcpy(length_and_key + 1, body_key, sizeof(body_key));
|
||||||
|
|
||||||
size_t payload_size = sizeof(nonce) +
|
size_t payload_size =
|
||||||
sizeof(public_key) +
|
sizeof(nonce) + sizeof(public_key) + (crypto_secretbox_MACBYTES + sizeof(length_and_key)) * recipient_count + crypto_secretbox_MACBYTES + message_size;
|
||||||
(crypto_secretbox_MACBYTES + sizeof(length_and_key)) * recipient_count +
|
|
||||||
crypto_secretbox_MACBYTES + message_size;
|
|
||||||
|
|
||||||
uint8_t* payload = tf_malloc(payload_size);
|
uint8_t* payload = tf_malloc(payload_size);
|
||||||
|
|
||||||
@ -1554,7 +1545,6 @@ static JSValue _tf_ssb_private_message_encrypt(JSContext* context, JSValueConst
|
|||||||
JS_FreeCString(context, signer_identity);
|
JS_FreeCString(context, signer_identity);
|
||||||
JS_FreeCString(context, message);
|
JS_FreeCString(context, message);
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue _tf_ssb_private_message_decrypt(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
static JSValue _tf_ssb_private_message_decrypt(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||||
@ -1583,8 +1573,12 @@ static JSValue _tf_ssb_private_message_decrypt(JSContext* context, JSValueConst
|
|||||||
uint8_t shared_secret[crypto_secretbox_KEYBYTES] = { 0 };
|
uint8_t shared_secret[crypto_secretbox_KEYBYTES] = { 0 };
|
||||||
if (crypto_scalarmult(shared_secret, private_key, public_key) == 0)
|
if (crypto_scalarmult(shared_secret, private_key, public_key) == 0)
|
||||||
{
|
{
|
||||||
enum { k_recipient_header_bytes = crypto_secretbox_MACBYTES + sizeof(uint8_t) + crypto_secretbox_KEYBYTES };
|
enum
|
||||||
for (uint8_t* p = decoded + crypto_box_NONCEBYTES + crypto_secretbox_KEYBYTES; p <= decoded + decoded_length - k_recipient_header_bytes; p += k_recipient_header_bytes)
|
{
|
||||||
|
k_recipient_header_bytes = crypto_secretbox_MACBYTES + sizeof(uint8_t) + crypto_secretbox_KEYBYTES
|
||||||
|
};
|
||||||
|
for (uint8_t* p = decoded + crypto_box_NONCEBYTES + crypto_secretbox_KEYBYTES; p <= decoded + decoded_length - k_recipient_header_bytes;
|
||||||
|
p += k_recipient_header_bytes)
|
||||||
{
|
{
|
||||||
uint8_t out[k_recipient_header_bytes] = { 0 };
|
uint8_t out[k_recipient_header_bytes] = { 0 };
|
||||||
int opened = crypto_secretbox_open_easy(out, p, k_recipient_header_bytes, nonce, shared_secret);
|
int opened = crypto_secretbox_open_easy(out, p, k_recipient_header_bytes, nonce, shared_secret);
|
||||||
@ -1737,8 +1731,7 @@ static JSValue _tf_ssb_following(JSContext* context, JSValueConst this_val, int
|
|||||||
void tf_ssb_register(JSContext* context, tf_ssb_t* ssb)
|
void tf_ssb_register(JSContext* context, tf_ssb_t* ssb)
|
||||||
{
|
{
|
||||||
JS_NewClassID(&_tf_ssb_classId);
|
JS_NewClassID(&_tf_ssb_classId);
|
||||||
JSClassDef def =
|
JSClassDef def = {
|
||||||
{
|
|
||||||
.class_name = "ssb",
|
.class_name = "ssb",
|
||||||
};
|
};
|
||||||
if (JS_NewClass(JS_GetRuntime(context), _tf_ssb_classId, &def) != 0)
|
if (JS_NewClass(JS_GetRuntime(context), _tf_ssb_classId, &def) != 0)
|
||||||
|
256
src/ssb.rpc.c
256
src/ssb.rpc.c
@ -45,19 +45,12 @@ static int64_t _get_global_setting_int64(tf_ssb_t* ssb, const char* name, int64_
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_rpc_gossip_ping_callback(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
static void _tf_ssb_rpc_gossip_ping_callback(
|
||||||
|
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
{
|
{
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
snprintf(buffer, sizeof(buffer), "%" PRId64, (int64_t)time(NULL) * 1000);
|
snprintf(buffer, sizeof(buffer), "%" PRId64, (int64_t)time(NULL) * 1000);
|
||||||
tf_ssb_connection_rpc_send(
|
tf_ssb_connection_rpc_send(connection, flags, -request_number, (const uint8_t*)buffer, strlen(buffer), NULL, NULL, NULL);
|
||||||
connection,
|
|
||||||
flags,
|
|
||||||
-request_number,
|
|
||||||
(const uint8_t*)buffer,
|
|
||||||
strlen(buffer),
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
if (flags & k_ssb_rpc_flag_end_error)
|
if (flags & k_ssb_rpc_flag_end_error)
|
||||||
{
|
{
|
||||||
tf_ssb_connection_remove_request(connection, request_number);
|
tf_ssb_connection_remove_request(connection, request_number);
|
||||||
@ -69,7 +62,8 @@ static void _tf_ssb_rpc_gossip_ping(tf_ssb_connection_t* connection, uint8_t fla
|
|||||||
tf_ssb_connection_add_request(connection, -request_number, _tf_ssb_rpc_gossip_ping_callback, NULL, NULL, NULL);
|
tf_ssb_connection_add_request(connection, -request_number, _tf_ssb_rpc_gossip_ping_callback, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_rpc_blobs_get_callback(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
static void _tf_ssb_rpc_blobs_get_callback(
|
||||||
|
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,15 +101,8 @@ static void _tf_ssb_rpc_blobs_get(tf_ssb_connection_t* connection, uint8_t flags
|
|||||||
{
|
{
|
||||||
for (size_t offset = 0; offset < size; offset += k_send_max)
|
for (size_t offset = 0; offset < size; offset += k_send_max)
|
||||||
{
|
{
|
||||||
tf_ssb_connection_rpc_send(
|
tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_binary | k_ssb_rpc_flag_stream, -request_number, blob + offset,
|
||||||
connection,
|
offset + k_send_max <= size ? k_send_max : (size - offset), NULL, NULL, NULL);
|
||||||
k_ssb_rpc_flag_binary | k_ssb_rpc_flag_stream,
|
|
||||||
-request_number,
|
|
||||||
blob + offset,
|
|
||||||
offset + k_send_max <= size ? k_send_max : (size - offset),
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
success = true;
|
success = true;
|
||||||
tf_free(blob);
|
tf_free(blob);
|
||||||
@ -124,15 +111,8 @@ static void _tf_ssb_rpc_blobs_get(tf_ssb_connection_t* connection, uint8_t flags
|
|||||||
JS_FreeValue(context, arg);
|
JS_FreeValue(context, arg);
|
||||||
}
|
}
|
||||||
JS_FreeValue(context, ids);
|
JS_FreeValue(context, ids);
|
||||||
tf_ssb_connection_rpc_send(
|
tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_json | k_ssb_rpc_flag_end_error | k_ssb_rpc_flag_stream, -request_number,
|
||||||
connection,
|
(const uint8_t*)(success ? "true" : "false"), strlen(success ? "true" : "false"), NULL, NULL, NULL);
|
||||||
k_ssb_rpc_flag_json | k_ssb_rpc_flag_end_error | k_ssb_rpc_flag_stream,
|
|
||||||
-request_number,
|
|
||||||
(const uint8_t*)(success ? "true" : "false"),
|
|
||||||
strlen(success ? "true" : "false"),
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_rpc_blobs_has(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
static void _tf_ssb_rpc_blobs_has(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
@ -146,15 +126,7 @@ static void _tf_ssb_rpc_blobs_has(tf_ssb_connection_t* connection, uint8_t flags
|
|||||||
JS_FreeCString(context, id_str);
|
JS_FreeCString(context, id_str);
|
||||||
JS_FreeValue(context, id);
|
JS_FreeValue(context, id);
|
||||||
JS_FreeValue(context, ids);
|
JS_FreeValue(context, ids);
|
||||||
tf_ssb_connection_rpc_send(
|
tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_json, -request_number, (const uint8_t*)(has ? "true" : "false"), strlen(has ? "true" : "false"), NULL, NULL, NULL);
|
||||||
connection,
|
|
||||||
k_ssb_rpc_flag_json,
|
|
||||||
-request_number,
|
|
||||||
(const uint8_t*)(has ? "true" : "false"),
|
|
||||||
strlen(has ? "true" : "false"),
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_rpc_blob_wants_added_callback(tf_ssb_t* ssb, const char* id, void* user_data)
|
static void _tf_ssb_rpc_blob_wants_added_callback(tf_ssb_t* ssb, const char* id, void* user_data)
|
||||||
@ -196,8 +168,7 @@ static void _tf_ssb_request_blob_wants_work(tf_ssb_connection_t* connection, voi
|
|||||||
sqlite3_stmt* statement;
|
sqlite3_stmt* statement;
|
||||||
if (sqlite3_prepare(db, "SELECT id FROM blob_wants_view WHERE id > ? AND timestamp > ? ORDER BY id LIMIT ?", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "SELECT id FROM blob_wants_view WHERE id > ? AND timestamp > ? ORDER BY id LIMIT ?", -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, blob_wants->last_id, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, blob_wants->last_id, -1, NULL) == SQLITE_OK && sqlite3_bind_int64(statement, 2, timestamp) == SQLITE_OK &&
|
||||||
sqlite3_bind_int64(statement, 2, timestamp) == SQLITE_OK &&
|
|
||||||
sqlite3_bind_int(statement, 3, _countof(work->out_id)) == SQLITE_OK)
|
sqlite3_bind_int(statement, 3, _countof(work->out_id)) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
while (sqlite3_step(statement) == SQLITE_ROW)
|
while (sqlite3_step(statement) == SQLITE_ROW)
|
||||||
@ -242,7 +213,8 @@ static void _tf_ssb_rpc_request_more_blobs(tf_ssb_connection_t* connection)
|
|||||||
tf_ssb_connection_run_work(connection, _tf_ssb_request_blob_wants_work, _tf_ssb_request_blob_wants_after_work, work);
|
tf_ssb_connection_run_work(connection, _tf_ssb_request_blob_wants_work, _tf_ssb_request_blob_wants_after_work, work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_rpc_blobs_createWants(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
static void _tf_ssb_rpc_blobs_createWants(
|
||||||
|
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
{
|
{
|
||||||
tf_ssb_blob_wants_t* blob_wants = tf_ssb_connection_get_blob_wants_state(connection);
|
tf_ssb_blob_wants_t* blob_wants = tf_ssb_connection_get_blob_wants_state(connection);
|
||||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
||||||
@ -292,9 +264,7 @@ static void _tf_ssb_rpc_tunnel_connect(tf_ssb_connection_t* connection, uint8_t
|
|||||||
JSValue portal = JS_GetPropertyStr(context, arg, "portal");
|
JSValue portal = JS_GetPropertyStr(context, arg, "portal");
|
||||||
JSValue target = JS_GetPropertyStr(context, arg, "target");
|
JSValue target = JS_GetPropertyStr(context, arg, "target");
|
||||||
|
|
||||||
if (JS_IsUndefined(origin) &&
|
if (JS_IsUndefined(origin) && !JS_IsUndefined(portal) && !JS_IsUndefined(target))
|
||||||
!JS_IsUndefined(portal) &&
|
|
||||||
!JS_IsUndefined(target))
|
|
||||||
{
|
{
|
||||||
const char* target_str = JS_ToCString(context, target);
|
const char* target_str = JS_ToCString(context, target);
|
||||||
|
|
||||||
@ -320,24 +290,15 @@ static void _tf_ssb_rpc_tunnel_connect(tf_ssb_connection_t* connection, uint8_t
|
|||||||
JS_SetPropertyStr(context, message, "args", arg_array);
|
JS_SetPropertyStr(context, message, "args", arg_array);
|
||||||
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "duplex"));
|
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "duplex"));
|
||||||
|
|
||||||
tf_ssb_connection_rpc_send_json(
|
tf_ssb_connection_rpc_send_json(target_connection, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request, tunnel_request_number, message, NULL, NULL, NULL);
|
||||||
target_connection,
|
|
||||||
k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request,
|
|
||||||
tunnel_request_number,
|
|
||||||
message,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
tunnel_t* data0 = tf_malloc(sizeof(tunnel_t));
|
tunnel_t* data0 = tf_malloc(sizeof(tunnel_t));
|
||||||
*data0 = (tunnel_t)
|
*data0 = (tunnel_t) {
|
||||||
{
|
|
||||||
.connection = target_connection,
|
.connection = target_connection,
|
||||||
.request_number = tunnel_request_number,
|
.request_number = tunnel_request_number,
|
||||||
};
|
};
|
||||||
tunnel_t* data1 = tf_malloc(sizeof(tunnel_t));
|
tunnel_t* data1 = tf_malloc(sizeof(tunnel_t));
|
||||||
*data1 = (tunnel_t)
|
*data1 = (tunnel_t) {
|
||||||
{
|
|
||||||
.connection = connection,
|
.connection = connection,
|
||||||
.request_number = -request_number,
|
.request_number = -request_number,
|
||||||
};
|
};
|
||||||
@ -353,9 +314,7 @@ static void _tf_ssb_rpc_tunnel_connect(tf_ssb_connection_t* connection, uint8_t
|
|||||||
}
|
}
|
||||||
JS_FreeCString(context, target_str);
|
JS_FreeCString(context, target_str);
|
||||||
}
|
}
|
||||||
else if (!JS_IsUndefined(origin) &&
|
else if (!JS_IsUndefined(origin) && !JS_IsUndefined(portal) && !JS_IsUndefined(target))
|
||||||
!JS_IsUndefined(portal) &&
|
|
||||||
!JS_IsUndefined(target))
|
|
||||||
{
|
{
|
||||||
const char* origin_str = JS_ToCString(context, origin);
|
const char* origin_str = JS_ToCString(context, origin);
|
||||||
const char* portal_str = JS_ToCString(context, portal);
|
const char* portal_str = JS_ToCString(context, portal);
|
||||||
@ -389,14 +348,7 @@ static void _tf_ssb_rpc_room_meta(tf_ssb_connection_t* connection, uint8_t flags
|
|||||||
JS_SetPropertyUint32(context, features, 2, JS_NewString(context, "room2"));
|
JS_SetPropertyUint32(context, features, 2, JS_NewString(context, "room2"));
|
||||||
JS_SetPropertyStr(context, response, "features", features);
|
JS_SetPropertyStr(context, response, "features", features);
|
||||||
}
|
}
|
||||||
tf_ssb_connection_rpc_send_json(
|
tf_ssb_connection_rpc_send_json(connection, flags, -request_number, response, NULL, NULL, NULL);
|
||||||
connection,
|
|
||||||
flags,
|
|
||||||
-request_number,
|
|
||||||
response,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
JS_FreeValue(context, response);
|
JS_FreeValue(context, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,19 +380,11 @@ static void _tf_ssb_rpc_room_attendants(tf_ssb_connection_t* connection, uint8_t
|
|||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
char id[k_id_base64_len] = { 0 };
|
char id[k_id_base64_len] = { 0 };
|
||||||
if (tf_ssb_connection_is_attendant(connections[i]) &&
|
if (tf_ssb_connection_is_attendant(connections[i]) && tf_ssb_connection_get_id(connections[i], id, sizeof(id)))
|
||||||
tf_ssb_connection_get_id(connections[i], id, sizeof(id)))
|
|
||||||
{
|
{
|
||||||
JS_SetPropertyUint32(context, ids, id_count++, JS_NewString(context, id));
|
JS_SetPropertyUint32(context, ids, id_count++, JS_NewString(context, id));
|
||||||
|
|
||||||
tf_ssb_connection_rpc_send_json(
|
tf_ssb_connection_rpc_send_json(connections[i], flags, -tf_ssb_connection_get_attendant_request_number(connections[i]), joined, NULL, NULL, NULL);
|
||||||
connections[i],
|
|
||||||
flags,
|
|
||||||
-tf_ssb_connection_get_attendant_request_number(connections[i]),
|
|
||||||
joined,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
JS_SetPropertyStr(context, state, "ids", ids);
|
JS_SetPropertyStr(context, state, "ids", ids);
|
||||||
@ -472,7 +416,8 @@ static void _tf_ssb_rpc_blob_store_callback(const char* id, bool is_new, void* u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_rpc_connection_blobs_get_callback(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
static void _tf_ssb_rpc_connection_blobs_get_callback(
|
||||||
|
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
{
|
{
|
||||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
||||||
JSContext* context = tf_ssb_get_context(ssb);
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
@ -491,15 +436,8 @@ static void _tf_ssb_rpc_connection_blobs_get_callback(tf_ssb_connection_t* conne
|
|||||||
}
|
}
|
||||||
/* TODO: Should we send the response in the callback? */
|
/* TODO: Should we send the response in the callback? */
|
||||||
bool stored = true;
|
bool stored = true;
|
||||||
tf_ssb_connection_rpc_send(
|
tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_json | k_ssb_rpc_flag_stream | k_ssb_rpc_flag_end_error, -request_number,
|
||||||
connection,
|
(const uint8_t*)(stored ? "true" : "false"), strlen(stored ? "true" : "false"), NULL, NULL, NULL);
|
||||||
k_ssb_rpc_flag_json | k_ssb_rpc_flag_stream | k_ssb_rpc_flag_end_error,
|
|
||||||
-request_number,
|
|
||||||
(const uint8_t*)(stored ? "true" : "false"),
|
|
||||||
strlen(stored ? "true" : "false"),
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,19 +470,14 @@ static void _tf_ssb_rpc_connection_blobs_get(tf_ssb_connection_t* connection, co
|
|||||||
JS_SetPropertyUint32(context, args, 0, JS_NewString(context, blob_id));
|
JS_SetPropertyUint32(context, args, 0, JS_NewString(context, blob_id));
|
||||||
JS_SetPropertyStr(context, message, "args", args);
|
JS_SetPropertyStr(context, message, "args", args);
|
||||||
|
|
||||||
tf_ssb_connection_rpc_send_json(
|
tf_ssb_connection_rpc_send_json(connection, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request, tf_ssb_connection_next_request_number(connection), message,
|
||||||
connection,
|
_tf_ssb_rpc_connection_blobs_get_callback, _tf_ssb_rpc_connection_blobs_get_cleanup, get);
|
||||||
k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request,
|
|
||||||
tf_ssb_connection_next_request_number(connection),
|
|
||||||
message,
|
|
||||||
_tf_ssb_rpc_connection_blobs_get_callback,
|
|
||||||
_tf_ssb_rpc_connection_blobs_get_cleanup,
|
|
||||||
get);
|
|
||||||
|
|
||||||
JS_FreeValue(context, message);
|
JS_FreeValue(context, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_rpc_connection_blobs_createWants_callback(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
static void _tf_ssb_rpc_connection_blobs_createWants_callback(
|
||||||
|
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
{
|
{
|
||||||
tf_ssb_blob_wants_t* blob_wants = tf_ssb_connection_get_blob_wants_state(connection);
|
tf_ssb_blob_wants_t* blob_wants = tf_ssb_connection_get_blob_wants_state(connection);
|
||||||
if (!blob_wants)
|
if (!blob_wants)
|
||||||
@ -592,28 +525,14 @@ static void _tf_ssb_rpc_connection_blobs_createWants_callback(tf_ssb_connection_
|
|||||||
{
|
{
|
||||||
JSValue message = JS_NewObject(context);
|
JSValue message = JS_NewObject(context);
|
||||||
JS_SetPropertyStr(context, message, blob_id, JS_NewInt64(context, blob_size));
|
JS_SetPropertyStr(context, message, blob_id, JS_NewInt64(context, blob_size));
|
||||||
tf_ssb_connection_rpc_send_json(
|
tf_ssb_connection_rpc_send_json(connection, k_ssb_rpc_flag_stream, -blob_wants->request_number, message, NULL, NULL, NULL);
|
||||||
connection,
|
|
||||||
k_ssb_rpc_flag_stream,
|
|
||||||
-blob_wants->request_number,
|
|
||||||
message,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
JS_FreeValue(context, message);
|
JS_FreeValue(context, message);
|
||||||
}
|
}
|
||||||
else if (size == -1LL)
|
else if (size == -1LL)
|
||||||
{
|
{
|
||||||
JSValue message = JS_NewObject(context);
|
JSValue message = JS_NewObject(context);
|
||||||
JS_SetPropertyStr(context, message, blob_id, JS_NewInt64(context, -2));
|
JS_SetPropertyStr(context, message, blob_id, JS_NewInt64(context, -2));
|
||||||
tf_ssb_connection_rpc_send_json(
|
tf_ssb_connection_rpc_send_json(connection, k_ssb_rpc_flag_stream, -blob_wants->request_number, message, NULL, NULL, NULL);
|
||||||
connection,
|
|
||||||
k_ssb_rpc_flag_stream,
|
|
||||||
-blob_wants->request_number,
|
|
||||||
message,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
JS_FreeValue(context, message);
|
JS_FreeValue(context, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -633,7 +552,8 @@ static void _tf_ssb_rpc_connection_blobs_createWants_callback(tf_ssb_connection_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_rpc_connection_room_attendants_callback(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
static void _tf_ssb_rpc_connection_room_attendants_callback(
|
||||||
|
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
{
|
{
|
||||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
||||||
JSContext* context = tf_ssb_get_context(ssb);
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
@ -707,7 +627,8 @@ static bool _is_error(JSContext* context, JSValue message)
|
|||||||
return is_error;
|
return is_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_rpc_connection_tunnel_isRoom_callback(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
static void _tf_ssb_rpc_connection_tunnel_isRoom_callback(
|
||||||
|
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
{
|
{
|
||||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
||||||
JSContext* context = tf_ssb_get_context(ssb);
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
@ -725,14 +646,8 @@ static void _tf_ssb_rpc_connection_tunnel_isRoom_callback(tf_ssb_connection_t* c
|
|||||||
JS_SetPropertyStr(context, message, "name", name);
|
JS_SetPropertyStr(context, message, "name", name);
|
||||||
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "source"));
|
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "source"));
|
||||||
JS_SetPropertyStr(context, message, "args", JS_NewArray(context));
|
JS_SetPropertyStr(context, message, "args", JS_NewArray(context));
|
||||||
tf_ssb_connection_rpc_send_json(
|
tf_ssb_connection_rpc_send_json(connection, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request, tf_ssb_connection_next_request_number(connection), message,
|
||||||
connection,
|
_tf_ssb_rpc_connection_room_attendants_callback, NULL, NULL);
|
||||||
k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request,
|
|
||||||
tf_ssb_connection_next_request_number(connection),
|
|
||||||
message,
|
|
||||||
_tf_ssb_rpc_connection_room_attendants_callback,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
JS_FreeValue(context, message);
|
JS_FreeValue(context, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -762,10 +677,12 @@ static void _tf_ssb_connection_send_history_stream_work(tf_ssb_connection_t* con
|
|||||||
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
||||||
sqlite3_stmt* statement;
|
sqlite3_stmt* statement;
|
||||||
const int k_max = 32;
|
const int k_max = 32;
|
||||||
if (sqlite3_prepare(db, "SELECT previous, author, id, sequence, timestamp, hash, content, signature, sequence_before_author FROM messages WHERE author = ?1 AND sequence > ?2 AND sequence < ?3 ORDER BY sequence", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db,
|
||||||
|
"SELECT previous, author, id, sequence, timestamp, hash, content, signature, sequence_before_author FROM messages WHERE author = ?1 AND sequence > ?2 AND sequence "
|
||||||
|
"< ?3 ORDER BY sequence",
|
||||||
|
-1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, request->author, -1, NULL) == SQLITE_OK &&
|
if (sqlite3_bind_text(statement, 1, request->author, -1, NULL) == SQLITE_OK && sqlite3_bind_int64(statement, 2, request->sequence) == SQLITE_OK &&
|
||||||
sqlite3_bind_int64(statement, 2, request->sequence) == SQLITE_OK &&
|
|
||||||
sqlite3_bind_int64(statement, 3, request->sequence + k_max) == SQLITE_OK)
|
sqlite3_bind_int64(statement, 3, request->sequence + k_max) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
JSMallocFunctions funcs = { 0 };
|
JSMallocFunctions funcs = { 0 };
|
||||||
@ -778,16 +695,9 @@ static void _tf_ssb_connection_send_history_stream_work(tf_ssb_connection_t* con
|
|||||||
JSValue message = JS_UNDEFINED;
|
JSValue message = JS_UNDEFINED;
|
||||||
request->out_max_sequence_seen = sqlite3_column_int64(statement, 3);
|
request->out_max_sequence_seen = sqlite3_column_int64(statement, 3);
|
||||||
|
|
||||||
JSValue formatted = tf_ssb_format_message(
|
JSValue formatted = tf_ssb_format_message(context, (const char*)sqlite3_column_text(statement, 0), (const char*)sqlite3_column_text(statement, 1),
|
||||||
context,
|
sqlite3_column_int64(statement, 3), sqlite3_column_double(statement, 4), (const char*)sqlite3_column_text(statement, 5),
|
||||||
(const char*)sqlite3_column_text(statement, 0),
|
(const char*)sqlite3_column_text(statement, 6), (const char*)sqlite3_column_text(statement, 7), sqlite3_column_int(statement, 8));
|
||||||
(const char*)sqlite3_column_text(statement, 1),
|
|
||||||
sqlite3_column_int64(statement, 3),
|
|
||||||
sqlite3_column_double(statement, 4),
|
|
||||||
(const char*)sqlite3_column_text(statement, 5),
|
|
||||||
(const char*)sqlite3_column_text(statement, 6),
|
|
||||||
(const char*)sqlite3_column_text(statement, 7),
|
|
||||||
sqlite3_column_int(statement, 8));
|
|
||||||
if (request->keys)
|
if (request->keys)
|
||||||
{
|
{
|
||||||
message = JS_NewObject(context);
|
message = JS_NewObject(context);
|
||||||
@ -833,7 +743,8 @@ static void _tf_ssb_connection_send_history_stream_after_work(tf_ssb_connection_
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < request->out_messages_count; i++)
|
for (int i = 0; i < request->out_messages_count; i++)
|
||||||
{
|
{
|
||||||
tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_json, request->request_number, (const uint8_t*)request->out_messages[i], strlen(request->out_messages[i]), NULL, NULL, NULL);
|
tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_json, request->request_number, (const uint8_t*)request->out_messages[i],
|
||||||
|
strlen(request->out_messages[i]), NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
if (!request->out_finished)
|
if (!request->out_finished)
|
||||||
{
|
{
|
||||||
@ -841,15 +752,7 @@ static void _tf_ssb_connection_send_history_stream_after_work(tf_ssb_connection_
|
|||||||
}
|
}
|
||||||
else if (!request->live)
|
else if (!request->live)
|
||||||
{
|
{
|
||||||
tf_ssb_connection_rpc_send(
|
tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_json, request->request_number, (const uint8_t*)"false", strlen("false"), NULL, NULL, NULL);
|
||||||
connection,
|
|
||||||
k_ssb_rpc_flag_json,
|
|
||||||
request->request_number,
|
|
||||||
(const uint8_t*)"false",
|
|
||||||
strlen("false"),
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < request->out_messages_count; i++)
|
for (int i = 0; i < request->out_messages_count; i++)
|
||||||
@ -863,8 +766,7 @@ static void _tf_ssb_connection_send_history_stream_after_work(tf_ssb_connection_
|
|||||||
static void _tf_ssb_connection_send_history_stream(tf_ssb_connection_t* connection, int32_t request_number, const char* author, int64_t sequence, bool keys, bool live)
|
static void _tf_ssb_connection_send_history_stream(tf_ssb_connection_t* connection, int32_t request_number, const char* author, int64_t sequence, bool keys, bool live)
|
||||||
{
|
{
|
||||||
tf_ssb_connection_send_history_stream_t* async = tf_malloc(sizeof(tf_ssb_connection_send_history_stream_t));
|
tf_ssb_connection_send_history_stream_t* async = tf_malloc(sizeof(tf_ssb_connection_send_history_stream_t));
|
||||||
*async = (tf_ssb_connection_send_history_stream_t)
|
*async = (tf_ssb_connection_send_history_stream_t) {
|
||||||
{
|
|
||||||
.request_number = request_number,
|
.request_number = request_number,
|
||||||
.sequence = sequence,
|
.sequence = sequence,
|
||||||
.keys = keys,
|
.keys = keys,
|
||||||
@ -874,7 +776,8 @@ static void _tf_ssb_connection_send_history_stream(tf_ssb_connection_t* connecti
|
|||||||
tf_ssb_connection_run_work(connection, _tf_ssb_connection_send_history_stream_work, _tf_ssb_connection_send_history_stream_after_work, async);
|
tf_ssb_connection_run_work(connection, _tf_ssb_connection_send_history_stream_work, _tf_ssb_connection_send_history_stream_after_work, async);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_rpc_createHistoryStream(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
static void _tf_ssb_rpc_createHistoryStream(
|
||||||
|
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
{
|
{
|
||||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
||||||
JSContext* context = tf_ssb_get_context(ssb);
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
@ -993,7 +896,8 @@ static void _tf_ssb_rpc_ebt_replicate_send_clock_after_work(tf_ssb_connection_t*
|
|||||||
tf_free(work->clock);
|
tf_free(work->clock);
|
||||||
if (work->out_clock)
|
if (work->out_clock)
|
||||||
{
|
{
|
||||||
tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_json, -work->request_number, (const uint8_t*)work->out_clock, strlen(work->out_clock), NULL, NULL, NULL);
|
tf_ssb_connection_rpc_send(
|
||||||
|
connection, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_json, -work->request_number, (const uint8_t*)work->out_clock, strlen(work->out_clock), NULL, NULL, NULL);
|
||||||
tf_free(work->out_clock);
|
tf_free(work->out_clock);
|
||||||
}
|
}
|
||||||
tf_free(work);
|
tf_free(work);
|
||||||
@ -1002,8 +906,7 @@ static void _tf_ssb_rpc_ebt_replicate_send_clock_after_work(tf_ssb_connection_t*
|
|||||||
static void _tf_ssb_rpc_ebt_replicate_send_clock(tf_ssb_connection_t* connection, int32_t request_number, JSValue message)
|
static void _tf_ssb_rpc_ebt_replicate_send_clock(tf_ssb_connection_t* connection, int32_t request_number, JSValue message)
|
||||||
{
|
{
|
||||||
ebt_replicate_send_clock_t* work = tf_malloc(sizeof(ebt_replicate_send_clock_t));
|
ebt_replicate_send_clock_t* work = tf_malloc(sizeof(ebt_replicate_send_clock_t));
|
||||||
*work = (ebt_replicate_send_clock_t)
|
*work = (ebt_replicate_send_clock_t) {
|
||||||
{
|
|
||||||
.request_number = request_number,
|
.request_number = request_number,
|
||||||
};
|
};
|
||||||
JSContext* context = tf_ssb_connection_get_context(connection);
|
JSContext* context = tf_ssb_connection_get_context(connection);
|
||||||
@ -1133,7 +1036,8 @@ static void _tf_ssb_rpc_ebt_replicate(tf_ssb_connection_t* connection, uint8_t f
|
|||||||
JS_FreeValue(context, author);
|
JS_FreeValue(context, author);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_rpc_ebt_replicate_client(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
static void _tf_ssb_rpc_ebt_replicate_client(
|
||||||
|
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
{
|
{
|
||||||
_tf_ssb_rpc_ebt_replicate(connection, flags, request_number, args, message, size, user_data);
|
_tf_ssb_rpc_ebt_replicate(connection, flags, request_number, args, message, size, user_data);
|
||||||
}
|
}
|
||||||
@ -1155,14 +1059,7 @@ static void _tf_ssb_rpc_send_ebt_replicate(tf_ssb_connection_t* connection)
|
|||||||
JS_SetPropertyStr(context, message, "args", args);
|
JS_SetPropertyStr(context, message, "args", args);
|
||||||
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "duplex"));
|
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "duplex"));
|
||||||
int32_t request_number = tf_ssb_connection_next_request_number(connection);
|
int32_t request_number = tf_ssb_connection_next_request_number(connection);
|
||||||
tf_ssb_connection_rpc_send_json(
|
tf_ssb_connection_rpc_send_json(connection, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request, request_number, message, _tf_ssb_rpc_ebt_replicate_client, NULL, NULL);
|
||||||
connection,
|
|
||||||
k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request,
|
|
||||||
request_number,
|
|
||||||
message,
|
|
||||||
_tf_ssb_rpc_ebt_replicate_client,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
if (!tf_ssb_connection_get_ebt_request_number(connection))
|
if (!tf_ssb_connection_get_ebt_request_number(connection))
|
||||||
{
|
{
|
||||||
tf_ssb_connection_set_ebt_request_number(connection, request_number);
|
tf_ssb_connection_set_ebt_request_number(connection, request_number);
|
||||||
@ -1170,7 +1067,8 @@ static void _tf_ssb_rpc_send_ebt_replicate(tf_ssb_connection_t* connection)
|
|||||||
JS_FreeValue(context, message);
|
JS_FreeValue(context, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_rpc_ebt_replicate_server(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
static void _tf_ssb_rpc_ebt_replicate_server(
|
||||||
|
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
{
|
{
|
||||||
if (flags & k_ssb_rpc_flag_end_error)
|
if (flags & k_ssb_rpc_flag_end_error)
|
||||||
{
|
{
|
||||||
@ -1192,14 +1090,8 @@ static void _tf_ssb_rpc_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_chang
|
|||||||
JS_SetPropertyStr(context, message, "name", name);
|
JS_SetPropertyStr(context, message, "name", name);
|
||||||
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "source"));
|
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "source"));
|
||||||
JS_SetPropertyStr(context, message, "args", JS_NewArray(context));
|
JS_SetPropertyStr(context, message, "args", JS_NewArray(context));
|
||||||
tf_ssb_connection_rpc_send_json(
|
tf_ssb_connection_rpc_send_json(connection, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request, tf_ssb_connection_next_request_number(connection), message,
|
||||||
connection,
|
_tf_ssb_rpc_connection_blobs_createWants_callback, NULL, NULL);
|
||||||
k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request,
|
|
||||||
tf_ssb_connection_next_request_number(connection),
|
|
||||||
message,
|
|
||||||
_tf_ssb_rpc_connection_blobs_createWants_callback,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
JS_FreeValue(context, message);
|
JS_FreeValue(context, message);
|
||||||
|
|
||||||
if (tf_ssb_connection_is_client(connection))
|
if (tf_ssb_connection_is_client(connection))
|
||||||
@ -1210,14 +1102,8 @@ static void _tf_ssb_rpc_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_chang
|
|||||||
JS_SetPropertyUint32(context, name, 1, JS_NewString(context, "isRoom"));
|
JS_SetPropertyUint32(context, name, 1, JS_NewString(context, "isRoom"));
|
||||||
JS_SetPropertyStr(context, message, "name", name);
|
JS_SetPropertyStr(context, message, "name", name);
|
||||||
JS_SetPropertyStr(context, message, "args", JS_NewArray(context));
|
JS_SetPropertyStr(context, message, "args", JS_NewArray(context));
|
||||||
tf_ssb_connection_rpc_send_json(
|
tf_ssb_connection_rpc_send_json(connection, k_ssb_rpc_flag_new_request, tf_ssb_connection_next_request_number(connection), message,
|
||||||
connection,
|
_tf_ssb_rpc_connection_tunnel_isRoom_callback, NULL, NULL);
|
||||||
k_ssb_rpc_flag_new_request,
|
|
||||||
tf_ssb_connection_next_request_number(connection),
|
|
||||||
message,
|
|
||||||
_tf_ssb_rpc_connection_tunnel_isRoom_callback,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
JS_FreeValue(context, message);
|
JS_FreeValue(context, message);
|
||||||
|
|
||||||
_tf_ssb_rpc_send_ebt_replicate(connection);
|
_tf_ssb_rpc_send_ebt_replicate(connection);
|
||||||
@ -1240,13 +1126,7 @@ static void _tf_ssb_rpc_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_chang
|
|||||||
if (tf_ssb_connection_is_attendant(connections[i]))
|
if (tf_ssb_connection_is_attendant(connections[i]))
|
||||||
{
|
{
|
||||||
tf_ssb_connection_rpc_send_json(
|
tf_ssb_connection_rpc_send_json(
|
||||||
connections[i],
|
connections[i], k_ssb_rpc_flag_stream, -tf_ssb_connection_get_attendant_request_number(connections[i]), left, NULL, NULL, NULL);
|
||||||
k_ssb_rpc_flag_stream,
|
|
||||||
-tf_ssb_connection_get_attendant_request_number(connections[i]),
|
|
||||||
left,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
JS_FreeValue(context, left);
|
JS_FreeValue(context, left);
|
||||||
@ -1302,10 +1182,10 @@ static void _tf_ssb_rpc_delete_blobs_work(uv_work_t* work)
|
|||||||
" JOIN messages_refs ON blobs.id = messages_refs.ref "
|
" JOIN messages_refs ON blobs.id = messages_refs.ref "
|
||||||
" JOIN messages ON messages.id = messages_refs.message "
|
" JOIN messages ON messages.id = messages_refs.message "
|
||||||
" WHERE blobs.created < ?1 / 1000 "
|
" WHERE blobs.created < ?1 / 1000 "
|
||||||
" GROUP BY blobs.id HAVING MAX(messages.timestamp) < ?1 LIMIT ?2)", -1, &statement, NULL) == SQLITE_OK)
|
" GROUP BY blobs.id HAVING MAX(messages.timestamp) < ?1 LIMIT ?2)",
|
||||||
|
-1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_int64(statement, 1, timestamp) == SQLITE_OK &&
|
if (sqlite3_bind_int64(statement, 1, timestamp) == SQLITE_OK && sqlite3_bind_int(statement, 2, k_limit) == SQLITE_OK)
|
||||||
sqlite3_bind_int(statement, 2, k_limit) == SQLITE_OK)
|
|
||||||
{
|
{
|
||||||
int r = sqlite3_step(statement);
|
int r = sqlite3_step(statement);
|
||||||
if (r != SQLITE_DONE)
|
if (r != SQLITE_DONE)
|
||||||
@ -1341,7 +1221,7 @@ static void _tf_ssb_rpc_delete_blobs_after_work(uv_work_t* work, int status)
|
|||||||
static void _tf_ssb_rpc_start_delete_callback(tf_ssb_t* ssb, void* user_data)
|
static void _tf_ssb_rpc_start_delete_callback(tf_ssb_t* ssb, void* user_data)
|
||||||
{
|
{
|
||||||
delete_blobs_work_t* work = tf_malloc(sizeof(delete_blobs_work_t));
|
delete_blobs_work_t* work = tf_malloc(sizeof(delete_blobs_work_t));
|
||||||
*work = (delete_blobs_work_t) { .work = { .data = work}, .ssb = ssb };
|
*work = (delete_blobs_work_t) { .work = { .data = work }, .ssb = ssb };
|
||||||
tf_ssb_ref(ssb);
|
tf_ssb_ref(ssb);
|
||||||
int r = uv_queue_work(tf_ssb_get_loop(ssb), &work->work, _tf_ssb_rpc_delete_blobs_work, _tf_ssb_rpc_delete_blobs_after_work);
|
int r = uv_queue_work(tf_ssb_get_loop(ssb), &work->work, _tf_ssb_rpc_delete_blobs_work, _tf_ssb_rpc_delete_blobs_after_work);
|
||||||
if (r)
|
if (r)
|
||||||
|
@ -34,7 +34,8 @@ void tf_ssb_test_id_conversion(const tf_test_options_t* options)
|
|||||||
assert(b);
|
assert(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct _test_t {
|
typedef struct _test_t
|
||||||
|
{
|
||||||
tf_ssb_t* ssb0;
|
tf_ssb_t* ssb0;
|
||||||
tf_ssb_t* ssb1;
|
tf_ssb_t* ssb1;
|
||||||
tf_ssb_t* ssb2;
|
tf_ssb_t* ssb2;
|
||||||
@ -238,8 +239,7 @@ void tf_ssb_test_ssb(const tf_test_options_t* options)
|
|||||||
tf_ssb_connect(ssb1, "127.0.0.1", 12347, id0bin);
|
tf_ssb_connect(ssb1, "127.0.0.1", 12347, id0bin);
|
||||||
|
|
||||||
tf_printf("Waiting for connection.\n");
|
tf_printf("Waiting for connection.\n");
|
||||||
while (test.connection_count0 != 1 ||
|
while (test.connection_count0 != 1 || test.connection_count1 != 1)
|
||||||
test.connection_count1 != 1)
|
|
||||||
{
|
{
|
||||||
uv_run(&loop, UV_RUN_ONCE);
|
uv_run(&loop, UV_RUN_ONCE);
|
||||||
}
|
}
|
||||||
@ -373,8 +373,7 @@ void tf_ssb_test_rooms(const tf_test_options_t* options)
|
|||||||
uv_idle_init(&loop, &idle2);
|
uv_idle_init(&loop, &idle2);
|
||||||
uv_idle_start(&idle2, _ssb_test_idle);
|
uv_idle_start(&idle2, _ssb_test_idle);
|
||||||
|
|
||||||
test_t test =
|
test_t test = {
|
||||||
{
|
|
||||||
.ssb0 = ssb0,
|
.ssb0 = ssb0,
|
||||||
.ssb1 = ssb1,
|
.ssb1 = ssb1,
|
||||||
.ssb2 = ssb2,
|
.ssb2 = ssb2,
|
||||||
@ -412,17 +411,14 @@ void tf_ssb_test_rooms(const tf_test_options_t* options)
|
|||||||
tf_ssb_connect(ssb2, "127.0.0.1", 12347, id0bin);
|
tf_ssb_connect(ssb2, "127.0.0.1", 12347, id0bin);
|
||||||
|
|
||||||
tf_printf("Waiting for connection.\n");
|
tf_printf("Waiting for connection.\n");
|
||||||
while (test.connection_count0 != 2 ||
|
while (test.connection_count0 != 2 || test.connection_count1 != 1 || test.connection_count2 != 1)
|
||||||
test.connection_count1 != 1 ||
|
|
||||||
test.connection_count2 != 1)
|
|
||||||
{
|
{
|
||||||
uv_run(&loop, UV_RUN_ONCE);
|
uv_run(&loop, UV_RUN_ONCE);
|
||||||
}
|
}
|
||||||
tf_ssb_server_close(ssb0);
|
tf_ssb_server_close(ssb0);
|
||||||
|
|
||||||
tf_printf("Waiting for broadcasts.\n");
|
tf_printf("Waiting for broadcasts.\n");
|
||||||
while (test.broadcast_count1 != 1 ||
|
while (test.broadcast_count1 != 1 || test.broadcast_count2 != 1)
|
||||||
test.broadcast_count2 != 1)
|
|
||||||
{
|
{
|
||||||
uv_run(&loop, UV_RUN_ONCE);
|
uv_run(&loop, UV_RUN_ONCE);
|
||||||
}
|
}
|
||||||
@ -448,14 +444,7 @@ void tf_ssb_test_rooms(const tf_test_options_t* options)
|
|||||||
JS_SetPropertyStr(context, message, "args", args);
|
JS_SetPropertyStr(context, message, "args", args);
|
||||||
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "duplex"));
|
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "duplex"));
|
||||||
|
|
||||||
tf_ssb_connection_rpc_send_json(
|
tf_ssb_connection_rpc_send_json(connections[0], k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request, tunnel_request_number, message, NULL, NULL, NULL);
|
||||||
connections[0],
|
|
||||||
k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request,
|
|
||||||
tunnel_request_number,
|
|
||||||
message,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
JS_FreeValue(context, message);
|
JS_FreeValue(context, message);
|
||||||
|
|
||||||
tf_ssb_connection_t* tun0 = tf_ssb_connection_tunnel_create(ssb1, id0, tunnel_request_number, id2);
|
tf_ssb_connection_t* tun0 = tf_ssb_connection_tunnel_create(ssb1, id0, tunnel_request_number, id2);
|
||||||
@ -463,9 +452,7 @@ void tf_ssb_test_rooms(const tf_test_options_t* options)
|
|||||||
|
|
||||||
tf_printf("Done.\n");
|
tf_printf("Done.\n");
|
||||||
|
|
||||||
while (test.connection_count0 != 2 ||
|
while (test.connection_count0 != 2 || test.connection_count1 != 2 || test.connection_count2 != 2)
|
||||||
test.connection_count1 != 2 ||
|
|
||||||
test.connection_count2 != 2)
|
|
||||||
{
|
{
|
||||||
uv_run(&loop, UV_RUN_ONCE);
|
uv_run(&loop, UV_RUN_ONCE);
|
||||||
}
|
}
|
||||||
@ -556,7 +543,7 @@ void tf_ssb_test_following(const tf_test_options_t* options)
|
|||||||
JSValue signed_message;
|
JSValue signed_message;
|
||||||
bool stored;
|
bool stored;
|
||||||
|
|
||||||
#define FOLLOW_BLOCK(id, priv, contact, follow, block) \
|
#define FOLLOW_BLOCK(id, priv, contact, follow, block) \
|
||||||
message = JS_NewObject(context); \
|
message = JS_NewObject(context); \
|
||||||
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "contact")); \
|
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "contact")); \
|
||||||
JS_SetPropertyStr(context, message, "contact", JS_NewString(context, contact)); \
|
JS_SetPropertyStr(context, message, "contact", JS_NewString(context, contact)); \
|
||||||
@ -567,7 +554,7 @@ void tf_ssb_test_following(const tf_test_options_t* options)
|
|||||||
tf_ssb_verify_strip_and_store_message(ssb0, signed_message, _message_stored, &stored); \
|
tf_ssb_verify_strip_and_store_message(ssb0, signed_message, _message_stored, &stored); \
|
||||||
_wait_stored(ssb0, &stored); \
|
_wait_stored(ssb0, &stored); \
|
||||||
JS_FreeValue(context, signed_message); \
|
JS_FreeValue(context, signed_message); \
|
||||||
JS_FreeValue(context, message); \
|
JS_FreeValue(context, message);
|
||||||
|
|
||||||
FOLLOW_BLOCK(id0, priv0, id1, true, false);
|
FOLLOW_BLOCK(id0, priv0, id1, true, false);
|
||||||
FOLLOW_BLOCK(id1, priv1, id2, true, false);
|
FOLLOW_BLOCK(id1, priv1, id2, true, false);
|
||||||
@ -582,7 +569,7 @@ void tf_ssb_test_following(const tf_test_options_t* options)
|
|||||||
_assert_visible(ssb0, id0, id2, true);
|
_assert_visible(ssb0, id0, id2, true);
|
||||||
_assert_visible(ssb0, id0, id3, false);
|
_assert_visible(ssb0, id0, id3, false);
|
||||||
|
|
||||||
#undef FOLLOW_BLOCK
|
#undef FOLLOW_BLOCK
|
||||||
|
|
||||||
uv_run(&loop, UV_RUN_DEFAULT);
|
uv_run(&loop, UV_RUN_DEFAULT);
|
||||||
|
|
||||||
@ -705,10 +692,7 @@ void tf_ssb_test_bench(const tf_test_options_t* options)
|
|||||||
|
|
||||||
static void _ssb_test_room_connections_changed(tf_ssb_t* ssb, tf_ssb_change_t change, tf_ssb_connection_t* connection, void* user_data)
|
static void _ssb_test_room_connections_changed(tf_ssb_t* ssb, tf_ssb_change_t change, tf_ssb_connection_t* connection, void* user_data)
|
||||||
{
|
{
|
||||||
const char* changes[] =
|
const char* changes[] = { "create", "connect", "remove" };
|
||||||
{
|
|
||||||
"create", "connect", "remove"
|
|
||||||
};
|
|
||||||
tf_printf("change=%s %p connection=%s:%d\n", changes[change], connection, tf_ssb_connection_get_host(connection), tf_ssb_connection_get_port(connection));
|
tf_printf("change=%s %p connection=%s:%d\n", changes[change], connection, tf_ssb_connection_get_host(connection), tf_ssb_connection_get_port(connection));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -731,15 +715,8 @@ static void _close_callback(uv_timer_t* timer)
|
|||||||
close_t* data = timer->data;
|
close_t* data = timer->data;
|
||||||
tf_printf("breaking %s %p\n", data->id, data->connection);
|
tf_printf("breaking %s %p\n", data->id, data->connection);
|
||||||
const char* message = "{\"name\":\"Error\",\"message\":\"whoops\",\"stack\":\"nah\"}";
|
const char* message = "{\"name\":\"Error\",\"message\":\"whoops\",\"stack\":\"nah\"}";
|
||||||
tf_ssb_connection_rpc_send(
|
tf_ssb_connection_rpc_send(data->connection, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_json | k_ssb_rpc_flag_end_error, data->request_number, (const uint8_t*)message,
|
||||||
data->connection,
|
strlen(message), NULL, NULL, NULL);
|
||||||
k_ssb_rpc_flag_stream | k_ssb_rpc_flag_json | k_ssb_rpc_flag_end_error,
|
|
||||||
data->request_number,
|
|
||||||
(const uint8_t*)message,
|
|
||||||
strlen(message),
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
uv_close((uv_handle_t*)timer, _timer_close);
|
uv_close((uv_handle_t*)timer, _timer_close);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -767,9 +744,7 @@ static void _ssb_test_room_broadcasts_visit(const char* host, const struct socka
|
|||||||
char id[k_id_base64_len] = { 0 };
|
char id[k_id_base64_len] = { 0 };
|
||||||
tf_ssb_id_bin_to_str(id, sizeof(id), pub);
|
tf_ssb_id_bin_to_str(id, sizeof(id), pub);
|
||||||
tf_ssb_connection_t* connections[8];
|
tf_ssb_connection_t* connections[8];
|
||||||
if (tunnel &&
|
if (tunnel && strcmp(id, "@Jqm63iKumgaWfUI6mXtmQCDHiQJhzMiEWXYUqtcGs9o=.ed25519") != 0 && tf_ssb_get_connections(ssb, connections, 8) == 1)
|
||||||
strcmp(id, "@Jqm63iKumgaWfUI6mXtmQCDHiQJhzMiEWXYUqtcGs9o=.ed25519") != 0 &&
|
|
||||||
tf_ssb_get_connections(ssb, connections, 8) == 1)
|
|
||||||
{
|
{
|
||||||
tf_printf("%s %p %s\n", host, tunnel, id);
|
tf_printf("%s %p %s\n", host, tunnel, id);
|
||||||
|
|
||||||
@ -794,14 +769,7 @@ static void _ssb_test_room_broadcasts_visit(const char* host, const struct socka
|
|||||||
JS_SetPropertyStr(context, message, "args", args);
|
JS_SetPropertyStr(context, message, "args", args);
|
||||||
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "duplex"));
|
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "duplex"));
|
||||||
|
|
||||||
tf_ssb_connection_rpc_send_json(
|
tf_ssb_connection_rpc_send_json(tunnel, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request, tunnel_request_number, message, NULL, NULL, NULL);
|
||||||
tunnel,
|
|
||||||
k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request,
|
|
||||||
tunnel_request_number,
|
|
||||||
message,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
JS_FreeValue(context, message);
|
JS_FreeValue(context, message);
|
||||||
|
|
||||||
tf_printf("tunnel create ssb=%p portal=%s rn=%d target=%s\n", ssb, portal, (int)tunnel_request_number, target);
|
tf_printf("tunnel create ssb=%p portal=%s rn=%d target=%s\n", ssb, portal, (int)tunnel_request_number, target);
|
||||||
|
114
src/task.c
114
src/task.c
@ -235,8 +235,7 @@ static import_record_t** _tf_task_find_import(tf_task_t* task, taskid_t task_id,
|
|||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
import_record_t search =
|
import_record_t search = {
|
||||||
{
|
|
||||||
._task = task_id,
|
._task = task_id,
|
||||||
._export = export_id,
|
._export = export_id,
|
||||||
};
|
};
|
||||||
@ -583,8 +582,7 @@ static JSValue _invokeCatch(JSContext* context, JSValueConst this_val, int argc,
|
|||||||
static void _forward_promise(tf_task_t* from, tf_taskstub_t* to, promiseid_t promise, JSValue result)
|
static void _forward_promise(tf_task_t* from, tf_taskstub_t* to, promiseid_t promise, JSValue result)
|
||||||
{
|
{
|
||||||
// We're not going to serialize/deserialize a promise...
|
// We're not going to serialize/deserialize a promise...
|
||||||
JSValue data[] =
|
JSValue data[] = {
|
||||||
{
|
|
||||||
JS_NewInt32(from->_context, tf_taskstub_get_id(to)),
|
JS_NewInt32(from->_context, tf_taskstub_get_id(to)),
|
||||||
JS_NewInt32(from->_context, promise),
|
JS_NewInt32(from->_context, promise),
|
||||||
};
|
};
|
||||||
@ -744,13 +742,13 @@ exportid_t tf_task_export_function(tf_task_t* task, tf_taskstub_t* to, JSValue f
|
|||||||
if (!export)
|
if (!export)
|
||||||
{
|
{
|
||||||
int id = -1;
|
int id = -1;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
id = task->_nextExport++;
|
id = task->_nextExport++;
|
||||||
} while (_task_get_export(task, id));
|
} while (_task_get_export(task, id));
|
||||||
|
|
||||||
export = tf_malloc(sizeof(export_record_t));
|
export = tf_malloc(sizeof(export_record_t));
|
||||||
*export = (export_record_t)
|
*export = (export_record_t) {
|
||||||
{
|
|
||||||
._export_id = id,
|
._export_id = id,
|
||||||
._taskid = tf_taskstub_get_id(to),
|
._taskid = tf_taskstub_get_id(to),
|
||||||
._function = JS_DupValue(task->_context, function),
|
._function = JS_DupValue(task->_context, function),
|
||||||
@ -885,20 +883,13 @@ char* tf_task_get_debug(tf_task_t* task)
|
|||||||
if (task->_promise_stacks[i].cstack_count)
|
if (task->_promise_stacks[i].cstack_count)
|
||||||
{
|
{
|
||||||
JSValue cstack = JS_NewArray(context);
|
JSValue cstack = JS_NewArray(context);
|
||||||
backtrace_t bt =
|
backtrace_t bt = {
|
||||||
{
|
|
||||||
.context = context,
|
.context = context,
|
||||||
.array = cstack,
|
.array = cstack,
|
||||||
};
|
};
|
||||||
for (int k = 0; k < task->_promise_stacks[i].cstack_count; k++)
|
for (int k = 0; k < task->_promise_stacks[i].cstack_count; k++)
|
||||||
{
|
{
|
||||||
backtrace_pcinfo(
|
backtrace_pcinfo(g_backtrace_state, (uintptr_t)task->_promise_stacks[i].cstack[k], _tf_backtrace_callback, _tf_backtrace_error, &bt);
|
||||||
g_backtrace_state,
|
|
||||||
(uintptr_t)task->_promise_stacks[i].cstack[k],
|
|
||||||
_tf_backtrace_callback,
|
|
||||||
_tf_backtrace_error,
|
|
||||||
&bt);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
JS_SetPropertyStr(context, entry, "cstack", cstack);
|
JS_SetPropertyStr(context, entry, "cstack", cstack);
|
||||||
}
|
}
|
||||||
@ -971,20 +962,34 @@ static const char* _tf_task_get_message_type(tf_task_message_t type)
|
|||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case kResolvePromise: return "kResolvePromise";
|
case kResolvePromise:
|
||||||
case kRejectPromise: return "kRejectPromise";
|
return "kResolvePromise";
|
||||||
case kInvokeExport: return "kInvokeExport";
|
case kRejectPromise:
|
||||||
case kReleaseExport: return "kReleaseExport";
|
return "kRejectPromise";
|
||||||
case kReleaseImport: return "kReleaseImport";
|
case kInvokeExport:
|
||||||
case kActivate: return "kActivate";
|
return "kInvokeExport";
|
||||||
case kExecute: return "kExecute";
|
case kReleaseExport:
|
||||||
case kKill: return "kKill";
|
return "kReleaseExport";
|
||||||
case kSetImports: return "kSetImports";
|
case kReleaseImport:
|
||||||
case kGetExports: return "kGetExports";
|
return "kReleaseImport";
|
||||||
case kLoadFile: return "kLoadFile";
|
case kActivate:
|
||||||
case kTaskError: return "kTaskError";
|
return "kActivate";
|
||||||
case kTaskTrace: return "kTaskTrace";
|
case kExecute:
|
||||||
case kPrint: return "kPrint";
|
return "kExecute";
|
||||||
|
case kKill:
|
||||||
|
return "kKill";
|
||||||
|
case kSetImports:
|
||||||
|
return "kSetImports";
|
||||||
|
case kGetExports:
|
||||||
|
return "kGetExports";
|
||||||
|
case kLoadFile:
|
||||||
|
return "kLoadFile";
|
||||||
|
case kTaskError:
|
||||||
|
return "kTaskError";
|
||||||
|
case kTaskTrace:
|
||||||
|
return "kTaskTrace";
|
||||||
|
case kPrint:
|
||||||
|
return "kPrint";
|
||||||
}
|
}
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
@ -1005,7 +1010,8 @@ void tf_task_on_receive_packet(int packetType, const char* begin, size_t length,
|
|||||||
memcpy(&promise, begin, sizeof(promise));
|
memcpy(&promise, begin, sizeof(promise));
|
||||||
memcpy(&exportId, begin + sizeof(promise), sizeof(exportId));
|
memcpy(&exportId, begin + sizeof(promise), sizeof(exportId));
|
||||||
|
|
||||||
JSValue result = _task_invokeExport_internal(from, to, exportId, begin + sizeof(promiseid_t) + sizeof(exportid_t), length - sizeof(promiseid_t) - sizeof(exportid_t));
|
JSValue result =
|
||||||
|
_task_invokeExport_internal(from, to, exportId, begin + sizeof(promiseid_t) + sizeof(exportid_t), length - sizeof(promiseid_t) - sizeof(exportid_t));
|
||||||
if (JS_IsException(result))
|
if (JS_IsException(result))
|
||||||
{
|
{
|
||||||
_tf_task_sendPromiseReject(to, from, promise, result);
|
_tf_task_sendPromiseReject(to, from, promise, result);
|
||||||
@ -1296,12 +1302,12 @@ JSValue tf_task_allocate_promise(tf_task_t* task, promiseid_t* out_promise)
|
|||||||
JS_FreeValue(task->_context, error);
|
JS_FreeValue(task->_context, error);
|
||||||
|
|
||||||
promiseid_t promiseId;
|
promiseid_t promiseId;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
promiseId = task->_nextPromise++;
|
promiseId = task->_nextPromise++;
|
||||||
} while (_tf_task_find_promise(task, promiseId) || !promiseId);
|
} while (_tf_task_find_promise(task, promiseId) || !promiseId);
|
||||||
|
|
||||||
promise_t promise =
|
promise_t promise = {
|
||||||
{
|
|
||||||
.id = promiseId,
|
.id = promiseId,
|
||||||
.values = { JS_NULL, JS_NULL },
|
.values = { JS_NULL, JS_NULL },
|
||||||
.stack_hash = stack_hash,
|
.stack_hash = stack_hash,
|
||||||
@ -1389,13 +1395,13 @@ static void _promise_release_for_task(tf_task_t* task, taskid_t task_id)
|
|||||||
taskid_t tf_task_allocate_task_id(tf_task_t* task, tf_taskstub_t* stub)
|
taskid_t tf_task_allocate_task_id(tf_task_t* task, tf_taskstub_t* stub)
|
||||||
{
|
{
|
||||||
taskid_t id = 0;
|
taskid_t id = 0;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
id = task->_nextTask++;
|
id = task->_nextTask++;
|
||||||
} while (id == k_task_parent_id || _tf_task_get_stub(task, id));
|
} while (id == k_task_parent_id || _tf_task_get_stub(task, id));
|
||||||
|
|
||||||
task_child_node_t* node = tf_malloc(sizeof(task_child_node_t));
|
task_child_node_t* node = tf_malloc(sizeof(task_child_node_t));
|
||||||
*node = (task_child_node_t)
|
*node = (task_child_node_t) {
|
||||||
{
|
|
||||||
.id = id,
|
.id = id,
|
||||||
.stub = stub,
|
.stub = stub,
|
||||||
.next = task->_children,
|
.next = task->_children,
|
||||||
@ -1410,9 +1416,7 @@ void tf_task_remove_child(tf_task_t* task, tf_taskstub_t* child)
|
|||||||
_import_record_release_for_task(task, tf_taskstub_get_id(child));
|
_import_record_release_for_task(task, tf_taskstub_get_id(child));
|
||||||
_export_record_release_for_task(task, tf_taskstub_get_id(child));
|
_export_record_release_for_task(task, tf_taskstub_get_id(child));
|
||||||
_promise_release_for_task(task, tf_taskstub_get_id(child));
|
_promise_release_for_task(task, tf_taskstub_get_id(child));
|
||||||
for (task_child_node_t** it = &task->_children;
|
for (task_child_node_t** it = &task->_children; *it; it = &(*it)->next)
|
||||||
*it;
|
|
||||||
it = &(*it)->next)
|
|
||||||
{
|
{
|
||||||
if ((*it)->stub == child)
|
if ((*it)->stub == child)
|
||||||
{
|
{
|
||||||
@ -1474,8 +1478,7 @@ static void _tf_task_trace_timer(uv_timer_t* timer)
|
|||||||
task->thread_percent = tf_ssb_get_average_thread_percent(task->_ssb);
|
task->thread_percent = tf_ssb_get_average_thread_percent(task->_ssb);
|
||||||
task->last_hrtime = hrtime;
|
task->last_hrtime = hrtime;
|
||||||
task->last_idle_time = idle_time;
|
task->last_idle_time = idle_time;
|
||||||
const char* k_names[] =
|
const char* k_names[] = {
|
||||||
{
|
|
||||||
"child_tasks",
|
"child_tasks",
|
||||||
"imports",
|
"imports",
|
||||||
"exports",
|
"exports",
|
||||||
@ -1483,8 +1486,7 @@ static void _tf_task_trace_timer(uv_timer_t* timer)
|
|||||||
"idle_percent",
|
"idle_percent",
|
||||||
"thread_percent",
|
"thread_percent",
|
||||||
};
|
};
|
||||||
int64_t values[] =
|
int64_t values[] = {
|
||||||
{
|
|
||||||
task->_child_count,
|
task->_child_count,
|
||||||
task->_import_count,
|
task->_import_count,
|
||||||
task->_export_count,
|
task->_export_count,
|
||||||
@ -1608,8 +1610,7 @@ tf_task_t* tf_task_create()
|
|||||||
JS_SetModuleLoaderFunc(task->_runtime, NULL, _tf_task_module_loader, task);
|
JS_SetModuleLoaderFunc(task->_runtime, NULL, _tf_task_module_loader, task);
|
||||||
|
|
||||||
JS_NewClassID(&_import_class_id);
|
JS_NewClassID(&_import_class_id);
|
||||||
JSClassDef def =
|
JSClassDef def = {
|
||||||
{
|
|
||||||
.class_name = "imported_function",
|
.class_name = "imported_function",
|
||||||
.finalizer = _import_finalizer,
|
.finalizer = _import_finalizer,
|
||||||
.gc_mark = _import_mark_func,
|
.gc_mark = _import_mark_func,
|
||||||
@ -1818,7 +1819,6 @@ void tf_task_destroy(tf_task_t* task)
|
|||||||
for (task_child_node_t* node = task->_children; node; node = node->next)
|
for (task_child_node_t* node = task->_children; node; node = node->next)
|
||||||
{
|
{
|
||||||
JS_FreeValue(task->_context, tf_taskstub_kill(node->stub));
|
JS_FreeValue(task->_context, tf_taskstub_kill(node->stub));
|
||||||
|
|
||||||
}
|
}
|
||||||
uv_run(&task->_loop, UV_RUN_ONCE);
|
uv_run(&task->_loop, UV_RUN_ONCE);
|
||||||
}
|
}
|
||||||
@ -1906,12 +1906,7 @@ void tf_task_destroy(tf_task_t* task)
|
|||||||
uv_signal_stop(&task->sig_int);
|
uv_signal_stop(&task->sig_int);
|
||||||
uv_close((uv_handle_t*)&task->sig_int, _tf_task_on_handle_close);
|
uv_close((uv_handle_t*)&task->sig_int, _tf_task_on_handle_close);
|
||||||
|
|
||||||
while (task->trace_timer.data ||
|
while (task->trace_timer.data || task->gc_timer.data || task->idle.data || task->prepare.data || task->sig_term.data || task->sig_int.data)
|
||||||
task->gc_timer.data ||
|
|
||||||
task->idle.data ||
|
|
||||||
task->prepare.data ||
|
|
||||||
task->sig_term.data ||
|
|
||||||
task->sig_int.data)
|
|
||||||
{
|
{
|
||||||
uv_run(&task->_loop, UV_RUN_ONCE);
|
uv_run(&task->_loop, UV_RUN_ONCE);
|
||||||
}
|
}
|
||||||
@ -1957,8 +1952,7 @@ JSValue tf_task_add_import(tf_task_t* task, taskid_t stub_id, exportid_t export_
|
|||||||
JSValue function = JS_NewObjectClass(task->_context, _import_class_id);
|
JSValue function = JS_NewObjectClass(task->_context, _import_class_id);
|
||||||
import_record_t* import = tf_malloc(sizeof(import_record_t));
|
import_record_t* import = tf_malloc(sizeof(import_record_t));
|
||||||
JS_SetOpaque(function, import);
|
JS_SetOpaque(function, import);
|
||||||
*import = (import_record_t)
|
*import = (import_record_t) {
|
||||||
{
|
|
||||||
._function = function,
|
._function = function,
|
||||||
._export = export_id,
|
._export = export_id,
|
||||||
._owner = task,
|
._owner = task,
|
||||||
@ -2102,12 +2096,7 @@ static void _tf_task_timeout_callback(uv_timer_t* handle)
|
|||||||
timeout_t* timeout = handle->data;
|
timeout_t* timeout = handle->data;
|
||||||
tf_trace_begin(tf_task_get_trace(timeout->_task), "_tf_task_timeout_callback");
|
tf_trace_begin(tf_task_get_trace(timeout->_task), "_tf_task_timeout_callback");
|
||||||
JSContext* context = tf_task_get_context(timeout->_task);
|
JSContext* context = tf_task_get_context(timeout->_task);
|
||||||
JSValue result = JS_Call(
|
JSValue result = JS_Call(context, timeout->_callback, JS_NULL, 0, NULL);
|
||||||
context,
|
|
||||||
timeout->_callback,
|
|
||||||
JS_NULL,
|
|
||||||
0,
|
|
||||||
NULL);
|
|
||||||
tf_util_report_error(context, result);
|
tf_util_report_error(context, result);
|
||||||
JS_FreeValue(context, result);
|
JS_FreeValue(context, result);
|
||||||
JS_FreeValue(context, timeout->_callback);
|
JS_FreeValue(context, timeout->_callback);
|
||||||
@ -2121,8 +2110,7 @@ static JSValue _tf_task_setTimeout(JSContext* context, JSValueConst this_val, in
|
|||||||
tf_task_t* task = JS_GetContextOpaque(context);
|
tf_task_t* task = JS_GetContextOpaque(context);
|
||||||
|
|
||||||
timeout_t* timeout = tf_malloc(sizeof(timeout_t));
|
timeout_t* timeout = tf_malloc(sizeof(timeout_t));
|
||||||
*timeout = (timeout_t)
|
*timeout = (timeout_t) {
|
||||||
{
|
|
||||||
._task = task,
|
._task = task,
|
||||||
._callback = JS_DupValue(context, argv[0]),
|
._callback = JS_DupValue(context, argv[0]),
|
||||||
._timer = { .data = timeout },
|
._timer = { .data = timeout },
|
||||||
|
@ -17,7 +17,8 @@ typedef struct _tf_ssb_t tf_ssb_t;
|
|||||||
|
|
||||||
static const taskid_t k_task_parent_id = 0;
|
static const taskid_t k_task_parent_id = 0;
|
||||||
|
|
||||||
typedef enum _tf_task_message_t {
|
typedef enum _tf_task_message_t
|
||||||
|
{
|
||||||
kResolvePromise,
|
kResolvePromise,
|
||||||
kRejectPromise,
|
kRejectPromise,
|
||||||
kInvokeExport,
|
kInvokeExport,
|
||||||
@ -71,8 +72,8 @@ void tf_task_remove_child(tf_task_t* task, tf_taskstub_t* child);
|
|||||||
|
|
||||||
void tf_task_report_error(tf_task_t* task, JSValue error);
|
void tf_task_report_error(tf_task_t* task, JSValue error);
|
||||||
|
|
||||||
JSValue tf_try_get_typed_array_buffer(JSContext *ctx, JSValueConst obj, size_t *pbyte_offset, size_t *pbyte_length, size_t *pbytes_per_element);
|
JSValue tf_try_get_typed_array_buffer(JSContext* ctx, JSValueConst obj, size_t* pbyte_offset, size_t* pbyte_length, size_t* pbytes_per_element);
|
||||||
uint8_t *tf_try_get_array_buffer(JSContext *ctx, size_t *psize, JSValueConst obj);
|
uint8_t* tf_try_get_array_buffer(JSContext* ctx, size_t* psize, JSValueConst obj);
|
||||||
|
|
||||||
bool tf_task_send_error_to_parent(tf_task_t* task, JSValue error);
|
bool tf_task_send_error_to_parent(tf_task_t* task, JSValue error);
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ static JSValue _taskstub_get_on_print(JSContext* context, JSValueConst this_val,
|
|||||||
static JSValue _taskstub_set_on_print(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
static JSValue _taskstub_set_on_print(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
||||||
static JSValue _taskstub_loadFile(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
static JSValue _taskstub_loadFile(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
||||||
static void _taskstub_on_process_exit(uv_process_t* process, int64_t status, int terminationSignal);
|
static void _taskstub_on_process_exit(uv_process_t* process, int64_t status, int terminationSignal);
|
||||||
static void _taskstub_finalizer(JSRuntime *runtime, JSValue value);
|
static void _taskstub_finalizer(JSRuntime* runtime, JSValue value);
|
||||||
|
|
||||||
static void _tf_taskstub_run_sandbox_thread(void* data)
|
static void _tf_taskstub_run_sandbox_thread(void* data)
|
||||||
{
|
{
|
||||||
@ -92,32 +92,17 @@ static JSValue _taskstub_create(JSContext* context, JSValueConst this_val, int a
|
|||||||
|
|
||||||
JSAtom atom = JS_NewAtom(context, "onExit");
|
JSAtom atom = JS_NewAtom(context, "onExit");
|
||||||
JS_DefinePropertyGetSet(
|
JS_DefinePropertyGetSet(
|
||||||
context,
|
context, taskObject, atom, JS_NewCFunction(context, _taskstub_get_on_exit, "getOnExit", 0), JS_NewCFunction(context, _taskstub_set_on_exit, "setOnExit", 0), 0);
|
||||||
taskObject,
|
|
||||||
atom,
|
|
||||||
JS_NewCFunction(context, _taskstub_get_on_exit, "getOnExit", 0),
|
|
||||||
JS_NewCFunction(context, _taskstub_set_on_exit, "setOnExit", 0),
|
|
||||||
0);
|
|
||||||
JS_FreeAtom(context, atom);
|
JS_FreeAtom(context, atom);
|
||||||
|
|
||||||
atom = JS_NewAtom(context, "onError");
|
atom = JS_NewAtom(context, "onError");
|
||||||
JS_DefinePropertyGetSet(
|
JS_DefinePropertyGetSet(
|
||||||
context,
|
context, taskObject, atom, JS_NewCFunction(context, _taskstub_get_on_error, "getOnError", 0), JS_NewCFunction(context, _taskstub_set_on_error, "setOnError", 0), 0);
|
||||||
taskObject,
|
|
||||||
atom,
|
|
||||||
JS_NewCFunction(context, _taskstub_get_on_error, "getOnError", 0),
|
|
||||||
JS_NewCFunction(context, _taskstub_set_on_error, "setOnError", 0),
|
|
||||||
0);
|
|
||||||
JS_FreeAtom(context, atom);
|
JS_FreeAtom(context, atom);
|
||||||
|
|
||||||
atom = JS_NewAtom(context, "onPrint");
|
atom = JS_NewAtom(context, "onPrint");
|
||||||
JS_DefinePropertyGetSet(
|
JS_DefinePropertyGetSet(
|
||||||
context,
|
context, taskObject, atom, JS_NewCFunction(context, _taskstub_get_on_print, "getOnPrint", 0), JS_NewCFunction(context, _taskstub_set_on_print, "setOnPrint", 0), 0);
|
||||||
taskObject,
|
|
||||||
atom,
|
|
||||||
JS_NewCFunction(context, _taskstub_get_on_print, "getOnPrint", 0),
|
|
||||||
JS_NewCFunction(context, _taskstub_set_on_print, "setOnPrint", 0),
|
|
||||||
0);
|
|
||||||
JS_FreeAtom(context, atom);
|
JS_FreeAtom(context, atom);
|
||||||
|
|
||||||
JS_SetPropertyStr(context, taskObject, "activate", JS_NewCFunction(context, _taskstub_activate, "activate", 0));
|
JS_SetPropertyStr(context, taskObject, "activate", JS_NewCFunction(context, _taskstub_activate, "activate", 0));
|
||||||
@ -184,7 +169,7 @@ static JSValue _taskstub_create(JSContext* context, JSValueConst this_val, int a
|
|||||||
io[2].flags = UV_INHERIT_FD;
|
io[2].flags = UV_INHERIT_FD;
|
||||||
io[2].data.fd = STDERR_FILENO;
|
io[2].data.fd = STDERR_FILENO;
|
||||||
|
|
||||||
uv_process_options_t options = {0};
|
uv_process_options_t options = { 0 };
|
||||||
options.args = command_argv;
|
options.args = command_argv;
|
||||||
options.exit_cb = _taskstub_on_process_exit;
|
options.exit_cb = _taskstub_on_process_exit;
|
||||||
options.stdio = io;
|
options.stdio = io;
|
||||||
@ -221,8 +206,7 @@ static void _taskstub_gc_mark(JSRuntime* rt, JSValueConst value, JS_MarkFunc mar
|
|||||||
|
|
||||||
JSValue tf_taskstub_register(JSContext* context)
|
JSValue tf_taskstub_register(JSContext* context)
|
||||||
{
|
{
|
||||||
JSClassDef def =
|
JSClassDef def = {
|
||||||
{
|
|
||||||
.class_name = "TaskStub",
|
.class_name = "TaskStub",
|
||||||
.finalizer = &_taskstub_finalizer,
|
.finalizer = &_taskstub_finalizer,
|
||||||
.gc_mark = _taskstub_gc_mark,
|
.gc_mark = _taskstub_gc_mark,
|
||||||
@ -285,9 +269,7 @@ tf_taskstub_t* tf_taskstub_create_parent(tf_task_t* task, uv_file file)
|
|||||||
|
|
||||||
static void _taskstub_cleanup(tf_taskstub_t* stub)
|
static void _taskstub_cleanup(tf_taskstub_t* stub)
|
||||||
{
|
{
|
||||||
if (!stub->_process.data &&
|
if (!stub->_process.data && JS_IsUndefined(stub->_object) && stub->_finalized)
|
||||||
JS_IsUndefined(stub->_object) &&
|
|
||||||
stub->_finalized)
|
|
||||||
{
|
{
|
||||||
tf_free(stub);
|
tf_free(stub);
|
||||||
}
|
}
|
||||||
|
90
src/tests.c
90
src/tests.c
@ -60,8 +60,7 @@ static void _test_nop(const tf_test_options_t* options)
|
|||||||
|
|
||||||
static void _test_child(const tf_test_options_t* options)
|
static void _test_child(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
_write_file(
|
_write_file("out/test.js",
|
||||||
"out/test.js",
|
|
||||||
"var task = new Task();\n"
|
"var task = new Task();\n"
|
||||||
"task.onExit = function() {\n"
|
"task.onExit = function() {\n"
|
||||||
" print('child exited');\n"
|
" print('child exited');\n"
|
||||||
@ -73,8 +72,7 @@ static void _test_child(const tf_test_options_t* options)
|
|||||||
" });\n"
|
" });\n"
|
||||||
"});");
|
"});");
|
||||||
|
|
||||||
_write_file(
|
_write_file("out/child.js",
|
||||||
"out/child.js",
|
|
||||||
"print('I am the child process.');\n"
|
"print('I am the child process.');\n"
|
||||||
"exit(0);\n");
|
"exit(0);\n");
|
||||||
|
|
||||||
@ -109,8 +107,7 @@ static void _test_promise(const tf_test_options_t* options)
|
|||||||
" });\n"
|
" });\n"
|
||||||
"});\n");
|
"});\n");
|
||||||
|
|
||||||
_write_file(
|
_write_file("out/child.js",
|
||||||
"out/child.js",
|
|
||||||
"exports = {\n"
|
"exports = {\n"
|
||||||
" add: function(left, right) {\n"
|
" add: function(left, right) {\n"
|
||||||
" return left + right;\n"
|
" return left + right;\n"
|
||||||
@ -131,8 +128,7 @@ static void _test_promise(const tf_test_options_t* options)
|
|||||||
|
|
||||||
static void _test_promise_remote_throw(const tf_test_options_t* options)
|
static void _test_promise_remote_throw(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
_write_file(
|
_write_file("out/test.js",
|
||||||
"out/test.js",
|
|
||||||
"var task = new Task();\n"
|
"var task = new Task();\n"
|
||||||
"task.activate();\n"
|
"task.activate();\n"
|
||||||
"File.readFile('out/child.js').then(function(data) {\n"
|
"File.readFile('out/child.js').then(function(data) {\n"
|
||||||
@ -153,8 +149,7 @@ static void _test_promise_remote_throw(const tf_test_options_t* options)
|
|||||||
" });\n"
|
" });\n"
|
||||||
"});\n");
|
"});\n");
|
||||||
|
|
||||||
_write_file(
|
_write_file("out/child.js",
|
||||||
"out/child.js",
|
|
||||||
"exports = {\n"
|
"exports = {\n"
|
||||||
" add: function(left, right) {\n"
|
" add: function(left, right) {\n"
|
||||||
" throw new Error('fail');\n"
|
" throw new Error('fail');\n"
|
||||||
@ -175,8 +170,7 @@ static void _test_promise_remote_throw(const tf_test_options_t* options)
|
|||||||
|
|
||||||
static void _test_promise_remote_reject(const tf_test_options_t* options)
|
static void _test_promise_remote_reject(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
_write_file(
|
_write_file("out/test.js",
|
||||||
"out/test.js",
|
|
||||||
"var task = new Task();\n"
|
"var task = new Task();\n"
|
||||||
"task.activate();\n"
|
"task.activate();\n"
|
||||||
"File.readFile('out/child.js').then(function(data) {\n"
|
"File.readFile('out/child.js').then(function(data) {\n"
|
||||||
@ -197,8 +191,7 @@ static void _test_promise_remote_reject(const tf_test_options_t* options)
|
|||||||
" });\n"
|
" });\n"
|
||||||
"});\n");
|
"});\n");
|
||||||
|
|
||||||
_write_file(
|
_write_file("out/child.js",
|
||||||
"out/child.js",
|
|
||||||
"exports = {\n"
|
"exports = {\n"
|
||||||
" add: function(left, right) {\n"
|
" add: function(left, right) {\n"
|
||||||
" return new Promise(function(resolve, reject) {\n"
|
" return new Promise(function(resolve, reject) {\n"
|
||||||
@ -221,8 +214,7 @@ static void _test_promise_remote_reject(const tf_test_options_t* options)
|
|||||||
|
|
||||||
static void _test_database(const tf_test_options_t* options)
|
static void _test_database(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
_write_file(
|
_write_file("out/test.js",
|
||||||
"out/test.js",
|
|
||||||
"var db = new Database('testdb');\n"
|
"var db = new Database('testdb');\n"
|
||||||
"if (db.get('a')) {\n"
|
"if (db.get('a')) {\n"
|
||||||
" exit(1);\n"
|
" exit(1);\n"
|
||||||
@ -265,8 +257,7 @@ static void _test_database(const tf_test_options_t* options)
|
|||||||
|
|
||||||
static void _test_this(const tf_test_options_t* options)
|
static void _test_this(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
_write_file(
|
_write_file("out/test.js",
|
||||||
"out/test.js",
|
|
||||||
"var task = new Task();\n"
|
"var task = new Task();\n"
|
||||||
"task.activate.bind(null).apply();\n"
|
"task.activate.bind(null).apply();\n"
|
||||||
"exit(0);\n");
|
"exit(0);\n");
|
||||||
@ -284,8 +275,7 @@ static void _test_this(const tf_test_options_t* options)
|
|||||||
|
|
||||||
static void _test_await(const tf_test_options_t* options)
|
static void _test_await(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
_write_file(
|
_write_file("out/test.js",
|
||||||
"out/test.js",
|
|
||||||
"print('hi');\n"
|
"print('hi');\n"
|
||||||
"function foobar() {\n"
|
"function foobar() {\n"
|
||||||
" return new Promise(function(resolve, reject) {\n"
|
" return new Promise(function(resolve, reject) {\n"
|
||||||
@ -315,21 +305,18 @@ static void _test_await(const tf_test_options_t* options)
|
|||||||
|
|
||||||
static void _test_import(const tf_test_options_t* options)
|
static void _test_import(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
_write_file(
|
_write_file("out/test.js",
|
||||||
"out/test.js",
|
|
||||||
"import * as req from './required.js';\n"
|
"import * as req from './required.js';\n"
|
||||||
"if (req.foo() != 12345) {\n"
|
"if (req.foo() != 12345) {\n"
|
||||||
" exit(1);\n"
|
" exit(1);\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
|
|
||||||
_write_file(
|
_write_file("out/required.js",
|
||||||
"out/required.js",
|
|
||||||
"export function foo() {\n"
|
"export function foo() {\n"
|
||||||
" return 12345;\n"
|
" return 12345;\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
|
|
||||||
_write_file(
|
_write_file("out/bad.js",
|
||||||
"out/bad.js",
|
|
||||||
"import * as req from './missing.js';\n"
|
"import * as req from './missing.js';\n"
|
||||||
"if (req.foo() != 12345) {\n"
|
"if (req.foo() != 12345) {\n"
|
||||||
" exit(1);\n"
|
" exit(1);\n"
|
||||||
@ -374,8 +361,7 @@ static void _test_exit(const tf_test_options_t* options)
|
|||||||
|
|
||||||
static void _test_icu(const tf_test_options_t* options)
|
static void _test_icu(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
_write_file(
|
_write_file("out/test.js",
|
||||||
"out/test.js",
|
|
||||||
"print('Hi');\n"
|
"print('Hi');\n"
|
||||||
"print(parseInt('3').toLocaleString());\n");
|
"print(parseInt('3').toLocaleString());\n");
|
||||||
|
|
||||||
@ -392,8 +378,7 @@ static void _test_icu(const tf_test_options_t* options)
|
|||||||
|
|
||||||
static void _test_uint8array(const tf_test_options_t* options)
|
static void _test_uint8array(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
_write_file(
|
_write_file("out/test.js",
|
||||||
"out/test.js",
|
|
||||||
"var task = new Task();\n"
|
"var task = new Task();\n"
|
||||||
"task.onExit = function() {\n"
|
"task.onExit = function() {\n"
|
||||||
" print('child exited');\n"
|
" print('child exited');\n"
|
||||||
@ -421,8 +406,7 @@ static void _test_uint8array(const tf_test_options_t* options)
|
|||||||
" })\n"
|
" })\n"
|
||||||
"})\n");
|
"})\n");
|
||||||
|
|
||||||
_write_file(
|
_write_file("out/child.js",
|
||||||
"out/child.js",
|
|
||||||
"exports = {\n"
|
"exports = {\n"
|
||||||
" test: function(data) {\n"
|
" test: function(data) {\n"
|
||||||
" return data;\n"
|
" return data;\n"
|
||||||
@ -443,8 +427,7 @@ static void _test_uint8array(const tf_test_options_t* options)
|
|||||||
|
|
||||||
static void _test_float(const tf_test_options_t* options)
|
static void _test_float(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
_write_file(
|
_write_file("out/test.js",
|
||||||
"out/test.js",
|
|
||||||
"var task = new Task();\n"
|
"var task = new Task();\n"
|
||||||
"task.onExit = function() {\n"
|
"task.onExit = function() {\n"
|
||||||
" print('child exited');\n"
|
" print('child exited');\n"
|
||||||
@ -461,8 +444,7 @@ static void _test_float(const tf_test_options_t* options)
|
|||||||
" });\n"
|
" });\n"
|
||||||
"});");
|
"});");
|
||||||
|
|
||||||
_write_file(
|
_write_file("out/child.js",
|
||||||
"out/child.js",
|
|
||||||
"print(\"child\");\n"
|
"print(\"child\");\n"
|
||||||
"exports = {\n"
|
"exports = {\n"
|
||||||
" test: function(value) {\n"
|
" test: function(value) {\n"
|
||||||
@ -470,8 +452,7 @@ static void _test_float(const tf_test_options_t* options)
|
|||||||
" return value;\n"
|
" return value;\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"print(\"child ready\");\n"
|
"print(\"child ready\");\n");
|
||||||
);
|
|
||||||
|
|
||||||
char command[256];
|
char command[256];
|
||||||
snprintf(command, sizeof(command), "%s run --db-path=:memory: -s out/test.js" TEST_ARGS, options->exe_path);
|
snprintf(command, sizeof(command), "%s run --db-path=:memory: -s out/test.js" TEST_ARGS, options->exe_path);
|
||||||
@ -487,8 +468,7 @@ static void _test_float(const tf_test_options_t* options)
|
|||||||
|
|
||||||
static void _test_socket(const tf_test_options_t* options)
|
static void _test_socket(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
_write_file(
|
_write_file("out/test.js",
|
||||||
"out/test.js",
|
|
||||||
"'use strict';\n"
|
"'use strict';\n"
|
||||||
"\n"
|
"\n"
|
||||||
"var s = new Socket();\n"
|
"var s = new Socket();\n"
|
||||||
@ -574,8 +554,7 @@ static void _test_socket(const tf_test_options_t* options)
|
|||||||
|
|
||||||
static void _test_file(const tf_test_options_t* options)
|
static void _test_file(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
_write_file(
|
_write_file("out/test.js",
|
||||||
"out/test.js",
|
|
||||||
"'use strict';\n"
|
"'use strict';\n"
|
||||||
"File.readFile('out/test.js').then(function(data) {\n"
|
"File.readFile('out/test.js').then(function(data) {\n"
|
||||||
"}).catch(function(error) {\n"
|
"}).catch(function(error) {\n"
|
||||||
@ -602,8 +581,7 @@ static void _test_file(const tf_test_options_t* options)
|
|||||||
|
|
||||||
static void _test_sign(const tf_test_options_t* options)
|
static void _test_sign(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
_write_file(
|
_write_file("out/test.js",
|
||||||
"out/test.js",
|
|
||||||
"'use strict';\n"
|
"'use strict';\n"
|
||||||
"let id = ssb.createIdentity('test');\n"
|
"let id = ssb.createIdentity('test');\n"
|
||||||
"print(id);\n"
|
"print(id);\n"
|
||||||
@ -617,8 +595,7 @@ static void _test_sign(const tf_test_options_t* options)
|
|||||||
"}\n"
|
"}\n"
|
||||||
"if (ssb.hmacsha256verify(id, 'hello1', sig)) {\n"
|
"if (ssb.hmacsha256verify(id, 'hello1', sig)) {\n"
|
||||||
" exit(1);\n"
|
" exit(1);\n"
|
||||||
"}\n"
|
"}\n");
|
||||||
);
|
|
||||||
|
|
||||||
char command[256];
|
char command[256];
|
||||||
snprintf(command, sizeof(command), "%s run --db-path=:memory: -s out/test.js" TEST_ARGS, options->exe_path);
|
snprintf(command, sizeof(command), "%s run --db-path=:memory: -s out/test.js" TEST_ARGS, options->exe_path);
|
||||||
@ -633,16 +610,14 @@ static void _test_sign(const tf_test_options_t* options)
|
|||||||
|
|
||||||
static void _test_b64(const tf_test_options_t* options)
|
static void _test_b64(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
_write_file(
|
_write_file("out/test.js",
|
||||||
"out/test.js",
|
|
||||||
"'use strict';\n"
|
"'use strict';\n"
|
||||||
"print(base64Encode('hello'));\n"
|
"print(base64Encode('hello'));\n"
|
||||||
"let x = utf8Decode(base64Decode(base64Encode('hello')));\n"
|
"let x = utf8Decode(base64Decode(base64Encode('hello')));\n"
|
||||||
"if (x !== 'hello') {\n"
|
"if (x !== 'hello') {\n"
|
||||||
" print(x);\n"
|
" print(x);\n"
|
||||||
" exit(1);\n"
|
" exit(1);\n"
|
||||||
"}\n"
|
"}\n");
|
||||||
);
|
|
||||||
|
|
||||||
char command[256];
|
char command[256];
|
||||||
snprintf(command, sizeof(command), "%s run --db-path=:memory: -s out/test.js" TEST_ARGS, options->exe_path);
|
snprintf(command, sizeof(command), "%s run --db-path=:memory: -s out/test.js" TEST_ARGS, options->exe_path);
|
||||||
@ -656,7 +631,8 @@ static void _test_b64(const tf_test_options_t* options)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char* k_bip39_test_key_base64 = "GO0Lv5BvcuuJJdHrokHoo0PmCDC/XjO/SZ6H+ddq4UvWd/VPW1RJrjd1aCUIfPIojFXrWMb8R54vVerU2TwjdQ==.ed25519";
|
static const char* k_bip39_test_key_base64 = "GO0Lv5BvcuuJJdHrokHoo0PmCDC/XjO/SZ6H+ddq4UvWd/VPW1RJrjd1aCUIfPIojFXrWMb8R54vVerU2TwjdQ==.ed25519";
|
||||||
static const char* k_bip32_test_key_words = "body hair useful camp warm into cause riot two bamboo kick educate dinosaur advice seed type crisp where guilt avocado output rely lunch goddess";
|
static const char* k_bip32_test_key_words =
|
||||||
|
"body hair useful camp warm into cause riot two bamboo kick educate dinosaur advice seed type crisp where guilt avocado output rely lunch goddess";
|
||||||
|
|
||||||
static void _test_bip39(const tf_test_options_t* options)
|
static void _test_bip39(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
@ -712,9 +688,9 @@ static void _test_http_thread(void* data)
|
|||||||
|
|
||||||
static void _test_http_handler(tf_http_request_t* request)
|
static void _test_http_handler(tf_http_request_t* request)
|
||||||
{
|
{
|
||||||
const char* headers[] =
|
const char* headers[] = {
|
||||||
{
|
"User-Agent",
|
||||||
"User-Agent", "TildeFriends/1.0",
|
"TildeFriends/1.0",
|
||||||
};
|
};
|
||||||
const char* k_payload = "Hello, world!\n";
|
const char* k_payload = "Hello, world!\n";
|
||||||
tf_http_respond(request, 200, headers, 1, k_payload, strlen(k_payload));
|
tf_http_respond(request, 200, headers, 1, k_payload, strlen(k_payload));
|
||||||
@ -725,9 +701,9 @@ static void _test_http_handler_post(tf_http_request_t* request)
|
|||||||
const void* body = NULL;
|
const void* body = NULL;
|
||||||
size_t size = tf_http_get_body(request, &body);
|
size_t size = tf_http_get_body(request, &body);
|
||||||
tf_printf("size = %zd body=%.*s\n", size, (int)size, (const char*)body);
|
tf_printf("size = %zd body=%.*s\n", size, (int)size, (const char*)body);
|
||||||
const char* headers[] =
|
const char* headers[] = {
|
||||||
{
|
"Connection",
|
||||||
"Connection", "close",
|
"close",
|
||||||
};
|
};
|
||||||
const char* k_payload = "Hello, world!\n";
|
const char* k_payload = "Hello, world!\n";
|
||||||
tf_http_respond(request, 200, headers, 1, k_payload, strlen(k_payload));
|
tf_http_respond(request, 200, headers, 1, k_payload, strlen(k_payload));
|
||||||
|
@ -10,17 +10,20 @@
|
|||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
|
|
||||||
typedef enum _direction_t {
|
typedef enum _direction_t
|
||||||
|
{
|
||||||
k_direction_undetermined,
|
k_direction_undetermined,
|
||||||
k_direction_accept,
|
k_direction_accept,
|
||||||
k_direction_connect,
|
k_direction_connect,
|
||||||
} direction_t;
|
} direction_t;
|
||||||
|
|
||||||
typedef struct _tf_tls_context_t {
|
typedef struct _tf_tls_context_t
|
||||||
|
{
|
||||||
SSL_CTX* context;
|
SSL_CTX* context;
|
||||||
} tf_tls_context_t;
|
} tf_tls_context_t;
|
||||||
|
|
||||||
typedef struct _tf_tls_session_t {
|
typedef struct _tf_tls_session_t
|
||||||
|
{
|
||||||
tf_tls_context_t* context;
|
tf_tls_context_t* context;
|
||||||
BIO* bio_in;
|
BIO* bio_in;
|
||||||
BIO* bio_out;
|
BIO* bio_out;
|
||||||
|
@ -6,13 +6,15 @@
|
|||||||
typedef struct _tf_tls_context_t tf_tls_context_t;
|
typedef struct _tf_tls_context_t tf_tls_context_t;
|
||||||
typedef struct _tf_tls_session_t tf_tls_session_t;
|
typedef struct _tf_tls_session_t tf_tls_session_t;
|
||||||
|
|
||||||
typedef enum _tf_tls_handshake_t {
|
typedef enum _tf_tls_handshake_t
|
||||||
|
{
|
||||||
k_tls_handshake_done,
|
k_tls_handshake_done,
|
||||||
k_tls_handshake_more,
|
k_tls_handshake_more,
|
||||||
k_tls_handshake_failed,
|
k_tls_handshake_failed,
|
||||||
} tf_tls_handshake_t;
|
} tf_tls_handshake_t;
|
||||||
|
|
||||||
typedef enum _tf_tls_read_t {
|
typedef enum _tf_tls_read_t
|
||||||
|
{
|
||||||
k_tls_read_zero = -1,
|
k_tls_read_zero = -1,
|
||||||
k_tls_read_failed = -2,
|
k_tls_read_failed = -2,
|
||||||
} tf_tls_read_t;
|
} tf_tls_read_t;
|
||||||
|
@ -11,14 +11,15 @@
|
|||||||
static JSClassID _classId;
|
static JSClassID _classId;
|
||||||
static int _count;
|
static int _count;
|
||||||
|
|
||||||
typedef struct _tf_tls_context_t {
|
typedef struct _tf_tls_context_t
|
||||||
|
{
|
||||||
tf_tls_context_t* context;
|
tf_tls_context_t* context;
|
||||||
tf_task_t* task;
|
tf_task_t* task;
|
||||||
JSValue object;
|
JSValue object;
|
||||||
} tf_tls_context_t;
|
} tf_tls_context_t;
|
||||||
|
|
||||||
static JSValue _tls_context_create(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
static JSValue _tls_context_create(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
||||||
static void _tls_context_finalizer(JSRuntime *runtime, JSValue value);
|
static void _tls_context_finalizer(JSRuntime* runtime, JSValue value);
|
||||||
|
|
||||||
static JSValue _tls_context_set_certificate(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
static JSValue _tls_context_set_certificate(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||||
{
|
{
|
||||||
@ -50,8 +51,7 @@ static JSValue _tls_context_add_trusted_certificate(JSContext* context, JSValueC
|
|||||||
JSValue tf_tls_context_register(JSContext* context)
|
JSValue tf_tls_context_register(JSContext* context)
|
||||||
{
|
{
|
||||||
JS_NewClassID(&_classId);
|
JS_NewClassID(&_classId);
|
||||||
JSClassDef def =
|
JSClassDef def = {
|
||||||
{
|
|
||||||
.class_name = "TlsContext",
|
.class_name = "TlsContext",
|
||||||
.finalizer = _tls_context_finalizer,
|
.finalizer = _tls_context_finalizer,
|
||||||
};
|
};
|
||||||
@ -92,7 +92,7 @@ static JSValue _tls_context_create(JSContext* context, JSValueConst this_val, in
|
|||||||
return tls->object;
|
return tls->object;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tls_context_finalizer(JSRuntime *runtime, JSValue value)
|
static void _tls_context_finalizer(JSRuntime* runtime, JSValue value)
|
||||||
{
|
{
|
||||||
tf_tls_context_t* tls = JS_GetOpaque(value, _classId);
|
tf_tls_context_t* tls = JS_GetOpaque(value, _classId);
|
||||||
if (tls->context)
|
if (tls->context)
|
||||||
|
24
src/trace.c
24
src/trace.c
@ -208,8 +208,7 @@ static tf_trace_thread_t* _tf_trace_get_thread(tf_trace_t* trace, pthread_t self
|
|||||||
if (!found)
|
if (!found)
|
||||||
{
|
{
|
||||||
found = tf_malloc(sizeof(tf_trace_thread_t));
|
found = tf_malloc(sizeof(tf_trace_thread_t));
|
||||||
*found = (tf_trace_thread_t)
|
*found = (tf_trace_thread_t) {
|
||||||
{
|
|
||||||
.id = self,
|
.id = self,
|
||||||
};
|
};
|
||||||
#if defined(__linux__) && !defined(__ANDROID__)
|
#if defined(__linux__) && !defined(__ANDROID__)
|
||||||
@ -242,7 +241,6 @@ static void _tf_push_stack(tf_trace_t* trace, pthread_t self, const char* name,
|
|||||||
stack->names[stack->count] = name;
|
stack->names[stack->count] = name;
|
||||||
stack->tags[stack->count] = tag;
|
stack->tags[stack->count] = tag;
|
||||||
stack->count++;
|
stack->count++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* _tf_pop_stack(tf_trace_t* trace, pthread_t self, void* tag)
|
static const char* _tf_pop_stack(tf_trace_t* trace, pthread_t self, void* tag)
|
||||||
@ -254,9 +252,7 @@ static const char* _tf_pop_stack(tf_trace_t* trace, pthread_t self, void* tag)
|
|||||||
stack = stack->next;
|
stack = stack->next;
|
||||||
}
|
}
|
||||||
const char* name = NULL;
|
const char* name = NULL;
|
||||||
if (stack &&
|
if (stack && stack->count > 0 && stack->tags[stack->count - 1] == tag)
|
||||||
stack->count > 0 &&
|
|
||||||
stack->tags[stack->count - 1] == tag)
|
|
||||||
{
|
{
|
||||||
name = stack->names[stack->count - 1];
|
name = stack->names[stack->count - 1];
|
||||||
stack->count--;
|
stack->count--;
|
||||||
@ -302,7 +298,8 @@ static void _tf_trace_end_tagged(tf_trace_t* trace, void* tag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char line[1024];
|
char line[1024];
|
||||||
int p = snprintf(line, sizeof(line), "{\"ph\": \"E\", \"pid\": %d, \"tid\": %" PRId64 ", \"ts\": %" PRId64 ", \"name\": \"", getpid(), (int64_t)pthread_self(), _trace_ts());
|
int p =
|
||||||
|
snprintf(line, sizeof(line), "{\"ph\": \"E\", \"pid\": %d, \"tid\": %" PRId64 ", \"ts\": %" PRId64 ", \"name\": \"", getpid(), (int64_t)pthread_self(), _trace_ts());
|
||||||
p += _tf_trace_escape_name(line + p, sizeof(line) - p, name);
|
p += _tf_trace_escape_name(line + p, sizeof(line) - p, name);
|
||||||
p += snprintf(line + p, sizeof(line) - p, "\"},");
|
p += snprintf(line + p, sizeof(line) - p, "\"},");
|
||||||
p = tf_min(p, tf_countof(line));
|
p = tf_min(p, tf_countof(line));
|
||||||
@ -330,20 +327,15 @@ char* tf_trace_export(tf_trace_t* trace)
|
|||||||
size += snprintf(buffer, k_buffer_size, "{\"displayTimeUnit\": \"ns\",\n\"traceEvents\": [\n");
|
size += snprintf(buffer, k_buffer_size, "{\"displayTimeUnit\": \"ns\",\n\"traceEvents\": [\n");
|
||||||
if (*trace->process_name)
|
if (*trace->process_name)
|
||||||
{
|
{
|
||||||
size += snprintf(buffer + size, k_buffer_size - size,
|
size += snprintf(
|
||||||
"{\"ph\":\"M\",\"pid\":%d,\"name\":\"process_name\",\"args\":{\"name\":\"%s\"}},\n",
|
buffer + size, k_buffer_size - size, "{\"ph\":\"M\",\"pid\":%d,\"name\":\"process_name\",\"args\":{\"name\":\"%s\"}},\n", getpid(), trace->process_name);
|
||||||
getpid(),
|
|
||||||
trace->process_name);
|
|
||||||
}
|
}
|
||||||
uv_rwlock_rdlock(&trace->threads_lock);
|
uv_rwlock_rdlock(&trace->threads_lock);
|
||||||
for (int i = 0; i < trace->threads_count; i++)
|
for (int i = 0; i < trace->threads_count; i++)
|
||||||
{
|
{
|
||||||
tf_trace_thread_t* thread = trace->threads[i];
|
tf_trace_thread_t* thread = trace->threads[i];
|
||||||
size += snprintf(buffer + size, k_buffer_size - size,
|
size += snprintf(buffer + size, k_buffer_size - size, "{\"ph\":\"M\",\"pid\":%d,\"tid\":%" PRId64 ",\"name\":\"thread_name\",\"args\":{\"name\":\"%s\"}},\n",
|
||||||
"{\"ph\":\"M\",\"pid\":%d,\"tid\":%" PRId64 ",\"name\":\"thread_name\",\"args\":{\"name\":\"%s\"}},\n",
|
getpid(), (uint64_t)thread->id, thread->name);
|
||||||
getpid(),
|
|
||||||
(uint64_t)thread->id,
|
|
||||||
thread->name);
|
|
||||||
}
|
}
|
||||||
uv_rwlock_rdunlock(&trace->threads_lock);
|
uv_rwlock_rdunlock(&trace->threads_lock);
|
||||||
if (begin)
|
if (begin)
|
||||||
|
@ -17,7 +17,7 @@ void tf_trace_end(tf_trace_t* trace);
|
|||||||
|
|
||||||
char* tf_trace_export(tf_trace_t* trace);
|
char* tf_trace_export(tf_trace_t* trace);
|
||||||
|
|
||||||
typedef void (tf_trace_write_callback_t)(tf_trace_t* trace, const char* buffer, size_t size, void* user_data);
|
typedef void(tf_trace_write_callback_t)(tf_trace_t* trace, const char* buffer, size_t size, void* user_data);
|
||||||
void tf_trace_set_write_callback(tf_trace_t* trace, tf_trace_write_callback_t* callback, void* user_data);
|
void tf_trace_set_write_callback(tf_trace_t* trace, tf_trace_write_callback_t* callback, void* user_data);
|
||||||
void tf_trace_raw(tf_trace_t* trace, const char* buffer, size_t size);
|
void tf_trace_raw(tf_trace_t* trace, const char* buffer, size_t size);
|
||||||
|
|
||||||
|
@ -273,7 +273,8 @@ static JSValue _util_parseHttpRequest(JSContext* context, JSValueConst this_val,
|
|||||||
|
|
||||||
if (array)
|
if (array)
|
||||||
{
|
{
|
||||||
int parse_result = phr_parse_request((const char*)array, length, &method, &method_length, &path, &path_length, &minor_version, headers, &header_count, previous_length);
|
int parse_result =
|
||||||
|
phr_parse_request((const char*)array, length, &method, &method_length, &path, &path_length, &minor_version, headers, &header_count, previous_length);
|
||||||
if (parse_result > 0)
|
if (parse_result > 0)
|
||||||
{
|
{
|
||||||
result = JS_NewObject(context);
|
result = JS_NewObject(context);
|
||||||
@ -363,7 +364,6 @@ static JSValue _util_parseHttpResponse(JSContext* context, JSValueConst this_val
|
|||||||
JS_FreeValue(context, buffer);
|
JS_FreeValue(context, buffer);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue _util_sha1_digest(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
static JSValue _util_sha1_digest(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||||
@ -518,12 +518,7 @@ const char* tf_util_backtrace_to_string(void* const* buffer, int count)
|
|||||||
char* string = NULL;
|
char* string = NULL;
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
backtrace_pcinfo(
|
backtrace_pcinfo(g_backtrace_state, (uintptr_t)buffer[i], _tf_util_backtrace_callback, _tf_util_backtrace_error, &string);
|
||||||
g_backtrace_state,
|
|
||||||
(uintptr_t)buffer[i],
|
|
||||||
_tf_util_backtrace_callback,
|
|
||||||
_tf_util_backtrace_error,
|
|
||||||
&string);
|
|
||||||
}
|
}
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
@ -543,12 +538,7 @@ const char* tf_util_function_to_string(void* function)
|
|||||||
{
|
{
|
||||||
extern struct backtrace_state* g_backtrace_state;
|
extern struct backtrace_state* g_backtrace_state;
|
||||||
char* string = NULL;
|
char* string = NULL;
|
||||||
backtrace_pcinfo(
|
backtrace_pcinfo(g_backtrace_state, (uintptr_t)function, _tf_util_backtrace_single_callback, _tf_util_backtrace_error, &string);
|
||||||
g_backtrace_state,
|
|
||||||
(uintptr_t)function,
|
|
||||||
_tf_util_backtrace_single_callback,
|
|
||||||
_tf_util_backtrace_error,
|
|
||||||
&string);
|
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,4 +22,9 @@ const char* tf_util_backtrace_string();
|
|||||||
|
|
||||||
const char* tf_util_function_to_string(void* function);
|
const char* tf_util_function_to_string(void* function);
|
||||||
|
|
||||||
#define tf_min(a, b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a > _b ? _b : _a; })
|
#define tf_min(a, b) \
|
||||||
|
({ \
|
||||||
|
__typeof__(a) _a = (a); \
|
||||||
|
__typeof__(b) _b = (b); \
|
||||||
|
_a > _b ? _b : _a; \
|
||||||
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user