forked from cory/tildefriends
		
	Reworked some following math.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4601 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
		@@ -1,5 +1,5 @@
 | 
			
		||||
{
 | 
			
		||||
  "type": "tildefriends-app",
 | 
			
		||||
  "emoji": "🐌",
 | 
			
		||||
  "previous": "&fDu52QJE1dYO2lB/HBpQqoGnGR1b0j38JkGrqt2wHQA=.sha256"
 | 
			
		||||
  "previous": "&JKRKYoQgzxByd80DTQQVWoDfoEd27h2jhaUrNXAGK7k=.sha256"
 | 
			
		||||
}
 | 
			
		||||
@@ -212,9 +212,18 @@ class TfElement extends LitElement {
 | 
			
		||||
		let whoami = this.whoami;
 | 
			
		||||
		let tags = this.load_recent_tags();
 | 
			
		||||
		let following = await tfrpc.rpc.following([whoami], 2);
 | 
			
		||||
		console.log(following);
 | 
			
		||||
		let users = {};
 | 
			
		||||
		users = await this.fetch_about(following.sort(), users);
 | 
			
		||||
		this.following = following;
 | 
			
		||||
		for (let [id, v] of Object.entries(following)) {
 | 
			
		||||
			users[id] = {
 | 
			
		||||
				following: v.of,
 | 
			
		||||
				blocking: v.ob,
 | 
			
		||||
				followed: v.if,
 | 
			
		||||
				blocked: v.ib,
 | 
			
		||||
			};
 | 
			
		||||
		}
 | 
			
		||||
		users = await this.fetch_about(Object.keys(following).sort(), users);
 | 
			
		||||
		this.following = Object.keys(following);
 | 
			
		||||
		this.users = users;
 | 
			
		||||
		await tags;
 | 
			
		||||
		console.log(`load finished ${whoami} => ${this.whoami}`);
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,8 @@ class TfProfileElement extends LitElement {
 | 
			
		||||
			users: {type: Object},
 | 
			
		||||
			size: {type: Number},
 | 
			
		||||
			server_follows_me: {type: Boolean},
 | 
			
		||||
			following: {type: Boolean},
 | 
			
		||||
			blocking: {type: Boolean},
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -28,11 +30,31 @@ class TfProfileElement extends LitElement {
 | 
			
		||||
		this.server_follows_me = undefined;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	async load() {
 | 
			
		||||
		if (this.whoami !== this._follow_whoami) {
 | 
			
		||||
			this._follow_whoami = this.whoami;
 | 
			
		||||
			this.following = undefined;
 | 
			
		||||
			this.blocking = undefined;
 | 
			
		||||
 | 
			
		||||
			let result = await tfrpc.rpc.query(`
 | 
			
		||||
				SELECT json_extract(content, '$.following') AS following
 | 
			
		||||
				FROM messages WHERE author = ? AND
 | 
			
		||||
				json_extract(content, '$.type') = 'contact' AND
 | 
			
		||||
				json_extract(content, '$.contact') = ?
 | 
			
		||||
				ORDER BY sequence DESC LIMIT 1
 | 
			
		||||
			`, [this.whoami, this.id]);
 | 
			
		||||
			console.log(result);
 | 
			
		||||
			this.following = result?.[0]?.following ?? false;
 | 
			
		||||
			console.log('FOLLOWING', this.whoami, this.id, this.following);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	async initial_load() {
 | 
			
		||||
		this.server_follows_me = undefined;
 | 
			
		||||
		let server_id = await tfrpc.rpc.getServerIdentity();
 | 
			
		||||
		let followed = await tfrpc.rpc.query(`
 | 
			
		||||
			SELECT json_extract(content, '$.following') AS following FROM messages
 | 
			
		||||
			SELECT json_extract(content, '$.following') AS following
 | 
			
		||||
			FROM messages
 | 
			
		||||
			WHERE author = ? AND
 | 
			
		||||
			json_extract(content, '$.type') = 'contact' AND
 | 
			
		||||
			json_extract(content, '$.contact') = ? ORDER BY sequence DESC LIMIT 1
 | 
			
		||||
@@ -138,6 +160,7 @@ class TfProfileElement extends LitElement {
 | 
			
		||||
		if (this.id == this.whoami && this.editing && this.server_follows_me === undefined) {
 | 
			
		||||
			this.initial_load();
 | 
			
		||||
		}
 | 
			
		||||
		this.load();
 | 
			
		||||
		let self = this;
 | 
			
		||||
		let profile = this.users[this.id] || {};
 | 
			
		||||
		tfrpc.rpc.query(
 | 
			
		||||
@@ -166,16 +189,16 @@ class TfProfileElement extends LitElement {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (this.id !== this.whoami &&
 | 
			
		||||
			this.users[this.whoami]?.following) {
 | 
			
		||||
			this.following !== undefined) {
 | 
			
		||||
			follow =
 | 
			
		||||
				this.users[this.whoami].following[this.id] ?
 | 
			
		||||
				this.following ?
 | 
			
		||||
				html`<input type="button" value="Unfollow" @click=${this.unfollow}></input>` :
 | 
			
		||||
				html`<input type="button" value="Follow" @click=${this.follow}></input>`;
 | 
			
		||||
		}
 | 
			
		||||
		if (this.id !== this.whoami &&
 | 
			
		||||
			this.users[this.whoami]?.blocking) {
 | 
			
		||||
			this.blocking !== undefined) {
 | 
			
		||||
			block =
 | 
			
		||||
				this.users[this.whoami].blocking[this.id] ?
 | 
			
		||||
				this.blocking ?
 | 
			
		||||
				html`<input type="button" value="Unblock" @click=${this.unblock}></input>` :
 | 
			
		||||
				html`<input type="button" value="Block" @click=${this.block}></input>`;
 | 
			
		||||
		}
 | 
			
		||||
@@ -208,10 +231,10 @@ class TfProfileElement extends LitElement {
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div>
 | 
			
		||||
				Following ${Object.keys(profile.following || {}).length} identities.
 | 
			
		||||
				Followed by ${Object.values(self.users).filter(x => (x.following || {})[self.id]).length} identities.
 | 
			
		||||
				Blocking ${Object.keys(profile.blocking || {}).length} identities.
 | 
			
		||||
				Blocked by ${Object.values(self.users).filter(x => (x.blocking || {})[self.id]).length} identities.
 | 
			
		||||
				Following ${profile.following} identities.
 | 
			
		||||
				Followed by ${profile.followed} identities.
 | 
			
		||||
				Blocking ${profile.blocking} identities.
 | 
			
		||||
				Blocked by ${profile.blocked} identities.
 | 
			
		||||
			</div>
 | 
			
		||||
			<div>
 | 
			
		||||
				${edit}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										84
									
								
								src/ssb.db.c
									
									
									
									
									
								
							
							
						
						
									
										84
									
								
								src/ssb.db.c
									
									
									
									
									
								
							@@ -1300,6 +1300,7 @@ typedef struct _following_t
 | 
			
		||||
	int blocking_count;
 | 
			
		||||
	int depth;
 | 
			
		||||
	int ref_count;
 | 
			
		||||
	int block_ref_count;
 | 
			
		||||
} following_t;
 | 
			
		||||
 | 
			
		||||
static int _following_compare(const void* a, const void* b)
 | 
			
		||||
@@ -1309,7 +1310,7 @@ static int _following_compare(const void* a, const void* b)
 | 
			
		||||
	return strcmp(ida, (*followingb)->id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _add_following_entry(following_t*** list, int* count, following_t* add)
 | 
			
		||||
static bool _add_following_entry(following_t*** list, int* count, following_t* add)
 | 
			
		||||
{
 | 
			
		||||
	int index = tf_util_insert_index(add->id, *list, *count, sizeof(following_t*), _following_compare);
 | 
			
		||||
	if (index >= *count || strcmp(add->id, (*list)[index]->id) != 0)
 | 
			
		||||
@@ -1321,10 +1322,12 @@ static void _add_following_entry(following_t*** list, int* count, following_t* a
 | 
			
		||||
		}
 | 
			
		||||
		(*list)[index] = add;
 | 
			
		||||
		(*count)++;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _remove_following_entry(following_t*** list, int* count, following_t* remove)
 | 
			
		||||
static bool _remove_following_entry(following_t*** list, int* count, following_t* remove)
 | 
			
		||||
{
 | 
			
		||||
	int index = tf_util_insert_index(remove->id, *list, *count, sizeof(following_t*), _following_compare);
 | 
			
		||||
	if (index < *count && strcmp(remove->id, (*list)[index]->id) == 0)
 | 
			
		||||
@@ -1335,7 +1338,9 @@ static void _remove_following_entry(following_t*** list, int* count, following_t
 | 
			
		||||
		}
 | 
			
		||||
		*list = tf_resize_vec(*list, sizeof(**list) * (*count - 1));
 | 
			
		||||
		(*count)--;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static following_t* _get_following(tf_ssb_t* ssb, const char* id, following_t*** following, int* following_count, int depth, int max_depth)
 | 
			
		||||
@@ -1384,26 +1389,36 @@ static following_t* _get_following(tf_ssb_t* ssb, const char* id, following_t***
 | 
			
		||||
						following_t* next = _get_following(ssb, contact, following, following_count, depth + 1, max_depth);
 | 
			
		||||
						if (is_following)
 | 
			
		||||
						{
 | 
			
		||||
							_add_following_entry(&entry->following, &entry->following_count, next);
 | 
			
		||||
							next->ref_count++;
 | 
			
		||||
							if (_add_following_entry(&entry->following, &entry->following_count, next))
 | 
			
		||||
							{
 | 
			
		||||
								next->ref_count++;
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
						else
 | 
			
		||||
						{
 | 
			
		||||
							_remove_following_entry(&entry->following, &entry->following_count, next);
 | 
			
		||||
							next->ref_count--;
 | 
			
		||||
							if (_remove_following_entry(&entry->following, &entry->following_count, next))
 | 
			
		||||
							{
 | 
			
		||||
								next->ref_count--;
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					if (sqlite3_column_type(statement, 2) != SQLITE_NULL)
 | 
			
		||||
					{
 | 
			
		||||
						bool is_blocking = sqlite3_column_int(statement, 2 != 0);
 | 
			
		||||
						bool is_blocking = sqlite3_column_int(statement, 2) != 0;
 | 
			
		||||
						following_t* next = _get_following(ssb, contact, following, following_count, depth + 1, 0 /* don't dig deeper into blocked users */);
 | 
			
		||||
						if (is_blocking)
 | 
			
		||||
						{
 | 
			
		||||
							_add_following_entry(&entry->blocking, &entry->blocking_count, next);
 | 
			
		||||
							if (_add_following_entry(&entry->blocking, &entry->blocking_count, next))
 | 
			
		||||
							{
 | 
			
		||||
								next->block_ref_count++;
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
						else
 | 
			
		||||
						{
 | 
			
		||||
							_remove_following_entry(&entry->blocking, &entry->blocking_count, next);
 | 
			
		||||
							if (_remove_following_entry(&entry->blocking, &entry->blocking_count, next))
 | 
			
		||||
							{
 | 
			
		||||
								next->block_ref_count--;
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
@@ -1415,7 +1430,54 @@ static following_t* _get_following(tf_ssb_t* ssb, const char* id, following_t***
 | 
			
		||||
	return entry;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char** 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)
 | 
			
		||||
{
 | 
			
		||||
	following_t** following = NULL;
 | 
			
		||||
	int following_count = 0;
 | 
			
		||||
	for (int i = 0; i < count; i++)
 | 
			
		||||
	{
 | 
			
		||||
		following_t* entry = _get_following(ssb, ids[i], &following, &following_count, 0, depth);
 | 
			
		||||
		entry->ref_count++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int actual_following_count = 0;
 | 
			
		||||
	for (int i = 0; i < following_count; i++)
 | 
			
		||||
	{
 | 
			
		||||
		if (following[i]->ref_count > 0)
 | 
			
		||||
		{
 | 
			
		||||
			actual_following_count++;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tf_ssb_following_t* result = tf_malloc(sizeof(tf_ssb_following_t) * (actual_following_count + 1));
 | 
			
		||||
	memset(result, 0, sizeof(tf_ssb_following_t) * (actual_following_count + 1));
 | 
			
		||||
 | 
			
		||||
	int write_index = 0;
 | 
			
		||||
	for (int i = 0; i < following_count; i++)
 | 
			
		||||
	{
 | 
			
		||||
		if (following[i]->ref_count > 0)
 | 
			
		||||
		{
 | 
			
		||||
			snprintf(result[write_index].id, sizeof(result[write_index].id), "%s", following[i]->id);
 | 
			
		||||
			result[write_index].following_count = following[i]->following_count;
 | 
			
		||||
			result[write_index].blocking_count = following[i]->blocking_count;
 | 
			
		||||
			result[write_index].followed_by_count = following[i]->ref_count;
 | 
			
		||||
			result[write_index].blocked_by_count = following[i]->block_ref_count;
 | 
			
		||||
			write_index++;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < following_count; i++)
 | 
			
		||||
	{
 | 
			
		||||
		tf_free(following[i]->following);
 | 
			
		||||
		tf_free(following[i]->blocking);
 | 
			
		||||
		tf_free(following[i]);
 | 
			
		||||
	}
 | 
			
		||||
	tf_free(following);
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char** tf_ssb_db_following_deep_ids(tf_ssb_t* ssb, const char** ids, int count, int depth)
 | 
			
		||||
{
 | 
			
		||||
	following_t** following = NULL;
 | 
			
		||||
	int following_count = 0;
 | 
			
		||||
@@ -1479,7 +1541,7 @@ const char** tf_ssb_db_get_all_visible_identities(tf_ssb_t* ssb, int depth)
 | 
			
		||||
{
 | 
			
		||||
	identities_t identities = { 0 };
 | 
			
		||||
	tf_ssb_db_identity_visit_all(ssb, _add_identity, &identities);
 | 
			
		||||
	const char** following = tf_ssb_db_following_deep(ssb, identities.ids, identities.count, depth);
 | 
			
		||||
	const char** following = tf_ssb_db_following_deep_ids(ssb, identities.ids, identities.count, depth);
 | 
			
		||||
	for (int i = 0; i < identities.count; i++)
 | 
			
		||||
	{
 | 
			
		||||
		tf_free((void*)identities.ids[i]);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								src/ssb.db.h
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/ssb.db.h
									
									
									
									
									
								
							@@ -46,7 +46,18 @@ JSValue tf_ssb_format_message(
 | 
			
		||||
	const char* content,
 | 
			
		||||
	const char* signature,
 | 
			
		||||
	bool sequence_before_author);
 | 
			
		||||
const char** tf_ssb_db_following_deep(tf_ssb_t* ssb, const char** ids, int count, int depth);
 | 
			
		||||
 | 
			
		||||
typedef struct _tf_ssb_following_t
 | 
			
		||||
{
 | 
			
		||||
	char id[k_id_base64_len];
 | 
			
		||||
	int following_count;
 | 
			
		||||
	int blocking_count;
 | 
			
		||||
	int followed_by_count;
 | 
			
		||||
	int blocked_by_count;
 | 
			
		||||
} tf_ssb_following_t;
 | 
			
		||||
 | 
			
		||||
const char** tf_ssb_db_following_deep_ids(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);
 | 
			
		||||
const char** tf_ssb_db_get_all_visible_identities(tf_ssb_t* ssb, int depth);
 | 
			
		||||
 | 
			
		||||
typedef struct _tf_ssb_db_stored_connection_t
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								src/ssb.js.c
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								src/ssb.js.c
									
									
									
									
									
								
							@@ -105,7 +105,7 @@ static JSValue _tf_ssb_set_server_following_me(JSContext* context, JSValueConst
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			const char* server_id_ptr = server_id;
 | 
			
		||||
			const char** current_following = tf_ssb_db_following_deep(ssb, &server_id_ptr, 1, 1);
 | 
			
		||||
			const char** current_following = tf_ssb_db_following_deep_ids(ssb, &server_id_ptr, 1, 1);
 | 
			
		||||
			bool is_following = false;
 | 
			
		||||
			for (const char** it = current_following; *it; it++)
 | 
			
		||||
			{
 | 
			
		||||
@@ -1519,7 +1519,7 @@ typedef struct _following_t
 | 
			
		||||
	JSContext* context;
 | 
			
		||||
	JSValue promise[2];
 | 
			
		||||
 | 
			
		||||
	const char** out_ids;
 | 
			
		||||
	tf_ssb_following_t* out_following;
 | 
			
		||||
 | 
			
		||||
	int depth;
 | 
			
		||||
	int ids_count;
 | 
			
		||||
@@ -1529,7 +1529,7 @@ typedef struct _following_t
 | 
			
		||||
static void _tf_ssb_following_work(uv_work_t* work)
 | 
			
		||||
{
 | 
			
		||||
	following_t* following = work->data;
 | 
			
		||||
	following->out_ids = tf_ssb_db_following_deep(following->ssb, following->ids, following->ids_count, following->depth);
 | 
			
		||||
	following->out_following = tf_ssb_db_following_deep(following->ssb, following->ids, following->ids_count, following->depth);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _tf_ssb_following_after_work(uv_work_t* work, int status)
 | 
			
		||||
@@ -1538,13 +1538,18 @@ static void _tf_ssb_following_after_work(uv_work_t* work, int status)
 | 
			
		||||
	JSContext* context = following->context;
 | 
			
		||||
	if (status == 0)
 | 
			
		||||
	{
 | 
			
		||||
		JSValue array = JS_NewArray(context);
 | 
			
		||||
		for (int i = 0; following->out_ids[i]; i++)
 | 
			
		||||
		JSValue object = JS_NewObject(context);
 | 
			
		||||
		for (int i = 0; *following->out_following[i].id; i++)
 | 
			
		||||
		{
 | 
			
		||||
			JS_SetPropertyUint32(context, array, i, JS_NewString(context, following->out_ids[i]));
 | 
			
		||||
			JSValue entry = JS_NewObject(context);
 | 
			
		||||
			JS_SetPropertyStr(context, entry, "of", JS_NewInt32(context, following->out_following[i].following_count));
 | 
			
		||||
			JS_SetPropertyStr(context, entry, "ob", JS_NewInt32(context, following->out_following[i].blocking_count));
 | 
			
		||||
			JS_SetPropertyStr(context, entry, "if", JS_NewInt32(context, following->out_following[i].followed_by_count));
 | 
			
		||||
			JS_SetPropertyStr(context, entry, "ib", JS_NewInt32(context, following->out_following[i].blocked_by_count));
 | 
			
		||||
			JS_SetPropertyStr(context, object, following->out_following[i].id, entry);
 | 
			
		||||
		}
 | 
			
		||||
		JS_Call(context, following->promise[0], JS_UNDEFINED, 1, &array);
 | 
			
		||||
		JS_FreeValue(context, array);
 | 
			
		||||
		JS_Call(context, following->promise[0], JS_UNDEFINED, 1, &object);
 | 
			
		||||
		JS_FreeValue(context, object);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
@@ -1559,7 +1564,7 @@ static void _tf_ssb_following_after_work(uv_work_t* work, int status)
 | 
			
		||||
	{
 | 
			
		||||
		tf_free((void*)following->ids[i]);
 | 
			
		||||
	}
 | 
			
		||||
	tf_free(following->out_ids);
 | 
			
		||||
	tf_free(following->out_following);
 | 
			
		||||
	tf_free(following);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user