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