This commit is contained in:
bobbydigitales
2024-10-07 00:24:22 -07:00
parent 2236ff0e6d
commit ac6846613a
7 changed files with 252 additions and 102 deletions

View File

@@ -59,6 +59,9 @@ function uuidToBase58(uuid) {
const bytes = uuidToBytes(uuid);
return encodeBase58(bytes);
}
function logID(ID) {
return ID.substring(0, 5);
}
let logLines = [];
let logLength = 10;
function log(message) {
@@ -142,11 +145,27 @@ async function base64ToArrayBuffer(base64String) {
// let buffer = new Uint8Array(arrayBuffer);
// return buffer;
}
async function compressString(input) {
// Convert the string to a Uint8Array
const textEncoder = new TextEncoder();
const inputArray = textEncoder.encode(input);
// Create a CompressionStream
const compressionStream = new CompressionStream('gzip');
const writer = compressionStream.writable.getWriter();
// Write the data and close the stream
writer.write(inputArray);
writer.close();
// Read the compressed data from the stream
const compressedArray = await new Response(compressionStream.readable).arrayBuffer();
// Convert the compressed data to a Uint8Array
return new Uint8Array(compressedArray);
}
class wsConnection {
send(message) {
async send(message) {
let json = "";
try {
json = JSON.stringify(message);
// console.log("*******", (await compressString(json)).byteLength, json.length);
}
catch (e) {
console.log(e, "wsConnection send: Couldn't serialize message", message);
@@ -165,17 +184,19 @@ class wsConnection {
console.log('helloResponseHandler', e);
}
users = [...users, ...Object.entries(data.userPeers)];
log(`Network: got ${users.length} users from bootstrap peer. ${users.join(',')}`);
log(`Net: got ${users.length} users from bootstrap peer. ${users.join(',')}`);
for (let [userID, peerIDs] of users) {
this.peers.set(userID, [...Object.keys(peerIDs)]);
for (let peerID of [...Object.keys(peerIDs)]) {
if (peerID === this.peerID) {
continue;
}
log(`Network: Requesting post IDs for user ${userID} from peer ${peerID}`);
log(`Net: Req post IDs for user ${logID(userID)} from peer ${logID(peerID)}`);
this.send({
type: "peer_message",
from: this.peerID,
from_username: app.username,
from_peername: app.peername,
to: peerID,
message: { type: "get_post_ids_for_user", user_id: userID }
});
@@ -187,15 +208,15 @@ class wsConnection {
async getPostIdsForUserResponseHandler(data) {
// log(`getPostsForUserResponse: ${data}`)
let message = data.message;
log(`Network: got ${message.post_ids.length} post IDs for user ${data.message.user_id} from peer ${data.from}`);
console.log(`Checking post IDs...`);
log(`Net: got ${message.post_ids.length} post IDs for user ${logID(data.message.user_id)} from peer ${logID(data.from)}`);
// console.log(`Checking post IDs...`);
let postIds = await checkPostIds(message.user_id, data.message.post_ids);
if (postIds.length === 0) {
log(`Don't need any posts from peer ${data.from}`);
log(`Don't need any posts for user ${logID(data.message.user_id)} from peer ${logID(data.from)}`);
return;
}
log(`Network: requesting ${postIds.length} posts for user ${message.user_id} from peer ${data.from}`);
let responseMessage = { type: "peer_message", from: app.peerID, to: data.from, message: { type: "get_posts_for_user", post_ids: postIds, user_id: message.user_id } };
log(`Net: Req ${postIds.length} posts for user ${logID(message.user_id)} from peer ${logID(data.from)}`);
let responseMessage = { type: "peer_message", from: app.peerID, to: data.from, from_username: app.username, from_peername: app.peername, message: { type: "get_posts_for_user", post_ids: postIds, user_id: message.user_id } };
this.send(responseMessage);
}
// static async compressArrayBuffer(data: ArrayBuffer): Promise<ArrayBuffer> {
@@ -210,18 +231,18 @@ class wsConnection {
let message = data.message;
let postIds = await getAllIds(message.user_id) ?? [];
if (postIds.length === 0) {
log(`Network: I know about user ${message.user_id} but I have 0 posts, so I'm not sending any to to peer ${data.from}`);
log(`Net: I know about user ${logID(message.user_id)} but I have 0 posts, so I'm not sending any to to peer ${logID(data.from)}`);
return;
}
log(`Network: Sending ${postIds.length} post Ids for user ${message.user_id} to peer ${data.from}`);
let responseMessage = { type: "peer_message", from: app.peerID, to: data.from, message: { type: "get_post_ids_for_user_response", post_ids: postIds, user_id: message.user_id } };
log(`Net: Sending ${postIds.length} post Ids for user ${logID(message.user_id)} to peer ${logID(data.from)}`);
let responseMessage = { type: "peer_message", from: app.peerID, to: data.from, from_username: app.username, from_peername: app.peername, message: { type: "get_post_ids_for_user_response", post_ids: postIds, user_id: message.user_id } };
this.send(responseMessage);
}
// Send posts to peer
async getPostsForUserHandler(data) {
let message = data.message;
let posts = await getPostsByIds(message.user_id, message.post_ids) ?? [];
log(`Network: Sending ${posts.length} posts for user ${message.user_id} to peer ${data.from}`);
log(`Net: Sending ${posts.length} posts for user ${logID(message.user_id)} to peer ${logID(data.from)}`);
app.timerStart();
let output = [];
for (let post of posts) {
@@ -237,7 +258,7 @@ class wsConnection {
}
// posts = posts.map((post:any)=>{let newPost = post.data; if (newPost.image_data){newPost.image_data = arraybufferto};return newPost});
// posts = posts.map((post:any)=>{})
let responseMessage = { type: "peer_message", from: app.peerID, to: data.from, message: { type: "get_posts_for_user_response", posts: output, user_id: message.user_id } };
let responseMessage = { type: "peer_message", from: app.peerID, to: data.from, from_username: app.username, from_peername: app.peername, message: { type: "get_posts_for_user_response", posts: output, user_id: message.user_id } };
this.send(responseMessage);
let sendTime = app.timerDelta();
log(`send took: ${sendTime.toFixed(2)}ms`);
@@ -246,8 +267,7 @@ class wsConnection {
async getPostsForUserReponseHandler(data) {
app.timerStart();
let message = data.message;
console.log(`Network: got ${message.posts.length} posts for user ${message.user_id} from peer ${data.from}`);
console.log(`getPostsForUserResponseHandler Got ${message.posts.length} from peer ${data.from}`);
console.log(`Net: got ${message.posts.length} posts for user ${logID(message.user_id)} from peer ${logID(data.from)}`);
for (let post of message.posts) {
if (message.user_id === app.userID) {
post.author_id = app.userID;
@@ -294,8 +314,8 @@ class wsConnection {
this.websocket.onopen = async (event) => {
log("ws:connected");
let knownUsers = [...(await indexedDB.databases())].map((db) => db.name?.replace('user_', ''));
console.log('Network: Sending known users', knownUsers);
this.send({ type: "hello", user_id: this.userID, peer_id: this.peerID, known_users: knownUsers });
console.log('Net: Sending known users', knownUsers);
this.send({ type: "hello", user_id: this.userID, user_name: app.username, peer_id: this.peerID, peer_name: app.peername, known_users: knownUsers });
this.websocketPingInterval = window.setInterval(() => {
if (!navigator.onLine) {
return;
@@ -355,14 +375,22 @@ class wsConnection {
class App {
constructor() {
this.username = '';
this.peername = '';
this.userID = '';
this.peerID = '';
this.following = [];
this.posts = [];
this.isHeadless = false;
this.showLog = false;
this.time = 0;
this.animals = ['shrew', 'jerboa', 'lemur', 'weasel', 'possum', 'possum', 'marmoset', 'planigale', 'mole', 'narwhal'];
this.adjectives = ['snazzy', 'whimsical', 'jazzy', 'bonkers', 'wobbly', 'spiffy', 'chirpy', 'zesty', 'bubbly', 'perky', 'sassy'];
this.snakes = ['mamba', 'cobra', 'python', 'viper', 'krait', 'sidewinder', 'constrictor', 'boa', 'asp', 'anaconda', 'krait'];
// keep a map of posts to dom nodes.
// on re-render
// posts that are not in our list that we need at add
// posts that are in our list that we need to remove
this.renderedPosts = new Map();
this.router = {
route: App.Route.HOME,
userID: '',
@@ -490,7 +518,7 @@ class App {
return;
}
let post = new Post(this.username, userID, postText, new Date(), mediaData);
this.posts.push(post);
// this.posts.push(post);
// localStorage.setItem(key, JSON.stringify(posts));
addData(userID, post);
this.render();
@@ -511,9 +539,9 @@ class App {
}
return id;
}
hashUserIdToIndices() {
hashIdToIndices(id) {
let indices = [];
for (let char of this.userID) {
for (let char of id) {
if (char !== '0' && char !== '-') {
indices.push(parseInt(char, 16));
if (indices.length == 2) {
@@ -523,17 +551,27 @@ class App {
}
return [indices[0], indices[1]];
}
funkyName(id, listOne, listTwo) {
let [one, two] = this.hashIdToIndices(id);
let first = listOne[one % this.adjectives.length];
let second = listTwo[two % this.animals.length];
return { first, second };
}
getUsername() {
let username = localStorage.getItem("dandelion_username");
if (!username || username === "not_set") {
let [one, two] = this.hashUserIdToIndices();
let adjective = this.adjectives[one % this.adjectives.length];
let animal = this.animals[two % this.animals.length];
username = `${adjective}_${animal}`;
localStorage.setItem("dandelion_username", username);
if (username && username !== "not_set") {
return username;
}
let { first: adjective, second: animal } = this.funkyName(this.userID, this.adjectives, this.animals);
username = `${adjective}_${animal}`;
localStorage.setItem("dandelion_username", username);
return username;
}
getPeername() {
let { first: adjective, second: snake } = this.funkyName(this.peerID, this.adjectives, this.snakes);
let peername = `${adjective}_${snake}`;
return peername;
}
setFont(fontName, fontSize) {
let content = document.getElementById('content');
if (!content) {
@@ -739,7 +777,11 @@ class App {
registration = await this.registerServiceWorker();
// }
this.username = this.getUsername();
document.getElementById('username').innerText = this.username;
document.getElementById('username').innerText = `${this.username}`;
this.peername = this.getPeername();
document.getElementById('peername').innerText = `peername:${this.peername}`;
document.getElementById('user_id').innerText = `user_id:${this.userID}`;
document.getElementById('peer_id').innerText = `peer_id:${this.peerID}`;
this.initButtons(userID, this.posts, registration);
let connectURL = `https://${document.location.hostname}/connect/${this.userID}`;
document.getElementById('connectURL').innerHTML = `<a href="${connectURL}">connect</a>`;
@@ -771,43 +813,52 @@ class App {
// file.appendTo(document.getElementById('torrent-content'));
// })
}
// keep a map of posts to dom nodes.
// on re-render
// posts that are not in our list that we need at add
// posts that are in our list that we need to remove
// postsSet = new Set();
computeDiff(newPosts) {
// return {added, deleted, same}
}
async render() {
if (this.isHeadless) {
console.log('Headless so skipping render...');
return;
}
this.timerStart();
let posts = [];
let existingPosts = this.posts;
this.posts = [];
switch (this.router.route) {
case App.Route.HOME:
case App.Route.CONNECT: {
posts = await this.loadPosts(this.userID) ?? [];
this.posts = await this.loadPosts(this.userID) ?? [];
break;
}
case App.Route.USER: {
posts = await this.loadPosts(this.router.userID) ?? [];
this.posts = await this.loadPosts(this.router.userID) ?? [];
break;
}
case App.Route.POST: {
posts = await this.loadPosts(this.router.userID, this.router.postID) ?? [];
this.posts = await this.loadPosts(this.router.userID, this.router.postID) ?? [];
break;
}
default: {
console.log("Render: got a route I didn't understand. Rendering HOME:", this.router.route);
posts = await this.loadPosts(this.userID) ?? [];
this.posts = await this.loadPosts(this.userID) ?? [];
break;
}
}
// let newPostsSet = new Set(posts.map(post=>post.post_id));
// let newPosts = (newPostsSet as any).difference(this.postsSet);
// // let removedPosts = (this.postsSet as any).difference(newPosts);
// let keepPosts = (this.postsSet as any).intersection(newPostsSet);
// let renderPosts = keepPosts.union(newPosts);
let existingPostSet = new Set(existingPosts.map(post => post.post_id));
let incomingPostSet = new Set(this.posts.map(post => post.post_id));
let addedPosts = [];
for (let post of this.posts) {
if (!existingPostSet.has(post.post_id)) {
addedPosts.push(post);
}
}
let deletedPosts = [];
for (let post of existingPosts) {
if (!incomingPostSet.has(post.post_id)) {
deletedPosts.push(post);
}
}
console.log("added:", addedPosts, "removed:", deletedPosts);
const fragment = document.createDocumentFragment();
let contentDiv = document.getElementById("content");
if (!contentDiv) {
@@ -815,9 +866,10 @@ class App {
}
contentDiv.innerHTML = "";
// let count = 0;
for (let i = posts.length - 1; i >= 0; i--) {
let postData = posts[i];
for (let i = this.posts.length - 1; i >= 0; i--) {
let postData = this.posts[i];
// this.postsSet.add(postData);
// return promises for all image loads and await those.
let post = this.renderPost(postData);
if (post) {
fragment.appendChild(post);