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 });