diff --git a/static/App.js b/static/App.js index 146bc69..050deaa 100644 --- a/static/App.js +++ b/static/App.js @@ -16,6 +16,52 @@ class Post { this.importSource = importSource; } } +class StatusBar { + constructor() { + this.peerStatus = new Map(); + this.headless = false; + } + setMessageHTML(html) { + let statusBarElement = document.getElementById('status_bar'); + if (!statusBarElement) { + return; + } + statusBarElement.innerHTML = html; + } + setHeadless(headless) { + this.headless = headless; + } + updatePeerMessage(peerID, message) { + this.peerStatus.set(peerID, { message, data: this.peerStatus.get(peerID)?.data }); + this.render(); + } + updatePeerData(peerID, data) { + this.peerStatus.set(peerID, { message: this.peerStatus.get(peerID)?.message, data: data }); + } + updatePeerStatus(peerID, message = "", data = {}) { + this.peerStatus.set(peerID, { message, data }); + this.render(); + } + getPeerData(peerID) { + let status = this.peerStatus.get(peerID); + if (status) { + return status.data; + } + return null; + } + render() { + if (this.headless) { + // TODO:Make a nice htop-like display for headless at some point + return; + } + let newStatus = ""; + for (let [peerID, status] of this.peerStatus.entries()) { + let statusBarItem = `(${logID(peerID)} | ${status.message}) `; + newStatus += statusBarItem; + } + this.setMessageHTML(newStatus); + } +} export class App { constructor() { this.username = ''; @@ -37,9 +83,10 @@ export class App { this.firstRun = false; this.peerManager = null; this.sync = new Sync(); - this.renderTimer = 0; + this.renderTimer = null; this.syncQueues = new Map(); this.syncing = new Set(); + this.statusBar = new StatusBar(); 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']; @@ -56,6 +103,24 @@ export class App { mediaID: '' }; } + // updateStatusBar() { + // let statusBarElement = document.getElementById('status_bar'); + // if (!statusBarElement) { + // return; + // } + // let newStatusBar = ""; + // for (let [userID, syncItems] of this.syncQueues.entries()) { + // for (let item of syncItems) { + // let {peerID, postIDs} = item; + // // let statusBarItem = ` 🤔(${postIDs.length})✉️ [${this.getUserFunkyName(userID)}]${logID(userID)} from [${this.getPeerFunkyName(peerID)}]${logID(peerID)} `; + // // let statusBarItem = ` 🤔(${postIDs.length})✉️ [${this.getUserFunkyName(userID)}] from [${this.getPeerFunkyName(peerID)}] `; + // let statusBarItem = ` (${this.getUserFunkyName(userID)}+${this.getPeerFunkyName(peerID)})🧐 `; + // newStatusBar+= statusBarItem; + // } + // } + // this.statusBar += newStatusBar; + // statusBarElement.innerHTML = this.statusBar; + // } async processSyncQueue(userID) { if (this.syncing.has(userID)) { return; @@ -72,13 +137,16 @@ export class App { let neededPostIDs = await this.sync.checkPostIds(userID, peerID, postIDs); if (neededPostIDs.length > 0) { console.log.apply(null, log(`[app] Need (${neededPostIDs.length}) posts for user ${logID(userID)} from peer ${logID(peerID)}`)); + let neededPostCount = neededPostIDs.length; + this.statusBar.updatePeerStatus(peerID, `need(${logID(userID)} | ${neededPostCount})`, { havePostCount: 0, neededPostCount: neededPostCount }); let neededPosts = await this.peerManager?.rpc.getPostsForUser(peerID, this.peerID, userID, neededPostIDs); - // console.log(neededPosts); } else { console.log.apply(null, log(`[app] Don't need any posts for user ${logID(userID)} from peer ${logID(peerID)}`)); + this.statusBar.updatePeerStatus(peerID, `synced(${logID(userID)})`); } } + // this.updateStatusBar(); this.syncing.delete(userID); } addPostIDsToSyncQueue(userID, peerID, postIDs) { @@ -100,6 +168,7 @@ export class App { return; } console.log.apply(null, log(`[app] got announceUsers from ${logID(sendingPeerID)}`, userIDs)); + this.statusBar.updatePeerStatus(sendingPeerID, `announcePeers(${userIDs.length})⬇️`); for (let userID of userIDs) { // console.log.apply(null, log(`[app] announceUsers, got user:${userID} from peer ${sendingPeerID}`)); this.sync.addUserPeer(userID, sendingPeerID); @@ -108,7 +177,10 @@ export class App { continue; } console.log.apply(null, log(`[app] calling getPostIDsForUser for user [${logID(userID)}] on peer [${logID(sendingPeerID)}]`)); + this.statusBar.updatePeerStatus(sendingPeerID, `getPostIDs(${logID(userID)})⬆️`); + let postIDs = await this.peerManager?.rpc.getPostIDsForUser(sendingPeerID, userID); + this.statusBar.updatePeerStatus(sendingPeerID, `syncing(${logID(userID)} ${postIDs.length})`); console.log.apply(null, log(`[app] Got (${postIDs.length}) post IDs for user [${logID(userID)}] from peer [${logID(sendingPeerID)}]`)); this.addPostIDsToSyncQueue(userID, sendingPeerID, postIDs); } @@ -155,8 +227,11 @@ export class App { }); this.peerManager.registerRPC('getPostsForUser', async (requestingPeerID, userID, postIDs) => { let posts = await this.sync.getPostsForUser(userID, postIDs); + let i = 0; for (let post of posts) { console.log.apply(null, log(`[app] sendPostForUser sending post [${logID(post.post_id)}] to [${logID(requestingPeerID)}]`, userID, post.author, post.text)); + i++; + this.statusBar.updatePeerStatus(this.peerID, `⬆️${logID(requestingPeerID)} ${i}/${posts.length}`); await this.peerManager?.rpc.sendPostForUser(requestingPeerID, this.peerID, userID, post); } return true; @@ -168,8 +243,16 @@ export class App { // if (post.text === "image...") { // debugger; // } + let peerData = this.statusBar.getPeerData(sendingPeerID); + if (peerData) { + this.statusBar.updatePeerMessage(sendingPeerID, `⬇️${logID(userID)} ${peerData.havePostCount}/${peerData.neededPostCount}}`); + } await this.sync.writePostForUser(userID, post); // if (userID === this.userID) { + if (peerData) { + peerData.havePostCount++; + this.statusBar.updatePeerMessage(sendingPeerID, `⬇️${logID(userID)} ${peerData.havePostCount}/${peerData.neededPostCount}}`); + } if (this.renderTimer) { clearTimeout(this.renderTimer); } @@ -177,9 +260,11 @@ export class App { return true; // } }); + this.statusBar.setMessageHTML("Connecting to ddln network..."); await this.peerManager.connect(); console.log.apply(null, log("*************** after peerManager.connect")); ; + this.statusBar.setMessageHTML("Connected to ddln network..."); if (this.isBootstrapPeer) { return; } @@ -486,19 +571,25 @@ export class App { let second = listTwo[two % listTwo.length]; return { first, second }; } + getUserFunkyName(userID) { + let { first: adjective, second: animal } = this.funkyName(userID, this.adjectives, this.animals); + return `${adjective}_${animal}`; + } + getPeerFunkyName(peerID) { + let { first: adjective, second: snake } = this.funkyName(peerID, this.adjectives, this.snakes); + return `${adjective}_${snake}`; + } getUsername() { let username = localStorage.getItem("dandelion_username"); if (username && username !== "not_set") { return username; } - let { first: adjective, second: animal } = this.funkyName(this.userID, this.adjectives, this.animals); - username = `${adjective}_${animal}`; + username = this.getUserFunkyName(this.userID); 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}`; + let peername = this.getPeerFunkyName(this.peerID); return peername; } setFont(fontName, fontSize) { @@ -792,6 +883,7 @@ export class App { this.isArchivePeer = urlParams.has('archive'); this.isBootstrapPeer = urlParams.has("bootstrap"); console.log(`[headless]${this.isHeadless} [archive] ${this.isArchivePeer} [bootstrap] ${this.isBootstrapPeer}`); + this.statusBar.setHeadless(this.isHeadless); let limitPostsParam = urlParams.get('limitPosts'); if (limitPostsParam) { this.limitPosts = parseInt(limitPostsParam);