ssb: Add a get_contacts command to enumerate follows, blocks, and friends.
Some checks failed
Build Tilde Friends / Build-All (push) Has been cancelled

This commit is contained in:
2025-01-11 15:49:49 -05:00
parent 287c6c06e1
commit f28e409ea5
4 changed files with 153 additions and 19 deletions

View File

@ -1304,9 +1304,9 @@ static bool _is_blocked_by_active_blocks(const char* id, const block_node_t* blo
return false;
}
static following_t* _make_following_node(const char* id, following_t*** following, int* following_count, block_node_t* blocks)
static following_t* _make_following_node(const char* id, following_t*** following, int* following_count, block_node_t* blocks, bool include_blocks)
{
if (_is_blocked_by_active_blocks(id, blocks))
if (!include_blocks && _is_blocked_by_active_blocks(id, blocks))
{
return NULL;
}
@ -1333,7 +1333,7 @@ static following_t* _make_following_node(const char* id, following_t*** followin
return entry;
}
static void _populate_follows_and_blocks(tf_ssb_t* ssb, following_t* entry, following_t*** following, int* following_count, block_node_t* active_blocks)
static void _populate_follows_and_blocks(tf_ssb_t* ssb, following_t* entry, following_t*** following, int* following_count, block_node_t* active_blocks, bool include_blocks)
{
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
sqlite3_stmt* statement = NULL;
@ -1352,7 +1352,7 @@ static void _populate_follows_and_blocks(tf_ssb_t* ssb, following_t* entry, foll
if (sqlite3_column_type(statement, 1) != SQLITE_NULL)
{
bool is_following = sqlite3_column_int(statement, 1) != 0;
following_t* next = _make_following_node(contact, following, following_count, active_blocks);
following_t* next = _make_following_node(contact, following, following_count, active_blocks, include_blocks);
if (next)
{
if (is_following)
@ -1374,7 +1374,7 @@ static void _populate_follows_and_blocks(tf_ssb_t* ssb, following_t* entry, foll
if (sqlite3_column_type(statement, 2) != SQLITE_NULL)
{
bool is_blocking = sqlite3_column_int(statement, 2) != 0;
following_t* next = _make_following_node(contact, following, following_count, active_blocks);
following_t* next = _make_following_node(contact, following, following_count, active_blocks, include_blocks);
if (next)
{
if (is_blocking)
@ -1400,13 +1400,14 @@ static void _populate_follows_and_blocks(tf_ssb_t* ssb, following_t* entry, foll
tf_ssb_release_db_reader(ssb, db);
}
static void _get_following(tf_ssb_t* ssb, following_t* entry, following_t*** following, int* following_count, int depth, int max_depth, block_node_t* active_blocks)
static void _get_following(
tf_ssb_t* ssb, following_t* entry, following_t*** following, int* following_count, int depth, int max_depth, block_node_t* active_blocks, bool include_blocks)
{
entry->depth = tf_min(depth, entry->depth);
if (depth < max_depth && !entry->populated && !_is_blocked_by_active_blocks(entry->id, active_blocks))
{
entry->populated = true;
_populate_follows_and_blocks(ssb, entry, following, following_count, active_blocks);
_populate_follows_and_blocks(ssb, entry, following, following_count, active_blocks, include_blocks);
if (depth < max_depth)
{
@ -1415,28 +1416,28 @@ static void _get_following(tf_ssb_t* ssb, following_t* entry, following_t*** fol
{
if (!_has_following_entry(entry->following[i]->id, entry->blocking, entry->blocking_count))
{
_get_following(ssb, entry->following[i], following, following_count, depth + 1, max_depth, &blocks);
_get_following(ssb, entry->following[i], following, following_count, depth + 1, max_depth, &blocks, include_blocks);
}
}
}
}
}
tf_ssb_following_t* tf_ssb_db_following_deep(tf_ssb_t* ssb, const char** ids, int count, int depth)
tf_ssb_following_t* tf_ssb_db_following_deep(tf_ssb_t* ssb, const char** ids, int count, int depth, bool include_blocks)
{
following_t** following = NULL;
int following_count = 0;
for (int i = 0; i < count; i++)
{
following_t* entry = _make_following_node(ids[i], &following, &following_count, NULL);
_get_following(ssb, entry, &following, &following_count, 0, depth, NULL);
following_t* entry = _make_following_node(ids[i], &following, &following_count, NULL, include_blocks);
_get_following(ssb, entry, &following, &following_count, 0, depth, NULL, include_blocks);
entry->ref_count++;
}
int actual_following_count = 0;
for (int i = 0; i < following_count; i++)
{
if (following[i]->ref_count > 0)
if (following[i]->ref_count > 0 || include_blocks)
{
actual_following_count++;
}
@ -1448,7 +1449,7 @@ tf_ssb_following_t* tf_ssb_db_following_deep(tf_ssb_t* ssb, const char** ids, in
int write_index = 0;
for (int i = 0; i < following_count; i++)
{
if (following[i]->ref_count > 0)
if (following[i]->ref_count > 0 || include_blocks)
{
snprintf(result[write_index].id, sizeof(result[write_index].id), "%s", following[i]->id);
result[write_index].following_count = following[i]->following_count;
@ -1477,8 +1478,8 @@ const char** tf_ssb_db_following_deep_ids(tf_ssb_t* ssb, const char** ids, int c
int following_count = 0;
for (int i = 0; i < count; i++)
{
following_t* entry = _make_following_node(ids[i], &following, &following_count, NULL);
_get_following(ssb, entry, &following, &following_count, 0, depth, NULL);
following_t* entry = _make_following_node(ids[i], &following, &following_count, NULL, false);
_get_following(ssb, entry, &following, &following_count, 0, depth, NULL, false);
entry->ref_count++;
}
@ -2109,3 +2110,30 @@ const char* tf_ssb_db_get_profile(sqlite3* db, const char* id)
}
return result;
}
const char* tf_ssb_db_get_profile_name(sqlite3* db, const char* id)
{
const char* result = NULL;
sqlite3_stmt* statement;
if (sqlite3_prepare(db,
"SELECT name FROM (SELECT messages.author, RANK() OVER (PARTITION BY messages.author ORDER BY messages.sequence DESC) AS author_rank, "
"messages.content ->> 'name' AS name FROM messages WHERE messages.author = ? "
"AND json_extract(messages.content, '$.type') = 'about' AND content ->> 'about' = messages.author AND name IS NOT NULL) "
"WHERE author_rank = 1",
-1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
result = tf_strdup((const char*)sqlite3_column_text(statement, 0));
}
}
sqlite3_finalize(statement);
}
else
{
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
}
return result;
}