I just decided. Braces on their own lines.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3668 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2021-10-10 21:51:38 +00:00
parent 470814f147
commit 843c53e15e
20 changed files with 2373 additions and 1110 deletions

View File

@ -7,7 +7,8 @@
JSValue _crypt_hashpw(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); JSValue _crypt_hashpw(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
JSValue _crypt_gensalt(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); JSValue _crypt_gensalt(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
void tf_bcrypt_init(JSContext* context) { void tf_bcrypt_init(JSContext* context)
{
JSValue global = JS_GetGlobalObject(context); JSValue global = JS_GetGlobalObject(context);
JSValue bcrypt = JS_NewObject(context); JSValue bcrypt = JS_NewObject(context);
JS_SetPropertyStr(context, global, "bCrypt", bcrypt); JS_SetPropertyStr(context, global, "bCrypt", bcrypt);
@ -16,7 +17,8 @@ void tf_bcrypt_init(JSContext* context) {
JS_FreeValue(context, global); JS_FreeValue(context, global);
} }
JSValue _crypt_hashpw(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _crypt_hashpw(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
const char* key = JS_ToCString(context, argv[0]); const char* key = JS_ToCString(context, argv[0]);
const char* salt = JS_ToCString(context, argv[1]); const char* salt = JS_ToCString(context, argv[1]);
char output[7 + 22 + 31 + 1]; char output[7 + 22 + 31 + 1];
@ -27,7 +29,8 @@ JSValue _crypt_hashpw(JSContext* context, JSValueConst this_val, int argc, JSVal
return result; return result;
} }
JSValue _crypt_gensalt(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _crypt_gensalt(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
int length; int length;
JS_ToInt32(context, &length, argv[0]); JS_ToInt32(context, &length, argv[0]);
char buffer[16]; char buffer[16];

View File

@ -9,7 +9,8 @@
static JSClassID _database_class_id; static JSClassID _database_class_id;
static int _database_count; static int _database_count;
typedef struct _database_t { typedef struct _database_t
{
JSContext* context; JSContext* context;
JSValue object; JSValue object;
void* task; void* task;
@ -26,13 +27,15 @@ static JSValue _database_remove(JSContext* context, JSValueConst this_val, int a
static JSValue _database_get_all(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _database_get_all(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
static JSValue _database_get_like(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _database_get_like(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
void tf_database_init(JSContext* context, sqlite3* sqlite) { void tf_database_init(JSContext* context, sqlite3* sqlite)
{
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,
}; };
if (JS_NewClass(JS_GetRuntime(context), _database_class_id, &def) != 0) { if (JS_NewClass(JS_GetRuntime(context), _database_class_id, &def) != 0)
{
printf("Failed to register database.\n"); printf("Failed to register database.\n");
} }
@ -44,14 +47,16 @@ void tf_database_init(JSContext* context, sqlite3* sqlite) {
JS_FreeValue(context, global); JS_FreeValue(context, global);
} }
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)
{
++_database_count; ++_database_count;
JSValue object = JS_NewObjectClass(context, _database_class_id); JSValue object = JS_NewObjectClass(context, _database_class_id);
sqlite3* db = NULL; sqlite3* db = NULL;
JS_ToInt64(context, (int64_t*)&db, data[0]); JS_ToInt64(context, (int64_t*)&db, data[0]);
database_t* database = malloc(sizeof(database_t)); database_t* database = 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,
@ -71,26 +76,32 @@ 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)
{
free((void*)database->id); free((void*)database->id);
free(database); free(database);
} }
--_database_count; --_database_count;
} }
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)
{
JSValue entry = JS_UNDEFINED; JSValue entry = JS_UNDEFINED;
database_t* database = JS_GetOpaque(this_val, _database_class_id); database_t* database = JS_GetOpaque(this_val, _database_class_id);
if (database) { if (database)
{
sqlite3_stmt* statement; sqlite3_stmt* statement;
if (sqlite3_prepare(database->db, "SELECT value FROM properties WHERE id = $1 AND key = $2", -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_prepare(database->db, "SELECT value FROM properties WHERE id = $1 AND key = $2", -1, &statement, NULL) == SQLITE_OK)
{
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));
} }
JS_FreeCString(context, keyString); JS_FreeCString(context, keyString);
@ -100,11 +111,14 @@ static JSValue _database_get(JSContext* context, JSValueConst this_val, int argc
return entry; return entry;
} }
JSValue _database_set(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _database_set(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
database_t* database = JS_GetOpaque(this_val, _database_class_id); database_t* database = JS_GetOpaque(this_val, _database_class_id);
if (database) { if (database)
{
sqlite3_stmt* statement; sqlite3_stmt* statement;
if (sqlite3_prepare(database->db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES ($1, $2, $3)", -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_prepare(database->db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES ($1, $2, $3)", -1, &statement, NULL) == SQLITE_OK)
{
size_t keyLength; size_t keyLength;
const char* keyString = JS_ToCStringLen(context, &keyLength, argv[0]); const char* keyString = JS_ToCStringLen(context, &keyLength, argv[0]);
size_t valueLength; size_t valueLength;
@ -112,7 +126,8 @@ JSValue _database_set(JSContext* context, JSValueConst this_val, int argc, JSVal
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_bind_text(statement, 3, valueString, valueLength, NULL) == SQLITE_OK &&
sqlite3_step(statement) == SQLITE_OK) { sqlite3_step(statement) == SQLITE_OK)
{
} }
JS_FreeCString(context, keyString); JS_FreeCString(context, keyString);
JS_FreeCString(context, valueString); JS_FreeCString(context, valueString);
@ -122,16 +137,20 @@ JSValue _database_set(JSContext* context, JSValueConst this_val, int argc, JSVal
return JS_UNDEFINED; return JS_UNDEFINED;
} }
JSValue _database_remove(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _database_remove(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
database_t* database = JS_GetOpaque(this_val, _database_class_id); database_t* database = JS_GetOpaque(this_val, _database_class_id);
if (database) { if (database)
{
sqlite3_stmt* statement; sqlite3_stmt* statement;
if (sqlite3_prepare(database->db, "DELETE FROM properties WHERE id = $1 AND key = $2", -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_prepare(database->db, "DELETE FROM properties WHERE id = $1 AND key = $2", -1, &statement, NULL) == SQLITE_OK)
{
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)
{
} }
JS_FreeCString(context, keyString); JS_FreeCString(context, keyString);
sqlite3_finalize(statement); sqlite3_finalize(statement);
@ -140,16 +159,21 @@ JSValue _database_remove(JSContext* context, JSValueConst this_val, int argc, JS
return JS_UNDEFINED; return JS_UNDEFINED;
} }
JSValue _database_get_all(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _database_get_all(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
JSValue array = JS_UNDEFINED; JSValue array = JS_UNDEFINED;
database_t* database = JS_GetOpaque(this_val, _database_class_id); database_t* database = JS_GetOpaque(this_val, _database_class_id);
if (database) { if (database)
{
sqlite3_stmt* statement; sqlite3_stmt* statement;
if (sqlite3_prepare(database->db, "SELECT key, value FROM properties WHERE id = $1", -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_prepare(database->db, "SELECT key, value FROM properties WHERE id = $1", -1, &statement, NULL) == SQLITE_OK)
if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK) { {
if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK)
{
array = JS_NewArray(context); array = JS_NewArray(context);
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)));
} }
} }
@ -159,17 +183,22 @@ JSValue _database_get_all(JSContext* context, JSValueConst this_val, int argc, J
return array; return array;
} }
JSValue _database_get_like(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _database_get_like(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
JSValue result = JS_UNDEFINED; JSValue result = JS_UNDEFINED;
database_t* database = JS_GetOpaque(this_val, _database_class_id); database_t* database = JS_GetOpaque(this_val, _database_class_id);
if (database) { if (database)
{
sqlite3_stmt* statement; sqlite3_stmt* statement;
if (sqlite3_prepare(database->db, "SELECT key, value FROM properties WHERE id = ? AND KEY LIKE ?", -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_prepare(database->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, context,
result, result,

View File

@ -31,7 +31,8 @@ typedef struct file_stat_t {
uv_fs_t _request; uv_fs_t _request;
} file_stat_t; } file_stat_t;
void tf_file_init(JSContext* context) { void tf_file_init(JSContext* context)
{
JSValue global = JS_GetGlobalObject(context); JSValue global = JS_GetGlobalObject(context);
JSValue file = JS_NewObject(context); JSValue file = JS_NewObject(context);
JS_SetPropertyStr(context, global, "File", file); JS_SetPropertyStr(context, global, "File", file);
@ -106,7 +107,8 @@ static void _file_read_open_callback(uv_fs_t* req)
} }
} }
static JSValue _file_read_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _file_read_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
void* task = JS_GetContextOpaque(context); void* task = JS_GetContextOpaque(context);
const char* file_name = JS_ToCString(context, argv[0]); const char* file_name = JS_ToCString(context, argv[0]);
@ -125,19 +127,24 @@ static JSValue _file_read_file(JSContext* context, JSValueConst this_val, int ar
return tf_task_get_promise(task, promise); return tf_task_get_promise(task, promise);
} }
static JSValue _file_write_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _file_write_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
JSValue result = JS_NULL; JSValue result = JS_NULL;
const char* fileName = JS_ToCString(context, argv[0]); const char* fileName = JS_ToCString(context, argv[0]);
FILE* file = fopen(fileName, "wb"); FILE* file = fopen(fileName, "wb");
JS_FreeCString(context, fileName); JS_FreeCString(context, fileName);
if (file) { if (file)
{
size_t size; size_t size;
uint8_t* buffer = tf_try_get_array_buffer(context, &size, argv[1]); uint8_t* buffer = tf_try_get_array_buffer(context, &size, argv[1]);
if (buffer) { if (buffer)
{
int written = fwrite((const char*)buffer, 1, size, file); int written = fwrite((const char*)buffer, 1, size, file);
result = JS_NewInt32(context, (size_t)written == size ? 0 : written); result = JS_NewInt32(context, (size_t)written == size ? 0 : written);
} else { }
else
{
const char* data = JS_ToCStringLen(context, &size, argv[1]); const char* data = JS_ToCStringLen(context, &size, argv[1]);
int written = fwrite((const char*)data, 1, size, file); int written = fwrite((const char*)data, 1, size, file);
result = JS_NewInt32(context, (size_t)written == size ? 0 : written); result = JS_NewInt32(context, (size_t)written == size ? 0 : written);
@ -148,7 +155,8 @@ static JSValue _file_write_file(JSContext* context, JSValueConst this_val, int a
return result; return result;
} }
static JSValue _file_rename_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _file_rename_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
void* task = JS_GetContextOpaque(context); void* task = JS_GetContextOpaque(context);
const char* oldName = JS_ToCString(context, argv[0]); const char* oldName = JS_ToCString(context, argv[0]);
const char* newName = JS_ToCString(context, argv[1]); const char* newName = JS_ToCString(context, argv[1]);
@ -159,7 +167,8 @@ static JSValue _file_rename_file(JSContext* context, JSValueConst this_val, int
return JS_NewInt32(context, result); return JS_NewInt32(context, result);
} }
static JSValue _file_unlink_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _file_unlink_file(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
void* task = JS_GetContextOpaque(context); void* task = JS_GetContextOpaque(context);
const char* fileName = JS_ToCString(context, argv[0]); const char* fileName = JS_ToCString(context, argv[0]);
uv_fs_t req; uv_fs_t req;
@ -168,7 +177,8 @@ static JSValue _file_unlink_file(JSContext* context, JSValueConst this_val, int
return JS_NewInt32(context, result); return JS_NewInt32(context, result);
} }
static JSValue _file_read_directory(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _file_read_directory(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
const char* directory = JS_ToCString(context, argv[0]); const char* directory = JS_ToCString(context, argv[0]);
JSValue array = JS_NewArray(context); JSValue array = JS_NewArray(context);
@ -177,7 +187,8 @@ static JSValue _file_read_directory(JSContext* context, JSValueConst this_val, i
std::string pattern = directory; std::string pattern = directory;
pattern += "\\*"; pattern += "\\*";
HANDLE handle = FindFirstFile(pattern.c_str(), &find); HANDLE handle = FindFirstFile(pattern.c_str(), &find);
if (handle != INVALID_HANDLE_VALUE) { if (handle != INVALID_HANDLE_VALUE)
{
int index = 0; int index = 0;
do { do {
JS_SetPropertyUint32(context, array, index++, JS_NewString(context, find.cFileName)); JS_SetPropertyUint32(context, array, index++, JS_NewString(context, find.cFileName));
@ -186,10 +197,12 @@ static JSValue _file_read_directory(JSContext* context, JSValueConst this_val, i
} }
#else #else
DIR* dir = opendir(directory); DIR* dir = opendir(directory);
if (dir) { if (dir)
{
uint32_t index = 0; uint32_t index = 0;
struct dirent* entry = readdir(dir); struct dirent* entry = readdir(dir);
while (entry) { while (entry)
{
JS_SetPropertyUint32(context, array, index++, JS_NewString(context, entry->d_name)); JS_SetPropertyUint32(context, array, index++, JS_NewString(context, entry->d_name));
entry = readdir(dir); entry = readdir(dir);
} }
@ -201,7 +214,8 @@ static JSValue _file_read_directory(JSContext* context, JSValueConst this_val, i
return array; return array;
} }
JSValue _file_make_directory(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _file_make_directory(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
void* task = JS_GetContextOpaque(context); void* task = JS_GetContextOpaque(context);
const char* directory = JS_ToCString(context, argv[0]); const char* directory = JS_ToCString(context, argv[0]);
@ -211,7 +225,8 @@ JSValue _file_make_directory(JSContext* context, JSValueConst this_val, int argc
return JS_NewInt32(context, result); return JS_NewInt32(context, result);
} }
JSValue _file_stat(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _file_stat(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
void* task = JS_GetContextOpaque(context); void* task = JS_GetContextOpaque(context);
const char* path = JS_ToCString(context, argv[0]); const char* path = JS_ToCString(context, argv[0]);
promiseid_t promise = tf_task_allocate_promise(task); promiseid_t promise = tf_task_allocate_promise(task);
@ -223,7 +238,8 @@ JSValue _file_stat(JSContext* context, JSValueConst this_val, int argc, JSValueC
data->_context = context; data->_context = context;
int result = uv_fs_stat(tf_task_get_loop(task), &data->_request, path, _file_on_stat_complete); int result = uv_fs_stat(tf_task_get_loop(task), &data->_request, path, _file_on_stat_complete);
if (result) { if (result)
{
tf_task_reject_promise(task, promise, JS_NewInt32(context, result)); tf_task_reject_promise(task, promise, JS_NewInt32(context, result));
free(data); free(data);
} }
@ -231,17 +247,22 @@ JSValue _file_stat(JSContext* context, JSValueConst this_val, int argc, JSValueC
return tf_task_get_promise(task, promise); return tf_task_get_promise(task, promise);
} }
static double _time_spec_to_double(const uv_timespec_t* time_spec) { static double _time_spec_to_double(const uv_timespec_t* time_spec)
{
return time_spec->tv_sec + (double)(time_spec->tv_nsec) / 1e9; return time_spec->tv_sec + (double)(time_spec->tv_nsec) / 1e9;
} }
static void _file_on_stat_complete(uv_fs_t* request) { static void _file_on_stat_complete(uv_fs_t* request)
{
file_stat_t* data = (file_stat_t*)(request->data); file_stat_t* data = (file_stat_t*)(request->data);
JSContext* context = data->_context; JSContext* context = data->_context;
if (request->result) { if (request->result)
{
tf_task_reject_promise(data->_task, data->_promise, JS_NewInt32(context, request->result)); tf_task_reject_promise(data->_task, data->_promise, JS_NewInt32(context, request->result));
} else { }
else
{
JSValue result = JS_NewObject(context); JSValue result = JS_NewObject(context);
JS_SetPropertyStr(context, result, "mtime", JS_NewFloat64(context, _time_spec_to_double(&request->statbuf.st_mtim))); JS_SetPropertyStr(context, result, "mtime", JS_NewFloat64(context, _time_spec_to_double(&request->statbuf.st_mtim)));
JS_SetPropertyStr(context, result, "ctime", JS_NewFloat64(context, _time_spec_to_double(&request->statbuf.st_ctim))); JS_SetPropertyStr(context, result, "ctime", JS_NewFloat64(context, _time_spec_to_double(&request->statbuf.st_ctim)));

View File

@ -29,7 +29,8 @@
_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) \
{ \
xoptAutohelpOptions __xopt_autohelp_opts; \ xoptAutohelpOptions __xopt_autohelp_opts; \
__xopt_autohelp_opts.usage = (autohelp_usage); \ __xopt_autohelp_opts.usage = (autohelp_usage); \
__xopt_autohelp_opts.prefix = (autohelp_prefix); \ __xopt_autohelp_opts.prefix = (autohelp_prefix); \
@ -91,24 +92,29 @@ void shedPrivileges()
// RLIMIT_SIGPENDING // RLIMIT_SIGPENDING
// RLIMIT_STACK // RLIMIT_STACK
if (setrlimit(RLIMIT_FSIZE, &zeroLimit) != 0) { if (setrlimit(RLIMIT_FSIZE, &zeroLimit) != 0)
{
perror("setrlimit(RLIMIT_FSIZE, {0, 0})"); perror("setrlimit(RLIMIT_FSIZE, {0, 0})");
exit(-1); exit(-1);
} }
if (setrlimit(RLIMIT_NOFILE, &zeroLimit) != 0) { if (setrlimit(RLIMIT_NOFILE, &zeroLimit) != 0)
{
perror("setrlimit(RLIMIT_NOFILE, {0, 0})"); perror("setrlimit(RLIMIT_NOFILE, {0, 0})");
exit(-1); exit(-1);
} }
if (setrlimit(RLIMIT_NPROC, &zeroLimit) != 0) { if (setrlimit(RLIMIT_NPROC, &zeroLimit) != 0)
{
perror("setrlimit(RLIMIT_NPROC, {0, 0})"); perror("setrlimit(RLIMIT_NPROC, {0, 0})");
exit(-1); exit(-1);
} }
#if !defined (__MACH__) #if !defined (__MACH__)
if (setrlimit(RLIMIT_LOCKS, &zeroLimit) != 0) { if (setrlimit(RLIMIT_LOCKS, &zeroLimit) != 0)
{
perror("setrlimit(RLIMIT_LOCKS, {0, 0})"); perror("setrlimit(RLIMIT_LOCKS, {0, 0})");
exit(-1); exit(-1);
} }
if (setrlimit(RLIMIT_MSGQUEUE, &zeroLimit) != 0) { if (setrlimit(RLIMIT_MSGQUEUE, &zeroLimit) != 0)
{
perror("setrlimit(RLIMIT_MSGQUEUE, {0, 0})"); perror("setrlimit(RLIMIT_MSGQUEUE, {0, 0})");
exit(-1); exit(-1);
} }
@ -134,10 +140,12 @@ static int _tf_command_test(const char* file, int argc, char* argv[])
int extra_count = 0; int extra_count = 0;
const char *err = NULL; const char *err = NULL;
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, "test [options]", "options:", NULL, 15); XOPT_PARSE(file, XOPT_CTX_KEEPFIRST, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, "test [options]", "options:", NULL, 15);
if (extras) { if (extras)
{
free((void*)extras); free((void*)extras);
} }
if (err) { if (err)
{
fprintf(stderr, "Error: %s\n", err); fprintf(stderr, "Error: %s\n", err);
return 2; return 2;
} }
@ -150,7 +158,8 @@ static int _tf_command_test(const char* file, int argc, char* argv[])
tf_tests(&test_options); tf_tests(&test_options);
return 0; return 0;
xopt_help: xopt_help:
if (extras) { if (extras)
{
free((void*)extras); free((void*)extras);
} }
return 1; return 1;
@ -177,40 +186,50 @@ static int _tf_command_import(const char* file, int argc, char* argv[])
const char *err = NULL; const char *err = NULL;
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER, 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, 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);
if (extras) { if (extras)
{
free((void*)extras); free((void*)extras);
} }
return 2; return 2;
} }
sqlite3* db = NULL; sqlite3* db = NULL;
if (args.db_path) { if (args.db_path)
{
sqlite3_open(args.db_path, &db); sqlite3_open(args.db_path, &db);
} }
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db, NULL); tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db, NULL);
if (extra_count) { if (extra_count)
for (int i = 0; i < extra_count; i++) { {
for (int i = 0; i < extra_count; i++)
{
printf("Importing %s...\n", extras[i]); printf("Importing %s...\n", extras[i]);
tf_ssb_import(ssb, args.user, extras[i]); tf_ssb_import(ssb, args.user, extras[i]);
} }
} else { }
else
{
printf("Importing %s...\n", "apps"); printf("Importing %s...\n", "apps");
tf_ssb_import(ssb, args.user, "apps"); tf_ssb_import(ssb, args.user, "apps");
} }
tf_ssb_destroy(ssb); tf_ssb_destroy(ssb);
if (db) { if (db)
{
sqlite3_close(db); sqlite3_close(db);
} }
if (extras) { if (extras)
{
free((void*)extras); free((void*)extras);
} }
return 0; return 0;
xopt_help: xopt_help:
if (extras) { if (extras)
{
free((void*)extras); free((void*)extras);
} }
return 1; return 1;
@ -233,38 +252,47 @@ static int _tf_command_export(const char* file, int argc, char* argv[])
const char *err = NULL; const char *err = NULL;
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER, 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, 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);
if (extras) { if (extras)
{
free((void*)extras); free((void*)extras);
} }
return 2; return 2;
} }
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, NULL, NULL); tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, NULL, NULL);
if (extra_count) { if (extra_count)
for (int i = 0; i < extra_count; i++) { {
for (int i = 0; i < extra_count; i++)
{
printf("Exporting %s...\n", extras[i]); printf("Exporting %s...\n", extras[i]);
tf_ssb_export(ssb, extras[i]); tf_ssb_export(ssb, extras[i]);
} }
} else { }
else
{
const char* k_export[] = { const char* k_export[] = {
"/~cory/index", "/~cory/index",
"/~cory/docs", "/~cory/docs",
}; };
for (int i = 0; i < _countof(k_export); i++) { for (int i = 0; i < _countof(k_export); i++)
{
printf("Exporting %s...\n", k_export[i]); printf("Exporting %s...\n", k_export[i]);
tf_ssb_export(ssb, k_export[i]); tf_ssb_export(ssb, k_export[i]);
} }
} }
tf_ssb_destroy(ssb); tf_ssb_destroy(ssb);
if (extras) { if (extras)
{
free((void*)extras); free((void*)extras);
} }
return 0; return 0;
xopt_help: xopt_help:
if (extras) { if (extras)
{
free((void*)extras); free((void*)extras);
} }
return 1; return 1;
@ -304,14 +332,17 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
const char *err = NULL; const char *err = NULL;
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER, 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, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, "run [options] [paths] ...", "options:", NULL, 15);
if (err) { if (err)
{
fprintf(stderr, "Error: %s\n", err); fprintf(stderr, "Error: %s\n", err);
if (extras) { if (extras)
{
free((void*)extras); free((void*)extras);
} }
return 2; return 2;
} }
if (extras) { if (extras)
{
free((void*)extras); free((void*)extras);
} }
@ -340,7 +371,8 @@ static int _tf_command_run(const char* file, int argc, char* argv[])
return result; return result;
xopt_help: xopt_help:
if (extras) { if (extras)
{
free((void*)extras); free((void*)extras);
} }
return 1; return 1;
@ -364,14 +396,17 @@ static int _tf_command_sandbox(const char* file, int argc, char* argv[])
const char *err = NULL; const char *err = NULL;
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST | XOPT_CTX_POSIXMEHARDER, 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, 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);
if (extras) { if (extras)
{
free((void*)extras); free((void*)extras);
} }
return 2; return 2;
} }
if (extras) { if (extras)
{
free((void*)extras); free((void*)extras);
} }
@ -387,7 +422,8 @@ static int _tf_command_sandbox(const char* file, int argc, char* argv[])
return 0; return 0;
xopt_help: xopt_help:
if (extras) { if (extras)
{
free((void*)extras); free((void*)extras);
} }
return 1; return 1;
@ -411,10 +447,12 @@ static int _tf_command_post(const char* file, int argc, char* argv[])
int extra_count = 0; int extra_count = 0;
const char *err = NULL; const char *err = NULL;
XOPT_PARSE(file, XOPT_CTX_KEEPFIRST, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, "post [options]", "options:", NULL, 15); XOPT_PARSE(file, XOPT_CTX_KEEPFIRST, options, &args, argc, (const char**)argv, &extra_count, &extras, &err, stderr, "post [options]", "options:", NULL, 15);
if (extras) { if (extras)
{
free((void*)extras); free((void*)extras);
} }
if (err) { if (err)
{
fprintf(stderr, "Error: %s\n", err); fprintf(stderr, "Error: %s\n", err);
return 2; return 2;
} }
@ -426,7 +464,8 @@ static int _tf_command_post(const char* file, int argc, char* argv[])
return 0; return 0;
xopt_help: xopt_help:
if (extras) { if (extras)
{
free((void*)extras); free((void*)extras);
} }
return 1; return 1;
@ -436,7 +475,8 @@ static int _tf_command_usage(const char* file, int argc, char* argv[])
{ {
printf("Usage: %s command [command-options]\n", file); printf("Usage: %s command [command-options]\n", file);
printf("commands:\n"); printf("commands:\n");
for (int i = 0; i < _countof(k_commands); i++) { for (int i = 0; i < _countof(k_commands); i++)
{
printf(" %s - %s\n", k_commands[i].name, k_commands[i].description); printf(" %s - %s\n", k_commands[i].name, k_commands[i].description);
} }
return 0; return 0;
@ -449,15 +489,19 @@ int main(int argc, char* argv[])
tf_taskstub_startup(); tf_taskstub_startup();
#if !defined (_WIN32) #if !defined (_WIN32)
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
{
perror("signal"); perror("signal");
} }
#endif #endif
if (argc >= 2) { if (argc >= 2)
for (int i = 0; i < _countof(k_commands); i++) { {
for (int i = 0; i < _countof(k_commands); i++)
{
const command_t* command = &k_commands[i]; const command_t* command = &k_commands[i];
if (strcmp(argv[1], command->name) == 0) { if (strcmp(argv[1], command->name) == 0)
{
return command->callback(argv[0], argc - 2, argv + 2); return command->callback(argv[0], argc - 2, argv + 2);
} }
} }

View File

@ -15,84 +15,106 @@ typedef struct _tf_packetstream_t {
bool destroyed; bool destroyed;
} tf_packetstream_t; } tf_packetstream_t;
tf_packetstream_t* tf_packetstream_create() { tf_packetstream_t* tf_packetstream_create()
{
tf_packetstream_t* impl = malloc(sizeof(tf_packetstream_t)); tf_packetstream_t* impl = malloc(sizeof(tf_packetstream_t));
*impl = (tf_packetstream_t) { 0 }; *impl = (tf_packetstream_t) { 0 };
return impl; return impl;
} }
void tf_packetstream_destroy(tf_packetstream_t* stream) { void tf_packetstream_destroy(tf_packetstream_t* stream)
{
stream->onreceive = NULL; stream->onreceive = NULL;
stream->onreceive_user_data = NULL; stream->onreceive_user_data = NULL;
stream->destroyed = true; stream->destroyed = true;
if (stream->stream.data) { if (stream->stream.data)
{
tf_packetstream_close(stream); tf_packetstream_close(stream);
} else { }
else
{
free(stream); free(stream);
} }
} }
static void _packetstream_allocate(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buffer) { static void _packetstream_allocate(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buffer)
{
buffer->base = malloc(suggested_size); buffer->base = malloc(suggested_size);
buffer->len = suggested_size; buffer->len = suggested_size;
} }
static void _packetstream_process_messages(tf_packetstream_t* stream) { static void _packetstream_process_messages(tf_packetstream_t* stream)
{
int packet_type = 0; int packet_type = 0;
size_t length = 0; size_t length = 0;
while (stream->buffer_size >= sizeof(packet_type) + sizeof(length)) { while (stream->buffer_size >= sizeof(packet_type) + sizeof(length))
{
memcpy(&packet_type, stream->buffer, sizeof(packet_type)); memcpy(&packet_type, stream->buffer, sizeof(packet_type));
memcpy(&length, stream->buffer + sizeof(packet_type), sizeof(length)); memcpy(&length, stream->buffer + sizeof(packet_type), sizeof(length));
if (stream->buffer_size >= sizeof(packet_type) + sizeof(length) + length) { if (stream->buffer_size >= sizeof(packet_type) + sizeof(length) + length)
if (stream->onreceive) { {
if (stream->onreceive)
{
stream->onreceive(packet_type, stream->buffer + sizeof(length) + sizeof(packet_type), length, stream->onreceive_user_data); stream->onreceive(packet_type, stream->buffer + sizeof(length) + sizeof(packet_type), length, stream->onreceive_user_data);
} }
size_t consumed = sizeof(length) + sizeof(packet_type) + length; size_t consumed = sizeof(length) + sizeof(packet_type) + length;
memmove(stream->buffer, stream->buffer + consumed, stream->buffer_size - consumed); memmove(stream->buffer, stream->buffer + consumed, stream->buffer_size - consumed);
stream->buffer_size -= consumed; stream->buffer_size -= consumed;
stream->buffer = realloc(stream->buffer, stream->buffer_size); stream->buffer = realloc(stream->buffer, stream->buffer_size);
} else { }
else
{
break; break;
} }
} }
} }
static void _packetstream_on_read(uv_stream_t* handle, ssize_t count, const uv_buf_t* buffer) { static void _packetstream_on_read(uv_stream_t* handle, ssize_t count, const uv_buf_t* buffer)
{
tf_packetstream_t* stream = handle->data; tf_packetstream_t* stream = handle->data;
if (count >= 0) { if (count >= 0)
if (count > 0) { {
if (count > 0)
{
char* new_buffer = realloc(stream->buffer, stream->buffer_size + count); char* new_buffer = realloc(stream->buffer, stream->buffer_size + count);
if (new_buffer) { if (new_buffer)
{
memcpy(new_buffer + stream->buffer_size, buffer->base, count); memcpy(new_buffer + stream->buffer_size, buffer->base, count);
stream->buffer = new_buffer; stream->buffer = new_buffer;
stream->buffer_size += count; stream->buffer_size += count;
} }
_packetstream_process_messages(stream); _packetstream_process_messages(stream);
} }
} else { }
else
{
tf_packetstream_close(stream); tf_packetstream_close(stream);
} }
free(buffer->base); free(buffer->base);
} }
void tf_packetstream_start(tf_packetstream_t* stream) { void tf_packetstream_start(tf_packetstream_t* stream)
{
stream->stream.data = stream; stream->stream.data = stream;
uv_read_start((uv_stream_t*)&stream->stream, _packetstream_allocate, _packetstream_on_read); uv_read_start((uv_stream_t*)&stream->stream, _packetstream_allocate, _packetstream_on_read);
} }
static void _packetstream_on_write(uv_write_t* request, int status) { static void _packetstream_on_write(uv_write_t* request, int status)
{
free(request); free(request);
} }
void tf_packetstream_send(tf_packetstream_t* stream, int packet_type, char* begin, size_t length) { void tf_packetstream_send(tf_packetstream_t* stream, int packet_type, char* begin, size_t length)
{
size_t buffer_length = sizeof(uv_write_t) + sizeof(packet_type) + sizeof(length) + length; size_t buffer_length = sizeof(uv_write_t) + sizeof(packet_type) + sizeof(length) + length;
uv_write_t* request = malloc(buffer_length); uv_write_t* request = malloc(buffer_length);
memset(request, 0, sizeof(uv_write_t)); memset(request, 0, sizeof(uv_write_t));
char* buffer = (char*)(request + 1); char* buffer = (char*)(request + 1);
memcpy(buffer, &packet_type, sizeof(packet_type)); memcpy(buffer, &packet_type, sizeof(packet_type));
memcpy(buffer + sizeof(packet_type), &length, sizeof(length)); memcpy(buffer + sizeof(packet_type), &length, sizeof(length));
if (length) { if (length)
{
memcpy(buffer + sizeof(packet_type) + sizeof(length), begin, length); memcpy(buffer + sizeof(packet_type) + sizeof(length), begin, length);
} }
uv_buf_t write_buffer; uv_buf_t write_buffer;
@ -101,7 +123,8 @@ void tf_packetstream_send(tf_packetstream_t* stream, int packet_type, char* begi
uv_write(request, (uv_stream_t*)&stream->stream, &write_buffer, 1, _packetstream_on_write); uv_write(request, (uv_stream_t*)&stream->stream, &write_buffer, 1, _packetstream_on_write);
} }
void tf_packetstream_set_on_receive(tf_packetstream_t* stream, tf_packetstream_onreceive_t* callback, void* user_data) { void tf_packetstream_set_on_receive(tf_packetstream_t* stream, tf_packetstream_onreceive_t* callback, void* user_data)
{
stream->onreceive = callback; stream->onreceive = callback;
stream->onreceive_user_data = user_data; stream->onreceive_user_data = user_data;
} }
@ -110,17 +133,21 @@ static void _tf_packetstream_handle_closed(uv_handle_t* handle)
{ {
tf_packetstream_t* packetstream = handle->data; tf_packetstream_t* packetstream = handle->data;
handle->data = NULL; handle->data = NULL;
if (packetstream->destroyed) { if (packetstream->destroyed)
{
free(packetstream); free(packetstream);
} }
} }
void tf_packetstream_close(tf_packetstream_t* stream) { void tf_packetstream_close(tf_packetstream_t* stream)
if (stream->stream.data && !uv_is_closing((uv_handle_t*)&stream->stream)) { {
if (stream->stream.data && !uv_is_closing((uv_handle_t*)&stream->stream))
{
uv_close((uv_handle_t*)&stream->stream, _tf_packetstream_handle_closed); uv_close((uv_handle_t*)&stream->stream, _tf_packetstream_handle_closed);
} }
} }
uv_pipe_t* tf_packetstream_get_pipe(tf_packetstream_t* stream) { uv_pipe_t* tf_packetstream_get_pipe(tf_packetstream_t* stream)
{
return &stream->stream; return &stream->stream;
} }

View File

@ -48,7 +48,8 @@ static int32_t _serialize_readInt32(const char** buffer, size_t* size);
static int64_t _serialize_readInt64(const char** buffer, size_t* size); static int64_t _serialize_readInt64(const char** buffer, size_t* size);
static double _serialize_readDouble(const char** buffer, size_t* size); static double _serialize_readDouble(const char** buffer, size_t* size);
void tf_serialize_store(tf_task_t* task, tf_taskstub_t* to, void** out_buffer, size_t* out_size, JSValue value) { void tf_serialize_store(tf_task_t* task, tf_taskstub_t* to, void** out_buffer, size_t* out_size, JSValue value)
{
buffer_t tmp = { 0 }; buffer_t tmp = { 0 };
_serialize_store(task, to, &tmp, value); _serialize_store(task, to, &tmp, value);
tmp.data = realloc(tmp.data, tmp.size); tmp.data = realloc(tmp.data, tmp.size);
@ -56,12 +57,15 @@ void tf_serialize_store(tf_task_t* task, tf_taskstub_t* to, void** out_buffer, s
*out_size = tmp.size; *out_size = tmp.size;
} }
JSValue tf_serialize_load(tf_task_t* task, tf_taskstub_t* from, const char* buffer, size_t size) { JSValue tf_serialize_load(tf_task_t* task, tf_taskstub_t* from, const char* buffer, size_t size)
{
return _serialize_load(task, from, buffer, size); return _serialize_load(task, from, buffer, size);
} }
static void _buffer_append(buffer_t* buffer, const void* data, size_t size) { static void _buffer_append(buffer_t* buffer, const void* data, size_t size)
if (buffer->capacity < buffer->size + size) { {
if (buffer->capacity < buffer->size + size)
{
size_t new_capacity = (size + buffer->capacity) * 2; size_t new_capacity = (size + buffer->capacity) * 2;
buffer->data = realloc(buffer->data, new_capacity); buffer->data = realloc(buffer->data, new_capacity);
buffer->capacity = new_capacity; buffer->capacity = new_capacity;
@ -70,54 +74,64 @@ static void _buffer_append(buffer_t* buffer, const void* data, size_t size) {
buffer->size += size; buffer->size += size;
} }
void _serialize_writeInt8(buffer_t* buffer, int8_t value) { void _serialize_writeInt8(buffer_t* buffer, int8_t value)
{
_buffer_append(buffer, &value, sizeof(value)); _buffer_append(buffer, &value, sizeof(value));
} }
void _serialize_writeInt32(buffer_t* buffer, int32_t value) { void _serialize_writeInt32(buffer_t* buffer, int32_t value)
{
_buffer_append(buffer, &value, sizeof(value)); _buffer_append(buffer, &value, sizeof(value));
} }
void _serialize_writeInt64(buffer_t* buffer, int64_t value) { void _serialize_writeInt64(buffer_t* buffer, int64_t value)
{
_buffer_append(buffer, &value, sizeof(value)); _buffer_append(buffer, &value, sizeof(value));
} }
void _serialize_writeDouble(buffer_t* buffer, double value) { void _serialize_writeDouble(buffer_t* buffer, double value)
{
_buffer_append(buffer, &value, sizeof(value)); _buffer_append(buffer, &value, sizeof(value));
} }
static void _serialize_read(const char** buffer, size_t* size, void* target, size_t target_size) { static void _serialize_read(const char** buffer, size_t* size, void* target, size_t target_size)
{
assert(*size >= target_size); assert(*size >= target_size);
memcpy(target, *buffer, target_size); memcpy(target, *buffer, target_size);
*buffer += target_size; *buffer += target_size;
*size -= target_size; *size -= target_size;
} }
static int8_t _serialize_readInt8(const char** buffer, size_t* size) { static int8_t _serialize_readInt8(const char** buffer, size_t* size)
{
int8_t result; int8_t result;
_serialize_read(buffer, size, &result, sizeof(result)); _serialize_read(buffer, size, &result, sizeof(result));
return result; return result;
} }
int32_t _serialize_readInt32(const char** buffer, size_t* size) { int32_t _serialize_readInt32(const char** buffer, size_t* size)
{
int32_t result; int32_t result;
_serialize_read(buffer, size, &result, sizeof(result)); _serialize_read(buffer, size, &result, sizeof(result));
return result; return result;
} }
int64_t _serialize_readInt64(const char** buffer, size_t* size) { int64_t _serialize_readInt64(const char** buffer, size_t* size)
{
int64_t result; int64_t result;
_serialize_read(buffer, size, &result, sizeof(result)); _serialize_read(buffer, size, &result, sizeof(result));
return result; return result;
} }
double _serialize_readDouble(const char** buffer, size_t* size) { double _serialize_readDouble(const char** buffer, size_t* size)
{
double result; double result;
_serialize_read(buffer, size, &result, sizeof(result)); _serialize_read(buffer, size, &result, sizeof(result));
return result; return result;
} }
static bool _serialize_store(tf_task_t* task, tf_taskstub_t* to, buffer_t* buffer, JSValue value) { static bool _serialize_store(tf_task_t* task, tf_taskstub_t* to, buffer_t* buffer, JSValue value)
{
return _serialize_storeInternal(task, to, buffer, value, 0); return _serialize_storeInternal(task, to, buffer, value, 0);
} }
@ -129,16 +143,25 @@ static bool _serialize_storeInternal(tf_task_t* task, tf_taskstub_t* to, buffer_
size_t element_size; size_t element_size;
JSValue typed; JSValue typed;
uint8_t* bytes; uint8_t* bytes;
if (JS_IsUndefined(value)) { if (JS_IsUndefined(value))
{
_serialize_writeInt32(buffer, kUndefined); _serialize_writeInt32(buffer, kUndefined);
} else if (JS_IsUninitialized(value)) { }
else if (JS_IsUninitialized(value))
{
_serialize_writeInt32(buffer, kUninitialized); _serialize_writeInt32(buffer, kUninitialized);
} else if (JS_IsNull(value)) { }
else if (JS_IsNull(value))
{
_serialize_writeInt32(buffer, kNull); _serialize_writeInt32(buffer, kNull);
} else if (JS_IsBool(value)) { }
else if (JS_IsBool(value))
{
_serialize_writeInt32(buffer, kBoolean); _serialize_writeInt32(buffer, kBoolean);
_serialize_writeInt8(buffer, JS_ToBool(tf_task_get_context(task), value) ? 1 : 0); _serialize_writeInt8(buffer, JS_ToBool(tf_task_get_context(task), value) ? 1 : 0);
} else if (JS_IsNumber(value)) { }
else if (JS_IsNumber(value))
{
int64_t result = 0; int64_t result = 0;
if (JS_ToInt64(tf_task_get_context(task), &result, value) == 0) if (JS_ToInt64(tf_task_get_context(task), &result, value) == 0)
{ {
@ -149,7 +172,9 @@ static bool _serialize_storeInternal(tf_task_t* task, tf_taskstub_t* to, buffer_
{ {
fprintf(stderr, "Unable to store integer.\n"); fprintf(stderr, "Unable to store integer.\n");
} }
} else if (JS_IsNumber(value)) { }
else if (JS_IsNumber(value))
{
double result = 0.0; double result = 0.0;
if (JS_ToFloat64(tf_task_get_context(task), &result, value) == 0) if (JS_ToFloat64(tf_task_get_context(task), &result, value) == 0)
{ {
@ -160,68 +185,93 @@ static bool _serialize_storeInternal(tf_task_t* task, tf_taskstub_t* to, buffer_
{ {
fprintf(stderr, "Unable to store number.\n"); fprintf(stderr, "Unable to store number.\n");
} }
} else if (JS_IsString(value)) { }
else if (JS_IsString(value))
{
size_t len = 0; size_t len = 0;
const char* result = JS_ToCStringLen(tf_task_get_context(task), &len, value); const char* result = JS_ToCStringLen(tf_task_get_context(task), &len, value);
_serialize_writeInt32(buffer, kString); _serialize_writeInt32(buffer, kString);
_serialize_writeInt32(buffer, (int32_t)len); _serialize_writeInt32(buffer, (int32_t)len);
_buffer_append(buffer, result, len); _buffer_append(buffer, result, len);
JS_FreeCString(tf_task_get_context(task), result); JS_FreeCString(tf_task_get_context(task), result);
} else if ((bytes = tf_try_get_array_buffer(tf_task_get_context(task), &size, value)) != 0) { }
else if ((bytes = tf_try_get_array_buffer(tf_task_get_context(task), &size, value)) != 0)
{
_serialize_writeInt32(buffer, kArrayBuffer); _serialize_writeInt32(buffer, kArrayBuffer);
_serialize_writeInt32(buffer, (int32_t)size); _serialize_writeInt32(buffer, (int32_t)size);
_buffer_append(buffer, bytes, size); _buffer_append(buffer, bytes, size);
} else if (!JS_IsException((typed = tf_try_get_typed_array_buffer(tf_task_get_context(task), value, &offset, &size, &element_size)))) { }
else if (!JS_IsException((typed = tf_try_get_typed_array_buffer(tf_task_get_context(task), value, &offset, &size, &element_size))))
{
size_t total_size; size_t total_size;
uint8_t* bytes = tf_try_get_array_buffer(tf_task_get_context(task), &total_size, typed); uint8_t* bytes = tf_try_get_array_buffer(tf_task_get_context(task), &total_size, typed);
_serialize_writeInt32(buffer, kArrayBuffer); _serialize_writeInt32(buffer, kArrayBuffer);
_serialize_writeInt32(buffer, (int32_t)size); _serialize_writeInt32(buffer, (int32_t)size);
_buffer_append(buffer, bytes, size); _buffer_append(buffer, bytes, size);
} else if (JS_IsArray(tf_task_get_context(task), value)) { }
else if (JS_IsArray(tf_task_get_context(task), value))
{
_serialize_writeInt32(buffer, kArray); _serialize_writeInt32(buffer, kArray);
JSValue length_val = JS_GetPropertyStr(tf_task_get_context(task), value, "length"); JSValue length_val = JS_GetPropertyStr(tf_task_get_context(task), value, "length");
int length; int length;
if (JS_ToInt32(tf_task_get_context(task), &length, length_val) == 0) { if (JS_ToInt32(tf_task_get_context(task), &length, length_val) == 0)
{
_serialize_writeInt32(buffer, length); _serialize_writeInt32(buffer, length);
for (int i = 0; i < length; ++i) { for (int i = 0; i < length; ++i)
{
_serialize_storeInternal(task, to, buffer, JS_GetPropertyUint32(tf_task_get_context(task), value, i), depth + 1); _serialize_storeInternal(task, to, buffer, JS_GetPropertyUint32(tf_task_get_context(task), value, i), depth + 1);
} }
} else { }
else
{
_serialize_writeInt32(buffer, 0); _serialize_writeInt32(buffer, 0);
} }
} else if (JS_IsFunction(tf_task_get_context(task), value)) { }
else if (JS_IsFunction(tf_task_get_context(task), value))
{
_serialize_writeInt32(buffer, kFunction); _serialize_writeInt32(buffer, kFunction);
exportid_t exportId = tf_task_export_function(task, to, value); exportid_t exportId = tf_task_export_function(task, to, value);
_serialize_writeInt32(buffer, exportId); _serialize_writeInt32(buffer, exportId);
} else if (JS_IsException(value)) { }
else if (JS_IsException(value))
{
JSValue exception = JS_GetException(context); JSValue exception = JS_GetException(context);
JSValue error = JS_NewObject(context); JSValue error = JS_NewObject(context);
JSValue message = JS_GetPropertyStr(context, exception, "message"); JSValue message = JS_GetPropertyStr(context, exception, "message");
if (!JS_IsException(message)) { if (!JS_IsException(message))
{
JS_SetPropertyStr(context, error, "message", message); JS_SetPropertyStr(context, error, "message", message);
} else { }
else
{
JS_FreeValue(context, message); JS_FreeValue(context, message);
} }
if (JS_IsError(context, exception)) { if (JS_IsError(context, exception))
{
JSValue stack = JS_GetPropertyStr(context, exception, "stack"); JSValue stack = JS_GetPropertyStr(context, exception, "stack");
if (!JS_IsUndefined(stack)) { if (!JS_IsUndefined(stack))
{
JS_SetPropertyStr(context, error, "stack", JS_DupValue(context, stack)); JS_SetPropertyStr(context, error, "stack", JS_DupValue(context, stack));
} }
} }
_serialize_writeInt32(buffer, kException); _serialize_writeInt32(buffer, kException);
_serialize_storeInternal(task, to, buffer, error, depth + 1); _serialize_storeInternal(task, to, buffer, error, depth + 1);
JS_FreeValue(context, error); JS_FreeValue(context, error);
} else if (JS_IsError(tf_task_get_context(task), value)) { }
else if (JS_IsError(tf_task_get_context(task), value))
{
_serialize_writeInt32(buffer, kError); _serialize_writeInt32(buffer, kError);
JSPropertyEnum* ptab; JSPropertyEnum* ptab;
uint32_t plen; uint32_t plen;
JS_GetOwnPropertyNames(tf_task_get_context(task), &ptab, &plen, value, JS_GPN_STRING_MASK); JS_GetOwnPropertyNames(tf_task_get_context(task), &ptab, &plen, value, JS_GPN_STRING_MASK);
_serialize_writeInt32(buffer, plen); _serialize_writeInt32(buffer, plen);
for (uint32_t i = 0; i < plen; ++i) { for (uint32_t i = 0; i < plen; ++i)
{
JSValue key = JS_AtomToString(tf_task_get_context(task), ptab[i].atom); JSValue key = JS_AtomToString(tf_task_get_context(task), ptab[i].atom);
JSPropertyDescriptor desc; JSPropertyDescriptor desc;
JSValue key_value = JS_NULL; JSValue key_value = JS_NULL;
if (JS_GetOwnProperty(tf_task_get_context(task), &desc, value, ptab[i].atom) == 1) { if (JS_GetOwnProperty(tf_task_get_context(task), &desc, value, ptab[i].atom) == 1)
{
key_value = desc.value; key_value = desc.value;
} }
_serialize_storeInternal(task, to, buffer, key, depth + 1); _serialize_storeInternal(task, to, buffer, key, depth + 1);
@ -229,21 +279,26 @@ static bool _serialize_storeInternal(tf_task_t* task, tf_taskstub_t* to, buffer_
JS_FreeValue(tf_task_get_context(task), key); JS_FreeValue(tf_task_get_context(task), key);
JS_FreeValue(tf_task_get_context(task), key_value); JS_FreeValue(tf_task_get_context(task), key_value);
} }
for (uint32_t i = 0; i < plen; ++i) { for (uint32_t i = 0; i < plen; ++i)
{
JS_FreeAtom(tf_task_get_context(task), ptab[i].atom); JS_FreeAtom(tf_task_get_context(task), ptab[i].atom);
} }
js_free(tf_task_get_context(task), ptab); js_free(tf_task_get_context(task), ptab);
} else if (JS_IsObject(value)) { }
else if (JS_IsObject(value))
{
_serialize_writeInt32(buffer, kObject); _serialize_writeInt32(buffer, kObject);
JSPropertyEnum* ptab; JSPropertyEnum* ptab;
uint32_t plen; uint32_t plen;
JS_GetOwnPropertyNames(tf_task_get_context(task), &ptab, &plen, value, JS_GPN_STRING_MASK); JS_GetOwnPropertyNames(tf_task_get_context(task), &ptab, &plen, value, JS_GPN_STRING_MASK);
_serialize_writeInt32(buffer, plen); _serialize_writeInt32(buffer, plen);
for (uint32_t i = 0; i < plen; ++i) { for (uint32_t i = 0; i < plen; ++i)
{
JSValue key = JS_AtomToString(tf_task_get_context(task), ptab[i].atom); JSValue key = JS_AtomToString(tf_task_get_context(task), ptab[i].atom);
JSPropertyDescriptor desc; JSPropertyDescriptor desc;
JSValue key_value = JS_NULL; JSValue key_value = JS_NULL;
if (JS_GetOwnProperty(tf_task_get_context(task), &desc, value, ptab[i].atom) == 1) { if (JS_GetOwnProperty(tf_task_get_context(task), &desc, value, ptab[i].atom) == 1)
{
key_value = desc.value; key_value = desc.value;
} }
_serialize_storeInternal(task, to, buffer, key, depth + 1); _serialize_storeInternal(task, to, buffer, key, depth + 1);
@ -251,11 +306,14 @@ static bool _serialize_storeInternal(tf_task_t* task, tf_taskstub_t* to, buffer_
JS_FreeValue(tf_task_get_context(task), key); JS_FreeValue(tf_task_get_context(task), key);
JS_FreeValue(tf_task_get_context(task), key_value); JS_FreeValue(tf_task_get_context(task), key_value);
} }
for (uint32_t i = 0; i < plen; ++i) { for (uint32_t i = 0; i < plen; ++i)
{
JS_FreeAtom(tf_task_get_context(task), ptab[i].atom); JS_FreeAtom(tf_task_get_context(task), ptab[i].atom);
} }
js_free(tf_task_get_context(task), ptab); js_free(tf_task_get_context(task), ptab);
} else { }
else
{
fprintf(stderr, "Unknown JSValue type: %d.\n", JS_VALUE_GET_TAG(value)); fprintf(stderr, "Unknown JSValue type: %d.\n", JS_VALUE_GET_TAG(value));
abort(); abort();
} }
@ -263,18 +321,24 @@ static bool _serialize_storeInternal(tf_task_t* task, tf_taskstub_t* to, buffer_
return true; return true;
} }
static JSValue _serialize_load(tf_task_t* task, tf_taskstub_t* from, const char* buffer, size_t size) { static JSValue _serialize_load(tf_task_t* task, tf_taskstub_t* from, const char* buffer, size_t size)
{
return _serialize_loadInternal(task, from, &buffer, &size, 0); return _serialize_loadInternal(task, from, &buffer, &size, 0);
} }
static JSValue _serialize_loadInternal(tf_task_t* task, tf_taskstub_t* from, const char** buffer, size_t* size, int depth) { static JSValue _serialize_loadInternal(tf_task_t* task, tf_taskstub_t* from, const char** buffer, size_t* size, int depth)
if (*size < sizeof(size)) { {
if (*size < sizeof(size))
{
return JS_UNDEFINED; return JS_UNDEFINED;
} else { }
else
{
int32_t type = _serialize_readInt32(buffer, size); int32_t type = _serialize_readInt32(buffer, size);
JSValue result = JS_UNDEFINED; JSValue result = JS_UNDEFINED;
switch (type) { switch (type)
{
case kUndefined: case kUndefined:
result = JS_UNDEFINED; result = JS_UNDEFINED;
break; break;
@ -316,7 +380,8 @@ static JSValue _serialize_loadInternal(tf_task_t* task, tf_taskstub_t* from, con
{ {
int32_t length = _serialize_readInt32(buffer, size); int32_t length = _serialize_readInt32(buffer, size);
result = JS_NewArray(tf_task_get_context(task)); result = JS_NewArray(tf_task_get_context(task));
for (int i = 0; i < length; ++i) { for (int i = 0; i < length; ++i)
{
JS_SetPropertyUint32(tf_task_get_context(task), result, i, _serialize_loadInternal(task, from, buffer, size, depth + 1)); JS_SetPropertyUint32(tf_task_get_context(task), result, i, _serialize_loadInternal(task, from, buffer, size, depth + 1));
} }
} }
@ -332,7 +397,8 @@ static JSValue _serialize_loadInternal(tf_task_t* task, tf_taskstub_t* from, con
_serialize_readInt32(buffer, size); _serialize_readInt32(buffer, size);
JSValue error = JS_NewError(tf_task_get_context(task)); JSValue error = JS_NewError(tf_task_get_context(task));
int32_t length = _serialize_readInt32(buffer, size); int32_t length = _serialize_readInt32(buffer, size);
for (int i = 0; i < length; ++i) { for (int i = 0; i < length; ++i)
{
JSValue key = _serialize_loadInternal(task, from, buffer, size, depth + 1); JSValue key = _serialize_loadInternal(task, from, buffer, size, depth + 1);
JSValue value = _serialize_loadInternal(task, from, buffer, size, depth + 1); JSValue value = _serialize_loadInternal(task, from, buffer, size, depth + 1);
const char* key_str = JS_ToCString(tf_task_get_context(task), key); const char* key_str = JS_ToCString(tf_task_get_context(task), key);
@ -348,7 +414,8 @@ static JSValue _serialize_loadInternal(tf_task_t* task, tf_taskstub_t* from, con
{ {
int32_t length = _serialize_readInt32(buffer, size); int32_t length = _serialize_readInt32(buffer, size);
result = JS_NewObject(tf_task_get_context(task)); result = JS_NewObject(tf_task_get_context(task));
for (int i = 0; i < length; ++i) { for (int i = 0; i < length; ++i)
{
JSValue key = _serialize_loadInternal(task, from, buffer, size, depth + 1); JSValue key = _serialize_loadInternal(task, from, buffer, size, depth + 1);
JSValue value = _serialize_loadInternal(task, from, buffer, size, depth + 1); JSValue value = _serialize_loadInternal(task, from, buffer, size, depth + 1);
const char* key_str = JS_ToCString(tf_task_get_context(task), key); const char* key_str = JS_ToCString(tf_task_get_context(task), key);

View File

@ -86,23 +86,27 @@ private:
}; };
*/ */
JSValue tf_socket_init(JSContext* context) { JSValue tf_socket_init(JSContext* context)
{
JS_NewClassID(&_classId); JS_NewClassID(&_classId);
JSClassDef def = { JSClassDef def = {
.class_name = "Socket", .class_name = "Socket",
.finalizer = &_socket_finalizer, .finalizer = &_socket_finalizer,
}; };
if (JS_NewClass(JS_GetRuntime(context), _classId, &def) != 0) { if (JS_NewClass(JS_GetRuntime(context), _classId, &def) != 0)
{
fprintf(stderr, "Failed to register Socket.\n"); fprintf(stderr, "Failed to register Socket.\n");
} }
return JS_NewCFunction2(context, _socket_create, "Socket", 0, JS_CFUNC_constructor, 0); return JS_NewCFunction2(context, _socket_create, "Socket", 0, JS_CFUNC_constructor, 0);
} }
int tf_socket_get_count() { int tf_socket_get_count()
{
return _count; return _count;
} }
int tf_socket_get_open_count() { int tf_socket_get_open_count()
{
return _open_count; return _open_count;
} }
@ -112,7 +116,8 @@ typedef struct _socket_resolve_data_t {
promiseid_t promise; promiseid_t promise;
} socket_resolve_data_t; } socket_resolve_data_t;
socket_t* _socket_create_internal(JSContext* context) { socket_t* _socket_create_internal(JSContext* context)
{
socket_t* socket = malloc(sizeof(socket_t)); socket_t* socket = malloc(sizeof(socket_t));
memset(socket, 0, sizeof(*socket)); memset(socket, 0, sizeof(*socket));
@ -165,23 +170,28 @@ socket_t* _socket_create_internal(JSContext* context) {
return socket; return socket;
} }
JSValue _socket_create(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _socket_create(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
return _socket_create_internal(context)->_object; return _socket_create_internal(context)->_object;
} }
void _socket_finalizer(JSRuntime *runtime, JSValue value) { void _socket_finalizer(JSRuntime *runtime, JSValue value)
{
socket_t* socket = JS_GetOpaque(value, _classId); socket_t* socket = JS_GetOpaque(value, _classId);
--_count; --_count;
free(socket); free(socket);
} }
void _socket_close_internal(socket_t* socket) { void _socket_close_internal(socket_t* socket)
if (!uv_is_closing((uv_handle_t*)&socket->_socket)) { {
if (!uv_is_closing((uv_handle_t*)&socket->_socket))
{
JS_FreeValue(tf_task_get_context(socket->_task), socket->_onRead); JS_FreeValue(tf_task_get_context(socket->_task), socket->_onRead);
socket->_onRead = JS_UNDEFINED; socket->_onRead = JS_UNDEFINED;
JS_FreeValue(tf_task_get_context(socket->_task), socket->_onError); JS_FreeValue(tf_task_get_context(socket->_task), socket->_onError);
socket->_onError = JS_UNDEFINED; socket->_onError = JS_UNDEFINED;
if (socket->_tls) { if (socket->_tls)
{
tf_tls_session_destroy(socket->_tls); tf_tls_session_destroy(socket->_tls);
socket->_tls = NULL; socket->_tls = NULL;
} }
@ -189,82 +199,110 @@ void _socket_close_internal(socket_t* socket) {
} }
} }
void _socket_reportError(socket_t* socket, const char* error) { void _socket_reportError(socket_t* socket, const char* error)
if (JS_IsFunction(tf_task_get_context(socket->_task),socket-> _onError)) { {
if (JS_IsFunction(tf_task_get_context(socket->_task),socket-> _onError))
{
JSValue exception = JS_ThrowInternalError(tf_task_get_context(socket->_task), "%s", error); JSValue exception = JS_ThrowInternalError(tf_task_get_context(socket->_task), "%s", error);
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onError, socket->_object, 1, &exception); JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onError, socket->_object, 1, &exception);
if (JS_IsException(result)) { if (JS_IsException(result))
{
printf("Socket error.\n"); printf("Socket error.\n");
js_std_dump_error(tf_task_get_context(socket->_task)); js_std_dump_error(tf_task_get_context(socket->_task));
} }
tf_task_run_jobs(socket->_task); tf_task_run_jobs(socket->_task);
JS_FreeValue(tf_task_get_context(socket->_task), exception); JS_FreeValue(tf_task_get_context(socket->_task), exception);
JS_FreeValue(tf_task_get_context(socket->_task), result); JS_FreeValue(tf_task_get_context(socket->_task), result);
} else { }
else
{
fprintf(stderr, "Socket::reportError: %s\n", error); fprintf(stderr, "Socket::reportError: %s\n", error);
} }
} }
void _socket_reportTlsErrors(socket_t* socket) { void _socket_reportTlsErrors(socket_t* socket)
{
char buffer[4096]; char buffer[4096];
while (socket->_tls && tf_tls_session_get_error(socket->_tls, buffer, sizeof(buffer))) { while (socket->_tls && tf_tls_session_get_error(socket->_tls, buffer, sizeof(buffer)))
{
_socket_reportError(socket, buffer); _socket_reportError(socket, buffer);
} }
} }
JSValue _socket_startTls(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _socket_startTls(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->_tls) { if (!socket->_tls)
{
tf_tls_context_t* context = 0; tf_tls_context_t* context = 0;
if (argc > 0 && JS_IsObject(argv[0])) { if (argc > 0 && JS_IsObject(argv[0]))
{
context = tf_tls_context_wrapper_get(argv[0]); context = tf_tls_context_wrapper_get(argv[0]);
} else { }
if (!_defaultTlsContext) { else
{
if (!_defaultTlsContext)
{
_defaultTlsContext = tf_tls_context_create(); _defaultTlsContext = tf_tls_context_create();
} }
context = _defaultTlsContext; context = _defaultTlsContext;
} }
if (context) { if (context)
{
socket->_tls = tf_tls_context_create_session(context); socket->_tls = tf_tls_context_create_session(context);
} }
if (socket->_tls) { if (socket->_tls)
{
tf_tls_session_set_hostname(socket->_tls, socket->_peerName); tf_tls_session_set_hostname(socket->_tls, socket->_peerName);
if (socket->_direction == kAccept) { if (socket->_direction == kAccept)
{
tf_tls_session_start_accept(socket->_tls); tf_tls_session_start_accept(socket->_tls);
} else if (socket->_direction == kConnect) { }
else if (socket->_direction == kConnect)
{
tf_tls_session_start_connect(socket->_tls); tf_tls_session_start_connect(socket->_tls);
} }
socket->_startTlsPromise = tf_task_allocate_promise(socket->_task); socket->_startTlsPromise = tf_task_allocate_promise(socket->_task);
JSValue result = tf_task_get_promise(socket->_task, socket->_startTlsPromise); JSValue result = tf_task_get_promise(socket->_task, socket->_startTlsPromise);
_socket_processOutgoingTls(socket); _socket_processOutgoingTls(socket);
return result; return result;
} else { }
else
{
return JS_ThrowInternalError(tf_task_get_context(socket->_task), "Failed to get TLS context"); return JS_ThrowInternalError(tf_task_get_context(socket->_task), "Failed to get TLS context");
} }
} else { }
else
{
return JS_ThrowInternalError(tf_task_get_context(socket->_task), "startTls with TLS already started"); return JS_ThrowInternalError(tf_task_get_context(socket->_task), "startTls with TLS already started");
} }
} }
JSValue _socket_stopTls(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _socket_stopTls(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->_tls) { if (socket->_tls)
{
_socket_processOutgoingTls(socket); _socket_processOutgoingTls(socket);
tf_tls_session_destroy(socket->_tls); tf_tls_session_destroy(socket->_tls);
socket->_tls = NULL; socket->_tls = NULL;
} else { }
else
{
JS_ThrowInternalError(tf_task_get_context(socket->_task), "stopTls with TLS already stopped"); JS_ThrowInternalError(tf_task_get_context(socket->_task), "stopTls with TLS already stopped");
} }
return JS_NULL; return JS_NULL;
} }
bool _socket_processSomeOutgoingTls(socket_t* socket, promiseid_t promise, uv_write_cb callback) { bool _socket_processSomeOutgoingTls(socket_t* socket, promiseid_t promise, uv_write_cb callback)
{
char buffer[65536]; char buffer[65536];
int result = tf_tls_session_read_encrypted(socket->_tls, buffer, sizeof(buffer)); int result = tf_tls_session_read_encrypted(socket->_tls, buffer, sizeof(buffer));
if (result > 0) { if (result > 0)
{
char* request_buffer = malloc(sizeof(uv_write_t) + result); char* request_buffer = malloc(sizeof(uv_write_t) + result);
uv_write_t* request = (uv_write_t*)request_buffer; uv_write_t* request = (uv_write_t*)request_buffer;
memset(request, 0, sizeof(*request)); memset(request, 0, sizeof(*request));
@ -279,23 +317,30 @@ bool _socket_processSomeOutgoingTls(socket_t* socket, promiseid_t promise, uv_wr
}; };
int writeResult = uv_write(request, (uv_stream_t*)&socket->_socket, &writeBuffer, 1, callback); int writeResult = uv_write(request, (uv_stream_t*)&socket->_socket, &writeBuffer, 1, callback);
if (writeResult != 0) { if (writeResult != 0)
{
free(request_buffer); free(request_buffer);
char error[256]; char error[256];
snprintf(error, sizeof(error), "uv_write: %s", uv_strerror(writeResult)); snprintf(error, sizeof(error), "uv_write: %s", uv_strerror(writeResult));
_socket_reportError(socket, error); _socket_reportError(socket, error);
} }
} else { }
else
{
_socket_reportTlsErrors(socket); _socket_reportTlsErrors(socket);
} }
return result > 0; return result > 0;
} }
void _socket_processOutgoingTls(socket_t* socket) { void _socket_processOutgoingTls(socket_t* socket)
while (_socket_processSomeOutgoingTls(socket, -1, _socket_onWrite)) {} {
while (_socket_processSomeOutgoingTls(socket, -1, _socket_onWrite))
{
}
} }
JSValue _socket_bind(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _socket_bind(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);
const char* node = JS_ToCString(tf_task_get_context(socket->_task), argv[0]); const char* node = JS_ToCString(tf_task_get_context(socket->_task), argv[0]);
const char* port = JS_ToCString(tf_task_get_context(socket->_task), argv[1]); const char* port = JS_ToCString(tf_task_get_context(socket->_task), argv[1]);
@ -313,7 +358,8 @@ JSValue _socket_bind(JSContext* context, JSValueConst this_val, int argc, JSValu
data->promise = tf_task_allocate_promise(socket->_task); data->promise = tf_task_allocate_promise(socket->_task);
int result = uv_getaddrinfo(tf_task_get_loop(socket->_task), &data->resolver, _socket_onResolvedForBind, node, port, &hints); int result = uv_getaddrinfo(tf_task_get_loop(socket->_task), &data->resolver, _socket_onResolvedForBind, node, port, &hints);
if (result != 0) { if (result != 0)
{
char error[256]; char error[256];
snprintf(error, sizeof(error), "uv_getaddrinfo: %s", uv_strerror(result)); snprintf(error, sizeof(error), "uv_getaddrinfo: %s", uv_strerror(result));
tf_task_reject_promise(socket->_task, data->promise, JS_ThrowInternalError(tf_task_get_context(socket->_task), error)); tf_task_reject_promise(socket->_task, data->promise, JS_ThrowInternalError(tf_task_get_context(socket->_task), error));
@ -322,26 +368,34 @@ JSValue _socket_bind(JSContext* context, JSValueConst this_val, int argc, JSValu
return tf_task_get_promise(socket->_task, data->promise); return tf_task_get_promise(socket->_task, data->promise);
} }
void _socket_onResolvedForBind(uv_getaddrinfo_t* resolver, int status, struct addrinfo* result) { void _socket_onResolvedForBind(uv_getaddrinfo_t* resolver, int status, struct addrinfo* result)
{
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)
{
char error[256]; char error[256];
snprintf(error, sizeof(error), "uv_getaddrinfo: %s", uv_strerror(status)); snprintf(error, sizeof(error), "uv_getaddrinfo: %s", uv_strerror(status));
tf_task_reject_promise(data->socket->_task, data->promise, JS_ThrowInternalError(tf_task_get_context(data->socket->_task), error)); tf_task_reject_promise(data->socket->_task, data->promise, JS_ThrowInternalError(tf_task_get_context(data->socket->_task), error));
} 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)
{
char error[256]; char error[256];
snprintf(error, sizeof(error), "uv_tcp_bind: %s", uv_strerror(bindResult)); snprintf(error, sizeof(error), "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), error)); tf_task_reject_promise(data->socket->_task, data->promise, JS_ThrowInternalError(tf_task_get_context(data->socket->_task), error));
} else { }
else
{
tf_task_resolve_promise(data->socket->_task, data->promise, JS_UNDEFINED); tf_task_resolve_promise(data->socket->_task, data->promise, JS_UNDEFINED);
} }
} }
free(data); free(data);
} }
JSValue _socket_connect(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _socket_connect(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);
socket->_direction = kConnect; socket->_direction = kConnect;
const char* node = JS_ToCString(context, argv[0]); const char* node = JS_ToCString(context, argv[0]);
@ -363,7 +417,8 @@ JSValue _socket_connect(JSContext* context, JSValueConst this_val, int argc, JSV
data->promise = promise; data->promise = promise;
int result = uv_getaddrinfo(tf_task_get_loop(socket->_task), &data->resolver, _socket_onResolvedForConnect, node, port, &hints); int result = uv_getaddrinfo(tf_task_get_loop(socket->_task), &data->resolver, _socket_onResolvedForConnect, node, port, &hints);
if (result != 0) { if (result != 0)
{
char error[256]; char error[256];
snprintf(error, sizeof(error), "uv_getaddrinfo: %s", uv_strerror(result)); snprintf(error, sizeof(error), "uv_getaddrinfo: %s", uv_strerror(result));
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, "%s", error)); tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, "%s", error));
@ -375,18 +430,23 @@ JSValue _socket_connect(JSContext* context, JSValueConst this_val, int argc, JSV
return tf_task_get_promise(socket->_task, promise); return tf_task_get_promise(socket->_task, promise);
} }
void _socket_onResolvedForConnect(uv_getaddrinfo_t* resolver, int status, struct addrinfo* result) { void _socket_onResolvedForConnect(uv_getaddrinfo_t* resolver, int status, struct addrinfo* result)
{
socket_resolve_data_t* data = resolver->data; socket_resolve_data_t* data = resolver->data;
if (status != 0) { if (status != 0)
{
char error[256]; char error[256];
snprintf(error, sizeof(error), "uv_getaddrinfo: %s", uv_strerror(status)); snprintf(error, sizeof(error), "uv_getaddrinfo: %s", uv_strerror(status));
tf_task_reject_promise(data->socket->_task, data->promise, JS_ThrowInternalError(tf_task_get_context(data->socket->_task), "%s", error)); tf_task_reject_promise(data->socket->_task, data->promise, JS_ThrowInternalError(tf_task_get_context(data->socket->_task), "%s", error));
} else { }
else
{
uv_connect_t* request = malloc(sizeof(uv_connect_t)); uv_connect_t* request = malloc(sizeof(uv_connect_t));
memset(request, 0, sizeof(*request)); memset(request, 0, sizeof(*request));
request->data = (void*)(intptr_t)data->promise; request->data = (void*)(intptr_t)data->promise;
int connectResult = uv_tcp_connect(request, &data->socket->_socket, result->ai_addr, _socket_onConnect); int connectResult = uv_tcp_connect(request, &data->socket->_socket, result->ai_addr, _socket_onConnect);
if (connectResult != 0) { if (connectResult != 0)
{
char error[256]; char error[256];
snprintf(error, sizeof(error), "uv_tcp_connect: %s", uv_strerror(connectResult)); snprintf(error, sizeof(error), "uv_tcp_connect: %s", uv_strerror(connectResult));
tf_task_reject_promise(data->socket->_task, data->promise, JS_ThrowInternalError(tf_task_get_context(data->socket->_task), "%s", error)); tf_task_reject_promise(data->socket->_task, data->promise, JS_ThrowInternalError(tf_task_get_context(data->socket->_task), "%s", error));
@ -396,14 +456,19 @@ void _socket_onResolvedForConnect(uv_getaddrinfo_t* resolver, int status, struct
free(data); free(data);
} }
void _socket_onConnect(uv_connect_t* request, int status) { void _socket_onConnect(uv_connect_t* request, int status)
{
promiseid_t promise = (intptr_t)request->data; promiseid_t promise = (intptr_t)request->data;
if (promise != -1) { if (promise != -1)
{
socket_t* socket = request->handle->data; socket_t* socket = request->handle->data;
if (status == 0) { if (status == 0)
{
socket->_connected = true; socket->_connected = true;
tf_task_resolve_promise(socket->_task, promise, JS_NewInt32(tf_task_get_context(socket->_task), status)); tf_task_resolve_promise(socket->_task, promise, JS_NewInt32(tf_task_get_context(socket->_task), status));
} else { }
else
{
char error[256]; char error[256];
snprintf(error, sizeof(error), "uv_tcp_connect: %s", uv_strerror(status)); snprintf(error, sizeof(error), "uv_tcp_connect: %s", uv_strerror(status));
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(tf_task_get_context(socket->_task), "%s", error)); tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(tf_task_get_context(socket->_task), "%s", error));
@ -412,29 +477,37 @@ void _socket_onConnect(uv_connect_t* request, int status) {
free(request); free(request);
} }
JSValue _socket_listen(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _socket_listen(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);
int backlog = 1; int backlog = 1;
JS_ToInt32(context, &backlog, argv[0]); JS_ToInt32(context, &backlog, argv[0]);
if (JS_IsUndefined(socket->_onConnect)) { if (JS_IsUndefined(socket->_onConnect))
{
socket->_onConnect = JS_DupValue(context, argv[1]); socket->_onConnect = JS_DupValue(context, argv[1]);
int result = uv_listen((uv_stream_t*)&socket->_socket, backlog, _socket_onNewConnection); int result = uv_listen((uv_stream_t*)&socket->_socket, backlog, _socket_onNewConnection);
if (result != 0) { if (result != 0)
{
char error[256]; char error[256];
snprintf(error, sizeof(error), "uv_listen: %s", uv_strerror(result)); snprintf(error, sizeof(error), "uv_listen: %s", uv_strerror(result));
return JS_ThrowInternalError(context, error); return JS_ThrowInternalError(context, error);
} }
return JS_NewInt32(context, result); return JS_NewInt32(context, result);
} else { }
else
{
return JS_ThrowInternalError(context, "listen: Already listening."); return JS_ThrowInternalError(context, "listen: Already listening.");
} }
} }
void _socket_onNewConnection(uv_stream_t* server, int status) { void _socket_onNewConnection(uv_stream_t* server, int status)
{
socket_t* socket = server->data; socket_t* socket = server->data;
if (!JS_IsUndefined(socket->_onConnect)) { if (!JS_IsUndefined(socket->_onConnect))
{
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onConnect, socket->_object, 0, NULL); JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onConnect, socket->_object, 0, NULL);
if (JS_IsException(result)) { if (JS_IsException(result))
{
printf("Socket error on connection.\n"); printf("Socket error on connection.\n");
js_std_dump_error(tf_task_get_context(socket->_task)); js_std_dump_error(tf_task_get_context(socket->_task));
} }
@ -442,7 +515,8 @@ void _socket_onNewConnection(uv_stream_t* server, int status) {
} }
} }
JSValue _socket_accept(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _socket_accept(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);
socket_t* client = _socket_create_internal(context); socket_t* client = _socket_create_internal(context);
@ -450,10 +524,13 @@ JSValue _socket_accept(JSContext* context, JSValueConst this_val, int argc, JSVa
promiseid_t promise = tf_task_allocate_promise(socket->_task); promiseid_t promise = tf_task_allocate_promise(socket->_task);
JSValue result = tf_task_get_promise(socket->_task, promise); JSValue result = tf_task_get_promise(socket->_task, promise);
int status = uv_accept((uv_stream_t*)&socket->_socket, (uv_stream_t*)&client->_socket); int status = uv_accept((uv_stream_t*)&socket->_socket, (uv_stream_t*)&client->_socket);
if (status == 0) { if (status == 0)
{
client->_connected = true; client->_connected = true;
tf_task_resolve_promise(socket->_task, promise, client->_object); tf_task_resolve_promise(socket->_task, promise, client->_object);
} else { }
else
{
char error[256]; char error[256];
snprintf(error, sizeof(error), "uv_accept: %s", uv_strerror(status)); snprintf(error, sizeof(error), "uv_accept: %s", uv_strerror(status));
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, error)); tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, error));
@ -461,9 +538,11 @@ JSValue _socket_accept(JSContext* context, JSValueConst this_val, int argc, JSVa
return result; return result;
} }
JSValue _socket_close(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { 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->_closePromise = tf_task_allocate_promise(socket->_task); socket->_closePromise = tf_task_allocate_promise(socket->_task);
JSValue result = tf_task_get_promise(socket->_task, socket->_closePromise); JSValue result = tf_task_get_promise(socket->_task, socket->_closePromise);
_socket_close_internal(socket); _socket_close_internal(socket);
@ -472,24 +551,30 @@ JSValue _socket_close(JSContext* context, JSValueConst this_val, int argc, JSVal
return JS_UNDEFINED; return JS_UNDEFINED;
} }
JSValue _socket_shutdown(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _socket_shutdown(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);
promiseid_t promise = tf_task_allocate_promise(socket->_task); promiseid_t promise = tf_task_allocate_promise(socket->_task);
JSValue result = tf_task_get_promise(socket->_task, promise); JSValue result = tf_task_get_promise(socket->_task, promise);
if (socket->_tls) { if (socket->_tls)
{
_socket_processTlsShutdown(socket, promise); _socket_processTlsShutdown(socket, promise);
} else { }
else
{
_socket_shutdownInternal(socket, promise); _socket_shutdownInternal(socket, promise);
} }
return result; return result;
} }
void _socket_shutdownInternal(socket_t* socket, promiseid_t promise) { void _socket_shutdownInternal(socket_t* socket, promiseid_t promise)
{
uv_shutdown_t* request = malloc(sizeof(uv_shutdown_t)); uv_shutdown_t* request = malloc(sizeof(uv_shutdown_t));
memset(request, 0, sizeof(*request)); memset(request, 0, sizeof(*request));
request->data = (void*)(intptr_t)promise; request->data = (void*)(intptr_t)promise;
int result = uv_shutdown(request, (uv_stream_t*)&socket->_socket, _socket_onShutdown); int result = uv_shutdown(request, (uv_stream_t*)&socket->_socket, _socket_onShutdown);
if (result != 0) { if (result != 0)
{
char error[256]; char error[256];
snprintf(error, sizeof(error), "uv_shutdown: %s", uv_strerror(result)); snprintf(error, sizeof(error), "uv_shutdown: %s", uv_strerror(result));
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(tf_task_get_context(socket->_task), "%s", error)); tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(tf_task_get_context(socket->_task), "%s", error));
@ -497,23 +582,28 @@ void _socket_shutdownInternal(socket_t* socket, promiseid_t promise) {
} }
} }
void _socket_processTlsShutdown(socket_t* socket, promiseid_t promise) { void _socket_processTlsShutdown(socket_t* socket, promiseid_t promise)
{
tf_tls_session_shutdown(socket->_tls); tf_tls_session_shutdown(socket->_tls);
if (!_socket_processSomeOutgoingTls(socket, promise, _socket_onTlsShutdown)) { if (!_socket_processSomeOutgoingTls(socket, promise, _socket_onTlsShutdown))
{
_socket_shutdownInternal(socket, promise); _socket_shutdownInternal(socket, promise);
} }
} }
void _socket_onTlsShutdown(uv_write_t* request, int status) { void _socket_onTlsShutdown(uv_write_t* request, int status)
{
socket_t* socket = request->handle->data; socket_t* socket = request->handle->data;
promiseid_t promise = (intptr_t)request->data; promiseid_t promise = (intptr_t)request->data;
_socket_processTlsShutdown(socket, promise); _socket_processTlsShutdown(socket, promise);
free(request); free(request);
} }
JSValue _socket_onError(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _socket_onError(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 (!JS_IsUndefined(socket->_onError)) { if (!JS_IsUndefined(socket->_onError))
{
JS_FreeValue(context, socket->_onError); JS_FreeValue(context, socket->_onError);
socket->_onError = JS_UNDEFINED; socket->_onError = JS_UNDEFINED;
} }
@ -521,34 +611,43 @@ JSValue _socket_onError(JSContext* context, JSValueConst this_val, int argc, JSV
return JS_NULL; return JS_NULL;
} }
JSValue _socket_read(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _socket_read(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);
socket->_onRead = JS_DupValue(context, argv[0]); socket->_onRead = JS_DupValue(context, argv[0]);
int result = uv_read_start((uv_stream_t*)&socket->_socket, _socket_allocateBuffer, _socket_onRead); int result = uv_read_start((uv_stream_t*)&socket->_socket, _socket_allocateBuffer, _socket_onRead);
promiseid_t promise = tf_task_allocate_promise(socket->_task); promiseid_t promise = tf_task_allocate_promise(socket->_task);
JSValue read_result = tf_task_get_promise(socket->_task, promise); JSValue read_result = tf_task_get_promise(socket->_task, promise);
if (result != 0) { if (result != 0)
{
char error[256]; char error[256];
snprintf(error, sizeof(error), "uv_read_start: %s", uv_strerror(result)); snprintf(error, sizeof(error), "uv_read_start: %s", uv_strerror(result));
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, error)); tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, error));
} else { }
else
{
tf_task_resolve_promise(socket->_task, promise, JS_UNDEFINED); tf_task_resolve_promise(socket->_task, promise, JS_UNDEFINED);
} }
return read_result; return read_result;
} }
void _socket_allocateBuffer(uv_handle_t* handle, size_t suggestedSize, uv_buf_t* buf) { void _socket_allocateBuffer(uv_handle_t* handle, size_t suggestedSize, uv_buf_t* buf)
{
*buf = uv_buf_init(malloc(suggestedSize), suggestedSize); *buf = uv_buf_init(malloc(suggestedSize), suggestedSize);
} }
void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffer) { void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffer)
{
socket_t* socket = stream->data; socket_t* socket = stream->data;
if (readSize <= 0) { if (readSize <= 0)
{
socket->_connected = false; socket->_connected = false;
if (!JS_IsUndefined(socket->_onRead)) { if (!JS_IsUndefined(socket->_onRead))
{
JSValue args[] = { JS_UNDEFINED }; JSValue args[] = { JS_UNDEFINED };
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onRead, socket->_object, 1, args); JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onRead, socket->_object, 1, args);
if (JS_IsException(result)) { if (JS_IsException(result))
{
printf("Socket error on read.\n"); printf("Socket error on read.\n");
js_std_dump_error(tf_task_get_context(socket->_task)); js_std_dump_error(tf_task_get_context(socket->_task));
} }
@ -556,42 +655,60 @@ void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffe
tf_task_run_jobs(socket->_task); tf_task_run_jobs(socket->_task);
} }
_socket_close_internal(socket); _socket_close_internal(socket);
} else { }
if (socket->_tls) { else
{
if (socket->_tls)
{
_socket_reportTlsErrors(socket); _socket_reportTlsErrors(socket);
tf_tls_session_write_encrypted(socket->_tls, buffer->base, readSize); tf_tls_session_write_encrypted(socket->_tls, buffer->base, readSize);
if (socket->_startTlsPromise != -1) { if (socket->_startTlsPromise != -1)
{
tf_tls_handshake_t result = tf_tls_session_handshake(socket->_tls); tf_tls_handshake_t result = tf_tls_session_handshake(socket->_tls);
if (result == k_tls_handshake_done) { if (result == k_tls_handshake_done)
{
promiseid_t promise = socket->_startTlsPromise; promiseid_t promise = socket->_startTlsPromise;
socket->_startTlsPromise = -1; socket->_startTlsPromise = -1;
tf_task_resolve_promise(socket->_task, promise, JS_UNDEFINED); tf_task_resolve_promise(socket->_task, promise, JS_UNDEFINED);
} else if (result == k_tls_handshake_failed) { }
else if (result == k_tls_handshake_failed)
{
promiseid_t promise = socket->_startTlsPromise; promiseid_t promise = socket->_startTlsPromise;
socket->_startTlsPromise = -1; socket->_startTlsPromise = -1;
char buffer[8192]; char buffer[8192];
if (tf_tls_session_get_error(socket->_tls, buffer, sizeof(buffer))) { if (tf_tls_session_get_error(socket->_tls, buffer, sizeof(buffer)))
{
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(tf_task_get_context(socket->_task), buffer)); tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(tf_task_get_context(socket->_task), buffer));
} else { }
else
{
tf_task_reject_promise(socket->_task, promise, JS_UNDEFINED); tf_task_reject_promise(socket->_task, promise, JS_UNDEFINED);
} }
} }
} }
while (true) { while (true)
{
char plain[8192]; char plain[8192];
int result = tf_tls_session_read_plain(socket->_tls, plain, sizeof(plain)); int result = tf_tls_session_read_plain(socket->_tls, plain, sizeof(plain));
if (result > 0) { if (result > 0)
{
_socket_notifyDataRead(socket, plain, result); _socket_notifyDataRead(socket, plain, result);
} else if (result == k_tls_read_failed) { }
else if (result == k_tls_read_failed)
{
_socket_reportTlsErrors(socket); _socket_reportTlsErrors(socket);
_socket_close_internal(socket); _socket_close_internal(socket);
break; break;
} else if (result == k_tls_read_zero) { }
if (!JS_IsUndefined(socket->_onRead)) { else if (result == k_tls_read_zero)
{
if (!JS_IsUndefined(socket->_onRead))
{
JSValue args[] = { JS_UNDEFINED }; JSValue args[] = { JS_UNDEFINED };
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onRead, socket->_object, 1, args); JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onRead, socket->_object, 1, args);
if (JS_IsException(result)) { if (JS_IsException(result))
{
printf("Socket error on read plain.\n"); printf("Socket error on read plain.\n");
js_std_dump_error(tf_task_get_context(socket->_task)); js_std_dump_error(tf_task_get_context(socket->_task));
} }
@ -599,21 +716,27 @@ void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffe
tf_task_run_jobs(socket->_task); tf_task_run_jobs(socket->_task);
} }
break; break;
} else { }
else
{
break; break;
} }
} }
if (socket->_tls) { if (socket->_tls)
{
_socket_processOutgoingTls(socket); _socket_processOutgoingTls(socket);
} }
} else { }
else
{
_socket_notifyDataRead(socket, buffer->base, readSize); _socket_notifyDataRead(socket, buffer->base, readSize);
} }
} }
free(buffer->base); free(buffer->base);
} }
static JSValue _newUint8Array(JSContext* context, const void* data, size_t length) { static JSValue _newUint8Array(JSContext* context, const void* data, size_t length)
{
JSValue arrayBuffer = JS_NewArrayBufferCopy(context, (const uint8_t*)data, length); JSValue arrayBuffer = JS_NewArrayBufferCopy(context, (const uint8_t*)data, length);
JSValue global = JS_GetGlobalObject(context); JSValue global = JS_GetGlobalObject(context);
JSValue constructor = JS_GetPropertyStr(context, global, "Uint8Array"); JSValue constructor = JS_GetPropertyStr(context, global, "Uint8Array");
@ -624,13 +747,17 @@ static JSValue _newUint8Array(JSContext* context, const void* data, size_t lengt
return typedArray; return typedArray;
} }
void _socket_notifyDataRead(socket_t* socket, const char* data, size_t length) { void _socket_notifyDataRead(socket_t* socket, const char* data, size_t length)
if (!JS_IsUndefined(socket->_onRead)) { {
if (data && length > 0) { if (!JS_IsUndefined(socket->_onRead))
{
if (data && length > 0)
{
JSValue typedArray = _newUint8Array(tf_task_get_context(socket->_task), data, length); JSValue typedArray = _newUint8Array(tf_task_get_context(socket->_task), data, length);
JSValue args[] = { typedArray }; JSValue args[] = { typedArray };
JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onRead, socket->_object, 1, args); JSValue result = JS_Call(tf_task_get_context(socket->_task), socket->_onRead, socket->_object, 1, args);
if (JS_IsException(result)) { if (JS_IsException(result))
{
printf("Socket error on data read.\n"); printf("Socket error on data read.\n");
js_std_dump_error(tf_task_get_context(socket->_task)); js_std_dump_error(tf_task_get_context(socket->_task));
} }
@ -641,36 +768,45 @@ void _socket_notifyDataRead(socket_t* socket, const char* data, size_t length) {
} }
} }
int _socket_writeBytes(socket_t* socket, promiseid_t promise, int (*callback)(socket_t* socket, promiseid_t promise, const char*, size_t), JSValue value, int* outLength) { int _socket_writeBytes(socket_t* socket, promiseid_t promise, int (*callback)(socket_t* socket, promiseid_t promise, const char*, size_t), JSValue value, int* outLength)
{
int result = -1; int result = -1;
size_t length; size_t length;
uint8_t* array = NULL; uint8_t* array = NULL;
JSContext* context = tf_task_get_context(socket->_task); JSContext* context = tf_task_get_context(socket->_task);
if (JS_IsString(value)) { if (JS_IsString(value))
{
const char* stringValue = JS_ToCStringLen(context, &length, value); const char* stringValue = JS_ToCStringLen(context, &length, value);
result = callback(socket, promise, stringValue, length); result = callback(socket, promise, stringValue, length);
JS_FreeCString(context, stringValue); JS_FreeCString(context, stringValue);
} else if ((array = tf_try_get_array_buffer(context, &length, value)) != 0) { }
else if ((array = tf_try_get_array_buffer(context, &length, value)) != 0)
{
result = callback(socket, promise, (const char*)array, length); result = callback(socket, promise, (const char*)array, length);
} else { }
else
{
size_t offset; size_t offset;
size_t element_size; size_t element_size;
JSValue buffer = tf_try_get_typed_array_buffer(context, value, &offset, &length, &element_size); JSValue buffer = tf_try_get_typed_array_buffer(context, value, &offset, &length, &element_size);
size_t size; size_t size;
if ((array = tf_try_get_array_buffer(context, &size, buffer)) != 0) { if ((array = tf_try_get_array_buffer(context, &size, buffer)) != 0)
{
result = callback(socket, promise, (const char*)array, length); result = callback(socket, promise, (const char*)array, length);
} }
JS_FreeValue(context, buffer); JS_FreeValue(context, buffer);
} }
if (outLength) { if (outLength)
{
*outLength = (int)length; *outLength = (int)length;
} }
return result; return result;
} }
int _socket_writeInternal(socket_t* socket, promiseid_t promise, const char* data, size_t length) { int _socket_writeInternal(socket_t* socket, promiseid_t promise, const char* data, size_t length)
{
char* rawBuffer = malloc(sizeof(uv_write_t) + length); char* rawBuffer = malloc(sizeof(uv_write_t) + length);
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);
@ -684,51 +820,70 @@ int _socket_writeInternal(socket_t* socket, promiseid_t promise, const char* dat
return uv_write(request, (uv_stream_t*)&socket->_socket, &buffer, 1, _socket_onWrite); return uv_write(request, (uv_stream_t*)&socket->_socket, &buffer, 1, _socket_onWrite);
} }
static int _socket_write_tls(socket_t* socket, promiseid_t promise, const char* data, size_t size) { static int _socket_write_tls(socket_t* socket, promiseid_t promise, const char* data, size_t size)
{
return tf_tls_session_write_plain(socket->_tls, data, size); return tf_tls_session_write_plain(socket->_tls, data, size);
} }
JSValue _socket_write(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _socket_write(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);
promiseid_t promise = tf_task_allocate_promise(socket->_task); promiseid_t promise = tf_task_allocate_promise(socket->_task);
JSValue write_result = tf_task_get_promise(socket->_task, promise); JSValue write_result = tf_task_get_promise(socket->_task, promise);
if (!JS_IsUndefined(argv[0])) { if (!JS_IsUndefined(argv[0]))
if (socket->_tls) { {
if (socket->_tls)
{
_socket_reportTlsErrors(socket); _socket_reportTlsErrors(socket);
int length = 0; int length = 0;
int result = _socket_writeBytes(socket, -1, _socket_write_tls, argv[0], &length); int result = _socket_writeBytes(socket, -1, _socket_write_tls, argv[0], &length);
char buffer[8192]; char buffer[8192];
if (result <= 0 && tf_tls_session_get_error(socket->_tls, buffer, sizeof(buffer))) { if (result <= 0 && tf_tls_session_get_error(socket->_tls, buffer, sizeof(buffer)))
{
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, buffer)); tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, buffer));
} else if (result < length) { }
else if (result < length)
{
tf_task_reject_promise(socket->_task, promise, JS_NewInt32(context, result)); tf_task_reject_promise(socket->_task, promise, JS_NewInt32(context, result));
} else { }
else
{
tf_task_resolve_promise(socket->_task, promise, JS_NewInt32(context, result)); tf_task_resolve_promise(socket->_task, promise, JS_NewInt32(context, result));
} }
_socket_processOutgoingTls(socket); _socket_processOutgoingTls(socket);
} else { }
else
{
int length; int length;
int result = _socket_writeBytes(socket, promise, _socket_writeInternal, argv[0], &length); int result = _socket_writeBytes(socket, promise, _socket_writeInternal, argv[0], &length);
if (result != 0) { if (result != 0)
{
char error[256]; char error[256];
snprintf(error, sizeof(error), "uv_write: %s", uv_strerror(result)); snprintf(error, sizeof(error), "uv_write: %s", uv_strerror(result));
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, error)); tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(context, error));
} }
} }
} else { }
else
{
tf_task_reject_promise(socket->_task, promise, JS_NewInt32(context, -2)); tf_task_reject_promise(socket->_task, promise, JS_NewInt32(context, -2));
} }
return write_result; return write_result;
} }
void _socket_onWrite(uv_write_t* request, int status) { void _socket_onWrite(uv_write_t* request, int status)
{
socket_t* socket = request->handle->data; socket_t* socket = request->handle->data;
promiseid_t promise = (intptr_t)request->data; promiseid_t promise = (intptr_t)request->data;
if (promise != -1) { if (promise != -1)
if (status == 0) { {
if (status == 0)
{
tf_task_resolve_promise(socket->_task, promise, JS_NewInt32(tf_task_get_context(socket->_task), status)); tf_task_resolve_promise(socket->_task, promise, JS_NewInt32(tf_task_get_context(socket->_task), status));
} else { }
else
{
char error[256]; char error[256];
snprintf(error, sizeof(error), "uv_write: %s", uv_strerror(status)); snprintf(error, sizeof(error), "uv_write: %s", uv_strerror(status));
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(tf_task_get_context(socket->_task), error)); tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(tf_task_get_context(socket->_task), error));
@ -737,15 +892,18 @@ void _socket_onWrite(uv_write_t* request, int status) {
free(request); free(request);
} }
JSValue _socket_isConnected(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _socket_isConnected(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);
return socket->_connected ? JS_TRUE : JS_FALSE; return socket->_connected ? JS_TRUE : JS_FALSE;
} }
void _socket_onClose(uv_handle_t* handle) { void _socket_onClose(uv_handle_t* handle)
{
--_open_count; --_open_count;
socket_t* socket = handle->data; socket_t* socket = handle->data;
if (socket->_closePromise != -1) { if (socket->_closePromise != -1)
{
promiseid_t promise = socket->_closePromise; promiseid_t promise = socket->_closePromise;
socket->_closePromise = -1; socket->_closePromise = -1;
socket->_connected = false; socket->_connected = false;
@ -753,12 +911,16 @@ void _socket_onClose(uv_handle_t* handle) {
} }
} }
void _socket_onShutdown(uv_shutdown_t* request, int status) { void _socket_onShutdown(uv_shutdown_t* request, int status)
{
socket_t* socket = request->handle->data; socket_t* socket = request->handle->data;
promiseid_t promise = (intptr_t)request->data; promiseid_t promise = (intptr_t)request->data;
if (status == 0) { if (status == 0)
{
tf_task_resolve_promise(socket->_task, promise, JS_UNDEFINED); tf_task_resolve_promise(socket->_task, promise, JS_UNDEFINED);
} else { }
else
{
char error[256]; char error[256];
snprintf(error, sizeof(error), "uv_shutdown: %s", uv_strerror(status)); snprintf(error, sizeof(error), "uv_shutdown: %s", uv_strerror(status));
tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(tf_task_get_context(socket->_task), "%s", error)); tf_task_reject_promise(socket->_task, promise, JS_ThrowInternalError(tf_task_get_context(socket->_task), "%s", error));
@ -766,18 +928,25 @@ void _socket_onShutdown(uv_shutdown_t* request, int status) {
free(request); free(request);
} }
JSValue _socket_getPeerName(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _socket_getPeerName(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);
struct sockaddr_in6 addr; struct sockaddr_in6 addr;
int nameLength = sizeof(addr); int nameLength = sizeof(addr);
if (uv_tcp_getpeername(&socket->_socket, (struct sockaddr*)&addr, &nameLength) == 0) { if (uv_tcp_getpeername(&socket->_socket, (struct sockaddr*)&addr, &nameLength) == 0)
{
char name[1024]; char name[1024];
if ((size_t)nameLength > sizeof(struct sockaddr_in)) { if ((size_t)nameLength > sizeof(struct sockaddr_in))
if (uv_ip6_name(&addr, name, sizeof(name)) == 0) { {
if (uv_ip6_name(&addr, name, sizeof(name)) == 0)
{
return JS_NewString(context, name); return JS_NewString(context, name);
} }
} else { }
if (uv_ip4_name((struct sockaddr_in*)&addr, name, sizeof(name)) == 0) { else
{
if (uv_ip4_name((struct sockaddr_in*)&addr, name, sizeof(name)) == 0)
{
return JS_NewString(context, name); return JS_NewString(context, name);
} }
} }
@ -785,24 +954,29 @@ JSValue _socket_getPeerName(JSContext* context, JSValueConst this_val, int argc,
return JS_UNDEFINED; return JS_UNDEFINED;
} }
JSValue _socket_getPeerCertificate(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _socket_getPeerCertificate(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->_tls) { if (socket->_tls)
{
char buffer[128 * 1024]; char buffer[128 * 1024];
int result = tf_tls_session_get_peer_certificate(socket->_tls, buffer, sizeof(buffer)); int result = tf_tls_session_get_peer_certificate(socket->_tls, buffer, sizeof(buffer));
if (result > 0) { if (result > 0)
{
return _newUint8Array(tf_task_get_context(socket->_task), buffer, sizeof(buffer)); return _newUint8Array(tf_task_get_context(socket->_task), buffer, sizeof(buffer));
} }
} }
return JS_UNDEFINED; return JS_UNDEFINED;
} }
JSValue _socket_getNoDelay(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _socket_getNoDelay(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);
return JS_NewBool(context, socket->_noDelay); return JS_NewBool(context, socket->_noDelay);
} }
JSValue _socket_setNoDelay(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _socket_setNoDelay(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);
int result = JS_ToBool(context, argv[0]); int result = JS_ToBool(context, argv[0]);
socket->_noDelay = result > 0; socket->_noDelay = result > 0;

638
src/ssb.c

File diff suppressed because it is too large Load Diff

View File

@ -22,14 +22,16 @@ typedef struct _tf_ssb_connections_t
static void _tf_ssb_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_change_t change, tf_ssb_connection_t* connection, void* user_data) static void _tf_ssb_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_change_t change, tf_ssb_connection_t* connection, void* user_data)
{ {
tf_ssb_connections_t* connections = user_data; tf_ssb_connections_t* connections = user_data;
switch (change) { switch (change)
{
case k_tf_ssb_change_create: case k_tf_ssb_change_create:
{ {
char key[ID_BASE64_LEN]; char key[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_host(connection) &&
tf_ssb_connection_get_port(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_store(connections, tf_ssb_connection_get_host(connection), tf_ssb_connection_get_port(connection), key); tf_ssb_connections_store(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); tf_ssb_connections_set_attempted(connections, tf_ssb_connection_get_host(connection), tf_ssb_connection_get_port(connection), key);
} }
@ -38,7 +40,8 @@ static void _tf_ssb_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_change_t
case k_tf_ssb_change_connect: case k_tf_ssb_change_connect:
{ {
char key[ID_BASE64_LEN]; char key[ID_BASE64_LEN];
if (tf_ssb_connection_get_id(connection, key, sizeof(key))) { if (tf_ssb_connection_get_id(connection, key, sizeof(key)))
{
tf_ssb_connections_set_succeeded(connections, tf_ssb_connection_get_host(connection), tf_ssb_connection_get_port(connection), key); tf_ssb_connections_set_succeeded(connections, tf_ssb_connection_get_host(connection), tf_ssb_connection_get_port(connection), key);
} }
} }
@ -52,16 +55,20 @@ 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;
if (sqlite3_prepare(connections->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(connections->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);
snprintf(key, key_size, "%s", sqlite3_column_text(statement, 2)); snprintf(key, key_size, "%s", sqlite3_column_text(statement, 2));
result = true; result = true;
} }
sqlite3_finalize(statement); sqlite3_finalize(statement);
} else { }
else
{
printf("prepare: %s\n", sqlite3_errmsg(connections->db)); printf("prepare: %s\n", sqlite3_errmsg(connections->db));
} }
return result; return result;
@ -72,13 +79,16 @@ static void _tf_ssb_connections_timer(uv_timer_t* timer)
tf_ssb_connections_t* connections = timer->data; tf_ssb_connections_t* connections = timer->data;
tf_ssb_connection_t* active[4]; tf_ssb_connection_t* active[4];
int count = tf_ssb_get_connections(connections->ssb, active, _countof(active)); int count = tf_ssb_get_connections(connections->ssb, active, _countof(active));
if (count < _countof(active)) { if (count < _countof(active))
{
char host[256]; char host[256];
int port; int port;
char key[ID_BASE64_LEN]; char key[ID_BASE64_LEN];
if (_tf_ssb_connections_get_next_connection(connections, host, sizeof(host), &port, key, sizeof(key))) { if (_tf_ssb_connections_get_next_connection(connections, host, sizeof(host), &port, key, sizeof(key)))
{
uint8_t key_bin[ID_BIN_LEN]; uint8_t key_bin[ID_BIN_LEN];
if (tf_ssb_id_str_to_bin(key_bin, key)) { if (tf_ssb_id_str_to_bin(key_bin, key))
{
tf_ssb_connect(connections->ssb, host, port, key_bin); tf_ssb_connect(connections->ssb, host, port, key_bin);
} }
} }
@ -118,12 +128,15 @@ void tf_ssb_connections_destroy(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)
{ {
sqlite3_stmt* statement; sqlite3_stmt* statement;
if (sqlite3_prepare(connections->db, "INSERT INTO connections (host, port, key) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING", -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_prepare(connections->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, host, -1, NULL) == SQLITE_OK && if (sqlite3_bind_text(statement, 1, host, -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, key, -1, NULL) == SQLITE_OK) { sqlite3_bind_text(statement, 3, key, -1, NULL) == SQLITE_OK)
{
int r = sqlite3_step(statement); int r = sqlite3_step(statement);
if (r != SQLITE_DONE) { if (r != SQLITE_DONE)
{
printf("tf_ssb_connections_store: %d, %s.\n", r, sqlite3_errmsg(connections->db)); printf("tf_ssb_connections_store: %d, %s.\n", r, sqlite3_errmsg(connections->db));
} }
} }
@ -134,11 +147,14 @@ 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)
{ {
sqlite3_stmt* statement; sqlite3_stmt* statement;
if (sqlite3_prepare(connections->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(connections->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, host, -1, NULL) == SQLITE_OK && if (sqlite3_bind_text(statement, 1, host, -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, key, -1, NULL) == SQLITE_OK) { sqlite3_bind_text(statement, 3, key, -1, NULL) == SQLITE_OK)
if (sqlite3_step(statement) != SQLITE_DONE) { {
if (sqlite3_step(statement) != SQLITE_DONE)
{
printf("tf_ssb_connections_set_attempted: %s.\n", sqlite3_errmsg(connections->db)); printf("tf_ssb_connections_set_attempted: %s.\n", sqlite3_errmsg(connections->db));
} }
} }
@ -149,11 +165,14 @@ 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)
{ {
sqlite3_stmt* statement; sqlite3_stmt* statement;
if (sqlite3_prepare(connections->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(connections->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, host, -1, NULL) == SQLITE_OK && if (sqlite3_bind_text(statement, 1, host, -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, key, -1, NULL) == SQLITE_OK) { sqlite3_bind_text(statement, 3, key, -1, NULL) == SQLITE_OK)
if (sqlite3_step(statement) != SQLITE_DONE) { {
if (sqlite3_step(statement) != SQLITE_DONE)
{
printf("tf_ssb_connections_set_succeeded: %s.\n", sqlite3_errmsg(connections->db)); printf("tf_ssb_connections_set_succeeded: %s.\n", sqlite3_errmsg(connections->db));
} }
} }

View File

@ -82,7 +82,8 @@ bool tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id,
sqlite3_stmt* statement; sqlite3_stmt* statement;
int64_t last_row_id = -1; int64_t last_row_id = -1;
const char* query = "INSERT INTO messages (id, previous, author, sequence, timestamp, content, hash, signature) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT DO NOTHING"; const char* query = "INSERT INTO messages (id, previous, author, sequence, timestamp, content, hash, signature) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT DO NOTHING";
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 &&
@ -90,9 +91,11 @@ bool tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id,
sqlite3_bind_int64(statement, 5, timestamp) == SQLITE_OK && sqlite3_bind_int64(statement, 5, timestamp) == SQLITE_OK &&
sqlite3_bind_text(statement, 6, contentstr, content_len, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 6, contentstr, content_len, NULL) == SQLITE_OK &&
sqlite3_bind_text(statement, 7, "sha256", 6, 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_text(statement, 8, signature, -1, NULL) == SQLITE_OK)
{
int r = sqlite3_step(statement); int r = sqlite3_step(statement);
if (r != SQLITE_DONE) { if (r != SQLITE_DONE)
{
printf("%s\n", sqlite3_errmsg(db)); printf("%s\n", sqlite3_errmsg(db));
} }
stored = r == SQLITE_DONE && sqlite3_changes(db) != 0; stored = r == SQLITE_DONE && sqlite3_changes(db) != 0;
@ -102,27 +105,34 @@ bool tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id,
} }
} }
sqlite3_finalize(statement); sqlite3_finalize(statement);
} else { }
else
{
printf("prepare failed: %s\n", sqlite3_errmsg(db)); printf("prepare failed: %s\n", sqlite3_errmsg(db));
} }
if (last_row_id != -1) if (last_row_id != -1)
{ {
query = "INSERT INTO blob_wants (id) 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 ON CONFLICT DO NOTHING RETURNING id"; query = "INSERT INTO blob_wants (id) 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 ON CONFLICT DO NOTHING RETURNING id";
if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_int64(statement, 1, last_row_id) == SQLITE_OK && if (sqlite3_bind_int64(statement, 1, last_row_id) == SQLITE_OK &&
sqlite3_bind_int(statement, 2, BLOB_ID_LEN - 1) == SQLITE_OK) { sqlite3_bind_int(statement, 2, 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)
{ {
tf_ssb_notify_blob_want_added(ssb, (const char*)sqlite3_column_text(statement, 0)); tf_ssb_notify_blob_want_added(ssb, (const char*)sqlite3_column_text(statement, 0));
} }
if (r != SQLITE_DONE) { if (r != SQLITE_DONE)
{
printf("%s\n", sqlite3_errmsg(db)); printf("%s\n", sqlite3_errmsg(db));
} }
} }
sqlite3_finalize(statement); sqlite3_finalize(statement);
} else { }
else
{
printf("prepare failed: %s\n", sqlite3_errmsg(db)); printf("prepare failed: %s\n", sqlite3_errmsg(db));
} }
} }
@ -141,17 +151,21 @@ bool tf_ssb_db_message_content_get(tf_ssb_t* ssb, const char* id, uint8_t** out_
bool result = false; bool result = false;
sqlite3_stmt* statement; sqlite3_stmt* statement;
const char* query = "SELECT content FROM messages WHERE id = ?"; const char* query = "SELECT content FROM messages WHERE id = ?";
if (sqlite3_prepare(tf_ssb_get_db(ssb), query, -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_prepare(tf_ssb_get_db(ssb), 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);
if (out_blob) { if (out_blob)
{
*out_blob = malloc(size + 1); *out_blob = malloc(size + 1);
memcpy(*out_blob, blob, size); memcpy(*out_blob, blob, size);
(*out_blob)[size] = '\0'; (*out_blob)[size] = '\0';
} }
if (out_size) { if (out_size)
{
*out_size = size; *out_size = size;
} }
result = true; result = true;
@ -166,17 +180,21 @@ bool tf_ssb_db_blob_get(tf_ssb_t* ssb, const char* id, uint8_t** out_blob, size_
bool result = false; bool result = false;
sqlite3_stmt* statement; sqlite3_stmt* statement;
const char* query = "SELECT content FROM blobs WHERE id = $1"; const char* query = "SELECT content FROM blobs WHERE id = $1";
if (sqlite3_prepare(tf_ssb_get_db(ssb), query, -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_prepare(tf_ssb_get_db(ssb), 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);
if (out_blob) { if (out_blob)
{
*out_blob = malloc(size + 1); *out_blob = malloc(size + 1);
memcpy(*out_blob, blob, size); memcpy(*out_blob, blob, size);
(*out_blob)[size] = '\0'; (*out_blob)[size] = '\0';
} }
if (out_size) { if (out_size)
{
*out_size = size; *out_size = size;
} }
result = true; result = true;
@ -203,19 +221,26 @@ bool tf_ssb_db_blob_store(tf_ssb_t* ssb, const uint8_t* blob, size_t size, char*
printf("blob store %s\n", id); printf("blob store %s\n", id);
const char* query = "INSERT INTO blobs (id, content, created) VALUES ($1, $2, CAST(strftime('%s') AS INTEGER)) ON CONFLICT DO NOTHING"; const char* query = "INSERT INTO blobs (id, content, created) VALUES ($1, $2, CAST(strftime('%s') AS INTEGER)) ON CONFLICT DO NOTHING";
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_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;
} else { }
else
{
printf("bind failed: %s\n", sqlite3_errmsg(db)); printf("bind failed: %s\n", sqlite3_errmsg(db));
} }
sqlite3_finalize(statement); sqlite3_finalize(statement);
} else { }
else
{
printf("prepare failed: %s\n", sqlite3_errmsg(db)); printf("prepare failed: %s\n", sqlite3_errmsg(db));
} }
if (result && out_id) { if (result && out_id)
{
snprintf(out_id, out_id_size, "%s", id); snprintf(out_id, out_id_size, "%s", id);
} }
return result; return result;
@ -226,23 +251,30 @@ bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* aut
bool found = false; bool found = false;
sqlite3_stmt* statement; sqlite3_stmt* statement;
const char* query = "SELECT id, timestamp, content FROM messages WHERE author = $1 AND sequence = $2"; const char* query = "SELECT id, timestamp, content FROM messages WHERE author = $1 AND sequence = $2";
if (sqlite3_prepare(tf_ssb_get_db(ssb), query, -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_prepare(tf_ssb_get_db(ssb), 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)
{
strncpy(out_message_id, (const char*)sqlite3_column_text(statement, 0), out_message_id_size - 1); strncpy(out_message_id, (const char*)sqlite3_column_text(statement, 0), out_message_id_size - 1);
} }
if (out_timestamp) { if (out_timestamp)
{
*out_timestamp = sqlite3_column_int64(statement, 1); *out_timestamp = sqlite3_column_int64(statement, 1);
} }
if (out_content) { if (out_content)
{
*out_content = strdup((const char*)sqlite3_column_text(statement, 2)); *out_content = strdup((const char*)sqlite3_column_text(statement, 2));
} }
found = true; found = true;
} }
sqlite3_finalize(statement); sqlite3_finalize(statement);
} else { }
else
{
printf("prepare failed: %s\n", sqlite3_errmsg(tf_ssb_get_db(ssb))); printf("prepare failed: %s\n", sqlite3_errmsg(tf_ssb_get_db(ssb)));
} }
return found; return found;
@ -253,77 +285,105 @@ bool tf_ssb_db_get_latest_message_by_author(tf_ssb_t* ssb, const char* author, i
bool found = false; bool found = false;
sqlite3_stmt* statement; sqlite3_stmt* statement;
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(tf_ssb_get_db(ssb), query, -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_prepare(tf_ssb_get_db(ssb), 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)
{
*out_sequence = sqlite3_column_int64(statement, 1); *out_sequence = sqlite3_column_int64(statement, 1);
} }
if (out_message_id) { if (out_message_id)
{
strncpy(out_message_id, (const char*)sqlite3_column_text(statement, 0), out_message_id_size - 1); strncpy(out_message_id, (const char*)sqlite3_column_text(statement, 0), out_message_id_size - 1);
} }
found = true; found = true;
} }
sqlite3_finalize(statement); sqlite3_finalize(statement);
} else { }
else
{
printf("prepare failed: %s\n", sqlite3_errmsg(tf_ssb_get_db(ssb))); printf("prepare failed: %s\n", sqlite3_errmsg(tf_ssb_get_db(ssb)));
} }
return found; return found;
} }
static bool _tf_ssb_sqlite_bind_json(JSContext* context, sqlite3* db, sqlite3_stmt* statement, JSValue binds) { static bool _tf_ssb_sqlite_bind_json(JSContext* context, sqlite3* db, sqlite3_stmt* statement, JSValue binds)
{
bool all_bound = true; bool all_bound = true;
int32_t length = 0; int32_t length = 0;
if (JS_IsUndefined(binds)) { if (JS_IsUndefined(binds))
{
return true; return true;
} }
JSValue lengthval = JS_GetPropertyStr(context, binds, "length"); JSValue lengthval = JS_GetPropertyStr(context, binds, "length");
if (JS_ToInt32(context, &length, lengthval) == 0) { if (JS_ToInt32(context, &length, lengthval) == 0)
for (int i = 0; i < length; i++) { {
for (int i = 0; i < length; i++)
{
JSValue value = JS_GetPropertyUint32(context, binds, i); JSValue value = JS_GetPropertyUint32(context, binds, i);
if (JS_IsString(value)) { if (JS_IsString(value))
{
size_t str_len = 0; size_t str_len = 0;
const char* str = JS_ToCStringLen(context, &str_len, value); const char* str = JS_ToCStringLen(context, &str_len, value);
if (str) { if (str)
if (sqlite3_bind_text(statement, i + 1, str, str_len, SQLITE_TRANSIENT) != SQLITE_OK) { {
if (sqlite3_bind_text(statement, i + 1, str, str_len, SQLITE_TRANSIENT) != SQLITE_OK)
{
printf("failed to bind: %s\n", sqlite3_errmsg(db)); printf("failed to bind: %s\n", sqlite3_errmsg(db));
all_bound = false; all_bound = false;
} }
JS_FreeCString(context, str); JS_FreeCString(context, str);
} else { }
else
{
printf("expected cstring\n"); printf("expected cstring\n");
} }
} else if (JS_IsNumber(value)) { }
else if (JS_IsNumber(value))
{
int64_t number = 0; int64_t number = 0;
JS_ToInt64(context, &number, value); JS_ToInt64(context, &number, value);
if (sqlite3_bind_int64(statement, i + 1, number) != SQLITE_OK) { if (sqlite3_bind_int64(statement, i + 1, number) != SQLITE_OK)
{
printf("failed to bind: %s\n", sqlite3_errmsg(db)); printf("failed to bind: %s\n", sqlite3_errmsg(db));
all_bound = false; all_bound = false;
} }
} else if (JS_IsNull(value)) { }
if (sqlite3_bind_null(statement, i + 1) != SQLITE_OK) { else if (JS_IsNull(value))
{
if (sqlite3_bind_null(statement, i + 1) != SQLITE_OK)
{
printf("failed to bind: %s\n", sqlite3_errmsg(db)); printf("failed to bind: %s\n", sqlite3_errmsg(db));
all_bound = false; all_bound = false;
} }
} else { }
else
{
const char* str = JS_ToCString(context, value); const char* str = JS_ToCString(context, value);
printf("expected string: %s\n", str); printf("expected string: %s\n", str);
JS_FreeCString(context, str); JS_FreeCString(context, str);
} }
JS_FreeValue(context, value); JS_FreeValue(context, value);
} }
} else { }
else
{
printf("expected array\n"); printf("expected array\n");
} }
JS_FreeValue(context, lengthval); JS_FreeValue(context, lengthval);
return all_bound; return all_bound;
} }
static JSValue _tf_ssb_sqlite_row_to_json(JSContext* context, sqlite3_stmt* row) { static JSValue _tf_ssb_sqlite_row_to_json(JSContext* context, sqlite3_stmt* row)
{
JSValue result = JS_NewObject(context); JSValue result = JS_NewObject(context);
for (int i = 0; i < sqlite3_column_count(row); i++) { for (int i = 0; i < sqlite3_column_count(row); i++)
{
const char* name = sqlite3_column_name(row, i); const char* name = sqlite3_column_name(row, i);
switch (sqlite3_column_type(row, i)) { switch (sqlite3_column_type(row, i))
{
case SQLITE_INTEGER: case SQLITE_INTEGER:
JS_SetPropertyStr(context, result, name, JS_NewInt64(context, sqlite3_column_int64(row, i))); JS_SetPropertyStr(context, result, name, JS_NewInt64(context, sqlite3_column_int64(row, i)));
break; break;
@ -346,7 +406,8 @@ static JSValue _tf_ssb_sqlite_row_to_json(JSContext* context, sqlite3_stmt* row)
static int _tf_ssb_sqlite_authorizer(void* user_data, int action_code, const char* arg0, const char* arg1, const char* arg2, const char* arg3) static int _tf_ssb_sqlite_authorizer(void* user_data, int action_code, const char* arg0, const char* arg1, const char* arg2, const char* arg3)
{ {
switch (action_code) { switch (action_code)
{
case SQLITE_SELECT: case SQLITE_SELECT:
case SQLITE_FUNCTION: case SQLITE_FUNCTION:
return SQLITE_OK; return SQLITE_OK;
@ -365,10 +426,13 @@ void tf_ssb_db_visit_query(tf_ssb_t* ssb, const char* query, const JSValue binds
sqlite3* db = tf_ssb_get_db(ssb); sqlite3* db = tf_ssb_get_db(ssb);
sqlite3_stmt* statement; sqlite3_stmt* statement;
sqlite3_set_authorizer(db, _tf_ssb_sqlite_authorizer, ssb); sqlite3_set_authorizer(db, _tf_ssb_sqlite_authorizer, ssb);
if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_prepare(db, query, -1, &statement, NULL) == SQLITE_OK)
{
JSContext* context = tf_ssb_get_context(ssb); JSContext* context = tf_ssb_get_context(ssb);
if (_tf_ssb_sqlite_bind_json(context, db, statement, binds)) { if (_tf_ssb_sqlite_bind_json(context, db, statement, binds))
while (sqlite3_step(statement) == SQLITE_ROW) { {
while (sqlite3_step(statement) == SQLITE_ROW)
{
JSValue row = _tf_ssb_sqlite_row_to_json(context, statement); JSValue row = _tf_ssb_sqlite_row_to_json(context, statement);
tf_trace_t* trace = tf_ssb_get_trace(ssb); tf_trace_t* trace = tf_ssb_get_trace(ssb);
tf_trace_begin(trace, "callback"); tf_trace_begin(trace, "callback");
@ -378,7 +442,9 @@ void tf_ssb_db_visit_query(tf_ssb_t* ssb, const char* query, const JSValue binds
} }
} }
sqlite3_finalize(statement); sqlite3_finalize(statement);
} else { }
else
{
printf("prepare failed: %s\n", sqlite3_errmsg(db)); printf("prepare failed: %s\n", sqlite3_errmsg(db));
} }
sqlite3_set_authorizer(db, NULL, NULL); sqlite3_set_authorizer(db, NULL, NULL);

View File

@ -11,10 +11,13 @@
static void _write_file(const char* path, void* blob, size_t size) static void _write_file(const char* path, void* blob, size_t size)
{ {
FILE* file = fopen(path, "wb"); FILE* file = fopen(path, "wb");
if (file) { if (file)
{
fwrite(blob, 1, size, file); fwrite(blob, 1, size, file);
fclose(file); fclose(file);
} else { }
else
{
printf("Failed to open %s for write: %s.\n", path, strerror(errno)); printf("Failed to open %s for write: %s.\n", path, strerror(errno));
} }
} }
@ -23,7 +26,8 @@ void tf_ssb_export(tf_ssb_t* ssb, const char* key)
{ {
char user[256] = { 0 }; char user[256] = { 0 };
char path[256] = { 0 }; char path[256] = { 0 };
if (sscanf(key, "/~%255[^/]/%255s", user, path) != 2) { if (sscanf(key, "/~%255[^/]/%255s", user, path) != 2)
{
printf("Unable to export %s.\n", key); printf("Unable to export %s.\n", key);
return; return;
} }
@ -31,12 +35,15 @@ void tf_ssb_export(tf_ssb_t* ssb, const char* key)
char app_blob_id[64] = { 0 }; char app_blob_id[64] = { 0 };
sqlite3_stmt* statement; sqlite3_stmt* statement;
if (sqlite3_prepare(tf_ssb_get_db(ssb), "SELECT value FROM properties WHERE id = $1 AND key = 'path:' || $2", -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_prepare(tf_ssb_get_db(ssb), "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);
if (len >= (int)sizeof(app_blob_id)) { if (len >= (int)sizeof(app_blob_id))
{
len = sizeof(app_blob_id) - 1; len = sizeof(app_blob_id) - 1;
} }
memcpy(app_blob_id, sqlite3_column_text(statement, 0), len); memcpy(app_blob_id, sqlite3_column_text(statement, 0), len);
@ -45,14 +52,16 @@ void tf_ssb_export(tf_ssb_t* ssb, const char* key)
sqlite3_finalize(statement); sqlite3_finalize(statement);
} }
if (!*app_blob_id) { if (!*app_blob_id)
{
printf("Did not find app blob ID for %s.\n", key); printf("Did not find app blob ID for %s.\n", key);
return; return;
} }
uint8_t* blob = NULL; uint8_t* blob = NULL;
size_t size = 0; size_t size = 0;
if (!tf_ssb_db_blob_get(ssb, app_blob_id, &blob, &size)) { if (!tf_ssb_db_blob_get(ssb, app_blob_id, &blob, &size))
{
printf("Did not find blob for %s: %s.\n", key, app_blob_id); printf("Did not find blob for %s: %s.\n", key, app_blob_id);
return; return;
} }
@ -66,17 +75,21 @@ void tf_ssb_export(tf_ssb_t* ssb, const char* key)
JSValue files = JS_GetPropertyStr(context, app, "files"); JSValue files = JS_GetPropertyStr(context, app, "files");
JSPropertyEnum* ptab = NULL; JSPropertyEnum* ptab = NULL;
uint32_t plen = 0; uint32_t plen = 0;
if (JS_GetOwnPropertyNames(context, &ptab, &plen, files, JS_GPN_STRING_MASK) == 0) { if (JS_GetOwnPropertyNames(context, &ptab, &plen, files, JS_GPN_STRING_MASK) == 0)
for (uint32_t i = 0; i < plen; ++i) { {
for (uint32_t i = 0; i < plen; ++i)
{
JSPropertyDescriptor desc; JSPropertyDescriptor desc;
if (JS_GetOwnProperty(context, &desc, files, ptab[i].atom) == 1) { if (JS_GetOwnProperty(context, &desc, files, ptab[i].atom) == 1)
{
JSValue key = JS_AtomToString(context, ptab[i].atom); JSValue key = JS_AtomToString(context, ptab[i].atom);
const char* file_name = JS_ToCString(context, key); const char* file_name = JS_ToCString(context, key);
const char* blob_id = JS_ToCString(context, desc.value); const char* blob_id = JS_ToCString(context, desc.value);
uint8_t* file_blob = NULL; uint8_t* file_blob = NULL;
size_t file_size = 0; size_t file_size = 0;
if (tf_ssb_db_blob_get(ssb, blob_id, &file_blob, &file_size)) { if (tf_ssb_db_blob_get(ssb, blob_id, &file_blob, &file_size))
{
snprintf(file_path, sizeof(file_path), "apps/%s/%s/%s", user, path, file_name); snprintf(file_path, sizeof(file_path), "apps/%s/%s/%s", user, path, file_name);
_write_file(file_path, file_blob, file_size); _write_file(file_path, file_blob, file_size);
free(file_blob); free(file_blob);
@ -90,7 +103,8 @@ void tf_ssb_export(tf_ssb_t* ssb, const char* key)
} }
} }
for (uint32_t i = 0; i < plen; ++i) { for (uint32_t i = 0; i < plen; ++i)
{
JS_FreeAtom(context, ptab[i].atom); JS_FreeAtom(context, ptab[i].atom);
} }
js_free(context, ptab); js_free(context, ptab);

View File

@ -33,17 +33,22 @@ static void _tf_ssb_import_file_read(uv_fs_t* req)
{ {
tf_import_file_t* file = req->data; tf_import_file_t* file = req->data;
char id[k_id_base64_len]; char id[k_id_base64_len];
if (req->result >= 0) { if (req->result >= 0)
if (tf_ssb_db_blob_store(file->ssb, (const uint8_t*)file->data, req->result, id, sizeof(id))) { {
if (tf_ssb_db_blob_store(file->ssb, (const uint8_t*)file->data, req->result, id, sizeof(id)))
{
printf("Stored %s/%s as %s.\n", file->parent, file->name, id); printf("Stored %s/%s as %s.\n", file->parent, file->name, id);
if (strcasecmp(file->name + strlen(file->name) - strlen(".json"), ".json") == 0) { if (strcasecmp(file->name + strlen(file->name) - strlen(".json"), ".json") == 0)
{
sqlite3_stmt* statement; sqlite3_stmt* statement;
if (sqlite3_prepare(tf_ssb_get_db(file->ssb), "INSERT OR REPLACE INTO properties (id, key, value) VALUES ($1, 'path:' || $2, $3)", -1, &statement, NULL) == SQLITE_OK) { if (sqlite3_prepare(tf_ssb_get_db(file->ssb), "INSERT OR REPLACE INTO properties (id, key, value) VALUES ($1, 'path:' || $2, $3)", -1, &statement, NULL) == SQLITE_OK)
{
((char*)file->name)[strlen(file->name) - strlen(".json")] = '\0'; ((char*)file->name)[strlen(file->name) - strlen(".json")] = '\0';
if (sqlite3_bind_text(statement, 1, file->user, -1, NULL) == SQLITE_OK && if (sqlite3_bind_text(statement, 1, file->user, -1, NULL) == SQLITE_OK &&
sqlite3_bind_text(statement, 2, file->name, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, file->name, -1, NULL) == SQLITE_OK &&
sqlite3_bind_text(statement, 3, id, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 3, id, -1, NULL) == SQLITE_OK &&
sqlite3_step(statement) == SQLITE_DONE) { sqlite3_step(statement) == SQLITE_DONE)
{
printf("Registered %s path:%s as %s.\n", file->user, file->name, id); printf("Registered %s path:%s as %s.\n", file->user, file->name, id);
} }
sqlite3_finalize(statement); sqlite3_finalize(statement);
@ -75,13 +80,17 @@ static void _tf_ssb_import_scandir(uv_fs_t* req)
{ {
tf_import_t* import = req->data; tf_import_t* import = req->data;
uv_dirent_t ent; uv_dirent_t ent;
while (uv_fs_scandir_next(req, &ent) == 0) { while (uv_fs_scandir_next(req, &ent) == 0)
{
size_t len = strlen(import->parent) + strlen(ent.name) + 2; size_t len = strlen(import->parent) + strlen(ent.name) + 2;
char* path = malloc(len); char* path = malloc(len);
snprintf(path, len, "%s/%s", import->parent, ent.name); snprintf(path, len, "%s/%s", import->parent, ent.name);
if (ent.type == UV_DIRENT_DIR) { if (ent.type == UV_DIRENT_DIR)
{
tf_ssb_import(import->ssb, import->user, path); tf_ssb_import(import->ssb, import->user, path);
} else { }
else
{
size_t size = sizeof(tf_import_file_t) + strlen(import->parent) +1 + strlen(ent.name) + 1; size_t size = sizeof(tf_import_file_t) + strlen(import->parent) +1 + strlen(ent.name) + 1;
tf_import_file_t* file = malloc(size); tf_import_file_t* file = malloc(size);
memset(file, 0, size); memset(file, 0, size);
@ -96,7 +105,8 @@ static void _tf_ssb_import_scandir(uv_fs_t* req)
import->work_left++; import->work_left++;
int r = uv_fs_open(tf_ssb_get_loop(import->ssb), &file->req, path, 0, 0, _tf_ssb_import_file_open); int r = uv_fs_open(tf_ssb_get_loop(import->ssb), &file->req, path, 0, 0, _tf_ssb_import_file_open);
if (r < 0) { if (r < 0)
{
printf("Failed to open %s: %s.\n", path, uv_strerror(r)); printf("Failed to open %s: %s.\n", path, uv_strerror(r));
free(file); free(file);
import->work_left--; import->work_left--;
@ -117,11 +127,13 @@ void tf_ssb_import(tf_ssb_t* ssb, const char* user, const char* path)
}; };
import.req.data = &import; import.req.data = &import;
int r = uv_fs_scandir(tf_ssb_get_loop(ssb), &import.req, path, 0, _tf_ssb_import_scandir); int r = uv_fs_scandir(tf_ssb_get_loop(ssb), &import.req, path, 0, _tf_ssb_import_scandir);
if (r) { if (r)
{
printf("Failed to scan directory %s: %s.", path, uv_strerror(r)); printf("Failed to scan directory %s: %s.", path, uv_strerror(r));
} }
while (import.work_left > 0) { while (import.work_left > 0)
{
uv_run(tf_ssb_get_loop(ssb), UV_RUN_ONCE); uv_run(tf_ssb_get_loop(ssb), UV_RUN_ONCE);
} }
uv_fs_req_cleanup(&import.req); uv_fs_req_cleanup(&import.req);

View File

@ -19,9 +19,11 @@ static JSValue _tf_ssb_whoami(JSContext* context, JSValueConst this_val, int arg
{ {
tf_ssb_t* ssb = JS_GetOpaque(this_val, _tf_ssb_classId); tf_ssb_t* ssb = JS_GetOpaque(this_val, _tf_ssb_classId);
printf("WHOAMI on %p\n", ssb); printf("WHOAMI on %p\n", ssb);
if (ssb) { if (ssb)
{
char id[512]; char id[512];
if (tf_ssb_whoami(ssb, id, sizeof(id))) { if (tf_ssb_whoami(ssb, id, sizeof(id)))
{
return JS_NewString(context, id); return JS_NewString(context, id);
} }
} }
@ -32,13 +34,15 @@ static JSValue _tf_ssb_getMessage(JSContext* context, JSValueConst this_val, int
{ {
JSValue result = JS_NULL; JSValue result = JS_NULL;
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)
{
const char* id = JS_ToCString(context, argv[0]); const char* id = JS_ToCString(context, argv[0]);
int64_t sequence = 0; int64_t sequence = 0;
JS_ToInt64(context, &sequence, argv[1]); JS_ToInt64(context, &sequence, argv[1]);
int64_t timestamp = -1; int64_t timestamp = -1;
char* contents = NULL; char* contents = NULL;
if (tf_ssb_db_get_message_by_author_and_sequence(ssb, id, sequence, NULL, 0, &timestamp, &contents)) { if (tf_ssb_db_get_message_by_author_and_sequence(ssb, id, sequence, NULL, 0, &timestamp, &contents))
{
result = JS_NewObject(context); result = JS_NewObject(context);
JS_SetPropertyStr(context, result, "timestamp", JS_NewInt64(context, timestamp)); JS_SetPropertyStr(context, result, "timestamp", JS_NewInt64(context, timestamp));
JS_SetPropertyStr(context, result, "content", JS_NewString(context, contents)); JS_SetPropertyStr(context, result, "content", JS_NewString(context, contents));
@ -53,11 +57,13 @@ static JSValue _tf_ssb_blobGet(JSContext* context, JSValueConst this_val, int ar
{ {
JSValue result = JS_NULL; JSValue result = JS_NULL;
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)
{
const char* id = JS_ToCString(context, argv[0]); const char* id = JS_ToCString(context, argv[0]);
uint8_t* blob = NULL; uint8_t* blob = NULL;
size_t size = 0; size_t size = 0;
if (tf_ssb_db_blob_get(ssb, id, &blob, &size)) { if (tf_ssb_db_blob_get(ssb, id, &blob, &size))
{
result = JS_NewArrayBufferCopy(context, blob, size); result = JS_NewArrayBufferCopy(context, blob, size);
free(blob); free(blob);
} }
@ -70,18 +76,24 @@ static JSValue _tf_ssb_blobStore(JSContext* context, JSValueConst this_val, int
{ {
JSValue result = JS_NULL; JSValue result = JS_NULL;
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)
{
uint8_t* blob = NULL; uint8_t* blob = NULL;
size_t size = 0; size_t size = 0;
char id[512]; char id[512];
if (JS_IsString(argv[0])) { if (JS_IsString(argv[0]))
{
const char* text = JS_ToCStringLen(context, &size, argv[0]); const char* text = JS_ToCStringLen(context, &size, argv[0]);
if (tf_ssb_db_blob_store(ssb, (const uint8_t*)text, size, id, sizeof(id))) { if (tf_ssb_db_blob_store(ssb, (const uint8_t*)text, size, id, sizeof(id)))
{
result = JS_NewString(context, id); result = JS_NewString(context, id);
} }
JS_FreeCString(context, text); JS_FreeCString(context, text);
} else if ((blob = tf_try_get_array_buffer(context, &size, argv[0])) != 0) { }
if (tf_ssb_db_blob_store(ssb, blob, size, id, sizeof(id))) { else if ((blob = tf_try_get_array_buffer(context, &size, argv[0])) != 0)
{
if (tf_ssb_db_blob_store(ssb, blob, size, id, sizeof(id)))
{
result = JS_NewString(context, id); result = JS_NewString(context, id);
} }
} }
@ -93,11 +105,13 @@ static JSValue _tf_ssb_messageContentGet(JSContext* context, JSValueConst this_v
{ {
JSValue result = JS_NULL; JSValue result = JS_NULL;
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)
{
const char* id = JS_ToCString(context, argv[0]); const char* id = JS_ToCString(context, argv[0]);
uint8_t* blob = NULL; uint8_t* blob = NULL;
size_t size = 0; size_t size = 0;
if (tf_ssb_db_message_content_get(ssb, id, &blob, &size)) { if (tf_ssb_db_message_content_get(ssb, id, &blob, &size))
{
result = JS_NewArrayBufferCopy(context, blob, size); result = JS_NewArrayBufferCopy(context, blob, size);
free(blob); free(blob);
} }
@ -110,12 +124,15 @@ static JSValue _tf_ssb_connections(JSContext* context, JSValueConst this_val, in
{ {
JSValue result = JS_NULL; JSValue result = JS_NULL;
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)
{
const char** connections = tf_ssb_get_connection_ids(ssb); const char** connections = tf_ssb_get_connection_ids(ssb);
if (connections) { if (connections)
{
result = JS_NewArray(context); result = JS_NewArray(context);
uint32_t i = 0; uint32_t i = 0;
for (const char** p = connections; *p; p++, i++) { for (const char** p = connections; *p; p++, i++)
{
JS_SetPropertyUint32(context, result, i, JS_NewString(context, *p)); JS_SetPropertyUint32(context, result, i, JS_NewString(context, *p));
} }
free(connections); free(connections);
@ -132,7 +149,8 @@ static void _check_call(JSContext* context, JSValue result)
printf("ERROR: %s\n", value); printf("ERROR: %s\n", value);
JS_FreeCString(context, value); JS_FreeCString(context, value);
JSValue stack = JS_GetPropertyStr(context, result, "stack"); JSValue stack = JS_GetPropertyStr(context, result, "stack");
if (!JS_IsUndefined(stack)) { if (!JS_IsUndefined(stack))
{
const char* stack_str = JS_ToCString(context, stack); const char* stack_str = JS_ToCString(context, stack);
printf("%s\n", stack_str); printf("%s\n", stack_str);
JS_FreeCString(context, stack_str); JS_FreeCString(context, stack_str);
@ -157,7 +175,8 @@ typedef struct _sqlStream_callback_t
JSValue callback; JSValue callback;
} sqlStream_callback_t; } sqlStream_callback_t;
static void _tf_ssb_sqlStream_callback(JSValue row, void* user_data) { static void _tf_ssb_sqlStream_callback(JSValue row, void* user_data)
{
sqlStream_callback_t* info = user_data; sqlStream_callback_t* info = user_data;
JSValue response = JS_Call(info->context, info->callback, JS_UNDEFINED, 1, &row); JSValue response = JS_Call(info->context, info->callback, JS_UNDEFINED, 1, &row);
_check_call(info->context, response); _check_call(info->context, response);
@ -171,9 +190,11 @@ static void _tf_ssb_sqlStream_callback(JSValue row, void* user_data) {
static JSValue _tf_ssb_sqlStream(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) static JSValue _tf_ssb_sqlStream(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{ {
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)
{
const char* query = JS_ToCString(context, argv[0]); const char* query = JS_ToCString(context, argv[0]);
if (query) { if (query)
{
sqlStream_callback_t info = { sqlStream_callback_t info = {
.context = context, .context = context,
.callback = argv[2], .callback = argv[2],
@ -188,9 +209,11 @@ static JSValue _tf_ssb_sqlStream(JSContext* context, JSValueConst this_val, int
static JSValue _tf_ssb_post(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) static JSValue _tf_ssb_post(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{ {
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)
{
const char* post_text = JS_ToCString(context, argv[0]); const char* post_text = JS_ToCString(context, argv[0]);
if (post_text) { if (post_text)
{
tf_ssb_append_post(ssb, post_text); tf_ssb_append_post(ssb, post_text);
JS_FreeCString(context, post_text); JS_FreeCString(context, post_text);
} }
@ -201,7 +224,8 @@ static JSValue _tf_ssb_post(JSContext* context, JSValueConst this_val, int argc,
static JSValue _tf_ssb_appendMessage(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) static JSValue _tf_ssb_appendMessage(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{ {
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)
{
tf_ssb_append_message(ssb, argv[0]); tf_ssb_append_message(ssb, argv[0]);
} }
return JS_NULL; return JS_NULL;
@ -213,9 +237,12 @@ static JSValue _tf_ssb_storeMessage(JSContext* context, JSValueConst this_val, i
char signature[crypto_sign_BYTES + 128]; char signature[crypto_sign_BYTES + 128];
char id[crypto_hash_sha256_BYTES * 2 + 1]; char id[crypto_hash_sha256_BYTES * 2 + 1];
tf_ssb_calculate_message_id(context, argv[0], id, sizeof(id)); tf_ssb_calculate_message_id(context, argv[0], id, sizeof(id));
if (tf_ssb_verify_and_strip_signature(context, argv[0], signature, sizeof(signature))) { if (tf_ssb_verify_and_strip_signature(context, argv[0], signature, sizeof(signature)))
{
tf_ssb_db_store_message(ssb, context, id, argv[0], signature); tf_ssb_db_store_message(ssb, context, id, argv[0], signature);
} else { }
else
{
printf("failed to verify message\n"); printf("failed to verify message\n");
} }
return JS_UNDEFINED; return JS_UNDEFINED;
@ -246,7 +273,8 @@ static JSValue _tf_ssb_getBroadcasts(JSContext* context, JSValueConst this_val,
{ {
JSValue result = JS_UNDEFINED; JSValue result = JS_UNDEFINED;
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)
{
result = JS_NewArray(context); result = JS_NewArray(context);
broadcasts_t broadcasts = { broadcasts_t broadcasts = {
.context = context, .context = context,
@ -262,13 +290,17 @@ static JSValue _tf_ssb_connect(JSContext* context, JSValueConst this_val, int ar
{ {
JSValue args = argv[0]; JSValue args = argv[0];
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)
if (JS_IsString(args)) { {
if (JS_IsString(args))
{
const char* address_str = JS_ToCString(context, args); const char* address_str = JS_ToCString(context, args);
printf("Connecting to %s\n", address_str); printf("Connecting to %s\n", address_str);
tf_ssb_connect_str(ssb, address_str); tf_ssb_connect_str(ssb, address_str);
JS_FreeCString(context, address_str); JS_FreeCString(context, address_str);
} else { }
else
{
JSValue address = JS_GetPropertyStr(context, args, "address"); JSValue address = JS_GetPropertyStr(context, args, "address");
JSValue port = JS_GetPropertyStr(context, args, "port"); JSValue port = JS_GetPropertyStr(context, args, "port");
JSValue pubkey = JS_GetPropertyStr(context, args, "pubkey"); JSValue pubkey = JS_GetPropertyStr(context, args, "pubkey");
@ -296,7 +328,8 @@ static void _tf_ssb_call_callback(tf_ssb_t* ssb, const char* name, void* user_da
JSValue global = JS_GetGlobalObject(context); JSValue global = JS_GetGlobalObject(context);
JSValue ssbo = JS_GetPropertyStr(context, global, "ssb"); JSValue ssbo = JS_GetPropertyStr(context, global, "ssb");
JSValue callback = JS_GetPropertyStr(context, ssbo, name); JSValue callback = JS_GetPropertyStr(context, ssbo, name);
if (JS_IsFunction(context, callback)) { if (JS_IsFunction(context, callback))
{
JSValue args = JS_UNDEFINED; JSValue args = JS_UNDEFINED;
JSValue response = JS_Call(context, callback, JS_UNDEFINED, 0, &args); JSValue response = JS_Call(context, callback, JS_UNDEFINED, 0, &args);
_check_call(context, response); _check_call(context, response);
@ -358,7 +391,8 @@ static JSValue _tf_ssb_rpc_send_binary(JSContext* context, JSValueConst this_val
size_t size; size_t size;
uint8_t* message = tf_try_get_array_buffer(context, &size, argv[0]); uint8_t* message = tf_try_get_array_buffer(context, &size, argv[0]);
if (message) { if (message)
{
tf_ssb_connection_rpc_send( tf_ssb_connection_rpc_send(
connection, connection,
k_ssb_rpc_flag_binary | k_ssb_rpc_flag_stream, k_ssb_rpc_flag_binary | k_ssb_rpc_flag_stream,
@ -550,7 +584,8 @@ void tf_ssb_run_file(JSContext* context, const char* file_name)
printf("ERROR: %s\n", value); printf("ERROR: %s\n", value);
JS_FreeCString(context, value); JS_FreeCString(context, value);
JSValue stack = JS_GetPropertyStr(context, result, "stack"); JSValue stack = JS_GetPropertyStr(context, result, "stack");
if (!JS_IsUndefined(stack)) { if (!JS_IsUndefined(stack))
{
const char* stack_str = JS_ToCString(context, stack); const char* stack_str = JS_ToCString(context, stack);
printf("%s\n", stack_str); printf("%s\n", stack_str);
JS_FreeCString(context, stack_str); JS_FreeCString(context, stack_str);
@ -568,12 +603,14 @@ void tf_ssb_run_file(JSContext* context, const char* file_name)
} }
JSRuntime* runtime = JS_GetRuntime(context); JSRuntime* runtime = JS_GetRuntime(context);
while (JS_IsJobPending(runtime)) { while (JS_IsJobPending(runtime))
{
JSContext* context2 = NULL; JSContext* context2 = NULL;
int r = JS_ExecutePendingJob(runtime, &context2); int r = JS_ExecutePendingJob(runtime, &context2);
JSValue result = JS_GetException(context2); JSValue result = JS_GetException(context2);
_check_call(context, result); _check_call(context, result);
if (r == 0) { if (r == 0)
{
break; break;
} }
} }
@ -582,11 +619,16 @@ void tf_ssb_run_file(JSContext* context, const char* file_name)
free(source); free(source);
} }
JSValue _print(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _print(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
for (int i = 0; i < argc; ++i) { {
if (JS_IsNull(argv[i])) { for (int i = 0; i < argc; ++i)
{
if (JS_IsNull(argv[i]))
{
printf(" null"); printf(" null");
} else { }
else
{
const char* value = JS_ToCString(context, argv[i]); const char* value = JS_ToCString(context, argv[i]);
printf(" %s", value); printf(" %s", value);
JS_FreeCString(context, value); JS_FreeCString(context, value);
@ -596,27 +638,37 @@ JSValue _print(JSContext* context, JSValueConst this_val, int argc, JSValueConst
return JS_NULL; return JS_NULL;
} }
static JSValue _utf8Decode(JSContext* context, uint8_t* data, size_t length) { static JSValue _utf8Decode(JSContext* context, uint8_t* data, size_t length)
{
return JS_NewStringLen(context, (const char*)data, length); return JS_NewStringLen(context, (const char*)data, length);
} }
static JSValue _utf8_decode(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _utf8_decode(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
JSValue result = JS_NULL; JSValue result = JS_NULL;
size_t length; size_t length;
if (JS_IsString(argv[0])) { if (JS_IsString(argv[0]))
{
result = JS_DupValue(context, argv[0]); result = JS_DupValue(context, argv[0]);
} else { }
else
{
uint8_t* array = tf_try_get_array_buffer(context, &length, argv[0]); uint8_t* array = tf_try_get_array_buffer(context, &length, argv[0]);
if (array) { if (array)
{
result = _utf8Decode(context, array, length); result = _utf8Decode(context, array, length);
} else { }
else
{
size_t offset; size_t offset;
size_t element_size; size_t element_size;
JSValue buffer = tf_try_get_typed_array_buffer(context, argv[0], &offset, &length, &element_size); JSValue buffer = tf_try_get_typed_array_buffer(context, argv[0], &offset, &length, &element_size);
size_t size; size_t size;
if (!JS_IsException(buffer)) { if (!JS_IsException(buffer))
{
array = tf_try_get_array_buffer(context, &size, buffer); array = tf_try_get_array_buffer(context, &size, buffer);
if (array) { if (array)
{
result = _utf8Decode(context, array, size); result = _utf8Decode(context, array, size);
} }
} }
@ -629,10 +681,12 @@ static JSValue _utf8_decode(JSContext* context, JSValueConst this_val, int argc,
void tf_ssb_init(JSContext* context, tf_ssb_t* ssb) void tf_ssb_init(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)
{
fprintf(stderr, "Failed to register ssb.\n"); fprintf(stderr, "Failed to register ssb.\n");
} }

View File

@ -37,15 +37,19 @@ static void _ssb_test_connections_changed(tf_ssb_t* ssb, tf_ssb_change_t change,
int count = 0; int count = 0;
const char** c = tf_ssb_get_connection_ids(ssb); const char** c = tf_ssb_get_connection_ids(ssb);
for (const char** p = c; *p; p++) { for (const char** p = c; *p; p++)
{
count++; count++;
} }
free(c); free(c);
if (ssb == test->ssb0) { if (ssb == test->ssb0)
{
printf("callback0 change=%d connection=%p\n", change, connection); printf("callback0 change=%d connection=%p\n", change, connection);
test->connection_count0 = count; test->connection_count0 = count;
} else if (ssb == test->ssb1) { }
else if (ssb == test->ssb1)
{
printf("callback1 change=%d connection=%p\n", change, connection); printf("callback1 change=%d connection=%p\n", change, connection);
test->connection_count1 = count; test->connection_count1 = count;
} }
@ -131,17 +135,20 @@ 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);
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);
} }
tf_ssb_server_close(ssb0); tf_ssb_server_close(ssb0);
while (_ssb_test_count_messages(ssb1) < 3) { while (_ssb_test_count_messages(ssb1) < 3)
{
uv_run(&loop, UV_RUN_ONCE); uv_run(&loop, UV_RUN_ONCE);
} }
printf("waiting for blob\n"); printf("waiting for blob\n");
while (!tf_ssb_db_blob_get(ssb1, blob_id, NULL, NULL)) { while (!tf_ssb_db_blob_get(ssb1, blob_id, NULL, NULL))
{
uv_run(&loop, UV_RUN_ONCE); uv_run(&loop, UV_RUN_ONCE);
} }
printf("done\n"); printf("done\n");
@ -202,16 +209,19 @@ void tf_ssb_test_following(const tf_test_options_t* options)
#define DUMP(id, depth) #define DUMP(id, depth)
#else #else
#define DUMP(id, depth) \ #define DUMP(id, depth) \
do { \ do \
{ \
printf("following %d:\n", depth); \ printf("following %d:\n", depth); \
const char** tf_ssb_get_following_deep(tf_ssb_t* ssb_param, const char** ids, int depth_param); \ const char** tf_ssb_get_following_deep(tf_ssb_t* ssb_param, const char** ids, int depth_param); \
const char** f = tf_ssb_get_following_deep(ssb0, (const char*[]) { id, NULL }, depth); \ const char** f = tf_ssb_get_following_deep(ssb0, (const char*[]) { id, NULL }, depth); \
for (const char** p = f; p && *p; p++) { \ for (const char** p = f; p && *p; p++) \
{ \
printf("* %s\n", *p); \ printf("* %s\n", *p); \
} \ } \
printf("\n"); \ printf("\n"); \
free(f); \ free(f); \
} while (0) } \
while (0)
#endif #endif
FOLLOW(ssb0, id1, true); FOLLOW(ssb0, id1, true);

File diff suppressed because it is too large Load Diff

View File

@ -38,9 +38,11 @@ typedef struct _tf_taskstub_t {
bool _finalized; bool _finalized;
} tf_taskstub_t; } tf_taskstub_t;
void tf_taskstub_startup() { void tf_taskstub_startup()
{
static bool initialized; static bool initialized;
if (!initialized) { if (!initialized)
{
JS_NewClassID(&_classId); JS_NewClassID(&_classId);
size_t size = sizeof(_executable); size_t size = sizeof(_executable);
uv_exepath(_executable, &size); uv_exepath(_executable, &size);
@ -62,7 +64,8 @@ static JSValue _taskstub_loadFile(JSContext* context, JSValueConst this_val, int
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 JSValue _taskstub_create(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _taskstub_create(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_task_t* parent = tf_task_get(context); tf_task_t* parent = tf_task_get(context);
tf_taskstub_t* stub = malloc(sizeof(tf_taskstub_t)); tf_taskstub_t* stub = malloc(sizeof(tf_taskstub_t));
memset(stub, 0, sizeof(*stub)); memset(stub, 0, sizeof(*stub));
@ -106,7 +109,8 @@ static JSValue _taskstub_create(JSContext* context, JSValueConst this_val, int a
JS_SetPropertyStr(context, taskObject, "loadFile", JS_NewCFunction(context, _taskstub_loadFile, "loadFile", 1)); JS_SetPropertyStr(context, taskObject, "loadFile", JS_NewCFunction(context, _taskstub_loadFile, "loadFile", 1));
taskid_t id = k_task_parent_id; taskid_t id = k_task_parent_id;
if (parent) { if (parent)
{
id = tf_task_allocate_task_id(parent, (tf_taskstub_t*)stub); id = tf_task_allocate_task_id(parent, (tf_taskstub_t*)stub);
} }
stub->_id = id; stub->_id = id;
@ -116,7 +120,8 @@ static JSValue _taskstub_create(JSContext* context, JSValueConst this_val, int a
uv_pipe_t* pipe = tf_packetstream_get_pipe(stub->_stream); uv_pipe_t* pipe = tf_packetstream_get_pipe(stub->_stream);
memset(pipe, 0, sizeof(*pipe)); memset(pipe, 0, sizeof(*pipe));
if (uv_pipe_init(tf_task_get_loop(parent), pipe, 1) != 0) { if (uv_pipe_init(tf_task_get_loop(parent), pipe, 1) != 0)
{
fprintf(stderr, "uv_pipe_init failed\n"); fprintf(stderr, "uv_pipe_init failed\n");
} }
@ -138,55 +143,67 @@ static JSValue _taskstub_create(JSContext* context, JSValueConst this_val, int a
JSValue result = JS_NULL; JSValue result = JS_NULL;
stub->_process.data = stub; stub->_process.data = stub;
int spawn_result = uv_spawn(tf_task_get_loop(parent), &stub->_process, &options); int spawn_result = uv_spawn(tf_task_get_loop(parent), &stub->_process, &options);
if (spawn_result == 0) { if (spawn_result == 0)
{
tf_packetstream_set_on_receive(stub->_stream, tf_task_on_receive_packet, stub); tf_packetstream_set_on_receive(stub->_stream, tf_task_on_receive_packet, stub);
tf_packetstream_start(stub->_stream); tf_packetstream_start(stub->_stream);
result = taskObject; result = taskObject;
} else { }
else
{
fprintf(stderr, "uv_spawn failed: %s\n", uv_strerror(spawn_result)); fprintf(stderr, "uv_spawn failed: %s\n", uv_strerror(spawn_result));
JS_FreeValue(context, taskObject); JS_FreeValue(context, taskObject);
} }
return result; return result;
} }
void _taskstub_gc_mark(JSRuntime* rt, JSValueConst value, JS_MarkFunc mark_func) { void _taskstub_gc_mark(JSRuntime* rt, JSValueConst value, JS_MarkFunc mark_func)
{
tf_taskstub_t* stub = JS_GetOpaque(value, _classId); tf_taskstub_t* stub = JS_GetOpaque(value, _classId);
if (stub) { if (stub)
{
JS_MarkValue(rt, stub->_on_exit, mark_func); JS_MarkValue(rt, stub->_on_exit, mark_func);
JS_MarkValue(rt, stub->_on_error, mark_func); JS_MarkValue(rt, stub->_on_error, mark_func);
} }
} }
JSValue tf_taskstub_init(JSContext* context) { JSValue tf_taskstub_init(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,
}; };
if (JS_NewClass(JS_GetRuntime(context), _classId, &def) != 0) { if (JS_NewClass(JS_GetRuntime(context), _classId, &def) != 0)
{
fprintf(stderr, "Failed to register TaskStub class.\n"); fprintf(stderr, "Failed to register TaskStub class.\n");
} }
return JS_NewCFunction2(context, _taskstub_create, "TaskStub", 0, JS_CFUNC_constructor, 0); return JS_NewCFunction2(context, _taskstub_create, "TaskStub", 0, JS_CFUNC_constructor, 0);
} }
taskid_t tf_taskstub_get_id(const tf_taskstub_t* stub) { taskid_t tf_taskstub_get_id(const tf_taskstub_t* stub)
{
return stub->_id; return stub->_id;
} }
JSValue tf_taskstub_get_task_object(const tf_taskstub_t* stub) { JSValue tf_taskstub_get_task_object(const tf_taskstub_t* stub)
{
return stub->_taskObject; return stub->_taskObject;
} }
tf_packetstream_t* tf_taskstub_get_stream(const tf_taskstub_t* stub) { tf_packetstream_t* tf_taskstub_get_stream(const tf_taskstub_t* stub)
{
return stub->_stream; return stub->_stream;
} }
tf_task_t* tf_taskstub_get_owner(const tf_taskstub_t* stub) { tf_task_t* tf_taskstub_get_owner(const tf_taskstub_t* stub)
{
return stub->_owner; return stub->_owner;
} }
tf_taskstub_t* tf_taskstub_create_parent(tf_task_t* task, uv_file file) { tf_taskstub_t* tf_taskstub_create_parent(tf_task_t* task, uv_file file)
{
JSValue parentObject = JS_NewObject(tf_task_get_context(task)); JSValue parentObject = JS_NewObject(tf_task_get_context(task));
tf_taskstub_t* parentStub = malloc(sizeof(tf_taskstub_t)); tf_taskstub_t* parentStub = malloc(sizeof(tf_taskstub_t));
memset(parentStub, 0, sizeof(tf_taskstub_t)); memset(parentStub, 0, sizeof(tf_taskstub_t));
@ -200,11 +217,13 @@ tf_taskstub_t* tf_taskstub_create_parent(tf_task_t* task, uv_file file) {
parentStub->_id = k_task_parent_id; parentStub->_id = k_task_parent_id;
parentStub->_object = JS_DupValue(tf_task_get_context(task), parentObject); parentStub->_object = JS_DupValue(tf_task_get_context(task), parentObject);
if (uv_pipe_init(tf_task_get_loop(task), tf_packetstream_get_pipe(parentStub->_stream), 1) != 0) { if (uv_pipe_init(tf_task_get_loop(task), tf_packetstream_get_pipe(parentStub->_stream), 1) != 0)
{
fprintf(stderr, "uv_pipe_init failed\n"); fprintf(stderr, "uv_pipe_init failed\n");
} }
tf_packetstream_set_on_receive(parentStub->_stream, tf_task_on_receive_packet, parentStub); tf_packetstream_set_on_receive(parentStub->_stream, tf_task_on_receive_packet, parentStub);
if (uv_pipe_open(tf_packetstream_get_pipe(parentStub->_stream), file) != 0) { if (uv_pipe_open(tf_packetstream_get_pipe(parentStub->_stream), file) != 0)
{
fprintf(stderr, "uv_pipe_open failed\n"); fprintf(stderr, "uv_pipe_open failed\n");
} }
tf_packetstream_start(parentStub->_stream); tf_packetstream_start(parentStub->_stream);
@ -216,12 +235,14 @@ static void _taskstub_cleanup(tf_taskstub_t* stub)
{ {
if (!stub->_process.data && if (!stub->_process.data &&
JS_IsUndefined(stub->_object) && JS_IsUndefined(stub->_object) &&
stub->_finalized) { stub->_finalized)
{
free(stub); free(stub);
} }
} }
static void _taskstub_finalizer(JSRuntime* runtime, JSValue value) { static void _taskstub_finalizer(JSRuntime* runtime, JSValue value)
{
tf_taskstub_t* stub = JS_GetOpaque(value, _classId); tf_taskstub_t* stub = JS_GetOpaque(value, _classId);
stub->_on_exit = JS_UNDEFINED; stub->_on_exit = JS_UNDEFINED;
stub->_on_error = JS_UNDEFINED; stub->_on_error = JS_UNDEFINED;
@ -240,10 +261,12 @@ static void _taskstub_on_handle_close(uv_handle_t* handle)
_taskstub_cleanup(stub); _taskstub_cleanup(stub);
} }
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)
{
tf_taskstub_t* stub = process->data; tf_taskstub_t* stub = process->data;
JSContext* context = tf_task_get_context(stub->_owner); JSContext* context = tf_task_get_context(stub->_owner);
if (!JS_IsUndefined(stub->_on_exit)) { if (!JS_IsUndefined(stub->_on_exit))
{
JSValue argv[] = { JS_NewInt32(context, status), JS_NewInt32(context, terminationSignal) }; JSValue argv[] = { JS_NewInt32(context, status), JS_NewInt32(context, terminationSignal) };
JSValue result = JS_Call(context, stub->_on_exit, JS_NULL, 2, argv); JSValue result = JS_Call(context, stub->_on_exit, JS_NULL, 2, argv);
tf_task_report_error(stub->_owner, result); tf_task_report_error(stub->_owner, result);
@ -257,14 +280,16 @@ static void _taskstub_on_process_exit(uv_process_t* process, int64_t status, int
tf_taskstub_destroy(stub); tf_taskstub_destroy(stub);
} }
static JSValue _taskstub_getExports(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _taskstub_getExports(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId); tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId);
promiseid_t promise = tf_task_allocate_promise(stub->_owner); promiseid_t promise = tf_task_allocate_promise(stub->_owner);
tf_task_send_promise_message(stub->_owner, (tf_taskstub_t*)stub, kGetExports, promise, JS_UNDEFINED); tf_task_send_promise_message(stub->_owner, (tf_taskstub_t*)stub, kGetExports, promise, JS_UNDEFINED);
return tf_task_get_promise(stub->_owner, promise); return tf_task_get_promise(stub->_owner, promise);
} }
static JSValue _taskstub_setImports(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _taskstub_setImports(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId); tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId);
void* buffer; void* buffer;
size_t size; size_t size;
@ -273,7 +298,8 @@ static JSValue _taskstub_setImports(JSContext* context, JSValueConst this_val, i
return JS_UNDEFINED; return JS_UNDEFINED;
} }
static JSValue _taskstub_setRequires(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _taskstub_setRequires(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId); tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId);
void* buffer; void* buffer;
size_t size; size_t size;
@ -282,7 +308,8 @@ static JSValue _taskstub_setRequires(JSContext* context, JSValueConst this_val,
return JS_UNDEFINED; return JS_UNDEFINED;
} }
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)
{
tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId); tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId);
void* buffer; void* buffer;
size_t size; size_t size;
@ -291,57 +318,69 @@ static JSValue _taskstub_loadFile(JSContext* context, JSValueConst this_val, int
return JS_UNDEFINED; return JS_UNDEFINED;
} }
static JSValue _taskstub_get_on_exit(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _taskstub_get_on_exit(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId); tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId);
return JS_DupValue(context, stub->_on_exit); return JS_DupValue(context, stub->_on_exit);
} }
static JSValue _taskstub_set_on_exit(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _taskstub_set_on_exit(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId); tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId);
if (!JS_IsUndefined(stub->_on_exit)) { if (!JS_IsUndefined(stub->_on_exit))
{
JS_FreeValue(context, stub->_on_exit); JS_FreeValue(context, stub->_on_exit);
} }
stub->_on_exit = JS_DupValue(context, argv[0]); stub->_on_exit = JS_DupValue(context, argv[0]);
return JS_UNDEFINED; return JS_UNDEFINED;
} }
static JSValue _taskstub_get_on_error(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _taskstub_get_on_error(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId); tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId);
return JS_DupValue(context, stub->_on_error); return JS_DupValue(context, stub->_on_error);
} }
static JSValue _taskstub_set_on_error(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _taskstub_set_on_error(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId); tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId);
if (!JS_IsUndefined(stub->_on_error)) { if (!JS_IsUndefined(stub->_on_error))
{
JS_FreeValue(context, stub->_on_error); JS_FreeValue(context, stub->_on_error);
} }
stub->_on_error = JS_DupValue(context, argv[0]); stub->_on_error = JS_DupValue(context, argv[0]);
return JS_UNDEFINED; return JS_UNDEFINED;
} }
static JSValue _taskstub_activate(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _taskstub_activate(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId); tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId);
if (stub) { if (stub)
{
tf_packetstream_send(stub->_stream, kActivate, 0, 0); tf_packetstream_send(stub->_stream, kActivate, 0, 0);
} }
return JS_NULL; return JS_NULL;
} }
static JSValue _taskstub_execute(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _taskstub_execute(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId); tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId);
promiseid_t promise = tf_task_allocate_promise(stub->_owner); promiseid_t promise = tf_task_allocate_promise(stub->_owner);
tf_task_send_promise_message(stub->_owner, (tf_taskstub_t*)stub, kExecute, promise, argv[0]); tf_task_send_promise_message(stub->_owner, (tf_taskstub_t*)stub, kExecute, promise, argv[0]);
return tf_task_get_promise(stub->_owner, promise); return tf_task_get_promise(stub->_owner, promise);
} }
static JSValue _taskstub_kill(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { static JSValue _taskstub_kill(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId); tf_taskstub_t* stub = JS_GetOpaque(this_val, _classId);
uv_process_kill(&stub->_process, SIGTERM); uv_process_kill(&stub->_process, SIGTERM);
return JS_UNDEFINED; return JS_UNDEFINED;
} }
void tf_taskstub_destroy(tf_taskstub_t* stub) { void tf_taskstub_destroy(tf_taskstub_t* stub)
if (!JS_IsUndefined(stub->_object)) { {
if (!JS_IsUndefined(stub->_object))
{
JSValue object = stub->_object; JSValue object = stub->_object;
stub->_object = JS_UNDEFINED; stub->_object = JS_UNDEFINED;
JS_FreeValue(tf_task_get_context(stub->_owner), object); JS_FreeValue(tf_task_get_context(stub->_owner), object);
@ -351,7 +390,8 @@ void tf_taskstub_destroy(tf_taskstub_t* stub) {
void tf_taskstub_on_error(tf_taskstub_t* stub, JSValue error) void tf_taskstub_on_error(tf_taskstub_t* stub, JSValue error)
{ {
JSContext* context = tf_task_get_context(stub->_owner); JSContext* context = tf_task_get_context(stub->_owner);
if (!JS_IsUndefined(stub->_on_error)) { if (!JS_IsUndefined(stub->_on_error))
{
JSValue result = JS_Call(context, stub->_on_error, JS_NULL, 1, &error); JSValue result = JS_Call(context, stub->_on_error, JS_NULL, 1, &error);
tf_task_report_error(stub->_owner, result); tf_task_report_error(stub->_owner, result);
JS_FreeValue(context, result); JS_FreeValue(context, result);

View File

@ -513,12 +513,15 @@ static void _test_file(const tf_test_options_t* options)
static void _tf_test_run(const tf_test_options_t* options, const char* name, void (*test)(const tf_test_options_t* options)) static void _tf_test_run(const tf_test_options_t* options, const char* name, void (*test)(const tf_test_options_t* options))
{ {
bool specified = false; bool specified = false;
if (options->tests) { if (options->tests)
{
char* dup = strdup(options->tests); char* dup = strdup(options->tests);
char* state = NULL; char* state = NULL;
const char* t = NULL; const char* t = NULL;
while ((t = strtok_r(t ? NULL : dup, ",", &state)) != NULL) { while ((t = strtok_r(t ? NULL : dup, ",", &state)) != NULL)
if (strcmp(t, name) == 0) { {
if (strcmp(t, name) == 0)
{
specified = true; specified = true;
break; break;
} }
@ -526,7 +529,8 @@ static void _tf_test_run(const tf_test_options_t* options, const char* name, voi
free(dup); free(dup);
} }
if (!options->tests || specified) { if (!options->tests || specified)
{
printf("Running test %s.\n", name); printf("Running test %s.\n", name);
test(options); test(options);
printf("[\e[1;32mpass\e[0m] %s\n", name); printf("[\e[1;32mpass\e[0m] %s\n", name);

629
src/tls.c

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,8 @@ static JSValue _tls_context_wrapper_add_trusted_certificate(JSContext* context,
static JSValue _tls_context_wrapper_create(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _tls_context_wrapper_create(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
static void _tls_context_wrapper_finalizer(JSRuntime *runtime, JSValue value); static void _tls_context_wrapper_finalizer(JSRuntime *runtime, JSValue value);
JSValue _tls_context_wrapper_set_certificate(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _tls_context_wrapper_set_certificate(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_tls_context_wrapper_t* wrapper = JS_GetOpaque(this_val, _classId); tf_tls_context_wrapper_t* wrapper = JS_GetOpaque(this_val, _classId);
const char* value = JS_ToCString(context, argv[0]); const char* value = JS_ToCString(context, argv[0]);
tf_tls_context_set_certificate(wrapper->context, value); tf_tls_context_set_certificate(wrapper->context, value);
@ -31,7 +32,8 @@ JSValue _tls_context_wrapper_set_certificate(JSContext* context, JSValueConst th
return JS_UNDEFINED; return JS_UNDEFINED;
} }
JSValue _tls_context_wrapper_set_private_key(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _tls_context_wrapper_set_private_key(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_tls_context_wrapper_t* wrapper = JS_GetOpaque(this_val, _classId); tf_tls_context_wrapper_t* wrapper = JS_GetOpaque(this_val, _classId);
const char* value = JS_ToCString(context, argv[0]); const char* value = JS_ToCString(context, argv[0]);
tf_tls_context_set_private_key(wrapper->context, value); tf_tls_context_set_private_key(wrapper->context, value);
@ -39,7 +41,8 @@ JSValue _tls_context_wrapper_set_private_key(JSContext* context, JSValueConst th
return JS_UNDEFINED; return JS_UNDEFINED;
} }
JSValue _tls_context_wrapper_add_trusted_certificate(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _tls_context_wrapper_add_trusted_certificate(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_tls_context_wrapper_t* wrapper = JS_GetOpaque(this_val, _classId); tf_tls_context_wrapper_t* wrapper = JS_GetOpaque(this_val, _classId);
const char* value = JS_ToCString(context, argv[0]); const char* value = JS_ToCString(context, argv[0]);
tf_tls_context_add_trusted_certificate(wrapper->context, value); tf_tls_context_add_trusted_certificate(wrapper->context, value);
@ -47,28 +50,34 @@ JSValue _tls_context_wrapper_add_trusted_certificate(JSContext* context, JSValue
return JS_UNDEFINED; return JS_UNDEFINED;
} }
JSValue tf_tls_context_wrapper_init(JSContext* context) { JSValue tf_tls_context_wrapper_init(JSContext* context)
{
JS_NewClassID(&_classId); JS_NewClassID(&_classId);
JSClassDef def = { JSClassDef def =
{
.class_name = "TlsContext", .class_name = "TlsContext",
.finalizer = _tls_context_wrapper_finalizer, .finalizer = _tls_context_wrapper_finalizer,
}; };
if (JS_NewClass(JS_GetRuntime(context), _classId, &def) != 0) { if (JS_NewClass(JS_GetRuntime(context), _classId, &def) != 0)
{
fprintf(stderr, "Failed to register TlsContext.\n"); fprintf(stderr, "Failed to register TlsContext.\n");
} }
return JS_NewCFunction2(context, _tls_context_wrapper_create, "TlsContext", 0, JS_CFUNC_constructor, 0); return JS_NewCFunction2(context, _tls_context_wrapper_create, "TlsContext", 0, JS_CFUNC_constructor, 0);
} }
tf_tls_context_t* tf_tls_context_wrapper_get(JSValue value) { tf_tls_context_t* tf_tls_context_wrapper_get(JSValue value)
{
tf_tls_context_wrapper_t* wrapper = JS_GetOpaque(value, _classId); tf_tls_context_wrapper_t* wrapper = JS_GetOpaque(value, _classId);
return wrapper ? wrapper->context : NULL; return wrapper ? wrapper->context : NULL;
} }
int tf_tls_context_wrapper_get_count() { int tf_tls_context_wrapper_get_count()
{
return _count; return _count;
} }
JSValue _tls_context_wrapper_create(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { JSValue _tls_context_wrapper_create(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
{
tf_tls_context_wrapper_t* wrapper = malloc(sizeof(tf_tls_context_wrapper_t)); tf_tls_context_wrapper_t* wrapper = malloc(sizeof(tf_tls_context_wrapper_t));
memset(wrapper, 0, sizeof(*wrapper)); memset(wrapper, 0, sizeof(*wrapper));
@ -86,9 +95,11 @@ JSValue _tls_context_wrapper_create(JSContext* context, JSValueConst this_val, i
return wrapper->object; return wrapper->object;
} }
void _tls_context_wrapper_finalizer(JSRuntime *runtime, JSValue value) { void _tls_context_wrapper_finalizer(JSRuntime *runtime, JSValue value)
{
tf_tls_context_wrapper_t* wrapper = JS_GetOpaque(value, _classId); tf_tls_context_wrapper_t* wrapper = JS_GetOpaque(value, _classId);
if (wrapper->context) { if (wrapper->context)
{
tf_tls_context_destroy(wrapper->context); tf_tls_context_destroy(wrapper->context);
wrapper->context = NULL; wrapper->context = NULL;
} }

View File

@ -34,7 +34,8 @@ static int64_t _trace_ts()
{ {
int64_t result = 0; int64_t result = 0;
struct timespec ts; struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
{
result = (ts.tv_sec * 1e9 + ts.tv_nsec) / 1e3; result = (ts.tv_sec * 1e9 + ts.tv_nsec) / 1e3;
} }
return result; return result;
@ -42,12 +43,14 @@ static int64_t _trace_ts()
static void _trace_append(tf_trace_t* trace, const char* buffer, size_t size) static void _trace_append(tf_trace_t* trace, const char* buffer, size_t size)
{ {
if (trace->write_offset + size >= k_buffer_size) { if (trace->write_offset + size >= k_buffer_size)
{
trace->buffer[trace->write_offset] = '\0'; trace->buffer[trace->write_offset] = '\0';
trace->write_offset = 0; trace->write_offset = 0;
} }
if (trace->write_offset + size < k_buffer_size) { if (trace->write_offset + size < k_buffer_size)
{
memcpy(trace->buffer + trace->write_offset, buffer, size); memcpy(trace->buffer + trace->write_offset, buffer, size);
trace->write_offset += size; trace->write_offset += size;
trace->buffer[trace->write_offset++] = '\n'; trace->buffer[trace->write_offset++] = '\n';
@ -56,7 +59,8 @@ static void _trace_append(tf_trace_t* trace, const char* buffer, size_t size)
void tf_trace_counter(tf_trace_t* trace, const char* name, int argc, const char** arg_names, const int64_t* arg_values) void tf_trace_counter(tf_trace_t* trace, const char* name, int argc, const char** arg_names, const int64_t* arg_values)
{ {
if (!trace) { if (!trace)
{
return; return;
} }
@ -73,18 +77,22 @@ void tf_trace_counter(tf_trace_t* trace, const char* name, int argc, const char*
void tf_trace_begin(tf_trace_t* trace, const char* name) void tf_trace_begin(tf_trace_t* trace, const char* name)
{ {
if (!trace) { if (!trace)
{
return; return;
} }
char line[1024]; char line[1024];
int p = snprintf(line, sizeof(line), "{\"ph\": \"B\", \"pid\": %d, \"ts\": %" PRId64 ", \"name\": \"", getpid(), _trace_ts()); int p = snprintf(line, sizeof(line), "{\"ph\": \"B\", \"pid\": %d, \"ts\": %" PRId64 ", \"name\": \"", getpid(), _trace_ts());
for (const char* c = name; *c && p < (int)sizeof(line); c++) { for (const char* c = name; *c && p < (int)sizeof(line); c++)
switch (*c) { {
switch (*c)
{
case '"': case '"':
case '\\': case '\\':
line[p++] = '\\'; line[p++] = '\\';
if (p < (int)sizeof(line)) { if (p < (int)sizeof(line))
{
line[p++] = *c; line[p++] = *c;
} }
break; break;
@ -99,7 +107,8 @@ void tf_trace_begin(tf_trace_t* trace, const char* name)
void tf_trace_end(tf_trace_t* trace) void tf_trace_end(tf_trace_t* trace)
{ {
if (!trace) { if (!trace)
{
return; return;
} }
@ -110,7 +119,8 @@ void tf_trace_end(tf_trace_t* trace)
char* tf_trace_export(tf_trace_t* trace) char* tf_trace_export(tf_trace_t* trace)
{ {
if (!trace) { if (!trace)
{
return NULL; return NULL;
} }
@ -120,14 +130,16 @@ char* tf_trace_export(tf_trace_t* trace)
int begin = newline ? newline - trace->buffer : 0; int begin = newline ? newline - trace->buffer : 0;
size_t size = 0; size_t size = 0;
size += snprintf(buffer, k_buffer_size, "{\"displayTimeUnit\": \"ns\",\n\"traceEvents\": [\n"); size += snprintf(buffer, k_buffer_size, "{\"displayTimeUnit\": \"ns\",\n\"traceEvents\": [\n");
if (begin) { if (begin)
{
size_t this_size = strlen(trace->buffer + begin); size_t this_size = strlen(trace->buffer + begin);
memcpy(buffer + size, trace->buffer + begin, this_size); memcpy(buffer + size, trace->buffer + begin, this_size);
size += this_size; size += this_size;
} }
memcpy(buffer + size, trace->buffer, trace->write_offset); memcpy(buffer + size, trace->buffer, trace->write_offset);
size += trace->write_offset; size += trace->write_offset;
if (size > 2 && buffer[size - 1] == '\n' && buffer[size - 2] == ',') { if (size > 2 && buffer[size - 1] == '\n' && buffer[size - 2] == ',')
{
buffer[size - 2] = '\n'; buffer[size - 2] = '\n';
size--; size--;
} }
@ -140,11 +152,13 @@ char* tf_trace_export(tf_trace_t* trace)
static int _tf_trace_sqlite_callback(unsigned int t, void* c, void* p, void* x) static int _tf_trace_sqlite_callback(unsigned int t, void* c, void* p, void* x)
{ {
tf_trace_t* trace = c; tf_trace_t* trace = c;
switch (t) { switch (t)
{
case SQLITE_TRACE_STMT: case SQLITE_TRACE_STMT:
{ {
const char* statement = x; const char* statement = x;
if (statement[0] != '-' || statement[1] != '-') { if (statement[0] != '-' || statement[1] != '-')
{
tf_trace_begin(trace, statement); tf_trace_begin(trace, statement);
} }
} }
@ -158,9 +172,12 @@ static int _tf_trace_sqlite_callback(unsigned int t, void* c, void* p, void* x)
void tf_trace_sqlite(tf_trace_t* trace, sqlite3* sqlite) void tf_trace_sqlite(tf_trace_t* trace, sqlite3* sqlite)
{ {
if (sqlite) { if (sqlite)
{
sqlite3_trace_v2(sqlite, SQLITE_TRACE_STMT | SQLITE_TRACE_PROFILE, _tf_trace_sqlite_callback, trace); sqlite3_trace_v2(sqlite, SQLITE_TRACE_STMT | SQLITE_TRACE_PROFILE, _tf_trace_sqlite_callback, trace);
} else { }
else
{
sqlite3_trace_v2(sqlite, 0, NULL, NULL); sqlite3_trace_v2(sqlite, 0, NULL, NULL);
} }
} }