WIP
This commit is contained in:
24
main.go
24
main.go
@@ -77,7 +77,7 @@ func removePeer(peerID string, peer *Peer) {
|
|||||||
for userID, peers := range userPeers {
|
for userID, peers := range userPeers {
|
||||||
delete(peers, peerID)
|
delete(peers, peerID)
|
||||||
if len(peers) == 0 {
|
if len(peers) == 0 {
|
||||||
delete(userPeers, userID)
|
delete(userPeers, userID) // not safe need mutex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,13 +114,13 @@ func handleWebSocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
for {
|
for {
|
||||||
_, message, err := conn.ReadMessage()
|
_, message, err := conn.ReadMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("ReadMessage error:", err)
|
log.Println("ReadMessage error:", err, connectionPeers[conn])
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
peer.lastActive = time.Now()
|
peer.lastActive = time.Now()
|
||||||
|
|
||||||
fmt.Println("ws<-", connectionPeers[conn], ":", string(message[:min(80, len(message))]))
|
// fmt.Println("ws<-", connectionPeers[conn], ":", string(message[:min(80, len(message))]))
|
||||||
|
|
||||||
response, err := dispatchMessage(message, peer)
|
response, err := dispatchMessage(message, peer)
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@ func writePump(peer *Peer) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
peer.conn.SetWriteDeadline(time.Now().Add(writeWait))
|
peer.conn.SetWriteDeadline(time.Now().Add(writeWait))
|
||||||
fmt.Println("ws->", connectionPeers[peer.conn], ":", string(message[:min(80, len(message))]))
|
// fmt.Println("ws->", connectionPeers[peer.conn], ":", string(message[:min(80, len(message))]))
|
||||||
|
|
||||||
err := peer.conn.WriteMessage(websocket.TextMessage, message)
|
err := peer.conn.WriteMessage(websocket.TextMessage, message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -195,7 +195,9 @@ func handleHello(message []byte, peer *Peer) ([]byte, error) {
|
|||||||
var m struct {
|
var m struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
UserID string `json:"user_id"`
|
UserID string `json:"user_id"`
|
||||||
|
UserName string `json:"user_name"`
|
||||||
PeerID string `json:"peer_id"`
|
PeerID string `json:"peer_id"`
|
||||||
|
PeerName string `json:"peer_name"`
|
||||||
KnownUsers []string `json:"known_users"`
|
KnownUsers []string `json:"known_users"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +205,7 @@ func handleHello(message []byte, peer *Peer) ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// log.Printf("Received hello from peer: %s, user:%s", m.PeerID, m.UserID)
|
log.Printf("Received hello from peer %s:%s, user %s:%s", m.PeerID[0:5], m.PeerName, m.UserID[0:5], m.UserName)
|
||||||
if userPeers[m.UserID] == nil {
|
if userPeers[m.UserID] == nil {
|
||||||
userPeers[m.UserID] = make(PeerSet)
|
userPeers[m.UserID] = make(PeerSet)
|
||||||
}
|
}
|
||||||
@@ -238,10 +240,12 @@ func handlePeerMessage(message []byte, peer *Peer) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PeerMessage struct {
|
type PeerMessage struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
To string `json:"to"`
|
FromUserName string `json:"from_username"`
|
||||||
Message InnerMessage `json:"message"`
|
FromPeerName string `json:"from_peername"`
|
||||||
|
To string `json:"to"`
|
||||||
|
Message InnerMessage `json:"message"`
|
||||||
}
|
}
|
||||||
var m PeerMessage
|
var m PeerMessage
|
||||||
|
|
||||||
@@ -249,7 +253,7 @@ func handlePeerMessage(message []byte, peer *Peer) ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("peer message type %s from %s to %s with message length %d\n", m.Message.Type, m.From, m.To, len(message))
|
fmt.Printf("peer message type %s from %s:%s:%s to %s with message length %d\n", m.Message.Type, m.From[0:5], m.FromPeerName, m.FromUserName, m.To[0:5], len(message))
|
||||||
|
|
||||||
toPeer := peerConnections[m.To]
|
toPeer := peerConnections[m.To]
|
||||||
|
|
||||||
|
|||||||
161
src/main.ts
161
src/main.ts
@@ -1,7 +1,4 @@
|
|||||||
// TODO: virtual list, only rerender what's needed so things can keep playing.
|
// TODO: virtual list, only rerender what's needed so things can keep playing.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import { getData, addData, addDataArray, clearData, deleteData, mergeDataArray, getAllData, checkPostIds, getAllIds, getPostsByIds } from "./db.js"
|
import { getData, addData, addDataArray, clearData, deleteData, mergeDataArray, getAllData, checkPostIds, getAllIds, getPostsByIds } from "./db.js"
|
||||||
|
|
||||||
declare let WebTorrent: any;
|
declare let WebTorrent: any;
|
||||||
@@ -80,7 +77,9 @@ function uuidToBase58(uuid: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function logID(ID: string) {
|
||||||
|
return ID.substring(0, 5);
|
||||||
|
}
|
||||||
|
|
||||||
let logLines: string[] = [];
|
let logLines: string[] = [];
|
||||||
let logLength = 10;
|
let logLength = 10;
|
||||||
@@ -205,6 +204,26 @@ async function base64ToArrayBuffer(base64String: string) {
|
|||||||
// return buffer;
|
// return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function compressString(input: string) {
|
||||||
|
// 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 {
|
class wsConnection {
|
||||||
websocket: WebSocket | null = null;
|
websocket: WebSocket | null = null;
|
||||||
userID = "";
|
userID = "";
|
||||||
@@ -218,10 +237,11 @@ class wsConnection {
|
|||||||
peerMessageHandlers: Map<string, (data: any) => void> = new Map();
|
peerMessageHandlers: Map<string, (data: any) => void> = new Map();
|
||||||
|
|
||||||
|
|
||||||
send(message: any) {
|
async send(message: any) {
|
||||||
let json = ""
|
let json = ""
|
||||||
try {
|
try {
|
||||||
json = JSON.stringify(message);
|
json = JSON.stringify(message);
|
||||||
|
// console.log("*******", (await compressString(json)).byteLength, json.length);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e, "wsConnection send: Couldn't serialize message", message);
|
console.log(e, "wsConnection send: Couldn't serialize message", message);
|
||||||
}
|
}
|
||||||
@@ -242,7 +262,7 @@ class wsConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
users = [...users, ...Object.entries(data.userPeers)];
|
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) {
|
for (let [userID, peerIDs] of users) {
|
||||||
this.peers.set(userID, [...Object.keys(peerIDs as any)]);
|
this.peers.set(userID, [...Object.keys(peerIDs as any)]);
|
||||||
@@ -252,10 +272,12 @@ class wsConnection {
|
|||||||
continue;
|
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({
|
this.send({
|
||||||
type: "peer_message",
|
type: "peer_message",
|
||||||
from: this.peerID,
|
from: this.peerID,
|
||||||
|
from_username: app.username,
|
||||||
|
from_peername: app.peername,
|
||||||
to: peerID,
|
to: peerID,
|
||||||
message: { type: "get_post_ids_for_user", user_id: userID }
|
message: { type: "get_post_ids_for_user", user_id: userID }
|
||||||
})
|
})
|
||||||
@@ -270,23 +292,24 @@ class wsConnection {
|
|||||||
// log(`getPostsForUserResponse: ${data}`)
|
// log(`getPostsForUserResponse: ${data}`)
|
||||||
|
|
||||||
let message = data.message;
|
let message = data.message;
|
||||||
log(`Network: got ${message.post_ids.length} post IDs for user ${data.message.user_id} from peer ${data.from}`);
|
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...`);
|
// console.log(`Checking post IDs...`);
|
||||||
|
|
||||||
let postIds = await checkPostIds(message.user_id, data.message.post_ids);
|
let postIds = await checkPostIds(message.user_id, data.message.post_ids);
|
||||||
if (postIds.length === 0) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log(`Network: requesting ${postIds.length} posts for user ${message.user_id} from peer ${data.from}`)
|
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, message: { type: "get_posts_for_user", post_ids: postIds, 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", post_ids: postIds, user_id: message.user_id } }
|
||||||
|
|
||||||
this.send(responseMessage);
|
this.send(responseMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// static async compressArrayBuffer(data: ArrayBuffer): Promise<ArrayBuffer> {
|
// static async compressArrayBuffer(data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
// const compressionStream = new CompressionStream('gzip'); // You can also use 'deflate', 'deflate-raw', etc.
|
// const compressionStream = new CompressionStream('gzip'); // You can also use 'deflate', 'deflate-raw', etc.
|
||||||
|
|
||||||
@@ -303,12 +326,12 @@ class wsConnection {
|
|||||||
let message = data.message;
|
let message = data.message;
|
||||||
let postIds = await getAllIds(message.user_id) ?? [];
|
let postIds = await getAllIds(message.user_id) ?? [];
|
||||||
if (postIds.length === 0) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
log(`Network: Sending ${postIds.length} post Ids for user ${message.user_id} to peer ${data.from}`)
|
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, message: { type: "get_post_ids_for_user_response", post_ids: postIds, 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_post_ids_for_user_response", post_ids: postIds, user_id: message.user_id } }
|
||||||
this.send(responseMessage);
|
this.send(responseMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,7 +340,7 @@ class wsConnection {
|
|||||||
let message = data.message;
|
let message = data.message;
|
||||||
let posts = await getPostsByIds(message.user_id, message.post_ids) ?? [];
|
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();
|
app.timerStart();
|
||||||
let output = [];
|
let output = [];
|
||||||
@@ -338,7 +361,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 newPost = post.data; if (newPost.image_data){newPost.image_data = arraybufferto};return newPost});
|
||||||
// posts = posts.map((post:any)=>{})
|
// 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)
|
this.send(responseMessage)
|
||||||
let sendTime = app.timerDelta();
|
let sendTime = app.timerDelta();
|
||||||
|
|
||||||
@@ -350,8 +373,7 @@ class wsConnection {
|
|||||||
async getPostsForUserReponseHandler(data: any) {
|
async getPostsForUserReponseHandler(data: any) {
|
||||||
app.timerStart();
|
app.timerStart();
|
||||||
let message = data.message;
|
let message = data.message;
|
||||||
console.log(`Network: got ${message.posts.length} posts for user ${message.user_id} from peer ${data.from}`);
|
console.log(`Net: got ${message.posts.length} posts for user ${logID(message.user_id)} from peer ${logID(data.from)}`);
|
||||||
console.log(`getPostsForUserResponseHandler Got ${message.posts.length} from peer ${data.from}`);
|
|
||||||
for (let post of message.posts) {
|
for (let post of message.posts) {
|
||||||
if (message.user_id === app.userID) {
|
if (message.user_id === app.userID) {
|
||||||
post.author_id = app.userID;
|
post.author_id = app.userID;
|
||||||
@@ -406,9 +428,10 @@ class wsConnection {
|
|||||||
|
|
||||||
this.websocket.onopen = async (event) => {
|
this.websocket.onopen = async (event) => {
|
||||||
log("ws:connected");
|
log("ws:connected");
|
||||||
|
|
||||||
let knownUsers = [...(await indexedDB.databases())].map((db) => db.name?.replace('user_', ''));
|
let knownUsers = [...(await indexedDB.databases())].map((db) => db.name?.replace('user_', ''));
|
||||||
console.log('Network: Sending known users', knownUsers);
|
console.log('Net: Sending known users', knownUsers);
|
||||||
this.send({ type: "hello", user_id: this.userID, peer_id: this.peerID, 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(() => {
|
this.websocketPingInterval = window.setInterval(() => {
|
||||||
if (!navigator.onLine) {
|
if (!navigator.onLine) {
|
||||||
return;
|
return;
|
||||||
@@ -477,8 +500,10 @@ class wsConnection {
|
|||||||
|
|
||||||
class App {
|
class App {
|
||||||
username: string = '';
|
username: string = '';
|
||||||
|
peername: string = '';
|
||||||
userID: string = '';
|
userID: string = '';
|
||||||
peerID: string = '';
|
peerID: string = '';
|
||||||
|
following: string[] = [];
|
||||||
posts: Post[] = [];
|
posts: Post[] = [];
|
||||||
isHeadless: boolean = false;
|
isHeadless: boolean = false;
|
||||||
showLog: boolean = false;
|
showLog: boolean = false;
|
||||||
@@ -640,7 +665,7 @@ class App {
|
|||||||
|
|
||||||
let post = new Post(this.username, userID, postText, new Date(), mediaData);
|
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));
|
// localStorage.setItem(key, JSON.stringify(posts));
|
||||||
addData(userID, post)
|
addData(userID, post)
|
||||||
|
|
||||||
@@ -674,10 +699,11 @@ class App {
|
|||||||
|
|
||||||
animals = ['shrew', 'jerboa', 'lemur', 'weasel', 'possum', 'possum', 'marmoset', 'planigale', 'mole', 'narwhal'];
|
animals = ['shrew', 'jerboa', 'lemur', 'weasel', 'possum', 'possum', 'marmoset', 'planigale', 'mole', 'narwhal'];
|
||||||
adjectives = ['snazzy', 'whimsical', 'jazzy', 'bonkers', 'wobbly', 'spiffy', 'chirpy', 'zesty', 'bubbly', 'perky', 'sassy'];
|
adjectives = ['snazzy', 'whimsical', 'jazzy', 'bonkers', 'wobbly', 'spiffy', 'chirpy', 'zesty', 'bubbly', 'perky', 'sassy'];
|
||||||
|
snakes = ['mamba', 'cobra', 'python', 'viper', 'krait', 'sidewinder', 'constrictor', 'boa', 'asp', 'anaconda', 'krait']
|
||||||
|
|
||||||
hashUserIdToIndices() {
|
hashIdToIndices(id: string) {
|
||||||
let indices = [];
|
let indices = [];
|
||||||
for (let char of this.userID) {
|
for (let char of id) {
|
||||||
if (char !== '0' && char !== '-') {
|
if (char !== '0' && char !== '-') {
|
||||||
indices.push(parseInt(char, 16));
|
indices.push(parseInt(char, 16));
|
||||||
if (indices.length == 2) {
|
if (indices.length == 2) {
|
||||||
@@ -688,20 +714,33 @@ class App {
|
|||||||
return [indices[0], indices[1]];
|
return [indices[0], indices[1]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
funkyName(id: string, listOne: string[], listTwo: string[]) {
|
||||||
|
let [one, two] = this.hashIdToIndices(id);
|
||||||
|
let first = listOne[one % this.adjectives.length];
|
||||||
|
let second = listTwo[two % this.animals.length];
|
||||||
|
return { first, second }
|
||||||
|
}
|
||||||
|
|
||||||
getUsername() {
|
getUsername() {
|
||||||
let username = localStorage.getItem("dandelion_username");
|
let username = localStorage.getItem("dandelion_username");
|
||||||
|
|
||||||
if (!username || username === "not_set") {
|
if (username && username !== "not_set") {
|
||||||
let [one, two] = this.hashUserIdToIndices();
|
return username;
|
||||||
let adjective = this.adjectives[one % this.adjectives.length]
|
|
||||||
let animal = this.animals[two % this.animals.length]
|
|
||||||
username = `${adjective}_${animal}`
|
|
||||||
localStorage.setItem("dandelion_username", username);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let { first: adjective, second: animal } = this.funkyName(this.userID, this.adjectives, this.animals);
|
||||||
|
username = `${adjective}_${animal}`
|
||||||
|
localStorage.setItem("dandelion_username", username);
|
||||||
|
|
||||||
return 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: string, fontSize: string) {
|
setFont(fontName: string, fontSize: string) {
|
||||||
|
|
||||||
let content = document.getElementById('content');
|
let content = document.getElementById('content');
|
||||||
@@ -972,7 +1011,14 @@ class App {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
this.username = this.getUsername();
|
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);
|
this.initButtons(userID, this.posts, registration);
|
||||||
|
|
||||||
@@ -1024,7 +1070,14 @@ class App {
|
|||||||
// posts that are not in our list that we need at add
|
// posts that are not in our list that we need at add
|
||||||
// posts that are in our list that we need to remove
|
// posts that are in our list that we need to remove
|
||||||
|
|
||||||
// postsSet = new Set();
|
|
||||||
|
renderedPosts = new Map();
|
||||||
|
computeDiff(newPosts: []) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// return {added, deleted, same}
|
||||||
|
}
|
||||||
|
|
||||||
async render() {
|
async render() {
|
||||||
if (this.isHeadless) {
|
if (this.isHeadless) {
|
||||||
@@ -1033,37 +1086,51 @@ class App {
|
|||||||
}
|
}
|
||||||
this.timerStart();
|
this.timerStart();
|
||||||
|
|
||||||
let posts = [];
|
|
||||||
|
let existingPosts = this.posts;
|
||||||
|
|
||||||
|
this.posts = [];
|
||||||
switch (this.router.route) {
|
switch (this.router.route) {
|
||||||
case App.Route.HOME:
|
case App.Route.HOME:
|
||||||
case App.Route.CONNECT: {
|
case App.Route.CONNECT: {
|
||||||
posts = await this.loadPosts(this.userID) ?? [];
|
this.posts= await this.loadPosts(this.userID) ?? [];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case App.Route.USER: {
|
case App.Route.USER: {
|
||||||
posts = await this.loadPosts(this.router.userID) ?? [];
|
this.posts= await this.loadPosts(this.router.userID) ?? [];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case App.Route.POST: {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
console.log("Render: got a route I didn't understand. Rendering HOME:", this.router.route);
|
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;
|
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();
|
const fragment = document.createDocumentFragment();
|
||||||
let contentDiv = document.getElementById("content");
|
let contentDiv = document.getElementById("content");
|
||||||
if (!contentDiv) {
|
if (!contentDiv) {
|
||||||
@@ -1072,10 +1139,12 @@ class App {
|
|||||||
contentDiv.innerHTML = "";
|
contentDiv.innerHTML = "";
|
||||||
// let count = 0;
|
// let count = 0;
|
||||||
|
|
||||||
for (let i = posts.length - 1; i >= 0; i--) {
|
for (let i = this.posts.length - 1; i >= 0; i--) {
|
||||||
let postData = posts[i];
|
let postData = this.posts[i];
|
||||||
// this.postsSet.add(postData);
|
// this.postsSet.add(postData);
|
||||||
|
|
||||||
|
|
||||||
|
// return promises for all image loads and await those.
|
||||||
let post = this.renderPost(postData);
|
let post = this.renderPost(postData);
|
||||||
|
|
||||||
if (post) {
|
if (post) {
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
<div id="info" style="display:none">
|
<div id="info" style="display:none">
|
||||||
<div id="profile">
|
<div id="profile">
|
||||||
<span class="form_label">username:</span><span class="form_field" id="username" contenteditable="true">unnamed</span>
|
<span class="form_label">username:</span><span class="form_field" id="username" contenteditable="true">unnamed</span>
|
||||||
|
<div id="ids"><div id="user_id"></div><div id="peer_id"></div><div id="peername"></div></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- <div id="following">
|
<!-- <div id="following">
|
||||||
<div>fiona</div>
|
<div>fiona</div>
|
||||||
|
|||||||
@@ -1,12 +1,31 @@
|
|||||||
|
@media (prefers-reduced-motion) {
|
||||||
|
/* styles to apply if a user's device settings are set to reduced motion */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--main-bg-color: black;
|
--main-bg-color: white;
|
||||||
--border-color:rgb(132,136,138);
|
--border-color:rgb(132,136,138);
|
||||||
--edge-color:rgb(60,60,60);
|
--edge-color:rgb(60,60,60);
|
||||||
--main-fg-color:rgb(202,208,211);
|
--main-fg-color:black;
|
||||||
--highlight-fg-color:rgb(255,255,255);
|
--highlight-fg-color:rgb(255,255,255);
|
||||||
--link-color:rgb(29, 155, 240);
|
--link-color:rgb(29, 155, 240);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--main-bg-color: black;
|
||||||
|
--border-color:rgb(132,136,138);
|
||||||
|
--edge-color:rgb(60,60,60);
|
||||||
|
--main-fg-color:rgb(202,208,211);
|
||||||
|
--highlight-fg-color:rgb(255,255,255);
|
||||||
|
--link-color:rgb(29, 155, 240);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
@@ -151,3 +170,7 @@ iframe {
|
|||||||
background-color: var(--highlight-fg-color);
|
background-color: var(--highlight-fg-color);
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ids {
|
||||||
|
font-size:xx-small;
|
||||||
|
}
|
||||||
140
static/main.js
140
static/main.js
@@ -59,6 +59,9 @@ function uuidToBase58(uuid) {
|
|||||||
const bytes = uuidToBytes(uuid);
|
const bytes = uuidToBytes(uuid);
|
||||||
return encodeBase58(bytes);
|
return encodeBase58(bytes);
|
||||||
}
|
}
|
||||||
|
function logID(ID) {
|
||||||
|
return ID.substring(0, 5);
|
||||||
|
}
|
||||||
let logLines = [];
|
let logLines = [];
|
||||||
let logLength = 10;
|
let logLength = 10;
|
||||||
function log(message) {
|
function log(message) {
|
||||||
@@ -142,11 +145,27 @@ async function base64ToArrayBuffer(base64String) {
|
|||||||
// let buffer = new Uint8Array(arrayBuffer);
|
// let buffer = new Uint8Array(arrayBuffer);
|
||||||
// return buffer;
|
// 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 {
|
class wsConnection {
|
||||||
send(message) {
|
async send(message) {
|
||||||
let json = "";
|
let json = "";
|
||||||
try {
|
try {
|
||||||
json = JSON.stringify(message);
|
json = JSON.stringify(message);
|
||||||
|
// console.log("*******", (await compressString(json)).byteLength, json.length);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
console.log(e, "wsConnection send: Couldn't serialize message", message);
|
console.log(e, "wsConnection send: Couldn't serialize message", message);
|
||||||
@@ -165,17 +184,19 @@ class wsConnection {
|
|||||||
console.log('helloResponseHandler', e);
|
console.log('helloResponseHandler', e);
|
||||||
}
|
}
|
||||||
users = [...users, ...Object.entries(data.userPeers)];
|
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) {
|
for (let [userID, peerIDs] of users) {
|
||||||
this.peers.set(userID, [...Object.keys(peerIDs)]);
|
this.peers.set(userID, [...Object.keys(peerIDs)]);
|
||||||
for (let peerID of [...Object.keys(peerIDs)]) {
|
for (let peerID of [...Object.keys(peerIDs)]) {
|
||||||
if (peerID === this.peerID) {
|
if (peerID === this.peerID) {
|
||||||
continue;
|
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({
|
this.send({
|
||||||
type: "peer_message",
|
type: "peer_message",
|
||||||
from: this.peerID,
|
from: this.peerID,
|
||||||
|
from_username: app.username,
|
||||||
|
from_peername: app.peername,
|
||||||
to: peerID,
|
to: peerID,
|
||||||
message: { type: "get_post_ids_for_user", user_id: userID }
|
message: { type: "get_post_ids_for_user", user_id: userID }
|
||||||
});
|
});
|
||||||
@@ -187,15 +208,15 @@ class wsConnection {
|
|||||||
async getPostIdsForUserResponseHandler(data) {
|
async getPostIdsForUserResponseHandler(data) {
|
||||||
// log(`getPostsForUserResponse: ${data}`)
|
// log(`getPostsForUserResponse: ${data}`)
|
||||||
let message = data.message;
|
let message = data.message;
|
||||||
log(`Network: got ${message.post_ids.length} post IDs for user ${data.message.user_id} from peer ${data.from}`);
|
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...`);
|
// console.log(`Checking post IDs...`);
|
||||||
let postIds = await checkPostIds(message.user_id, data.message.post_ids);
|
let postIds = await checkPostIds(message.user_id, data.message.post_ids);
|
||||||
if (postIds.length === 0) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
log(`Network: requesting ${postIds.length} posts for user ${message.user_id} from peer ${data.from}`);
|
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, message: { type: "get_posts_for_user", post_ids: postIds, 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", post_ids: postIds, user_id: message.user_id } };
|
||||||
this.send(responseMessage);
|
this.send(responseMessage);
|
||||||
}
|
}
|
||||||
// static async compressArrayBuffer(data: ArrayBuffer): Promise<ArrayBuffer> {
|
// static async compressArrayBuffer(data: ArrayBuffer): Promise<ArrayBuffer> {
|
||||||
@@ -210,18 +231,18 @@ class wsConnection {
|
|||||||
let message = data.message;
|
let message = data.message;
|
||||||
let postIds = await getAllIds(message.user_id) ?? [];
|
let postIds = await getAllIds(message.user_id) ?? [];
|
||||||
if (postIds.length === 0) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
log(`Network: Sending ${postIds.length} post Ids for user ${message.user_id} to peer ${data.from}`);
|
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, message: { type: "get_post_ids_for_user_response", post_ids: postIds, 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_post_ids_for_user_response", post_ids: postIds, user_id: message.user_id } };
|
||||||
this.send(responseMessage);
|
this.send(responseMessage);
|
||||||
}
|
}
|
||||||
// Send posts to peer
|
// Send posts to peer
|
||||||
async getPostsForUserHandler(data) {
|
async getPostsForUserHandler(data) {
|
||||||
let message = data.message;
|
let message = data.message;
|
||||||
let posts = await getPostsByIds(message.user_id, message.post_ids) ?? [];
|
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();
|
app.timerStart();
|
||||||
let output = [];
|
let output = [];
|
||||||
for (let post of posts) {
|
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 newPost = post.data; if (newPost.image_data){newPost.image_data = arraybufferto};return newPost});
|
||||||
// posts = posts.map((post:any)=>{})
|
// 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);
|
this.send(responseMessage);
|
||||||
let sendTime = app.timerDelta();
|
let sendTime = app.timerDelta();
|
||||||
log(`send took: ${sendTime.toFixed(2)}ms`);
|
log(`send took: ${sendTime.toFixed(2)}ms`);
|
||||||
@@ -246,8 +267,7 @@ class wsConnection {
|
|||||||
async getPostsForUserReponseHandler(data) {
|
async getPostsForUserReponseHandler(data) {
|
||||||
app.timerStart();
|
app.timerStart();
|
||||||
let message = data.message;
|
let message = data.message;
|
||||||
console.log(`Network: got ${message.posts.length} posts for user ${message.user_id} from peer ${data.from}`);
|
console.log(`Net: got ${message.posts.length} posts for user ${logID(message.user_id)} from peer ${logID(data.from)}`);
|
||||||
console.log(`getPostsForUserResponseHandler Got ${message.posts.length} from peer ${data.from}`);
|
|
||||||
for (let post of message.posts) {
|
for (let post of message.posts) {
|
||||||
if (message.user_id === app.userID) {
|
if (message.user_id === app.userID) {
|
||||||
post.author_id = app.userID;
|
post.author_id = app.userID;
|
||||||
@@ -294,8 +314,8 @@ class wsConnection {
|
|||||||
this.websocket.onopen = async (event) => {
|
this.websocket.onopen = async (event) => {
|
||||||
log("ws:connected");
|
log("ws:connected");
|
||||||
let knownUsers = [...(await indexedDB.databases())].map((db) => db.name?.replace('user_', ''));
|
let knownUsers = [...(await indexedDB.databases())].map((db) => db.name?.replace('user_', ''));
|
||||||
console.log('Network: Sending known users', knownUsers);
|
console.log('Net: Sending known users', knownUsers);
|
||||||
this.send({ type: "hello", user_id: this.userID, peer_id: this.peerID, 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(() => {
|
this.websocketPingInterval = window.setInterval(() => {
|
||||||
if (!navigator.onLine) {
|
if (!navigator.onLine) {
|
||||||
return;
|
return;
|
||||||
@@ -355,14 +375,22 @@ class wsConnection {
|
|||||||
class App {
|
class App {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.username = '';
|
this.username = '';
|
||||||
|
this.peername = '';
|
||||||
this.userID = '';
|
this.userID = '';
|
||||||
this.peerID = '';
|
this.peerID = '';
|
||||||
|
this.following = [];
|
||||||
this.posts = [];
|
this.posts = [];
|
||||||
this.isHeadless = false;
|
this.isHeadless = false;
|
||||||
this.showLog = false;
|
this.showLog = false;
|
||||||
this.time = 0;
|
this.time = 0;
|
||||||
this.animals = ['shrew', 'jerboa', 'lemur', 'weasel', 'possum', 'possum', 'marmoset', 'planigale', 'mole', 'narwhal'];
|
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.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 = {
|
this.router = {
|
||||||
route: App.Route.HOME,
|
route: App.Route.HOME,
|
||||||
userID: '',
|
userID: '',
|
||||||
@@ -490,7 +518,7 @@ class App {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let post = new Post(this.username, userID, postText, new Date(), mediaData);
|
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));
|
// localStorage.setItem(key, JSON.stringify(posts));
|
||||||
addData(userID, post);
|
addData(userID, post);
|
||||||
this.render();
|
this.render();
|
||||||
@@ -511,9 +539,9 @@ class App {
|
|||||||
}
|
}
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
hashUserIdToIndices() {
|
hashIdToIndices(id) {
|
||||||
let indices = [];
|
let indices = [];
|
||||||
for (let char of this.userID) {
|
for (let char of id) {
|
||||||
if (char !== '0' && char !== '-') {
|
if (char !== '0' && char !== '-') {
|
||||||
indices.push(parseInt(char, 16));
|
indices.push(parseInt(char, 16));
|
||||||
if (indices.length == 2) {
|
if (indices.length == 2) {
|
||||||
@@ -523,17 +551,27 @@ class App {
|
|||||||
}
|
}
|
||||||
return [indices[0], indices[1]];
|
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() {
|
getUsername() {
|
||||||
let username = localStorage.getItem("dandelion_username");
|
let username = localStorage.getItem("dandelion_username");
|
||||||
if (!username || username === "not_set") {
|
if (username && username !== "not_set") {
|
||||||
let [one, two] = this.hashUserIdToIndices();
|
return username;
|
||||||
let adjective = this.adjectives[one % this.adjectives.length];
|
|
||||||
let animal = this.animals[two % this.animals.length];
|
|
||||||
username = `${adjective}_${animal}`;
|
|
||||||
localStorage.setItem("dandelion_username", username);
|
|
||||||
}
|
}
|
||||||
|
let { first: adjective, second: animal } = this.funkyName(this.userID, this.adjectives, this.animals);
|
||||||
|
username = `${adjective}_${animal}`;
|
||||||
|
localStorage.setItem("dandelion_username", username);
|
||||||
return 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) {
|
setFont(fontName, fontSize) {
|
||||||
let content = document.getElementById('content');
|
let content = document.getElementById('content');
|
||||||
if (!content) {
|
if (!content) {
|
||||||
@@ -739,7 +777,11 @@ class App {
|
|||||||
registration = await this.registerServiceWorker();
|
registration = await this.registerServiceWorker();
|
||||||
// }
|
// }
|
||||||
this.username = this.getUsername();
|
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);
|
this.initButtons(userID, this.posts, registration);
|
||||||
let connectURL = `https://${document.location.hostname}/connect/${this.userID}`;
|
let connectURL = `https://${document.location.hostname}/connect/${this.userID}`;
|
||||||
document.getElementById('connectURL').innerHTML = `<a href="${connectURL}">connect</a>`;
|
document.getElementById('connectURL').innerHTML = `<a href="${connectURL}">connect</a>`;
|
||||||
@@ -771,43 +813,52 @@ class App {
|
|||||||
// file.appendTo(document.getElementById('torrent-content'));
|
// file.appendTo(document.getElementById('torrent-content'));
|
||||||
// })
|
// })
|
||||||
}
|
}
|
||||||
// keep a map of posts to dom nodes.
|
computeDiff(newPosts) {
|
||||||
// on re-render
|
// return {added, deleted, same}
|
||||||
// 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();
|
|
||||||
async render() {
|
async render() {
|
||||||
if (this.isHeadless) {
|
if (this.isHeadless) {
|
||||||
console.log('Headless so skipping render...');
|
console.log('Headless so skipping render...');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.timerStart();
|
this.timerStart();
|
||||||
let posts = [];
|
let existingPosts = this.posts;
|
||||||
|
this.posts = [];
|
||||||
switch (this.router.route) {
|
switch (this.router.route) {
|
||||||
case App.Route.HOME:
|
case App.Route.HOME:
|
||||||
case App.Route.CONNECT: {
|
case App.Route.CONNECT: {
|
||||||
posts = await this.loadPosts(this.userID) ?? [];
|
this.posts = await this.loadPosts(this.userID) ?? [];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case App.Route.USER: {
|
case App.Route.USER: {
|
||||||
posts = await this.loadPosts(this.router.userID) ?? [];
|
this.posts = await this.loadPosts(this.router.userID) ?? [];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case App.Route.POST: {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
console.log("Render: got a route I didn't understand. Rendering HOME:", this.router.route);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// let newPostsSet = new Set(posts.map(post=>post.post_id));
|
let existingPostSet = new Set(existingPosts.map(post => post.post_id));
|
||||||
// let newPosts = (newPostsSet as any).difference(this.postsSet);
|
let incomingPostSet = new Set(this.posts.map(post => post.post_id));
|
||||||
// // let removedPosts = (this.postsSet as any).difference(newPosts);
|
let addedPosts = [];
|
||||||
// let keepPosts = (this.postsSet as any).intersection(newPostsSet);
|
for (let post of this.posts) {
|
||||||
// let renderPosts = keepPosts.union(newPosts);
|
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();
|
const fragment = document.createDocumentFragment();
|
||||||
let contentDiv = document.getElementById("content");
|
let contentDiv = document.getElementById("content");
|
||||||
if (!contentDiv) {
|
if (!contentDiv) {
|
||||||
@@ -815,9 +866,10 @@ class App {
|
|||||||
}
|
}
|
||||||
contentDiv.innerHTML = "";
|
contentDiv.innerHTML = "";
|
||||||
// let count = 0;
|
// let count = 0;
|
||||||
for (let i = posts.length - 1; i >= 0; i--) {
|
for (let i = this.posts.length - 1; i >= 0; i--) {
|
||||||
let postData = posts[i];
|
let postData = this.posts[i];
|
||||||
// this.postsSet.add(postData);
|
// this.postsSet.add(postData);
|
||||||
|
// return promises for all image loads and await those.
|
||||||
let post = this.renderPost(postData);
|
let post = this.renderPost(postData);
|
||||||
if (post) {
|
if (post) {
|
||||||
fragment.appendChild(post);
|
fragment.appendChild(post);
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user