Skip to content

Commit 7f285ab

Browse files
authored
Merge pull request #18 from 5stackgg/main
2 parents 56c6339 + 74d4495 commit 7f285ab

10 files changed

Lines changed: 162 additions & 59 deletions

src/auth/auth.controller.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ import { HasuraAction } from "../hasura/hasura.controller";
55
import { DiscordGuard } from "./strategies/DiscordGuard";
66
import { CacheService } from "../cache/cache.service";
77
import { HasuraService } from "../hasura/hasura.service";
8+
import { SocketsGateway } from "src/sockets/sockets.gateway";
9+
import { RedisManagerService } from "src/redis/redis-manager/redis-manager.service";
810

911
@Controller("auth")
1012
export class AuthController {
1113
constructor(
1214
private readonly cache: CacheService,
1315
private readonly hasura: HasuraService,
16+
private readonly redis: RedisManagerService,
1417
) {}
1518

1619
@UseGuards(SteamGuard)
@@ -73,6 +76,10 @@ export class AuthController {
7376
@HasuraAction()
7477
public async logout(@Req() request: Request) {
7578
if (request.session) {
79+
await this.redis
80+
.getConnection()
81+
.del(SocketsGateway.GET_PLAYER_CLIENT_LATENCY_TEST(request.session.id));
82+
7683
request.session.destroy((err) => {
7784
if (err) {
7885
console.error("Error destroying session:", err);

src/auth/auth.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { SteamSerializer } from "./strategies/SteamSerializer";
77
import { DiscordStrategy } from "./strategies/DiscordStrategy";
88
import { loggerFactory } from "../utilities/LoggerFactory";
99
import { CacheModule } from "../cache/cache.module";
10+
import { RedisModule } from "../redis/redis.module";
1011

1112
@Module({
1213
imports: [
@@ -15,6 +16,7 @@ import { CacheModule } from "../cache/cache.module";
1516
}),
1617
HasuraModule,
1718
CacheModule,
19+
RedisModule,
1820
],
1921
providers: [SteamStrategy, DiscordStrategy, SteamSerializer, loggerFactory()],
2022
controllers: [AuthController],
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Job } from "bullmq";
2+
import { WorkerHost } from "@nestjs/bullmq";
3+
import { MatchmakingQueues } from "../enums/MatchmakingQueues";
4+
import { UseQueue } from "../../utilities/QueueProcessors";
5+
import { MatchmakingLobbyService } from "../matchmaking-lobby.service";
6+
import { HasuraService } from "../../hasura/hasura.service";
7+
8+
@UseQueue("Matchmaking", MatchmakingQueues.Matchmaking)
9+
export class MarkPlayerOffline extends WorkerHost {
10+
constructor(
11+
private readonly hasura: HasuraService,
12+
private readonly matchmakingLobbyService: MatchmakingLobbyService,
13+
) {
14+
super();
15+
}
16+
17+
async process(
18+
job: Job<{
19+
steamId: string;
20+
}>,
21+
): Promise<void> {
22+
console.info(`Leaving queue for ${job.data.steamId}`);
23+
const { steamId } = job.data;
24+
25+
await this.hasura.mutation({
26+
delete_lobby_players: {
27+
__args: {
28+
where: {
29+
steam_id: {
30+
_eq: steamId,
31+
},
32+
status: {
33+
_eq: "Accepted",
34+
},
35+
},
36+
},
37+
__typename: true,
38+
},
39+
});
40+
41+
const lobby = await this.matchmakingLobbyService.getPlayerLobby(steamId);
42+
43+
if (!lobby) {
44+
return;
45+
}
46+
47+
await this.matchmakingLobbyService.removeLobbyFromQueue(lobby.id);
48+
await this.matchmakingLobbyService.removeLobbyDetails(lobby.id);
49+
}
50+
}

src/matchmaking/matchmake.service.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,22 @@ export class MatchmakeService {
412412
await this.redis.expire(lockKey, seconds);
413413
}
414414

415-
// TODO - watch for a player leaving a lobby and force the entire lobby to be left the queue with an error
415+
public async markOffline(steamId: string) {
416+
await this.queue.add(
417+
"MarkPlayerOffline",
418+
{
419+
steamId,
420+
},
421+
{
422+
delay: 60 * 1000,
423+
jobId: `matchmaking:mark-offline:${steamId}`,
424+
},
425+
);
426+
}
427+
428+
public async cancelOffline(steamId: string) {
429+
await this.queue.remove(`matchmaking:mark-offline:${steamId}`);
430+
}
416431

417432
private async createMatchConfirmation(
418433
region: string,

src/matchmaking/matchmaking-lobby.service.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ export class MatchmakingLobbyService {
3131
this.redis = this.redisManager.getConnection();
3232
}
3333

34-
public async getPlayerLobby(user: User): Promise<PlayerLobby> {
35-
let lobbyId = await this.getCurrentLobbyId(user.steam_id);
34+
public async getPlayerLobby(steamId: string): Promise<PlayerLobby> {
35+
let lobbyId = await this.getCurrentLobbyId(steamId);
3636

3737
let lobby;
3838
if (validateUUID(lobbyId)) {
@@ -64,11 +64,11 @@ export class MatchmakingLobbyService {
6464
}
6565

6666
if (!lobby) {
67-
lobbyId = user.steam_id;
67+
lobbyId = steamId;
6868
const { players_by_pk } = await this.hasura.query({
6969
players_by_pk: {
7070
__args: {
71-
steam_id: user.steam_id,
71+
steam_id: steamId,
7272
},
7373
name: true,
7474
steam_id: true,
@@ -271,8 +271,8 @@ export class MatchmakingLobbyService {
271271
}
272272

273273
// TODO - extermly inefficient
274-
public async sendQueueDetailsToPlayer(user: User) {
275-
const lobby = await this.getPlayerLobby(user);
274+
public async sendQueueDetailsToPlayer(steamId: string) {
275+
const lobby = await this.getPlayerLobby(steamId);
276276

277277
if (!lobby) {
278278
return;

src/matchmaking/matchmaking.gateway.ts

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { JoinQueueError } from "./utilities/joinQueueError";
1515
import { HasuraService } from "src/hasura/hasura.service";
1616
import { isRoleAbove } from "src/utilities/isRoleAbove";
1717
import { e_player_roles_enum } from "generated";
18+
import { SocketsGateway } from "src/sockets/sockets.gateway";
1819

1920
@WebSocketGateway({
2021
path: "/ws/web",
@@ -88,18 +89,59 @@ export class MatchmakingGateway {
8889

8990
let lobby;
9091
const user = client.user;
91-
const { type, regions } = data;
9292

9393
if (!user) {
9494
return;
9595
}
9696

97+
const latencyResults = await this.getLatencyResults(client);
98+
99+
const { server_regions } = await this.hasura.query({
100+
server_regions: {
101+
__args: {
102+
where: {
103+
status: {
104+
_eq: "Online",
105+
},
106+
},
107+
},
108+
value: true,
109+
is_lan: true,
110+
status: true,
111+
},
112+
});
113+
114+
// TODO - rather adding all regions at once we should add them when expanding the search
115+
116+
let regions = [];
117+
for (const region of data.regions) {
118+
const server_region = server_regions.find((server_region) => {
119+
return server_region.value === region;
120+
});
121+
122+
if (!server_region) {
123+
continue;
124+
}
125+
126+
const latency =
127+
latencyResults[region.toLocaleLowerCase().replace(" ", "_")];
128+
if (!server_region.is_lan || latency?.isLan === true) {
129+
regions.push(server_region.value);
130+
}
131+
}
132+
133+
if (regions.length === 0) {
134+
throw new JoinQueueError("No regions available");
135+
}
136+
137+
const { type } = data;
138+
97139
try {
98140
if (!type || !regions || regions.length === 0) {
99141
throw new JoinQueueError("Missing Type or Regions");
100142
}
101143

102-
lobby = await this.matchmakingLobbyService.getPlayerLobby(user);
144+
lobby = await this.matchmakingLobbyService.getPlayerLobby(user.steam_id);
103145

104146
if (!lobby) {
105147
throw new JoinQueueError("Unable to find Player Lobby");
@@ -161,7 +203,9 @@ export class MatchmakingGateway {
161203
return;
162204
}
163205

164-
const lobby = await this.matchmakingLobbyService.getPlayerLobby(user);
206+
const lobby = await this.matchmakingLobbyService.getPlayerLobby(
207+
user.steam_id,
208+
);
165209

166210
if (!lobby) {
167211
return;
@@ -190,4 +234,24 @@ export class MatchmakingGateway {
190234
user.steam_id,
191235
);
192236
}
237+
238+
private async getLatencyResults(client: FiveStackWebSocketClient) {
239+
const data = await this.redis.hgetall(
240+
SocketsGateway.GET_PLAYER_CLIENT_LATENCY_TEST(client.sessionId),
241+
);
242+
243+
const latencyResults: Record<
244+
string,
245+
{
246+
isLan: boolean;
247+
latency: number;
248+
}
249+
> = {};
250+
251+
for (const key in data) {
252+
latencyResults[key] = JSON.parse(data[key]);
253+
}
254+
255+
return latencyResults;
256+
}
193257
}

src/matchmaking/matchmaking.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { getQueuesProcessors } from "src/utilities/QueueProcessors";
1313
import { MatchmakingQueues } from "./enums/MatchmakingQueues";
1414
import { CancelMatchMaking } from "./jobs/CancelMatchMaking";
1515
import { MatchmakingController } from "./matchmaking.controller";
16+
import { MarkPlayerOffline } from "./jobs/MarkPlayerOffline";
1617

1718
@Module({
1819
imports: [
@@ -33,6 +34,7 @@ import { MatchmakingController } from "./matchmaking.controller";
3334
MatchmakeService,
3435
MatchmakingLobbyService,
3536
CancelMatchMaking,
37+
MarkPlayerOffline,
3638
...getQueuesProcessors("Matchmaking"),
3739
loggerFactory(),
3840
],

src/signal-server/signal-server.gateway.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { RegionSignalData } from "./types/SignalData";
1313

1414
interface WebRTCClient extends WebSocket {
1515
id: string;
16+
sessionId: string;
1617
}
1718

1819
@WebSocketGateway({
@@ -54,6 +55,7 @@ export class SignalServerGateway {
5455
signal,
5556
peerId,
5657
clientId: client.id,
58+
sessionId: client.sessionId,
5759
},
5860
}),
5961
);

src/sockets/sockets.gateway.ts

Lines changed: 9 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,6 @@ export class SocketsGateway {
2727
private nodeId: string = process.env.POD_NAME;
2828
private clients: Map<string, FiveStackWebSocketClient> = new Map();
2929

30-
public static GET_AVAILABLE_NODES_KEY() {
31-
return `available-socket-nodes`;
32-
}
33-
34-
public static GET_NODE_STATUS_KEY(nodeId: string) {
35-
return `socket-node:${nodeId}:status`;
36-
}
37-
3830
public static GET_PLAYER_KEY(steamId: string) {
3931
return `players:${steamId}`;
4032
}
@@ -55,6 +47,10 @@ export class SocketsGateway {
5547
return `${SocketsGateway.GET_PLAYER_CLIENTS_BY_NODE(steamId, nodeId)}:${clientId}`;
5648
}
5749

50+
public static GET_PLAYER_CLIENT_LATENCY_TEST(sessionId: string) {
51+
return `latency-test:${sessionId}`;
52+
}
53+
5854
constructor(
5955
private readonly logger: Logger,
6056
private readonly config: ConfigService,
@@ -90,8 +86,6 @@ export class SocketsGateway {
9086
break;
9187
}
9288
});
93-
94-
void this.setupNode();
9589
}
9690

9791
@SubscribeMessage("ping")
@@ -137,16 +131,19 @@ export class SocketsGateway {
137131

138132
client.id = uuidv4();
139133
client.user = request.user;
134+
client.sessionId = request.session.id;
140135
client.node = this.nodeId;
141136

142137
this.clients.set(client.id, client);
143138

144139
await this.updateClient(client.user.steam_id, client.id);
145140

141+
await this.matchmaking.cancelOffline(client.user.steam_id);
142+
146143
await this.sendPeopleOnline();
147144
await this.matchmaking.sendRegionStats(client.user);
148145
await this.matchmakingLobbyService.sendQueueDetailsToPlayer(
149-
client.user,
146+
client.user.steam_id,
150147
);
151148

152149
client.on("close", async () => {
@@ -169,24 +166,7 @@ export class SocketsGateway {
169166

170167
await this.sendPeopleOnline();
171168

172-
// GIVE THEM A DELAY
173-
// this.matchMaking.leaveQueue(client);
174-
175-
// await this.hasura.mutation({
176-
// delete_lobby_players: {
177-
// __args: {
178-
// where: {
179-
// steam_id: {
180-
// _eq: client.user.steam_id,
181-
// },
182-
// status: {
183-
// _eq: "Accepted",
184-
// },
185-
// },
186-
// },
187-
// __typename: true,
188-
// },
189-
// });
169+
this.matchmaking.markOffline(client.user.steam_id);
190170
}
191171
});
192172
});
@@ -285,24 +265,4 @@ export class SocketsGateway {
285265

286266
this.clients.delete(clientId);
287267
}
288-
289-
private async setupNode() {
290-
await this.redis.sadd(
291-
SocketsGateway.GET_AVAILABLE_NODES_KEY(),
292-
this.nodeId,
293-
);
294-
const markOnline = async () => {
295-
await this.redis.set(
296-
SocketsGateway.GET_NODE_STATUS_KEY(this.nodeId),
297-
"true",
298-
"EX",
299-
60,
300-
);
301-
};
302-
303-
// await markOnline();
304-
// setInterval(async () => {
305-
// await markOnline();
306-
// }, 30 * 1000);
307-
}
308268
}

0 commit comments

Comments
 (0)