Skip to content

Commit 387ada6

Browse files
authored
Merge pull request #362 from OpenCloudGaming/dev
Add stable device ID management in cloudmatch.ts (#361)
2 parents f486ed0 + 4255c25 commit 387ada6

1 file changed

Lines changed: 36 additions & 2 deletions

File tree

opennow-stable/src/main/gfn/cloudmatch.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import crypto from "node:crypto";
22
import dns from "node:dns";
3+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
4+
import { join } from "node:path";
5+
import { app } from "electron";
36

47
import type {
58
ActiveSessionInfo,
@@ -33,6 +36,9 @@ const GFN_USER_AGENT =
3336
const GFN_CLIENT_VERSION = "2.0.80.173";
3437
const SESSION_MODIFY_ACTION_AD_UPDATE = 6;
3538
const READY_SESSION_STATUSES = new Set([2, 3]);
39+
const GFN_DEVICE_ID_FILENAME = "gfn-device-id.json";
40+
41+
let cachedStableDeviceId: string | null = null;
3642

3743
const AD_ACTION_CODES: Record<SessionAdAction, number> = {
3844
start: 1,
@@ -52,6 +58,34 @@ function isReadySessionStatus(status: number): boolean {
5258
return READY_SESSION_STATUSES.has(status);
5359
}
5460

61+
function getStableDeviceId(): string {
62+
if (cachedStableDeviceId) {
63+
return cachedStableDeviceId;
64+
}
65+
66+
try {
67+
const path = join(app.getPath("userData"), GFN_DEVICE_ID_FILENAME);
68+
if (existsSync(path)) {
69+
const parsed = JSON.parse(readFileSync(path, "utf-8")) as { deviceId?: unknown };
70+
if (typeof parsed.deviceId === "string" && parsed.deviceId.length > 0) {
71+
cachedStableDeviceId = parsed.deviceId;
72+
return parsed.deviceId;
73+
}
74+
}
75+
76+
const deviceId = crypto.randomUUID();
77+
writeFileSync(path, JSON.stringify({ deviceId }, null, 2), "utf-8");
78+
cachedStableDeviceId = deviceId;
79+
return deviceId;
80+
} catch (error) {
81+
// Fallback to in-memory UUID if disk read/write fails.
82+
const fallback = crypto.randomUUID();
83+
cachedStableDeviceId = fallback;
84+
console.warn("[CloudMatch] Failed to load persisted device ID, using in-memory fallback:", error);
85+
return fallback;
86+
}
87+
}
88+
5589
async function resolveHostnameWithFallback(hostname: string): Promise<string | null> {
5690
// Try system resolver first, then fall back to Cloudflare (1.1.1.1) and Google (8.8.8.8)
5791
try {
@@ -1196,7 +1230,7 @@ function buildClaimRequestBody(sessionId: string, appId: string, settings: Strea
11961230
// The session is already configured on the server side. Sending different fps, resolution,
11971231
// codec, etc. causes HTTP 400 from the server because those parameters are immutable for
11981232
// an already-streaming session. Only send the action and minimal required fields.
1199-
const deviceId = crypto.randomUUID();
1233+
const deviceId = getStableDeviceId();
12001234
const subSessionId = crypto.randomUUID();
12011235
const timezoneMs = timezoneOffsetMs();
12021236

@@ -1262,7 +1296,7 @@ export async function claimSession(input: SessionClaimRequest): Promise<SessionI
12621296
throw new Error("Missing token for session claim");
12631297
}
12641298

1265-
const deviceId = crypto.randomUUID();
1299+
const deviceId = getStableDeviceId();
12661300
const clientId = crypto.randomUUID();
12671301

12681302
// Provide default values for optional parameters

0 commit comments

Comments
 (0)