Skip to content

Commit 7ad13d7

Browse files
committed
wip
1 parent b6f766d commit 7ad13d7

1 file changed

Lines changed: 69 additions & 33 deletions

File tree

src/matches/match-relay/match-relay.service.ts

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,41 @@ import { promisify } from "util";
33
import { Request, Response } from "express";
44
import { Injectable, Logger } from "@nestjs/common";
55

6+
type Fragment = {
7+
start?: Buffer;
8+
full?: Buffer;
9+
delta?: Buffer;
10+
start_ungzlen?: number;
11+
full_ungzlen?: number;
12+
delta_ungzlen?: number;
13+
tick?: number;
14+
endtick?: number;
15+
timestamp?: number;
16+
signup_fragment?: number;
17+
tps?: number;
18+
keyframe_interval?: number;
19+
map?: string;
20+
protocol?: number;
21+
[key: string]: any;
22+
};
23+
24+
type Broadcast = Fragment[];
25+
626
@Injectable()
727
export class MatchRelayService {
828
private readonly gzip = promisify(zlib.gzip);
929

10-
private readonly broadcasts: { [key: string]: any[] } = {};
30+
private readonly broadcasts: { [key: string]: Broadcast } = {};
1131

1232
constructor(private readonly logger: Logger) {}
1333

14-
public getStart(response: Response, matchId: string, fragment: number) {
34+
public getStart(response: Response, matchId: string, fragmentIndex: number) {
1535
const broadcast = this.broadcasts[matchId];
1636

17-
if (broadcast?.[0] == null || broadcast[0].signup_fragment != fragment) {
37+
if (
38+
broadcast?.[0] == null ||
39+
broadcast[0].signup_fragment != fragmentIndex
40+
) {
1841
return this.relayError(
1942
response,
2043
404,
@@ -29,7 +52,7 @@ export class MatchRelayService {
2952
response: Response,
3053
matchId: string,
3154
fragmentIndex: number,
32-
field: "start" | "full" | "delta",
55+
field: string,
3356
) {
3457
const broadcast = this.broadcasts[matchId];
3558
if (!broadcast) {
@@ -66,37 +89,41 @@ export class MatchRelayService {
6689
}
6790

6891
const match_field_0 = broadcast[0];
92+
// Check if start fragment exists at index 0 (start is a Buffer, so check if it exists)
6993
if (match_field_0 == null || match_field_0.start == null) {
7094
response.writeHead(404, "Broadcast has not started yet");
7195
response.end();
7296
return;
7397
}
7498

75-
let fragment: number | null = null;
99+
let fragmentIndex: number | null = null;
76100
const fragmentParam = request.query.fragment as string | undefined;
77-
let frag: any = null;
101+
let frag: Fragment | null = null;
78102

79103
if (fragmentParam == null) {
80-
fragment = Math.max(0, broadcast.length - 8);
104+
fragmentIndex = Math.max(0, broadcast.length - 8);
81105

82-
if (fragment >= 0 && fragment >= match_field_0.signup_fragment) {
83-
const _fragment = broadcast[fragment];
106+
if (
107+
fragmentIndex >= 0 &&
108+
fragmentIndex >= match_field_0.signup_fragment
109+
) {
110+
const _fragment = broadcast[fragmentIndex];
84111
if (this.isSyncReady(_fragment)) {
85112
frag = _fragment;
86113
}
87114
}
88115
} else {
89-
fragment = parseInt(fragmentParam);
116+
fragmentIndex = parseInt(fragmentParam);
90117

91-
if (fragment < match_field_0.signup_fragment) {
92-
fragment = match_field_0.signup_fragment;
118+
if (fragmentIndex < match_field_0.signup_fragment) {
119+
fragmentIndex = match_field_0.signup_fragment;
93120
}
94121

95-
for (let i = fragment; i < broadcast.length; i++) {
122+
for (let i = fragmentIndex; i < broadcast.length; i++) {
96123
const _fragment = broadcast[i];
97124
if (this.isSyncReady(_fragment)) {
98125
frag = _fragment;
99-
fragment = i;
126+
fragmentIndex = i;
100127
break;
101128
}
102129
}
@@ -119,8 +146,10 @@ export class MatchRelayService {
119146
endtick: frag.endtick,
120147
maxtick: this.getMatchBroadcastEndTick(broadcast),
121148
rtdelay: (nowMs - frag.timestamp) / 1000,
122-
rcvage: (nowMs - (broadcast[broadcast.length - 1]?.timestamp || nowMs)) / 1000,
123-
fragment: fragment,
149+
rcvage:
150+
(nowMs - (broadcast[broadcast.length - 1]?.timestamp || nowMs)) /
151+
1000,
152+
fragment: fragmentIndex,
124153
signup_fragment: match_field_0.signup_fragment,
125154
tps: match_field_0.tps,
126155
keyframe_interval: match_field_0.keyframe_interval,
@@ -135,7 +164,7 @@ export class MatchRelayService {
135164
response: Response,
136165
field: string,
137166
matchId: string,
138-
fragment: number,
167+
fragmentIndex: number,
139168
): void {
140169
if (!this.broadcasts[matchId]) {
141170
this.logger.log(`Creating new match broadcast for matchId ${matchId}`);
@@ -150,25 +179,29 @@ export class MatchRelayService {
150179
broadcast[0] = {};
151180
}
152181

153-
broadcast[0].signup_fragment = fragment;
154-
fragment = 0;
182+
// Start fragments are always stored at index 0
183+
// Store the original fragment number in signup_fragment
184+
broadcast[0].signup_fragment = fragmentIndex;
185+
fragmentIndex = 0;
155186
} else {
187+
// For non-start fields, ensure start fragment exists at index 0
188+
// Start fragment is always at index 0, check if the start Buffer exists
156189
if (broadcast[0] == null || broadcast[0].start == null) {
157190
response.writeHead(205);
158191
response.end();
159192
return;
160193
} else {
161194
response.writeHead(200);
162195
}
163-
if (broadcast[fragment] == null) {
164-
broadcast[fragment] = {};
196+
if (broadcast[fragmentIndex] == null) {
197+
broadcast[fragmentIndex] = {};
165198
}
166199
}
167200

168201
Object.entries(request.query).forEach(([key, value]) => {
169202
const strValue = String(value);
170203
const numValue = Number(strValue);
171-
broadcast[fragment][key] =
204+
broadcast[fragmentIndex][key] =
172205
!isNaN(numValue) && strValue === String(numValue) ? numValue : value;
173206
});
174207

@@ -178,22 +211,22 @@ export class MatchRelayService {
178211
});
179212
request.on("end", () => {
180213
const totalBuffer = Buffer.concat(body);
181-
214+
182215
// Send response immediately (like old code)
183216
response.end();
184217

185218
this.gzip(totalBuffer)
186219
.then((compressedBlob: Buffer) => {
187-
broadcast[fragment][field + "_ungzlen"] = totalBuffer.length;
188-
broadcast[fragment][field] = compressedBlob;
189-
broadcast[fragment].timestamp = Date.now();
220+
broadcast[fragmentIndex][field + "_ungzlen"] = totalBuffer.length;
221+
broadcast[fragmentIndex][field] = compressedBlob;
222+
broadcast[fragmentIndex].timestamp = Date.now();
190223
})
191224
.catch((error: Error) => {
192225
this.logger.error(
193226
`Cannot gzip ${totalBuffer.length} bytes: ${error}`,
194227
);
195-
broadcast[fragment][field] = totalBuffer;
196-
broadcast[fragment].timestamp = Date.now();
228+
broadcast[fragmentIndex][field] = totalBuffer;
229+
broadcast[fragmentIndex].timestamp = Date.now();
197230
});
198231
});
199232
}
@@ -207,19 +240,18 @@ export class MatchRelayService {
207240
response.end();
208241
}
209242

210-
private isSyncReady(fragment: any): boolean {
243+
private isSyncReady(fragment: Fragment | undefined): boolean {
211244
return (
212245
fragment != null &&
213-
typeof fragment === "object" &&
214246
fragment.full != null &&
215247
fragment.delta != null &&
216248
fragment.tick != null &&
217249
fragment.endtick != null &&
218-
fragment.timestamp
250+
fragment.timestamp != null
219251
);
220252
}
221253

222-
private getMatchBroadcastEndTick(broadcast: any[]): number {
254+
private getMatchBroadcastEndTick(broadcast: Broadcast): number {
223255
for (let i = broadcast.length - 1; i >= 0; i--) {
224256
const fragment = broadcast[i];
225257
if (fragment?.endtick != null) {
@@ -229,7 +261,11 @@ export class MatchRelayService {
229261
return 0;
230262
}
231263

232-
private serveBlob(response: Response, fragmentRec: any, field: string): void {
264+
private serveBlob(
265+
response: Response,
266+
fragmentRec: Fragment | undefined,
267+
field: string,
268+
): void {
233269
const blob = fragmentRec?.[field];
234270

235271
if (!blob) {

0 commit comments

Comments
 (0)