moons-ta-client 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/scraper.ts ADDED
@@ -0,0 +1,137 @@
1
+ import { CustomEventEmitter } from "./custom-event-emitter.js";
2
+ import { CoreServer, Tournament } from "./models/models.js";
3
+ import { TAClient } from "./tournament-assistant-client.js";
4
+
5
+ const MASTER_ADDRESS = "server.tournamentassistant.net";
6
+ const MASTER_PORT = "8676";
7
+
8
+ type OnProgress = {
9
+ totalServers: number;
10
+ succeededServers: number;
11
+ failedServers: number;
12
+ tournaments: Tournament[];
13
+ };
14
+
15
+ type ScraperEvents = {
16
+ onProgress: OnProgress;
17
+ };
18
+
19
+ export function getTournaments(
20
+ token: string,
21
+ onProgress: (
22
+ totalServers: number,
23
+ succeededServers: number,
24
+ failedServers: number
25
+ ) => void,
26
+ onComplete: (tournaments: Tournament[]) => void
27
+ ) {
28
+ const scraper = new Scraper(token);
29
+ scraper.on("onProgress", (progress) => {
30
+ onProgress(
31
+ progress.totalServers,
32
+ progress.succeededServers,
33
+ progress.failedServers
34
+ );
35
+
36
+ if (
37
+ progress.failedServers + progress.succeededServers ===
38
+ progress.totalServers
39
+ ) {
40
+ onComplete(progress.tournaments);
41
+ }
42
+ });
43
+ scraper.getTournaments();
44
+ }
45
+
46
+ class Scraper extends CustomEventEmitter<ScraperEvents> {
47
+ private servers: CoreServer[] = [];
48
+ private tournaments: Tournament[] = [];
49
+ private token: string;
50
+
51
+ private succeededServers = 0;
52
+ private failedServers = 0;
53
+
54
+ constructor(token: string) {
55
+ super();
56
+ this.token = token;
57
+ }
58
+
59
+ public getTournaments() {
60
+ const masterClient = new TAClient();
61
+ masterClient.setAuthToken(this.token);
62
+
63
+ masterClient.on("connectedToServer", async (response) => {
64
+ this.servers = response.state!.knownServers;
65
+ this.tournaments = response.state!.tournaments;
66
+
67
+ masterClient.disconnect();
68
+
69
+ //We successfully got tournaments from the master server
70
+ this.succeededServers++;
71
+ this.emit("onProgress", {
72
+ totalServers: this.servers.length,
73
+ succeededServers: this.succeededServers,
74
+ failedServers: this.failedServers,
75
+ tournaments: this.tournaments,
76
+ });
77
+
78
+ //Just running this map kicks off all the Promises, so no need to await them.
79
+ //This is probably a sin. If anyone knows the proper way to do this, hit me up on discord
80
+ this.servers
81
+ .filter(
82
+ (x) =>
83
+ `${x.address}:${x.websocketPort}` !==
84
+ `${MASTER_ADDRESS}:${MASTER_PORT}`
85
+ )
86
+ .map((x) =>
87
+ this.getTournamentsFromServer(x.address, `${x.websocketPort}`)
88
+ );
89
+ });
90
+
91
+ masterClient.on("failedToConnectToServer", () => {
92
+ //We failed to get tournaments from the master server
93
+ this.failedServers++;
94
+ this.emit("onProgress", {
95
+ totalServers: this.servers.length,
96
+ succeededServers: this.succeededServers,
97
+ failedServers: this.failedServers,
98
+ tournaments: this.tournaments,
99
+ });
100
+ });
101
+
102
+ masterClient.connect(MASTER_ADDRESS, MASTER_PORT);
103
+ }
104
+
105
+ private async getTournamentsFromServer(address: string, port: string) {
106
+ const client = new TAClient();
107
+ client.setAuthToken(this.token);
108
+
109
+ client.on("connectedToServer", (response) => {
110
+ this.tournaments = [...this.tournaments, ...response.state!.tournaments];
111
+
112
+ client.disconnect();
113
+
114
+ //We successfully got tournaments from the server
115
+ this.succeededServers++;
116
+ this.emit("onProgress", {
117
+ totalServers: this.servers.length,
118
+ succeededServers: this.succeededServers,
119
+ failedServers: this.failedServers,
120
+ tournaments: this.tournaments,
121
+ });
122
+ });
123
+
124
+ client.on("failedToConnectToServer", () => {
125
+ //We failed to get tournaments from the server
126
+ this.failedServers++;
127
+ this.emit("onProgress", {
128
+ totalServers: this.servers.length,
129
+ succeededServers: this.succeededServers,
130
+ failedServers: this.failedServers,
131
+ tournaments: this.tournaments,
132
+ });
133
+ });
134
+
135
+ client.connect(address, port);
136
+ }
137
+ }
@@ -0,0 +1,308 @@
1
+ import { CustomEventEmitter } from "./custom-event-emitter.js";
2
+ import {
3
+ User,
4
+ Tournament,
5
+ Match,
6
+ QualifierEvent,
7
+ CoreServer,
8
+ State,
9
+ } from "./models/models.js";
10
+ import { Packet } from "./models/packets.js";
11
+ import { v4 as uuidv4 } from "uuid";
12
+ import { Response_ResponseType } from "./models/responses.js";
13
+
14
+ type StateManagerEvents = {
15
+ userConnected: [User, Tournament];
16
+ userUpdated: [User, Tournament];
17
+ userDisconnected: [User, Tournament];
18
+
19
+ matchCreated: [Match, Tournament];
20
+ matchUpdated: [Match, Tournament];
21
+ matchDeleted: [Match, Tournament];
22
+
23
+ qualifierCreated: [QualifierEvent, Tournament];
24
+ qualifierUpdated: [QualifierEvent, Tournament];
25
+ qualifierDeleted: [QualifierEvent, Tournament];
26
+
27
+ tournamentCreated: Tournament;
28
+ tournamentUpdated: Tournament;
29
+ tournamentDeleted: Tournament;
30
+
31
+ serverAdded: CoreServer;
32
+ serverDeleted: CoreServer;
33
+ };
34
+
35
+ export class StateManager extends CustomEventEmitter<StateManagerEvents> {
36
+ private state: State;
37
+ private self: string;
38
+
39
+ constructor() {
40
+ super();
41
+ this.self = uuidv4();
42
+ this.state = {
43
+ tournaments: [],
44
+ knownServers: [],
45
+ };
46
+ }
47
+
48
+ // --- Packet handler --- //
49
+ public handlePacket(packet: Packet) {
50
+ if (packet.packet.oneofKind === "event") {
51
+ const event = packet.packet.event;
52
+ switch (event.changedObject.oneofKind) {
53
+ case "userAdded": {
54
+ this.userConnected(
55
+ event.changedObject.userAdded.tournamentId,
56
+ event.changedObject.userAdded.user!
57
+ );
58
+ break;
59
+ }
60
+ case "userUpdated": {
61
+ this.userUpdated(
62
+ event.changedObject.userUpdated.tournamentId,
63
+ event.changedObject.userUpdated.user!
64
+ );
65
+ break;
66
+ }
67
+ case "userLeft": {
68
+ this.userDisconnected(
69
+ event.changedObject.userLeft.tournamentId,
70
+ event.changedObject.userLeft.user!
71
+ );
72
+ break;
73
+ }
74
+ case "matchCreated": {
75
+ this.matchCreated(
76
+ event.changedObject.matchCreated.tournamentId,
77
+ event.changedObject.matchCreated.match!
78
+ );
79
+ break;
80
+ }
81
+ case "matchUpdated": {
82
+ this.matchUpdated(
83
+ event.changedObject.matchUpdated.tournamentId,
84
+ event.changedObject.matchUpdated.match!
85
+ );
86
+ break;
87
+ }
88
+ case "matchDeleted": {
89
+ this.matchDeleted(
90
+ event.changedObject.matchDeleted.tournamentId,
91
+ event.changedObject.matchDeleted.match!
92
+ );
93
+ break;
94
+ }
95
+ case "qualifierCreated": {
96
+ this.qualifierEventCreated(
97
+ event.changedObject.qualifierCreated.tournamentId,
98
+ event.changedObject.qualifierCreated.event!
99
+ );
100
+ break;
101
+ }
102
+ case "qualifierUpdated": {
103
+ this.qualifierEventUpdated(
104
+ event.changedObject.qualifierUpdated.tournamentId,
105
+ event.changedObject.qualifierUpdated.event!
106
+ );
107
+ break;
108
+ }
109
+ case "qualifierDeleted": {
110
+ this.qualifierEventDeleted(
111
+ event.changedObject.qualifierDeleted.tournamentId,
112
+ event.changedObject.qualifierDeleted.event!
113
+ );
114
+ break;
115
+ }
116
+ case "tournamentCreated": {
117
+ this.tournamentCreated(
118
+ event.changedObject.tournamentCreated.tournament!
119
+ );
120
+ break;
121
+ }
122
+ case "tournamentUpdated": {
123
+ this.tournamentUpdated(
124
+ event.changedObject.tournamentUpdated.tournament!
125
+ );
126
+ break;
127
+ }
128
+ case "tournamentDeleted": {
129
+ this.tournamentDeleted(
130
+ event.changedObject.tournamentDeleted.tournament!
131
+ );
132
+ break;
133
+ }
134
+ case "serverAdded": {
135
+ this.serverAdded(event.changedObject.serverAdded.server!);
136
+ break;
137
+ }
138
+ case "serverDeleted": {
139
+ this.serverDeleted(event.changedObject.serverDeleted.server!);
140
+ break;
141
+ }
142
+ }
143
+ } else if (packet.packet.oneofKind === "response") {
144
+ const response = packet.packet.response;
145
+
146
+ if (response.details.oneofKind === "connect") {
147
+ const connect = response.details.connect;
148
+
149
+ if (response.type === Response_ResponseType.Success) {
150
+ this.state = connect.state!;
151
+ }
152
+ } else if (response.details.oneofKind === "join") {
153
+ const join = response.details.join;
154
+
155
+ if (response.type === Response_ResponseType.Success) {
156
+ this.state = join.state!;
157
+ this.self = join.selfGuid;
158
+ }
159
+ }
160
+ }
161
+ }
162
+
163
+ // --- Helpers --- //
164
+ public getSelfGuid() {
165
+ return this.self;
166
+ }
167
+
168
+ public getTournaments() {
169
+ return this.state.tournaments;
170
+ }
171
+
172
+ public getTournament(id: string) {
173
+ return this.state.tournaments.find((x) => x.guid === id);
174
+ }
175
+
176
+ public getUsers(tournamentId: string) {
177
+ return this.getTournament(tournamentId)?.users;
178
+ }
179
+
180
+ public getUser(tournamentId: string, userId: string) {
181
+ return this.getUsers(tournamentId)?.find((x) => x.guid === userId);
182
+ }
183
+
184
+ public getMatches(tournamentId: string) {
185
+ return this.getTournament(tournamentId)?.matches;
186
+ }
187
+
188
+ public getMatch(tournamentId: string, matchId: string) {
189
+ return this.getMatches(tournamentId)?.find((x) => x.guid === matchId);
190
+ }
191
+
192
+ public getQualifiers(tournamentId: string) {
193
+ return this.getTournament(tournamentId)?.qualifiers;
194
+ }
195
+
196
+ public getQualifier(tournamentId: string, qualifierId: string) {
197
+ return this.getQualifiers(tournamentId)?.find((x) => x.guid === qualifierId);
198
+ }
199
+
200
+ public getKnownServers() {
201
+ return this.state.knownServers;
202
+ }
203
+
204
+ // --- Event handlers --- //
205
+ private userConnected = (tournamentId: string, user: User) => {
206
+ const tournament = this.getTournament(tournamentId);
207
+ tournament!.users = [...tournament!.users, user];
208
+ this.emit("userConnected", [user, tournament!]);
209
+ };
210
+
211
+ private userUpdated = (tournamentId: string, user: User) => {
212
+ const tournament = this.getTournament(tournamentId);
213
+ const index = tournament!.users.findIndex((x) => x.guid === user.guid);
214
+ tournament!.users[index] = user;
215
+ this.emit("userUpdated", [user, tournament!]);
216
+ };
217
+
218
+ private userDisconnected = (tournamentId: string, user: User) => {
219
+ const tournament = this.getTournament(tournamentId);
220
+ tournament!.users = tournament!.users.filter((x) => x.guid !== user.guid);
221
+ this.emit("userDisconnected", [user, tournament!]);
222
+ };
223
+
224
+ private matchCreated = (tournamentId: string, match: Match) => {
225
+ const tournament = this.getTournament(tournamentId);
226
+ tournament!.matches = [...tournament!.matches, match];
227
+ this.emit("matchCreated", [match, tournament!]);
228
+ };
229
+
230
+ private matchUpdated = (tournamentId: string, match: Match) => {
231
+ const tournament = this.getTournament(tournamentId);
232
+ const index = tournament!.matches.findIndex((x) => x.guid === match.guid);
233
+ tournament!.matches[index] = match;
234
+ this.emit("matchUpdated", [match, tournament!]);
235
+ };
236
+
237
+ private matchDeleted = (tournamentId: string, match: Match) => {
238
+ const tournament = this.getTournament(tournamentId);
239
+ tournament!.matches = tournament!.matches.filter(
240
+ (x) => x.guid !== match.guid
241
+ );
242
+ this.emit("matchDeleted", [match, tournament!]);
243
+ };
244
+
245
+ private qualifierEventCreated = (
246
+ tournamentId: string,
247
+ event: QualifierEvent
248
+ ) => {
249
+ const tournament = this.getTournament(tournamentId);
250
+ tournament!.qualifiers = [...tournament!.qualifiers, event];
251
+ this.emit("qualifierCreated", [event, tournament!]);
252
+ };
253
+
254
+ private qualifierEventUpdated = (
255
+ tournamentId: string,
256
+ event: QualifierEvent
257
+ ) => {
258
+ const tournament = this.getTournament(tournamentId);
259
+ const index = tournament!.qualifiers.findIndex(
260
+ (x) => x.guid === event.guid
261
+ );
262
+ tournament!.qualifiers[index] = event;
263
+ this.emit("qualifierUpdated", [event, tournament!]);
264
+ };
265
+
266
+ private qualifierEventDeleted = (
267
+ tournamentId: string,
268
+ event: QualifierEvent
269
+ ) => {
270
+ const tournament = this.getTournament(tournamentId);
271
+ tournament!.qualifiers = tournament!.qualifiers.filter(
272
+ (x) => x.guid !== event.guid
273
+ );
274
+ this.emit("qualifierDeleted", [event, tournament!]);
275
+ };
276
+
277
+ private tournamentCreated = (tournament: Tournament) => {
278
+ this.state.tournaments = [...this.state.tournaments, tournament];
279
+ this.emit("tournamentCreated", tournament);
280
+ };
281
+
282
+ private tournamentUpdated = (tournament: Tournament) => {
283
+ const index = this.state.tournaments.findIndex(
284
+ (x) => x.guid === tournament.guid
285
+ );
286
+ this.state.tournaments[index] = tournament;
287
+ this.emit("tournamentUpdated", tournament);
288
+ };
289
+
290
+ private tournamentDeleted = (tournament: Tournament) => {
291
+ this.state.tournaments = this.state.tournaments.filter(
292
+ (x) => x.guid !== tournament.guid
293
+ );
294
+ this.emit("tournamentDeleted", tournament);
295
+ };
296
+
297
+ private serverAdded = (server: CoreServer) => {
298
+ this.state.knownServers = [...this.state.knownServers, server];
299
+ this.emit("serverAdded", server);
300
+ };
301
+
302
+ private serverDeleted = (server: CoreServer) => {
303
+ this.state.knownServers = this.state.knownServers.filter(
304
+ (x) => `${server.address}:${server.port}` !== `${x.address}:${x.port}`
305
+ );
306
+ this.emit("serverDeleted", server);
307
+ };
308
+ }