decentralised sync engine
1import { OWNER_DID, SERVER_PORT, SERVICE_DID } from "@/lib/env"; 2import { connectToShards, performHandshakes } from "@/lib/setup"; 3import { handshakeTokens, setRegistrationState } from "@/lib/state"; 4import type { AtUri } from "@/lib/types/atproto"; 5import { getRecordFromFullAtUri } from "@/lib/utils/atproto"; 6import { newErrorResponse } from "@/lib/utils/http/responses"; 7import { connectToPrism } from "@/lib/utils/prism"; 8import { 9 attachLatticeRegistrationListener, 10 wrapHttpRegistrationCheck, 11 wrapWsRegistrationCheck, 12} from "@/lib/utils/registration"; 13import { routes } from "@/routes"; 14import { setupServer } from "@/server"; 15 16const main = async () => { 17 const server = await setupServer(); 18 for (const [url, route] of Object.entries(routes)) { 19 if (!route.wsHandler) { 20 const { handler, method, skipRegistrationCheck } = route; 21 server.route({ 22 url, 23 method, 24 handler: skipRegistrationCheck 25 ? handler 26 : wrapHttpRegistrationCheck(handler), 27 }); 28 } else { 29 const { 30 wsHandler, 31 method, 32 handler: httpHandler, 33 preHandler, 34 skipRegistrationCheckHttp, 35 skipRegistrationCheckWs, 36 } = route; 37 const handler = 38 httpHandler ?? 39 (() => 40 newErrorResponse(404, { 41 message: 42 "This is a websocket only route. Did you mean to initiate a websocket connection here?", 43 })); 44 server.route({ 45 url, 46 method: method ?? "GET", 47 handler: skipRegistrationCheckHttp 48 ? handler 49 : wrapHttpRegistrationCheck(handler), 50 wsHandler: skipRegistrationCheckWs 51 ? wsHandler 52 : wrapWsRegistrationCheck(wsHandler), 53 preHandler, 54 }); 55 } 56 } 57 58 server.listen({ port: SERVER_PORT }).catch((err: unknown) => { 59 server.log.error(err); 60 process.exit(1); 61 }); 62 63 let latticeUrlOrigin = decodeURIComponent( 64 SERVICE_DID.startsWith("did:web:") ? SERVICE_DID.slice(8) : "", 65 ); 66 if (latticeUrlOrigin === "localhost") 67 latticeUrlOrigin += `:${SERVER_PORT.toString()}`; 68 if (latticeUrlOrigin === "") { 69 // TODO: resolve did:plc endpoint to get the origin of the lattice endpoint described by the did:plc doc 70 // for now we just throw. 71 throw new Error( 72 "did:plc support not yet implemented. Provide a did:web for now. did:plc support will come in the future.", 73 ); 74 } 75 76 const latticeAtUri: Required<AtUri> = { 77 // @ts-expect-error alas, template literal weirdness continues uwu 78 authority: OWNER_DID, 79 collection: "systems.gmstn.development.lattice", 80 rKey: latticeUrlOrigin, 81 }; 82 83 const latticeRecord = await getRecordFromFullAtUri(latticeAtUri); 84 85 if (latticeRecord.ok) { 86 setRegistrationState(true); 87 } 88 89 const prismWebsocket = connectToPrism({ 90 wantedCollections: ["systems.gmstn.development.*"], 91 }); 92 93 // TODO: probably move this to an `attachListeners` hook that attaches the listeners we want. 94 // least tested. will probably have nuances we need to work on in the future 95 attachLatticeRegistrationListener(prismWebsocket); 96 97 await performHandshakes(latticeAtUri); 98 99 const test = await connectToShards(); 100 console.log( 101 "connected to", 102 test.map((socket) => socket.url), 103 ); 104 105 // TODO: change this to the actual WS sessions 106 const handshakeTokenEntries = handshakeTokens.entries().toArray(); 107 108 if (handshakeTokenEntries.length === 0) { 109 console.warn( 110 "Warning: there are zero handshake tokens on this Lattice.", 111 ); 112 console.warn( 113 "If you're hacking locally, you might want to make sure that there's a running Shard as well.", 114 ); 115 // NOTE: might change in the future 116 console.warn( 117 "Channel records connecting a local Lattice to a production Shard are not supported (for now). Local Lattices must point to a local Shard.", 118 ); 119 } 120}; 121 122main() 123 .then(() => { 124 console.log(`Server is running on port ${SERVER_PORT.toString()}`); 125 }) 126 .catch((err: unknown) => { 127 console.error("Something went wrong :("); 128 console.error( 129 "=========================== FULL ERROR BELOW ===========================", 130 ); 131 console.error(err); 132 });