| 
									
										
										
										
											2022-08-04 00:57:56 +00:00
										 |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var g_following_cache = {}; | 
					
						
							|  |  |  | var g_following_deep_cache = {}; | 
					
						
							|  |  |  | var g_about_cache = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function following(db, id) { | 
					
						
							|  |  |  | 	if (g_following_cache[id]) { | 
					
						
							|  |  |  | 		return g_following_cache[id]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var o = await db.get(id + ":following"); | 
					
						
							|  |  |  | 	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); | 
					
						
							| 
									
										
										
										
											2023-02-23 01:29:54 +00:00
										 |  |  | 	await ssb.sqlAsync( | 
					
						
							| 
									
										
										
										
											2022-08-04 00:57:56 +00:00
										 |  |  | 		"SELECT "+ | 
					
						
							|  |  |  | 		"  sequence, "+ | 
					
						
							|  |  |  | 		"  json_extract(content, '$.contact') AS contact, "+ | 
					
						
							|  |  |  | 		"  json_extract(content, '$.following') AS following "+ | 
					
						
							|  |  |  | 		"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.following) { | 
					
						
							|  |  |  | 				f.users.add(row.contact); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				f.users.delete(row.contact); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			f.sequence = row.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 + ":following", j); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	f.users = as_set; | 
					
						
							|  |  |  | 	g_following_cache[id] = f.users; | 
					
						
							|  |  |  | 	return f.users; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function followingDeep(db, seed_ids, depth) { | 
					
						
							|  |  |  | 	if (depth <= 0) { | 
					
						
							|  |  |  | 		return seed_ids; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var key = JSON.stringify([seed_ids, depth]); | 
					
						
							|  |  |  | 	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); | 
					
						
							|  |  |  | 	x = [...new Set([].concat(...x, ...seed_ids))].sort(); | 
					
						
							|  |  |  | 	g_following_deep_cache[key] = x; | 
					
						
							|  |  |  | 	return x; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function getAbout(db, id) { | 
					
						
							|  |  |  | 	if (g_about_cache[id]) { | 
					
						
							|  |  |  | 		return g_about_cache[id]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var o = await db.get(id + ":about"); | 
					
						
							|  |  |  | 	const k_version = 4; | 
					
						
							|  |  |  | 	var f = o ? JSON.parse(o) : o; | 
					
						
							|  |  |  | 	if (!f || f.version != k_version) { | 
					
						
							|  |  |  | 		f = {about: {}, sequence: 0, version: k_version}; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-02-23 01:29:54 +00:00
										 |  |  | 	await ssb.sqlAsync( | 
					
						
							| 
									
										
										
										
											2022-08-04 00:57:56 +00:00
										 |  |  | 		"SELECT "+ | 
					
						
							|  |  |  | 		"  sequence, "+ | 
					
						
							|  |  |  | 		"  content "+ | 
					
						
							|  |  |  | 		"FROM messages "+ | 
					
						
							|  |  |  | 		"WHERE "+ | 
					
						
							|  |  |  | 		"  author = ?1 AND "+ | 
					
						
							|  |  |  | 		"  sequence > ?2 AND "+ | 
					
						
							|  |  |  | 		"  json_extract(content, '$.type') = 'about' AND "+ | 
					
						
							|  |  |  | 		"  json_extract(content, '$.about') = ?1 "+ | 
					
						
							|  |  |  | 		"UNION SELECT MAX(sequence) as sequence, NULL FROM messages WHERE author = ?1 "+ | 
					
						
							|  |  |  | 		"ORDER BY sequence", | 
					
						
							|  |  |  | 		[id, f.sequence], | 
					
						
							|  |  |  | 		function(row) { | 
					
						
							|  |  |  | 			f.sequence = row.sequence; | 
					
						
							|  |  |  | 			if (row.content) { | 
					
						
							|  |  |  | 				var about = {}; | 
					
						
							|  |  |  | 				try { | 
					
						
							|  |  |  | 					about = JSON.parse(row.content); | 
					
						
							|  |  |  | 				} catch { | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				delete about.about; | 
					
						
							|  |  |  | 				delete about.type; | 
					
						
							|  |  |  | 				f.about = Object.assign(f.about, about); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	var j = JSON.stringify(f); | 
					
						
							|  |  |  | 	if (o != j) { | 
					
						
							|  |  |  | 		await db.set(id + ":about", j); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	g_about_cache[id] = f.about; | 
					
						
							|  |  |  | 	return f.about; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function getSize(db, id) { | 
					
						
							|  |  |  | 	let size = 0; | 
					
						
							| 
									
										
										
										
											2023-02-23 01:29:54 +00:00
										 |  |  | 	await ssb.sqlAsync( | 
					
						
							| 
									
										
										
										
											2022-08-04 00:57:56 +00:00
										 |  |  | 		"SELECT (SUM(LENGTH(content)) + SUM(LENGTH(author)) + SUM(LENGTH(id))) AS size FROM messages WHERE author = ?1", | 
					
						
							|  |  |  | 		[id], | 
					
						
							|  |  |  | 		function (row) { | 
					
						
							|  |  |  | 			size += row.size; | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	return size; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function niceSize(bytes) { | 
					
						
							|  |  |  | 	let value = bytes; | 
					
						
							|  |  |  | 	let unit = 'B'; | 
					
						
							|  |  |  | 	const k_units = ['kB', 'MB', 'GB', 'TB']; | 
					
						
							|  |  |  | 	for (let u of k_units) { | 
					
						
							|  |  |  | 		if (value >= 1024) { | 
					
						
							|  |  |  | 			value /= 1024; | 
					
						
							|  |  |  | 			unit = u; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return Math.round(value * 10) / 10 + ' ' + unit; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function buildTree(db, root, indent, depth) { | 
					
						
							|  |  |  | 	var f = await following(db, root); | 
					
						
							|  |  |  | 	var result = indent + '[' + f.size + '] ' + '<a target="_top" href="../index/#' + root + '">' + ((await getAbout(db, root)).name || root) + '</a> ' + niceSize(await getSize(db, root)) + '\n'; | 
					
						
							|  |  |  | 	if (depth > 0) { | 
					
						
							|  |  |  | 		for (let next of f) { | 
					
						
							|  |  |  | 			result += await buildTree(db, next, indent + '  ', depth - 1); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function main() { | 
					
						
							|  |  |  | 	await app.setDocument('<pre style="color: #fff">building...</pre>'); | 
					
						
							|  |  |  | 	var db = await database('ssb'); | 
					
						
							|  |  |  | 	var whoami = await ssb.getIdentities(); | 
					
						
							|  |  |  | 	var tree = ''; | 
					
						
							|  |  |  | 	for (let id of whoami) { | 
					
						
							| 
									
										
										
										
											2022-09-06 23:26:43 +00:00
										 |  |  | 		await app.setDocument(`<pre style="color: #fff">building... ${id}</pre>`); | 
					
						
							| 
									
										
										
										
											2022-08-04 00:57:56 +00:00
										 |  |  | 		tree += await buildTree(db, id, '', 2); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	await app.setDocument('<pre style="color: #fff">FOLLOWING:\n' + tree + '</pre>'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | main(); |