I guess we support sub-millisecond timestamps. Who knew?

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3835 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2022-02-12 01:44:11 +00:00
parent 50bef73200
commit 483638a7e6
3 changed files with 76 additions and 36 deletions

View File

@ -9,49 +9,56 @@
#include <stdlib.h>
#include <string.h>
static void _tf_ssb_db_exec(sqlite3* db, const char* statement)
{
char* error = NULL;
int result = sqlite3_exec(db, statement, NULL, NULL, &error);
if (result != SQLITE_OK)
{
printf("Error running '%s': %s.\n", statement, error);
abort();
}
}
void tf_ssb_db_init(tf_ssb_t* ssb)
{
sqlite3* db = tf_ssb_get_db(ssb);
sqlite3_exec(db, "PRAGMA journal_mode = WAL", NULL, NULL, NULL);
sqlite3_exec(db, "PRAGMA synchronous = NORMAL", NULL, NULL, NULL);
sqlite3_exec(db,
_tf_ssb_db_exec(db, "PRAGMA journal_mode = WAL");
_tf_ssb_db_exec(db, "PRAGMA synchronous = NORMAL");
_tf_ssb_db_exec(db,
"CREATE TABLE IF NOT EXISTS messages ("
" author TEXT,"
" id TEXT PRIMARY KEY,"
" sequence INTEGER,"
" timestamp INTEGER,"
" timestamp REAL,"
" previous TEXT,"
" hash TEXT,"
" content TEXT,"
" signature TEXT,"
" sequence_before_author INTEGER,"
" UNIQUE(author, sequence)"
")",
NULL, NULL, NULL);
sqlite3_exec(db, "ALTER TABLE messages ADD COLUMN sequence_before_author INTEGER", NULL, NULL, NULL);
sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_id_index ON messages (author, id)", NULL, NULL, NULL);
sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_sequence_index ON messages (author, sequence)", NULL, NULL, NULL);
sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_timestamp_index ON messages (author, timestamp)", NULL, NULL, NULL);
sqlite3_exec(db,
")");
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_id_index ON messages (author, id)");
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_sequence_index ON messages (author, sequence)");
_tf_ssb_db_exec(db, "CREATE INDEX IF NOT EXISTS messages_author_timestamp_index ON messages (author, timestamp)");
_tf_ssb_db_exec(db,
"CREATE TABLE IF NOT EXISTS blobs ("
" id TEXT PRIMARY KEY,"
" content BLOB,"
" created INTEGER"
")",
NULL, NULL, NULL);
sqlite3_exec(db,
")");
_tf_ssb_db_exec(db,
"CREATE TABLE IF NOT EXISTS blob_wants ("
" id TEXT PRIMARY KEY"
")",
NULL, NULL, NULL);
sqlite3_exec(db,
")");
_tf_ssb_db_exec(db,
"CREATE TABLE IF NOT EXISTS properties ("
" id TEXT,"
" key TEXT,"
" value TEXT,"
" UNIQUE(id, key)"
")",
NULL, NULL, NULL);
sqlite3_exec(db,
")");
_tf_ssb_db_exec(db,
"CREATE TABLE IF NOT EXISTS connections ("
" host TEXT,"
" port INTEGER,"
@ -59,8 +66,41 @@ void tf_ssb_db_init(tf_ssb_t* ssb)
" last_attempt INTEGER,"
" last_success INTEGER,"
" UNIQUE(host, port, key)"
")",
NULL, NULL, NULL);
")");
bool need_add_sequence_before_author = true;
bool need_convert_timestamp_to_real = false;
sqlite3_stmt* statement = NULL;
if (sqlite3_prepare(db, "PRAGMA table_info(messages)", -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
const char* name = (const char*)sqlite3_column_text(statement, 1);
const char* type = (const char*)sqlite3_column_text(statement, 1);
if (name && type && strcmp(name, "timestamp") == 0 && strcmp(type, "INTEGER") == 0)
{
need_convert_timestamp_to_real = true;
}
if (name && strcmp(name, "sequence_before_author") == 0)
{
need_add_sequence_before_author = false;
}
}
sqlite3_finalize(statement);
}
if (need_convert_timestamp_to_real)
{
_tf_ssb_db_exec(db, "ALTER TABLE messages ADD COLUMN timestamp_real REAL");
_tf_ssb_db_exec(db, "UPDATE messages SET timestamp_real = timestamp");
_tf_ssb_db_exec(db, "ALTER TABLE messages DROP COLUMN timestamp REAL");
_tf_ssb_db_exec(db, "ALTER TABLE messages RENAME COLUMN timestamp_real TO timestamp");
}
if (need_add_sequence_before_author)
{
_tf_ssb_db_exec(db, "ALTER TABLE messages ADD COLUMN sequence_before_author INTEGER");
}
}
static bool _tf_ssb_db_previous_message_exists(sqlite3* db, const char* author, int64_t sequence, const char* previous)
@ -97,8 +137,8 @@ bool tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id,
const char* author = JS_ToCString(context, authorval);
int64_t sequence = -1;
JS_ToInt64(context, &sequence, JS_GetPropertyStr(context, val, "sequence"));
int64_t timestamp = -1;
JS_ToInt64(context, &timestamp, JS_GetPropertyStr(context, val, "timestamp"));
double timestamp = -1.0;
JS_ToFloat64(context, &timestamp, JS_GetPropertyStr(context, val, "timestamp"));
JSValue contentval = JS_GetPropertyStr(context, val, "content");
JSValue content = JS_JSONStringify(context, contentval, JS_NULL, JS_NULL);
@ -119,7 +159,7 @@ bool tf_ssb_db_store_message(tf_ssb_t* ssb, JSContext* context, const char* id,
(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_int64(statement, 4, sequence) == SQLITE_OK &&
sqlite3_bind_int64(statement, 5, timestamp) == SQLITE_OK &&
sqlite3_bind_double(statement, 5, timestamp) == 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, 8, signature, -1, NULL) == SQLITE_OK &&
@ -304,7 +344,7 @@ bool tf_ssb_db_blob_store(tf_ssb_t* ssb, const uint8_t* blob, size_t size, char*
return result;
}
bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* author, int64_t sequence, char* out_message_id, size_t out_message_id_size, int64_t* out_timestamp, char** out_content)
bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* author, int64_t sequence, char* out_message_id, size_t out_message_id_size, double* out_timestamp, char** out_content)
{
bool found = false;
sqlite3_stmt* statement;
@ -321,7 +361,7 @@ bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* aut
}
if (out_timestamp)
{
*out_timestamp = sqlite3_column_int64(statement, 1);
*out_timestamp = sqlite3_column_double(statement, 1);
}
if (out_content)
{
@ -508,7 +548,7 @@ void tf_ssb_db_visit_query(tf_ssb_t* ssb, const char* query, const JSValue binds
sqlite3_set_authorizer(db, NULL, NULL);
}
static JSValue _tf_ssb_format_message(JSContext* context, const char* previous, const char* author, int64_t sequence, int64_t timestamp, const char* hash, const char* content, const char* signature, bool sequence_before_author)
static JSValue _tf_ssb_format_message(JSContext* context, const char* previous, const char* author, int64_t sequence, double timestamp, const char* hash, const char* content, const char* signature, bool sequence_before_author)
{
JSValue value = JS_NewObject(context);
JS_SetPropertyStr(context, value, "previous", previous ? JS_NewString(context, previous) : JS_NULL);
@ -522,7 +562,7 @@ static JSValue _tf_ssb_format_message(JSContext* context, const char* previous,
JS_SetPropertyStr(context, value, "author", JS_NewString(context, author));
JS_SetPropertyStr(context, value, "sequence", JS_NewInt64(context, sequence));
}
JS_SetPropertyStr(context, value, "timestamp", JS_NewInt64(context, timestamp));
JS_SetPropertyStr(context, value, "timestamp", JS_NewFloat64(context, timestamp));
JS_SetPropertyStr(context, value, "hash", JS_NewString(context, hash));
JS_SetPropertyStr(context, value, "content", JS_ParseJSON(context, content, strlen(content), NULL));
JS_SetPropertyStr(context, value, "signature", JS_NewString(context, signature));
@ -567,7 +607,7 @@ bool tf_ssb_db_check(sqlite3* db, const char* check_author)
const char* previous = (const char*)sqlite3_column_text(statement, 1);
const char* author = (const char*)sqlite3_column_text(statement, 2);
int64_t sequence = sqlite3_column_int64(statement, 3);
int64_t timestamp = sqlite3_column_int64(statement, 4);
double timestamp = sqlite3_column_double(statement, 4);
const char* hash = (const char*)sqlite3_column_text(statement, 5);
const char* content = (const char*)sqlite3_column_text(statement, 6);
const char* signature = (const char*)sqlite3_column_text(statement, 7);
@ -580,10 +620,10 @@ bool tf_ssb_db_check(sqlite3* db, const char* check_author)
const char* jv = JS_ToCString(context, j);
if (tf_ssb_verify_and_strip_signature(context, message, actual_id, sizeof(actual_id), out_signature, sizeof(out_signature), &actual_sequence_before_author))
{
/*if (previous && strcmp(previous, previous_id))
if (previous && strcmp(previous, previous_id))
{
printf("%s:%d previous was %s should be %s\n", id, (int)sequence, previous_id, previous);
}*/
}
if (strcmp(id, actual_id))
{
if (_tf_ssb_update_message_id(db, id, actual_id))
@ -598,7 +638,7 @@ bool tf_ssb_db_check(sqlite3* db, const char* check_author)
}
else
{
printf("unable to verify signature for %s\n", id);
printf("%s sequence=%" PRId64 " unable to verify signature for %s sequence_before_author=%d message=[%.*s]\n", author, sequence, id, sequence_before_author, (int)strlen(jv), jv);
}
JS_FreeCString(context, jv);
JS_FreeValue(context, j);

View File

@ -11,7 +11,7 @@ bool tf_ssb_db_message_content_get(tf_ssb_t* ssb, const char* id, uint8_t** out_
bool tf_ssb_db_blob_get(tf_ssb_t* ssb, const char* id, uint8_t** out_blob, size_t* out_size);
bool tf_ssb_db_blob_store(tf_ssb_t* ssb, const uint8_t* blob, size_t size, char* out_id, size_t out_id_size);
bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* author, int64_t sequence, char* out_message_id, size_t out_message_id_size, int64_t* out_timestamp, char** out_content);
bool tf_ssb_db_get_message_by_author_and_sequence(tf_ssb_t* ssb, const char* author, int64_t sequence, char* out_message_id, size_t out_message_id_size, double* out_timestamp, char** out_content);
bool tf_ssb_db_get_latest_message_by_author(tf_ssb_t* ssb, const char* author, int64_t* out_sequence, char* out_message_id, size_t out_message_id_size);
void tf_ssb_db_visit_query(tf_ssb_t* ssb, const char* query, const JSValue binds, void (*callback)(JSValue row, void* user_data), void* user_data);

View File

@ -41,12 +41,12 @@ static JSValue _tf_ssb_getMessage(JSContext* context, JSValueConst this_val, int
const char* id = JS_ToCString(context, argv[0]);
int64_t sequence = 0;
JS_ToInt64(context, &sequence, argv[1]);
int64_t timestamp = -1;
double timestamp = -1.0;
char* contents = NULL;
if (tf_ssb_db_get_message_by_author_and_sequence(ssb, id, sequence, NULL, 0, &timestamp, &contents))
{
result = JS_NewObject(context);
JS_SetPropertyStr(context, result, "timestamp", JS_NewInt64(context, timestamp));
JS_SetPropertyStr(context, result, "timestamp", JS_NewFloat64(context, timestamp));
JS_SetPropertyStr(context, result, "content", JS_NewString(context, contents));
free(contents);
}