decentralised message store
at main 4.1 kB view raw
1import { setupDbWithMigrations } from "@/db"; 2import { DB_URL, OWNER_DID, SERVER_PORT, SERVICE_DID } from "@/lib/env"; 3import { setRegistrationState } from "@/lib/state"; 4import type { AtUri } from "@/lib/types/atproto"; 5import { getRecordFromAtUri } from "@/lib/utils/atproto"; 6import { newErrorResponse } from "@/lib/utils/http/responses"; 7import { connectToPrism } from "@/lib/utils/prism"; 8import { 9 attachShardRegistrationListener, 10 wrapHttpRegistrationCheck, 11 wrapWsRegistrationCheck, 12} from "@/lib/utils/registration"; 13import { routes } from "@/routes"; 14import { setupServer } from "@/server"; 15 16const main = async () => { 17 if (DB_URL === ":memory:" || DB_URL.startsWith("file:")) { 18 console.log("migrating db") 19 await setupDbWithMigrations("./drizzle"); 20 } 21 22 const server = await setupServer(); 23 for (const [url, route] of Object.entries(routes)) { 24 console.log("Registering route", url); 25 if (!route.wsHandler) { 26 const { handler, method, skipRegistrationCheck } = route; 27 server.route({ 28 url, 29 method, 30 handler: skipRegistrationCheck 31 ? handler 32 : wrapHttpRegistrationCheck(handler), 33 }); 34 } else { 35 const { 36 wsHandler, 37 method, 38 handler: httpHandler, 39 preHandler, 40 skipRegistrationCheckHttp, 41 skipRegistrationCheckWs, 42 } = route; 43 44 const handler = 45 httpHandler ?? 46 (() => 47 newErrorResponse(404, { 48 message: 49 "This is a websocket only route. Did you mean to initiate a websocket connection here?", 50 })); 51 52 server.register(() => { 53 server.route({ 54 url, 55 method: method ?? "GET", 56 handler: skipRegistrationCheckHttp 57 ? handler 58 : wrapHttpRegistrationCheck(handler), 59 wsHandler: skipRegistrationCheckWs 60 ? wsHandler 61 : wrapWsRegistrationCheck(wsHandler), 62 preHandler, 63 }); 64 }); 65 } 66 } 67 68 server.listen({ port: SERVER_PORT, host: "::" }).catch((err: unknown) => { 69 server.log.error(err); 70 process.exit(1); 71 }); 72 73 let shardUrlOrigin = decodeURIComponent( 74 SERVICE_DID.startsWith("did:web:") ? SERVICE_DID.slice(8) : "", 75 ); 76 if (shardUrlOrigin === "localhost") 77 shardUrlOrigin += `:${SERVER_PORT.toString()}`; 78 if (shardUrlOrigin === "") { 79 // TODO: resolve did:plc endpoint to get the origin of the shard endpoint described by the did:plc doc 80 // for now we just throw. 81 throw new Error( 82 "did:plc support not yet implemented. Provide a did:web for now. did:plc support will come in the future.", 83 ); 84 } 85 86 const shardAtUri: Required<AtUri> = { 87 // @ts-expect-error alas, template literal weirdness continues uwu 88 authority: OWNER_DID, 89 collection: "systems.gmstn.development.shard", 90 rKey: shardUrlOrigin, 91 }; 92 93 const shardRecord = await getRecordFromAtUri(shardAtUri); 94 95 if (shardRecord.ok) { 96 setRegistrationState(true); 97 } 98 99 const prismWebsocket = connectToPrism({ 100 wantedCollections: ["systems.gmstn.development.*"], 101 }); 102 103 // TODO: probably move this to an `attachListeners` hook that attaches the listeners we want. 104 // least tested. will probably have nuances we need to work on in the future 105 attachShardRegistrationListener(prismWebsocket); 106}; 107 108main() 109 .then(() => { 110 console.log(`Server is running on port ${SERVER_PORT.toString()}`); 111 }) 112 .catch((err: unknown) => { 113 console.error("Something went wrong :("); 114 console.error( 115 "=========================== FULL ERROR BELOW ===========================", 116 ); 117 console.error(err); 118 });