Blocking and some random attempts to make things faster.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3843 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
		| @@ -1 +1 @@ | ||||
| {"type":"tildefriends-app","files":{"app.js":"&5rHyeAQKxrbvIm32W3rKrh+LVRxlqLkN2cStJf5tCSM=.sha256","index.md":"&5EeOHUkDadC+lJsDsKXbfrVDQdePyOHZ7KwaJtR5mrs=.sha256","todo.md":"&U6hrQ6cfJ6+Uvg+wA7ahpCQaM2XiYXKjZUOz2iZDSGM=.sha256","structure.md":"&T+CBfT9XP6ooKFvD1ZCI9hsutqsNIamfBxtAho0HtlU=.sha256","guide.md":"&SgnGL0+rjetY2o9A2+lVRbNvHIkqKwMnZr9gXWneIlc=.sha256","id_refactor.md":"&8yoYd14gX2Z3ppktVrPYf4qR78fuwAlvrtsWkSCkWUA=.sha256"}} | ||||
| {"type":"tildefriends-app","files":{"app.js":"&5rHyeAQKxrbvIm32W3rKrh+LVRxlqLkN2cStJf5tCSM=.sha256","index.md":"&5EeOHUkDadC+lJsDsKXbfrVDQdePyOHZ7KwaJtR5mrs=.sha256","todo.md":"&uQuym9MPT7fIym79K8e/gdi5yOJrMoetZcutcsWYhQY=.sha256","structure.md":"&T+CBfT9XP6ooKFvD1ZCI9hsutqsNIamfBxtAho0HtlU=.sha256","guide.md":"&SgnGL0+rjetY2o9A2+lVRbNvHIkqKwMnZr9gXWneIlc=.sha256","id_refactor.md":"&8yoYd14gX2Z3ppktVrPYf4qR78fuwAlvrtsWkSCkWUA=.sha256"}} | ||||
| @@ -2,11 +2,16 @@ | ||||
| [Back to index](#index) | ||||
|  | ||||
| ## MVP2 | ||||
| - multiple identities per user, in database | ||||
| - make a cool independent app | ||||
| - indicate when workspace differs from installed | ||||
| - / => Something good. | ||||
| - confirm posting all new messages | ||||
| - administrators config | ||||
| - update README | ||||
| - update docs | ||||
| - audit + document API exposed to apps | ||||
| - emoji reaction picker | ||||
| - logging to browser | ||||
| - fix weird HTTP warnings | ||||
| - ssb from child process? | ||||
| - channels | ||||
| @@ -15,7 +20,6 @@ | ||||
| - placeholder/missing images | ||||
| - connections 2.0 | ||||
| - no denial of service | ||||
| - multiple identities per user, in database | ||||
| - expose loads of stats | ||||
| - package standalone executable | ||||
| - build for windows | ||||
| @@ -23,12 +27,7 @@ | ||||
| - tf account timeout why | ||||
| - attribute blob wants to messages | ||||
| - installable apps (bring back an app message?) | ||||
| - make a cool independent app | ||||
| - editor without app iframe | ||||
| - indicate when workspace differs from installed | ||||
| - / => Something good. | ||||
| - administrators config | ||||
| - confirm posting all new messages | ||||
|  | ||||
| ## Maybe Done | ||||
| - auto-populate data on initial launch | ||||
| @@ -38,4 +37,5 @@ | ||||
| - keep working on good error feedback | ||||
|  | ||||
| ## Done | ||||
| - update LICENSE | ||||
| - update LICENSE | ||||
| - logging to browser | ||||
| @@ -1 +1 @@ | ||||
| {"type":"tildefriends-app","files":{"app.js":"&iqkvaTLEbxeintzHb07jiFncdg3N1aS8h8ZNUzy7MZI=.sha256","index.html":"&2LRN4tFXkx5lGQkoWDuBolODntJI95PBWoFzwB1tg/Q=.sha256","vue-material.js":"&K5cdLqXYCENPak/TCINHQhyJhpS4G9DlZHGwoh/LF2g=.sha256","tf-user.js":"&DdJwZYEo7AqFyutYMvEjykoVXxdHVog0UXye6Sbo0TU=.sha256","tf-message.js":"&kIpc5B2dt4oefsTgNASz2cVte3WRO0k2NCYJYRzu/MA=.sha256","tf.js":"&wbm9maPsAXoS3c6jfLAHMkCPOi8gL00bH+OmJys9t60=.sha256","commonmark.min.js":"&EP0OeR9zyLwZannz+0ga4s9AGES2RLvvIIQYHqqV6+k=.sha256","vue.js":"&g1wvA+yHl1sVC+eufTsg9If7ZeVyMTBU+h0tks7ZNzE=.sha256","vue-material-theme-default-dark.css":"&RP2nr+2CR18BpHHw5ST9a5GJUCOG9n0G2kuGkcQioWE=.sha256","vue-material.min.css":"&kGbUM2QgFSyHZRzqQb0b+0S3EVIlZ0AXpdiAVjIhou8=.sha256","roboto.css":"&jJv43Om673mQO5JK0jj7714s5E+5Yrf82H6LcDx7wUs=.sha256","material-icons.css":"&a28PdcVvgq/DxyIvJAx/e+ZOEtOuHnr3kjLWKyzH11M=.sha256","tf-shared.js":"&+qPP3g4CAUlkt8K4iBCZ+F5Fy6N7fu6MggvSVss2juE=.sha256"}} | ||||
| {"type":"tildefriends-app","files":{"app.js":"&iSr0GObnkNKOpDGUkCikfwI7XI4mg6E3YNazCHSza2A=.sha256","index.html":"&xCI4SATYvlJkVX5EdlRROoDSMWlajF+wDFrWSUYZqd8=.sha256","vue-material.js":"&K5cdLqXYCENPak/TCINHQhyJhpS4G9DlZHGwoh/LF2g=.sha256","tf-user.js":"&DdJwZYEo7AqFyutYMvEjykoVXxdHVog0UXye6Sbo0TU=.sha256","tf-message.js":"&kIpc5B2dt4oefsTgNASz2cVte3WRO0k2NCYJYRzu/MA=.sha256","tf.js":"&WvteLAg4G92YOUO3/B36kmar5lqFq8Pil4rsy7uFNDY=.sha256","commonmark.min.js":"&EP0OeR9zyLwZannz+0ga4s9AGES2RLvvIIQYHqqV6+k=.sha256","vue.js":"&g1wvA+yHl1sVC+eufTsg9If7ZeVyMTBU+h0tks7ZNzE=.sha256","vue-material-theme-default-dark.css":"&RP2nr+2CR18BpHHw5ST9a5GJUCOG9n0G2kuGkcQioWE=.sha256","vue-material.min.css":"&kGbUM2QgFSyHZRzqQb0b+0S3EVIlZ0AXpdiAVjIhou8=.sha256","roboto.css":"&jJv43Om673mQO5JK0jj7714s5E+5Yrf82H6LcDx7wUs=.sha256","material-icons.css":"&a28PdcVvgq/DxyIvJAx/e+ZOEtOuHnr3kjLWKyzH11M=.sha256","tf-shared.js":"&+qPP3g4CAUlkt8K4iBCZ+F5Fy6N7fu6MggvSVss2juE=.sha256"}} | ||||
| @@ -6,9 +6,9 @@ const k_votes_max = 20; | ||||
| var g_ready = false; | ||||
| var g_selected = null; | ||||
|  | ||||
| var g_blocking_cache = {}; | ||||
| var g_following_cache = {}; | ||||
| var g_following_deep_cache = {}; | ||||
| var g_stats = {}; | ||||
| var g_sequence = {}; | ||||
|  | ||||
| async function following(db, id) { | ||||
| @@ -41,9 +41,11 @@ async function following(db, id) { | ||||
| 			} else { | ||||
| 				f.users.delete(row.contact); | ||||
| 			} | ||||
| 			f.sequence = row.sequence; | ||||
| 			g_sequence[id] = row.sequence; | ||||
| 			if (row.sequence) { | ||||
| 				f.sequence = row.sequence; | ||||
| 			} | ||||
| 		}); | ||||
| 	g_sequence[id] = f.sequence; | ||||
| 	var as_set = f.users; | ||||
| 	f.users = Array.from(f.users).sort(); | ||||
| 	var j = JSON.stringify(f); | ||||
| @@ -55,30 +57,81 @@ async function following(db, id) { | ||||
| 	return f.users; | ||||
| } | ||||
|  | ||||
| async function followingDeep(db, seed_ids, depth) { | ||||
| async function followingDeep(db, seed_ids, depth, blocked) { | ||||
| 	if (depth <= 0) { | ||||
| 		return seed_ids; | ||||
| 	} | ||||
| 	var key = JSON.stringify([seed_ids, depth]); | ||||
| 	var key = JSON.stringify([seed_ids, depth, blocked]); | ||||
| 	if (g_following_deep_cache[key]) { | ||||
| 		return g_following_deep_cache[key]; | ||||
| 	} | ||||
| 	var f = await Promise.all(seed_ids.map(x => following(db, x).then(x => [...x]))); | ||||
| 	var ids = [].concat(...f); | ||||
| 	var x = await followingDeep(db, [...new Set(ids)].sort(), depth - 1); | ||||
| 	if (blocked) { | ||||
| 		ids = ids.filter(x => !blocked.has(x)); | ||||
| 	} | ||||
| 	var x = await followingDeep(db, [...new Set(ids)].sort(), depth - 1, blocked); | ||||
| 	x = [...new Set([].concat(...x, ...seed_ids))].sort(); | ||||
| 	g_following_deep_cache[key] = x; | ||||
| 	return x; | ||||
| } | ||||
|  | ||||
| async function blocking(db, id) { | ||||
| 	if (g_blocking_cache[id]) { | ||||
| 		return g_blocking_cache[id]; | ||||
| 	} | ||||
| 	var o = await db.get(id + ":blocking"); | ||||
| 	const k_version = 5; | ||||
| 	var f = o ? JSON.parse(o) : o; | ||||
| 	if (!f || f.version != k_version) { | ||||
| 		f = {users: [], sequence: 0, version: k_version}; | ||||
| 	} | ||||
| 	f.users = new Set(f.users); | ||||
| 	if (!g_sequence[id] || g_sequence[id] > f.sequence) { | ||||
| 		await ssb.sqlStream( | ||||
| 			"SELECT "+ | ||||
| 			"  sequence, "+ | ||||
| 			"  json_extract(content, '$.contact') AS contact, "+ | ||||
| 			"  json_extract(content, '$.blocking') AS blocking "+ | ||||
| 			"FROM messages "+ | ||||
| 			"WHERE "+ | ||||
| 			"  author = ?1 AND "+ | ||||
| 			"  sequence > ?2 AND "+ | ||||
| 			"  json_extract(content, '$.type') = 'contact' "+ | ||||
| 			"UNION SELECT MAX(sequence) AS sequence, NULL, NULL FROM messages WHERE author = ?1 "+ | ||||
| 			"ORDER BY sequence", | ||||
| 			[id, f.sequence], | ||||
| 			function(row) { | ||||
| 				if (row.blocking) { | ||||
| 					f.users.add(row.contact); | ||||
| 				} else { | ||||
| 					f.users.delete(row.contact); | ||||
| 				} | ||||
| 				if (row.sequence) { | ||||
| 					f.sequence = row.sequence; | ||||
| 				} | ||||
| 			}); | ||||
| 		g_sequence[id] = f.sequence; | ||||
| 	} | ||||
| 	var as_set = f.users; | ||||
| 	f.users = Array.from(f.users).sort(); | ||||
| 	var j = JSON.stringify(f); | ||||
| 	if (o != j) { | ||||
| 		await db.set(id + ":blocking", j); | ||||
| 	} | ||||
| 	f.users = as_set; | ||||
| 	g_blocking_cache[id] = f.users; | ||||
| 	return f.users; | ||||
| } | ||||
|  | ||||
| async function getAbout(db, id) { | ||||
| 	var o = await db.get(id + ":about"); | ||||
| 	const k_version = 4; | ||||
| 	const k_version = 5; | ||||
| 	var f = o ? JSON.parse(o) : o; | ||||
| 	if (!f || f.version != k_version) { | ||||
| 		f = {about: {}, sequence: 0, version: k_version}; | ||||
| 	} | ||||
| 	if (g_sequence[id] > f.sequence) { | ||||
| 	if (g_sequence[id] === undefined || g_sequence[id] > f.sequence) { | ||||
| 		await ssb.sqlStream( | ||||
| 			"SELECT "+ | ||||
| 			"  sequence, "+ | ||||
| @@ -93,8 +146,6 @@ async function getAbout(db, id) { | ||||
| 			"ORDER BY sequence", | ||||
| 			[id, f.sequence], | ||||
| 			function(row) { | ||||
| 				g_stats.rows_read = (g_stats.rows_read || 0) + 1; | ||||
| 				f.sequence = row.sequence; | ||||
| 				if (row.content) { | ||||
| 					var about = {}; | ||||
| 					try { | ||||
| @@ -105,12 +156,15 @@ async function getAbout(db, id) { | ||||
| 					delete about.type; | ||||
| 					f.about = Object.assign(f.about, about); | ||||
| 				} | ||||
| 				if (row.sequence) { | ||||
| 					f.sequence = Math.max(f.sequence, row.sequence); | ||||
| 				} | ||||
| 			}); | ||||
| 	} | ||||
| 	var j = JSON.stringify(f); | ||||
| 	if (o != j) { | ||||
| 		g_stats.rows_written = (g_stats.rows_written || 0) + 1; | ||||
| 		await db.set(id + ":about", j); | ||||
| 		g_sequence[id] = f.sequence; | ||||
| 		var j = JSON.stringify(f); | ||||
| 		if (o != j) { | ||||
| 			await db.set(id + ":about", j); | ||||
| 		} | ||||
| 	} | ||||
| 	return f.about; | ||||
| } | ||||
| @@ -152,7 +206,7 @@ async function getRecentPostIds(db, id, ids, limit) { | ||||
| 		return await getRecentPostsSingleId(db, ids[0], limit); | ||||
| 	} | ||||
| 	const k_version = 11; | ||||
| 	const k_batch_max = 16; | ||||
| 	const k_batch_max = 32; | ||||
| 	var o = await db.get(id + ':recent_posts'); | ||||
| 	var recent = []; | ||||
| 	var f = o ? JSON.parse(o) : o; | ||||
| @@ -251,12 +305,12 @@ async function getRelatedPostIds(db, message, ids, limit) { | ||||
| async function getVotes(db, id) { | ||||
| 	var o = await db.get(id + ":votes"); | ||||
| 	const k_version = 7; | ||||
| 	var votes = []; | ||||
| 	var f = o ? JSON.parse(o) : o; | ||||
| 	if (!f || f.version != k_version) { | ||||
| 		f = {votes: [], sequence: 0, version: k_version}; | ||||
| 	} | ||||
| 	if (!g_sequence[id] || g_sequence[id] > f.sequence) { | ||||
| 	if (g_sequence[id] === undefined || g_sequence[id] > f.sequence) { | ||||
| 		var votes = []; | ||||
| 		await ssb.sqlStream( | ||||
| 			"SELECT "+ | ||||
| 			"  author, "+ | ||||
| @@ -269,20 +323,24 @@ async function getVotes(db, id) { | ||||
| 			"  author = ? AND "+ | ||||
| 			"  sequence > ? AND "+ | ||||
| 			"  json_extract(content, '$.type') = 'vote' "+ | ||||
| 			"UNION SELECT NULL, NULL, MAX(sequence), NULL, NULL FROM messages WHERE author = ? "+ | ||||
| 			"UNION SELECT NULL, NULL, MAX(sequence) AS sequence, NULL, NULL FROM messages WHERE author = ? "+ | ||||
| 			"ORDER BY sequence DESC LIMIT ?", | ||||
| 			[id, f.sequence, id, k_votes_max], | ||||
| 			function(row) { | ||||
| 				if (row.id) { | ||||
| 					votes.push(row); | ||||
| 				} | ||||
| 				f.sequence = Math.max(f.sequence, row.sequence); | ||||
| 				if (row.sequence) { | ||||
| 					f.sequence = Math.max(f.sequence, row.sequence); | ||||
| 				} | ||||
| 			}); | ||||
| 	} | ||||
| 	f.votes = [].concat(votes, f.votes).slice(0, k_votes_max); | ||||
| 	var j = JSON.stringify(f); | ||||
| 	if (o != j) { | ||||
| 		await db.set(id + ":votes", j); | ||||
| 		g_sequence[id] = f.sequence; | ||||
| 		f.votes = [].concat(votes, f.votes).slice(0, k_votes_max); | ||||
| 		var j = JSON.stringify(f); | ||||
| 		if (o != j) { | ||||
| 			print('set', id + ':votes'); | ||||
| 			await db.set(id + ":votes", j); | ||||
| 		} | ||||
| 	} | ||||
| 	return f.votes; | ||||
| } | ||||
| @@ -322,7 +380,9 @@ async function refresh(selected) { | ||||
| 	var whoami = await ssb.whoami(); | ||||
| 	var db = await database("ssb"); | ||||
| 	timing.push({name: 'init', time: new Date()}); | ||||
| 	var all_followed = await followingDeep(db, [whoami], 2); | ||||
| 	var blocked = await blocking(db, whoami); | ||||
| 	timing.push({name: 'blocked', time: new Date()}); | ||||
| 	var all_followed = await followingDeep(db, [whoami], 2, blocked); | ||||
| 	timing.push({name: 'all_followed', time: new Date()}); | ||||
| 	if (selected) { | ||||
| 		g_selected = selected; | ||||
| @@ -376,13 +436,13 @@ async function refresh(selected) { | ||||
| 		) | ||||
| 	); | ||||
| 	timing.push({name: 'following', time: new Date()}); | ||||
|  | ||||
| 	print(JSON.stringify(g_stats)); | ||||
| 	await app.postMessage({blocking: {id: whoami, users: [...(g_blocking_cache[whoami] || [])]}}); | ||||
| 	timing.push({name: 'send_blocking', time: new Date()}); | ||||
|  | ||||
| 	var times = {}; | ||||
| 	var previous = null; | ||||
| 	for (let t of timing) { | ||||
| 		times[t.name] = t.time - (previous || t).time; | ||||
| 		times[t.name] = (t.time - (previous || t).time) / 1000.0 + ' s'; | ||||
| 		previous = t; | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -52,7 +52,7 @@ | ||||
| 							<span v-if="load_time" style="float: right"> | ||||
| 								Loaded in {{load_time}} seconds. | ||||
| 								<md-tooltip v-if="Object.keys(times).length" style="height: auto"> | ||||
| 									<div v-for="key in Object.keys(times)">{{key}}: {{times[key] / 1000.0}} s</div> | ||||
| 									<div v-for="key in Object.keys(times)">{{key}}: {{times[key]}}</div> | ||||
| 								</md-tooltip> | ||||
| 							</span> | ||||
| 							<md-card class="md-elevation-8"> | ||||
| @@ -137,6 +137,10 @@ | ||||
| 												<md-menu-item v-for="id of Object.keys(users[selected].following)" v-bind:key="id"><tf-user :id="id"></tf-user></md-menu-item> | ||||
| 											</md-menu-content> | ||||
| 										</md-menu> | ||||
| 										<template v-if="selected != whoami && users[whoami] && users[whoami].blocking"> | ||||
| 											<md-button @click="block(selected)" v-if="!users[whoami].blocking[selected]" class="md-raised md-secondary">Block</md-button> | ||||
| 											<md-button @click="unblock(selected)" v-else class="md-raised md-secondary">Unblock</md-button> | ||||
| 										</template> | ||||
| 										<template v-if="selected != whoami && users[whoami] && users[whoami].following"> | ||||
| 											<md-button @click="follow(selected)" v-if="!users[whoami].following[selected]" class="md-raised md-secondary">Follow</md-button> | ||||
| 											<md-button @click="unfollow(selected)" v-else class="md-raised md-secondary">Unfollow</md-button> | ||||
|   | ||||
| @@ -108,6 +108,16 @@ function processMessages() { | ||||
| 				} | ||||
| 				Vue.set(g_data.users[user].followers, event.data.following.id, true); | ||||
| 			} | ||||
| 		} else if (key == 'blocking') { | ||||
| 			if (!g_data.users[event.data.blocking.id]) { | ||||
| 				Vue.set(g_data.users, event.data.blocking.id, {}); | ||||
| 			} | ||||
| 			if (!g_data.users[event.data.blocking.id].blocking) { | ||||
| 				Vue.set(g_data.users[event.data.blocking.id], 'blocking', {}); | ||||
| 			} | ||||
| 			for (let user of event.data.blocking.users) { | ||||
| 				Vue.set(g_data.users[event.data.blocking.id].blocking, user, true); | ||||
| 			} | ||||
| 		} else if (key == 'broadcasts') { | ||||
| 			g_data.broadcasts = event.data.broadcasts; | ||||
| 		} else if (key == 'pubs') { | ||||
| @@ -234,6 +244,16 @@ window.addEventListener('load', function() { | ||||
| 					window.parent.postMessage({appendMessage: {type: "contact", following: false, contact: id}}, '*'); | ||||
| 				} | ||||
| 			}, | ||||
| 			block: function(id) { | ||||
| 				if (confirm('Are you sure you want to block ' + id + '?')) { | ||||
| 					window.parent.postMessage({appendMessage: {type: "contact", blocking: true, contact: id}}, '*'); | ||||
| 				} | ||||
| 			}, | ||||
| 			unblock: function(id) { | ||||
| 				if (confirm('Are you sure you want to unblock ' + id + '?')) { | ||||
| 					window.parent.postMessage({appendMessage: {type: "contact", blocking: false, contact: id}}, '*'); | ||||
| 				} | ||||
| 			}, | ||||
| 			set_hash(hash) { | ||||
| 				window.parent.postMessage({action: 'setHash', hash: hash ? hash : '#'}, '*'); | ||||
| 			}, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user