api.ts
1 2 // So need to return an array of users with their trust levels of other users 3 // included, and then the frontend can parse that. 4 5 /** 6 * The whole world kind of needs to be loaded and cached here, and then you can 7 * request it from the perspective of a user and only the relevant things to 8 * that user are returned instead of the entire world. So that the client has the 9 * minimal stuff to render, while the server caches the world in memory. 10 * 11 * Need some way of the server world auto-updating and caching when new messages 12 * come in from the network too. How would that work? Need some kind of automatic 13 * state and flow update. 14 */ 15 16 import express from 'express' 17 import levelup from 'levelup'; 18 import leveldown from 'leveldown'; 19 import { createClient } from 'redis'; 20 import { User } from './models'; 21 22 23 const app = express(); 24 25 const MAX_USER_ID = 200000; 26 const MAX_DEPTH = 3; 27 const db = levelup(leveldown('./likesdb')) 28 29 let client; 30 let totalGets = 0; 31 32 type UserData = Record<string, string> 33 34 const users: User[] = []; 35 36 async function getSingleUserData(userId, depth = 1): Promise<UserData> { 37 let userData = {}; 38 try { 39 totalGets++; 40 userData = await client.get(userId); 41 } catch (e) { 42 return {}; 43 } 44 if (!userData) { 45 return {}; 46 } 47 const userDataObject = JSON.parse(userData.toString()); 48 return userDataObject 49 } 50 51 async function getMultiUserData(userData: UserData, depth = 1) { 52 if (!userData) { 53 return {}; 54 } 55 if (depth >= MAX_DEPTH) { 56 return userData; 57 } 58 const subUserKeys = Object.keys(userData); 59 totalGets++; 60 const subUserData = await client.mGet(subUserKeys); 61 const userDataFilled = await Promise.all( 62 subUserData.map(async (userData) => { 63 const expandedData = await getMultiUserData(JSON.parse(userData), ++depth); 64 return expandedData; 65 }) 66 ); 67 return userDataFilled; 68 } 69 70 async function loadUsers(maxUserId) { 71 console.time("loadUsers"); 72 console.log("Loading Users"); 73 for (let i = 0; i < maxUserId; i++) { 74 users[i] = new User(i); 75 } 76 77 console.log("Setting trust levels"); 78 for (let i = 0; i < maxUserId; i++) { 79 let userData; 80 try { 81 userData = await db.get(i.toString()); 82 } catch (e) { 83 continue; 84 } 85 if (!userData) continue; 86 const userDataObject = JSON.parse(userData.toString()); 87 Object.entries(userDataObject).forEach(([id, trust]) => { 88 try { 89 users[i].trustUser(users[id], trust); 90 } catch (e) { 91 // Ignore 92 } 93 }); 94 } 95 96 console.timeEnd("loadUsers"); 97 } 98 99 async function getUserTrustLevels(userId): Promise<Record<string, number>> { 100 const user = users[Number(userId)]; 101 console.log("User: ", user); 102 user.calculateTrust(MAX_DEPTH); 103 return user.getTrustLevels(); 104 } 105 106 async function init() { 107 await db.open(); 108 client = await createClient() 109 .on('error', err => console.log('Redis Client Error', err)) 110 .connect(); 111 await loadUsers(MAX_USER_ID); 112 } 113 114 app.get('/user/:id', async (req, res) => { 115 totalGets = 0; 116 const id = req.params.id; 117 console.log("Getting user ", id); 118 console.time('getUserData'); 119 const userTrustLevels = await getUserTrustLevels(req.params.id); 120 console.timeEnd('getUserData'); 121 console.log("Total gets: ", totalGets); 122 res.json(userTrustLevels); 123 }); 124 125 init(); 126 console.log("Api running"); 127 app.listen(4000);