Repository navigation
Expand file tree
/
Copy pathrelay.ts
More file actions
129 lines (111 loc) · 3.62 KB
/
Copy pathrelay.ts
File metadata and controls
129 lines (111 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import { MemoryKvStore } from "@fedify/fedify";
import { createRelay, type Relay, type RelayType } from "@fedify/relay";
import { SqliteKvStore } from "@fedify/sqlite";
import { getLogger } from "@logtape/logtape";
import type { InferValue } from "@optique/core";
import Table from "cli-table3";
import process from "node:process";
import { DatabaseSync } from "node:sqlite";
import ora from "ora";
import { configureLogging } from "./log.ts";
import type { GlobalOptions } from "./options.ts";
import { tableStyle } from "./table.ts";
import { spawnTemporaryServer, type TemporaryServer } from "./tempserver.ts";
import { colors, matchesActor } from "./utils.ts";
const logger = getLogger(["fedify", "cli", "relay"]);
type RelayCommand =
& InferValue<typeof import("./relay/command.ts").relayCommand>
& GlobalOptions;
export async function runRelay(
command: RelayCommand,
): Promise<void> {
if (command.debug) {
await configureLogging();
}
const spinner = ora({
text: "Starting relay server...",
discardStdin: false,
}).start();
let kv: MemoryKvStore | SqliteKvStore;
if (command.persistent) {
logger.debug("Using SQLite storage at {path}.", {
path: command.persistent,
});
const db = new DatabaseSync(command.persistent);
kv = new SqliteKvStore(db);
} else {
logger.debug("Using in-memory storage.");
kv = new MemoryKvStore();
}
// deno-lint-ignore prefer-const
let relay: Relay;
let server: TemporaryServer | null = null;
const acceptFollows: string[] = [];
const rejectFollows: string[] = [];
if (command.acceptFollow != null && command.acceptFollow.length > 0) {
acceptFollows.push(...(command.acceptFollow ?? []));
}
if (command.rejectFollow != null && command.rejectFollow.length > 0) {
rejectFollows.push(...(command.rejectFollow ?? []));
}
server = await spawnTemporaryServer(async (request) => {
return await relay.fetch(request);
}, {
noTunnel: !command.tunnel,
port: command.port,
...(command.tunnel && { service: command.tunnelService }),
});
relay = createRelay(
command.protocol as RelayType,
{
origin: server?.url.origin,
name: command.name,
kv: kv,
subscriptionHandler: async (_ctx, actor) => {
const isInAcceptList = await matchesActor(actor, acceptFollows);
const isInRejectList = await matchesActor(actor, rejectFollows);
return isInAcceptList && !isInRejectList;
},
},
);
spinner.succeed(
`Relay server is running: ${colors.green(server.url.href)}`,
);
await printRelayInfo(relay, {
protocol: command.protocol,
name: command.name,
persistent: command.persistent,
});
// Handle graceful shutdown
process.on("SIGINT", async () => {
spinner.start("Shutting down relay server...");
await server.close();
spinner.succeed("Relay server stopped.");
process.exit(0);
});
}
interface RelayInfoOptions {
protocol: string;
name: string;
persistent?: string;
}
async function printRelayInfo(
relay: Relay,
options: RelayInfoOptions,
): Promise<void> {
const actorUri = await relay.getActorUri();
const sharedInboxUri = await relay.getSharedInboxUri();
const table = new Table({
chars: tableStyle,
style: { head: [], border: [] },
});
table.push(
{ "Actor URI:": colors.green(actorUri.href) },
{ "Shared Inbox:": colors.green(sharedInboxUri.href) },
{ "Protocol:": colors.green(options.protocol) },
{ "Name:": colors.green(options.name) },
{ "Storage:": colors.green(options.persistent ?? "in-memory") },
);
console.log(table.toString());
console.log("\nPress ^C to stop the relay server.");
}