-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathstate-handler.ts
More file actions
104 lines (89 loc) · 2.7 KB
/
Copy pathstate-handler.ts
File metadata and controls
104 lines (89 loc) · 2.7 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
import got from "got";
import {Logger} from "./logger.js";
import {Ticker} from "./ticker.js";
import {to} from "./utils.js";
import {io} from "socket.io-client";
export interface StateKing {
bind_port: number;
host: string;
ports: string;
shutting_down: boolean;
beat: number;
location: string;
noise_public_key: string | null;
}
export interface StateLing {
ling_id: string;
shutting_down: boolean;
beat: number;
}
export interface StateService {
name: string;
token: string;
service_id: string;
ling_id: string;
preferred_location: string;
ling_ready: boolean;
king_ready: boolean;
host: string | null;
bind_port: number | null;
remote_port: number | null;
}
export interface State {
services: StateService[];
kings: StateKing[];
lings: StateLing[];
revision: number;
}
interface StateHandlerOpts {
logger: Logger;
councilHost: string;
stateChanged: (state: State) => Promise<void> | void;
}
export class StateHandler extends Ticker {
private readonly logger;
private readonly stateChanged;
private readonly councilHost;
private readonly socketIo;
private state: State | null = null;
constructor ({logger, councilHost, stateChanged}: StateHandlerOpts) {
super({interval: 5000, tick: async () => await this.fetchState()});
this.stateChanged = stateChanged;
this.councilHost = councilHost;
this.logger = logger;
this.socketIo = io(councilHost);
this.socketIo.on("connect", () => {
logger.info("socket.io connected");
});
this.socketIo.on("disconnected", () => {
logger.info("socket.io disconnected");
});
this.socketIo.on("state-changed", async () => {
logger.info("State changed event received force ticking");
await this.forceTick();
});
}
hasState () {
return this.state !== null;
}
stop () {
super.stop();
this.socketIo.disconnect();
}
async fetchState () {
const logger = this.logger;
const [err, response] = await to(got.get(`${this.councilHost}/state`));
if (err || response.statusCode !== 200) {
return logger.error("Failed to fetch state from council", {
"error.message": err?.message,
"error.stack_trace": err?.stack,
"http.response.status_code": response?.statusCode,
});
}
const newState = JSON.parse(response.body) as State;
if (this.state === null || this.state.revision !== newState.revision) {
this.state = newState;
await this.stateChanged(newState);
}
}
}