@apocaliss92/nodelink-js 0.3.5 → 0.4.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/dist/{DiagnosticsTools-2JQRV5FE.js → DiagnosticsTools-XIIYZDXL.js} +8 -2
- package/dist/{chunk-APEEZ4UN.js → chunk-DUHWTZ7U.js} +433 -1
- package/dist/chunk-DUHWTZ7U.js.map +1 -0
- package/dist/{chunk-UDS2UR4S.js → chunk-SDRNJQ5U.js} +18 -8
- package/dist/chunk-SDRNJQ5U.js.map +1 -0
- package/dist/cli/rtsp-server.cjs +446 -5
- package/dist/cli/rtsp-server.cjs.map +1 -1
- package/dist/cli/rtsp-server.js +2 -2
- package/dist/index.cjs +454 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +73 -1
- package/dist/index.d.ts +77 -0
- package/dist/index.js +11 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-APEEZ4UN.js.map +0 -1
- package/dist/chunk-UDS2UR4S.js.map +0 -1
- /package/dist/{DiagnosticsTools-2JQRV5FE.js.map → DiagnosticsTools-XIIYZDXL.js.map} +0 -0
package/dist/cli/rtsp-server.cjs
CHANGED
|
@@ -4912,15 +4912,18 @@ var init_zip = __esm({
|
|
|
4912
4912
|
// src/debug/DiagnosticsTools.ts
|
|
4913
4913
|
var DiagnosticsTools_exports = {};
|
|
4914
4914
|
__export(DiagnosticsTools_exports, {
|
|
4915
|
+
captureModelFixtures: () => captureModelFixtures,
|
|
4915
4916
|
collectCgiDiagnostics: () => collectCgiDiagnostics,
|
|
4916
4917
|
collectMultifocalDiagnostics: () => collectMultifocalDiagnostics,
|
|
4917
4918
|
collectNativeDiagnostics: () => collectNativeDiagnostics,
|
|
4918
4919
|
collectNvrDiagnostics: () => collectNvrDiagnostics,
|
|
4920
|
+
computeExpectedStreamCompatibility: () => computeExpectedStreamCompatibility,
|
|
4919
4921
|
createDiagnosticsBundle: () => createDiagnosticsBundle,
|
|
4920
4922
|
printNvrDiagnostics: () => printNvrDiagnostics,
|
|
4921
4923
|
runAllDiagnosticsConsecutively: () => runAllDiagnosticsConsecutively,
|
|
4922
4924
|
runMultifocalDiagnosticsConsecutively: () => runMultifocalDiagnosticsConsecutively,
|
|
4923
4925
|
sampleStreams: () => sampleStreams,
|
|
4926
|
+
sanitizeFixtureData: () => sanitizeFixtureData,
|
|
4924
4927
|
testChannelStreams: () => testChannelStreams
|
|
4925
4928
|
});
|
|
4926
4929
|
function safeStringifyError(error) {
|
|
@@ -4945,6 +4948,10 @@ function writeJson(filePath, obj) {
|
|
|
4945
4948
|
mkdirp(path4.dirname(filePath));
|
|
4946
4949
|
fs4.writeFileSync(filePath, JSON.stringify(obj, null, 2));
|
|
4947
4950
|
}
|
|
4951
|
+
function writeText(filePath, text) {
|
|
4952
|
+
mkdirp(path4.dirname(filePath));
|
|
4953
|
+
fs4.writeFileSync(filePath, text);
|
|
4954
|
+
}
|
|
4948
4955
|
function appendNdjson(filePath, obj) {
|
|
4949
4956
|
mkdirp(path4.dirname(filePath));
|
|
4950
4957
|
fs4.appendFileSync(filePath, JSON.stringify(obj) + "\n");
|
|
@@ -7208,7 +7215,411 @@ async function runAllDiagnosticsConsecutively(params) {
|
|
|
7208
7215
|
streamsDir
|
|
7209
7216
|
};
|
|
7210
7217
|
}
|
|
7211
|
-
|
|
7218
|
+
function maskIp(ip) {
|
|
7219
|
+
const parts = ip.split(".");
|
|
7220
|
+
return `${parts[0]}.***.***.***`;
|
|
7221
|
+
}
|
|
7222
|
+
function maskMac(mac) {
|
|
7223
|
+
const sep = mac.includes("-") ? "-" : ":";
|
|
7224
|
+
const parts = mac.split(/[:-]/);
|
|
7225
|
+
return `${parts[0]}${sep}${parts[1]}${sep}**${sep}**${sep}**${sep}**`;
|
|
7226
|
+
}
|
|
7227
|
+
function maskSerial(val) {
|
|
7228
|
+
if (val.length <= 4) return "****";
|
|
7229
|
+
return val.slice(0, 2) + "*".repeat(val.length - 4) + val.slice(-2);
|
|
7230
|
+
}
|
|
7231
|
+
function sanitizeString(s) {
|
|
7232
|
+
let out = s;
|
|
7233
|
+
out = out.replace(/:\/\/([^:@]+):([^@]+)@/g, "://***:***@");
|
|
7234
|
+
out = out.replace(/(password=)[^&\s]*/gi, "$1***");
|
|
7235
|
+
out = out.replace(/(user=)[^&\s]*/gi, "$1***");
|
|
7236
|
+
out = out.replace(IPV4_RE, (match) => maskIp(match));
|
|
7237
|
+
out = out.replace(MAC_RE, (match) => maskMac(match));
|
|
7238
|
+
return out;
|
|
7239
|
+
}
|
|
7240
|
+
function sanitizeFixtureData(value) {
|
|
7241
|
+
if (value === null || value === void 0) return value;
|
|
7242
|
+
if (typeof value === "string") {
|
|
7243
|
+
return sanitizeString(value);
|
|
7244
|
+
}
|
|
7245
|
+
if (Array.isArray(value)) {
|
|
7246
|
+
return value.map(sanitizeFixtureData);
|
|
7247
|
+
}
|
|
7248
|
+
if (typeof value === "object") {
|
|
7249
|
+
const out = {};
|
|
7250
|
+
for (const [k, v] of Object.entries(value)) {
|
|
7251
|
+
const kLower = k.toLowerCase();
|
|
7252
|
+
if (REDACT_KEYS.has(kLower)) {
|
|
7253
|
+
out[k] = "***";
|
|
7254
|
+
} else if (MASK_KEYS.has(kLower) || kLower === "serialnumber") {
|
|
7255
|
+
out[k] = typeof v === "string" ? maskSerial(v) : "***";
|
|
7256
|
+
} else if (kLower === "mac") {
|
|
7257
|
+
out[k] = typeof v === "string" ? maskMac(v) : "***";
|
|
7258
|
+
} else if (kLower === "ip" || kLower === "ipaddress" || kLower === "host") {
|
|
7259
|
+
out[k] = typeof v === "string" ? maskIp(v) : v;
|
|
7260
|
+
} else if (kLower === "name" && typeof v === "string" && k !== "name") {
|
|
7261
|
+
out[k] = v;
|
|
7262
|
+
} else {
|
|
7263
|
+
out[k] = sanitizeFixtureData(v);
|
|
7264
|
+
}
|
|
7265
|
+
}
|
|
7266
|
+
return out;
|
|
7267
|
+
}
|
|
7268
|
+
return value;
|
|
7269
|
+
}
|
|
7270
|
+
function computeExpectedStreamCompatibility(params) {
|
|
7271
|
+
const { channelCount } = params;
|
|
7272
|
+
const profiles = params.profiles ?? ["main", "sub", "ext"];
|
|
7273
|
+
const expectedStreamType = { main: 0, sub: 1, ext: 0 };
|
|
7274
|
+
const allStreams = [];
|
|
7275
|
+
for (let ch = 0; ch < channelCount; ch++) {
|
|
7276
|
+
for (const p of profiles) {
|
|
7277
|
+
allStreams.push({ ch, profile: p, label: channelCount > 1 ? `ch${ch}_${p}` : p });
|
|
7278
|
+
}
|
|
7279
|
+
}
|
|
7280
|
+
const results = [];
|
|
7281
|
+
for (let i = 0; i < allStreams.length; i++) {
|
|
7282
|
+
for (let j = i + 1; j < allStreams.length; j++) {
|
|
7283
|
+
const a = allStreams[i];
|
|
7284
|
+
const b = allStreams[j];
|
|
7285
|
+
const stA = expectedStreamType[a.profile] ?? 0;
|
|
7286
|
+
const stB = expectedStreamType[b.profile] ?? 0;
|
|
7287
|
+
const sameChannel = a.ch === b.ch;
|
|
7288
|
+
let expectedOk;
|
|
7289
|
+
let reason;
|
|
7290
|
+
if (sameChannel && stA === stB) {
|
|
7291
|
+
expectedOk = false;
|
|
7292
|
+
reason = `same streamType (${stA}) on same channel`;
|
|
7293
|
+
} else if (!sameChannel && a.profile === b.profile) {
|
|
7294
|
+
expectedOk = false;
|
|
7295
|
+
reason = `multifocal rejects same profile (${a.profile}) across channels`;
|
|
7296
|
+
} else if (!sameChannel && stA === stB) {
|
|
7297
|
+
expectedOk = false;
|
|
7298
|
+
reason = `same streamType (${stA}) across channels`;
|
|
7299
|
+
} else {
|
|
7300
|
+
expectedOk = true;
|
|
7301
|
+
reason = `different streamTypes (${stA} vs ${stB})`;
|
|
7302
|
+
}
|
|
7303
|
+
results.push({ pair: [a.label, b.label], expectedOk, reason });
|
|
7304
|
+
}
|
|
7305
|
+
}
|
|
7306
|
+
return results;
|
|
7307
|
+
}
|
|
7308
|
+
async function captureModelFixtures(params) {
|
|
7309
|
+
const { api, channel, outDir } = params;
|
|
7310
|
+
const log = params.log ?? console.log;
|
|
7311
|
+
mkdirp(outDir);
|
|
7312
|
+
const writeJsonSafe = (filePath, data) => writeJson(filePath, sanitizeFixtureData(data));
|
|
7313
|
+
const writeTextSafe = (filePath, text) => writeText(filePath, sanitizeString(text));
|
|
7314
|
+
const calls = {};
|
|
7315
|
+
const errors = [];
|
|
7316
|
+
async function capture(name, fn, writer) {
|
|
7317
|
+
try {
|
|
7318
|
+
const value = await fn();
|
|
7319
|
+
calls[name] = { ok: true, value };
|
|
7320
|
+
if (writer && value !== void 0 && value !== null) {
|
|
7321
|
+
writer(value);
|
|
7322
|
+
}
|
|
7323
|
+
log(` \u2713 ${name}`);
|
|
7324
|
+
return value;
|
|
7325
|
+
} catch (e) {
|
|
7326
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
7327
|
+
calls[name] = { ok: false, error: msg };
|
|
7328
|
+
errors.push(`${name}: ${msg}`);
|
|
7329
|
+
log(` \u2717 ${name}: ${msg}`);
|
|
7330
|
+
return void 0;
|
|
7331
|
+
}
|
|
7332
|
+
}
|
|
7333
|
+
const info = await capture(
|
|
7334
|
+
"getInfo",
|
|
7335
|
+
() => api.getInfo(channel),
|
|
7336
|
+
(v) => writeJsonSafe(path4.join(outDir, "device-info.json"), v)
|
|
7337
|
+
);
|
|
7338
|
+
const support = await capture(
|
|
7339
|
+
"getSupportInfo",
|
|
7340
|
+
() => api.getSupportInfo(),
|
|
7341
|
+
(v) => writeJsonSafe(path4.join(outDir, "support-info.json"), v)
|
|
7342
|
+
);
|
|
7343
|
+
const abilities = await capture(
|
|
7344
|
+
"getAbilityInfo",
|
|
7345
|
+
() => api.getAbilityInfo(),
|
|
7346
|
+
(v) => writeJsonSafe(path4.join(outDir, "ability-info.json"), v)
|
|
7347
|
+
);
|
|
7348
|
+
await capture(
|
|
7349
|
+
"getDeviceCapabilities",
|
|
7350
|
+
() => api.getDeviceCapabilities(channel),
|
|
7351
|
+
(v) => writeJsonSafe(path4.join(outDir, "capabilities.json"), v)
|
|
7352
|
+
);
|
|
7353
|
+
await capture("cmd289-WhiteLed", () => api.sendXml({
|
|
7354
|
+
cmdId: BC_CMD_ID_GET_WHITE_LED,
|
|
7355
|
+
channel,
|
|
7356
|
+
timeoutMs: 3e3
|
|
7357
|
+
}), (v) => writeTextSafe(path4.join(outDir, "cmd289-white-led.xml"), v));
|
|
7358
|
+
await capture(
|
|
7359
|
+
"getStreamMetadata",
|
|
7360
|
+
() => api.getStreamMetadata(channel),
|
|
7361
|
+
(v) => writeJsonSafe(path4.join(outDir, "stream-metadata.json"), v)
|
|
7362
|
+
);
|
|
7363
|
+
await capture(
|
|
7364
|
+
"getEncXml",
|
|
7365
|
+
() => api.getEncXml(channel),
|
|
7366
|
+
(v) => writeTextSafe(path4.join(outDir, "enc-config.xml"), v)
|
|
7367
|
+
);
|
|
7368
|
+
await capture(
|
|
7369
|
+
"getPorts",
|
|
7370
|
+
() => api.getPorts(),
|
|
7371
|
+
(v) => writeJsonSafe(path4.join(outDir, "ports.json"), v)
|
|
7372
|
+
);
|
|
7373
|
+
await capture(
|
|
7374
|
+
"getTalkAbility",
|
|
7375
|
+
() => api.getTalkAbility(channel),
|
|
7376
|
+
(v) => writeJsonSafe(path4.join(outDir, "talk-ability.json"), v)
|
|
7377
|
+
);
|
|
7378
|
+
await capture(
|
|
7379
|
+
"getTwoWayAudioConfig",
|
|
7380
|
+
() => api.getTwoWayAudioConfig(channel),
|
|
7381
|
+
(v) => writeJsonSafe(path4.join(outDir, "two-way-audio-config.json"), v)
|
|
7382
|
+
);
|
|
7383
|
+
await capture(
|
|
7384
|
+
"getAiState",
|
|
7385
|
+
() => api.getAiState(channel),
|
|
7386
|
+
(v) => writeJsonSafe(path4.join(outDir, "ai-state.json"), v)
|
|
7387
|
+
);
|
|
7388
|
+
await capture(
|
|
7389
|
+
"getAiCfg",
|
|
7390
|
+
() => api.getAiCfg(channel),
|
|
7391
|
+
(v) => writeJsonSafe(path4.join(outDir, "ai-cfg.json"), v)
|
|
7392
|
+
);
|
|
7393
|
+
await capture(
|
|
7394
|
+
"getOsd",
|
|
7395
|
+
() => api.getOsd(channel),
|
|
7396
|
+
(v) => writeJsonSafe(path4.join(outDir, "osd.json"), v)
|
|
7397
|
+
);
|
|
7398
|
+
await capture(
|
|
7399
|
+
"getMotionAlarm",
|
|
7400
|
+
() => api.getMotionAlarm(channel),
|
|
7401
|
+
(v) => writeJsonSafe(path4.join(outDir, "motion-alarm.json"), v)
|
|
7402
|
+
);
|
|
7403
|
+
await capture(
|
|
7404
|
+
"getRecordCfg",
|
|
7405
|
+
() => api.getRecordCfg(channel),
|
|
7406
|
+
(v) => writeJsonSafe(path4.join(outDir, "record-cfg.json"), v)
|
|
7407
|
+
);
|
|
7408
|
+
await capture(
|
|
7409
|
+
"getVideoInput",
|
|
7410
|
+
() => api.getVideoInput(channel),
|
|
7411
|
+
(v) => writeJsonSafe(path4.join(outDir, "video-input.json"), v)
|
|
7412
|
+
);
|
|
7413
|
+
await capture(
|
|
7414
|
+
"getPtzPresets",
|
|
7415
|
+
() => api.getPtzPresets(channel),
|
|
7416
|
+
(v) => writeJsonSafe(path4.join(outDir, "ptz-presets.json"), v)
|
|
7417
|
+
);
|
|
7418
|
+
await capture(
|
|
7419
|
+
"getNetworkInfo",
|
|
7420
|
+
() => api.getNetworkInfo(),
|
|
7421
|
+
(v) => writeJsonSafe(path4.join(outDir, "network-info.json"), v)
|
|
7422
|
+
);
|
|
7423
|
+
await capture(
|
|
7424
|
+
"getSystemGeneral",
|
|
7425
|
+
() => api.getSystemGeneral(),
|
|
7426
|
+
(v) => writeJsonSafe(path4.join(outDir, "system-general.json"), v)
|
|
7427
|
+
);
|
|
7428
|
+
await capture(
|
|
7429
|
+
"getWifiSignal",
|
|
7430
|
+
() => api.getWifiSignal(channel),
|
|
7431
|
+
(v) => writeJsonSafe(path4.join(outDir, "wifi-signal.json"), v)
|
|
7432
|
+
);
|
|
7433
|
+
await capture(
|
|
7434
|
+
"getWhiteLedState",
|
|
7435
|
+
() => api.getWhiteLedState(channel),
|
|
7436
|
+
(v) => writeJsonSafe(path4.join(outDir, "white-led-state.json"), v)
|
|
7437
|
+
);
|
|
7438
|
+
await capture(
|
|
7439
|
+
"getFloodlightOnMotion",
|
|
7440
|
+
() => api.getFloodlightOnMotion(channel),
|
|
7441
|
+
(v) => writeJsonSafe(path4.join(outDir, "floodlight-on-motion.json"), v)
|
|
7442
|
+
);
|
|
7443
|
+
await capture(
|
|
7444
|
+
"buildVideoStreamOptions",
|
|
7445
|
+
() => api.buildVideoStreamOptions({ channel }),
|
|
7446
|
+
(v) => writeJsonSafe(path4.join(outDir, "video-stream-options.json"), v)
|
|
7447
|
+
);
|
|
7448
|
+
await capture(
|
|
7449
|
+
"getDualLensChannelInfo",
|
|
7450
|
+
() => api.getDualLensChannelInfo(channel),
|
|
7451
|
+
(v) => writeJsonSafe(path4.join(outDir, "dual-lens-info.json"), v)
|
|
7452
|
+
);
|
|
7453
|
+
await capture("streamCombinationTest", async () => {
|
|
7454
|
+
let dualLensInfo;
|
|
7455
|
+
try {
|
|
7456
|
+
dualLensInfo = await api.getDualLensChannelInfo(channel);
|
|
7457
|
+
} catch {
|
|
7458
|
+
}
|
|
7459
|
+
const isMultifocal = dualLensInfo?.isDualLens === true;
|
|
7460
|
+
const channelCount = dualLensInfo?.streamChannelCount ?? 1;
|
|
7461
|
+
const allStreams = [];
|
|
7462
|
+
const profiles = ["main", "sub", "ext"];
|
|
7463
|
+
for (let ch = 0; ch < channelCount; ch++) {
|
|
7464
|
+
for (const p of profiles) {
|
|
7465
|
+
const label = channelCount > 1 ? `ch${ch}_${p}` : p;
|
|
7466
|
+
allStreams.push({ ch, profile: p, label });
|
|
7467
|
+
}
|
|
7468
|
+
}
|
|
7469
|
+
const pairs = [];
|
|
7470
|
+
for (let i = 0; i < allStreams.length; i++) {
|
|
7471
|
+
for (let j = i + 1; j < allStreams.length; j++) {
|
|
7472
|
+
pairs.push([allStreams[i], allStreams[j]]);
|
|
7473
|
+
}
|
|
7474
|
+
}
|
|
7475
|
+
const expectedStreamType = { main: 0, sub: 1, ext: 0 };
|
|
7476
|
+
const expectedCompat = [];
|
|
7477
|
+
for (const [a, b] of pairs) {
|
|
7478
|
+
const stA = expectedStreamType[a.profile];
|
|
7479
|
+
const stB = expectedStreamType[b.profile];
|
|
7480
|
+
const sameChannel = a.ch === b.ch;
|
|
7481
|
+
let expectedOk;
|
|
7482
|
+
let reason;
|
|
7483
|
+
if (sameChannel && stA === stB) {
|
|
7484
|
+
expectedOk = false;
|
|
7485
|
+
reason = `same streamType (${stA}) on same channel`;
|
|
7486
|
+
} else if (!sameChannel && a.profile === b.profile) {
|
|
7487
|
+
expectedOk = false;
|
|
7488
|
+
reason = `multifocal rejects same profile (${a.profile}) across channels`;
|
|
7489
|
+
} else if (!sameChannel && stA === stB) {
|
|
7490
|
+
expectedOk = false;
|
|
7491
|
+
reason = `same streamType (${stA}) across channels`;
|
|
7492
|
+
} else {
|
|
7493
|
+
expectedOk = true;
|
|
7494
|
+
reason = `different streamTypes (${stA} vs ${stB})`;
|
|
7495
|
+
}
|
|
7496
|
+
expectedCompat.push({ pair: [a.label, b.label], expectedOk, reason });
|
|
7497
|
+
}
|
|
7498
|
+
const results = [];
|
|
7499
|
+
const TEST_DURATION_MS = 4e3;
|
|
7500
|
+
for (let pairIdx = 0; pairIdx < pairs.length; pairIdx++) {
|
|
7501
|
+
const [a, b] = pairs[pairIdx];
|
|
7502
|
+
const expected = expectedCompat[pairIdx];
|
|
7503
|
+
log(` testing ${a.label}+${b.label} on shared socket...`);
|
|
7504
|
+
let session;
|
|
7505
|
+
try {
|
|
7506
|
+
session = await api.createDedicatedSession(
|
|
7507
|
+
`test:combo:${a.label}_${b.label}`
|
|
7508
|
+
);
|
|
7509
|
+
} catch (e) {
|
|
7510
|
+
const result2 = {
|
|
7511
|
+
pair: [a.label, b.label],
|
|
7512
|
+
ok: false,
|
|
7513
|
+
framesA: 0,
|
|
7514
|
+
framesB: 0,
|
|
7515
|
+
mismatches: 0,
|
|
7516
|
+
error: `session: ${e instanceof Error ? e.message : String(e)}`,
|
|
7517
|
+
durationMs: 0,
|
|
7518
|
+
expectedOk: expected.expectedOk,
|
|
7519
|
+
expectedReason: expected.reason,
|
|
7520
|
+
matchesExpected: !expected.expectedOk
|
|
7521
|
+
// failed as expected if we expected failure
|
|
7522
|
+
};
|
|
7523
|
+
results.push(result2);
|
|
7524
|
+
continue;
|
|
7525
|
+
}
|
|
7526
|
+
const testClient = session.client;
|
|
7527
|
+
let framesA = 0;
|
|
7528
|
+
let framesB = 0;
|
|
7529
|
+
let mismatches = 0;
|
|
7530
|
+
const start = Date.now();
|
|
7531
|
+
const stTypes = {
|
|
7532
|
+
main: /* @__PURE__ */ new Set([0, 2]),
|
|
7533
|
+
sub: /* @__PURE__ */ new Set([1, 3]),
|
|
7534
|
+
ext: /* @__PURE__ */ new Set([0, 2])
|
|
7535
|
+
};
|
|
7536
|
+
const setA = stTypes[a.profile];
|
|
7537
|
+
const setB = stTypes[b.profile];
|
|
7538
|
+
const onFrame = (frame) => {
|
|
7539
|
+
if (frame.header?.cmdId !== BC_CMD_ID_VIDEO) return;
|
|
7540
|
+
const st = frame.header.streamType;
|
|
7541
|
+
if (setA.has(st)) framesA++;
|
|
7542
|
+
else if (setB.has(st)) framesB++;
|
|
7543
|
+
else mismatches++;
|
|
7544
|
+
};
|
|
7545
|
+
testClient.on("frame", onFrame);
|
|
7546
|
+
let error;
|
|
7547
|
+
try {
|
|
7548
|
+
await api.startVideoStream(a.ch, a.profile, { client: testClient });
|
|
7549
|
+
await api.startVideoStream(b.ch, b.profile, { client: testClient });
|
|
7550
|
+
await new Promise((r) => setTimeout(r, TEST_DURATION_MS));
|
|
7551
|
+
await api.stopVideoStream(a.ch, a.profile, { client: testClient }).catch(() => {
|
|
7552
|
+
});
|
|
7553
|
+
await api.stopVideoStream(b.ch, b.profile, { client: testClient }).catch(() => {
|
|
7554
|
+
});
|
|
7555
|
+
} catch (e) {
|
|
7556
|
+
error = e instanceof Error ? e.message : String(e);
|
|
7557
|
+
} finally {
|
|
7558
|
+
testClient.removeListener("frame", onFrame);
|
|
7559
|
+
await session.release().catch(() => {
|
|
7560
|
+
});
|
|
7561
|
+
}
|
|
7562
|
+
const elapsed = Date.now() - start;
|
|
7563
|
+
const ok2 = !error && framesA > 0 && framesB > 0 && mismatches === 0;
|
|
7564
|
+
const result = {
|
|
7565
|
+
pair: [a.label, b.label],
|
|
7566
|
+
ok: ok2,
|
|
7567
|
+
framesA,
|
|
7568
|
+
framesB,
|
|
7569
|
+
mismatches,
|
|
7570
|
+
...error ? { error } : {},
|
|
7571
|
+
durationMs: elapsed,
|
|
7572
|
+
expectedOk: expected.expectedOk,
|
|
7573
|
+
expectedReason: expected.reason,
|
|
7574
|
+
matchesExpected: ok2 === expected.expectedOk
|
|
7575
|
+
};
|
|
7576
|
+
results.push(result);
|
|
7577
|
+
const matchStr = result.matchesExpected ? "" : " *** UNEXPECTED ***";
|
|
7578
|
+
log(` ${a.label}+${b.label}: ${ok2 ? "OK" : "FAIL"} (expected=${expected.expectedOk ? "OK" : "FAIL"}) A=${framesA} B=${framesB} mismatch=${mismatches}${matchStr}`);
|
|
7579
|
+
}
|
|
7580
|
+
const unexpected = results.filter((r) => !r.matchesExpected);
|
|
7581
|
+
return {
|
|
7582
|
+
isMultifocal,
|
|
7583
|
+
channelCount,
|
|
7584
|
+
results,
|
|
7585
|
+
summary: {
|
|
7586
|
+
total: results.length,
|
|
7587
|
+
ok: results.filter((r) => r.ok).length,
|
|
7588
|
+
failed: results.filter((r) => !r.ok).length,
|
|
7589
|
+
matchesExpected: results.filter((r) => r.matchesExpected).length,
|
|
7590
|
+
unexpected: unexpected.map((r) => `${r.pair[0]}+${r.pair[1]}: got ${r.ok ? "OK" : "FAIL"}, expected ${r.expectedOk ? "OK" : "FAIL"}`)
|
|
7591
|
+
}
|
|
7592
|
+
};
|
|
7593
|
+
}, (v) => writeJsonSafe(path4.join(outDir, "stream-combination-test.json"), v));
|
|
7594
|
+
const total = Object.keys(calls).length;
|
|
7595
|
+
const ok = Object.values(calls).filter((c) => c.ok).length;
|
|
7596
|
+
const failed = total - ok;
|
|
7597
|
+
const summary = { total, ok, failed, errors };
|
|
7598
|
+
writeJsonSafe(path4.join(outDir, "_summary.json"), {
|
|
7599
|
+
collectedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7600
|
+
model: info?.type ?? "unknown",
|
|
7601
|
+
itemNo: info?.itemNo ?? "unknown",
|
|
7602
|
+
firmwareVersion: info?.firmwareVersion ?? "unknown",
|
|
7603
|
+
channel,
|
|
7604
|
+
...summary,
|
|
7605
|
+
calls: Object.fromEntries(
|
|
7606
|
+
Object.entries(calls).map(([k, v]) => [
|
|
7607
|
+
k,
|
|
7608
|
+
v.ok ? "ok" : `FAILED: ${v.error}`
|
|
7609
|
+
])
|
|
7610
|
+
)
|
|
7611
|
+
});
|
|
7612
|
+
log(`
|
|
7613
|
+
Summary: ${ok}/${total} ok, ${failed} failed`);
|
|
7614
|
+
if (errors.length) {
|
|
7615
|
+
log(` Errors:`);
|
|
7616
|
+
for (const err of errors) {
|
|
7617
|
+
log(` - ${err}`);
|
|
7618
|
+
}
|
|
7619
|
+
}
|
|
7620
|
+
return { calls, outDir, summary };
|
|
7621
|
+
}
|
|
7622
|
+
var fs4, path4, import_node_child_process2, import_node_path, REDACT_KEYS, MASK_KEYS, IPV4_RE, MAC_RE;
|
|
7212
7623
|
var init_DiagnosticsTools = __esm({
|
|
7213
7624
|
"src/debug/DiagnosticsTools.ts"() {
|
|
7214
7625
|
"use strict";
|
|
@@ -7224,6 +7635,27 @@ var init_DiagnosticsTools = __esm({
|
|
|
7224
7635
|
init_H265Converter();
|
|
7225
7636
|
init_constants();
|
|
7226
7637
|
init_xml();
|
|
7638
|
+
REDACT_KEYS = /* @__PURE__ */ new Set([
|
|
7639
|
+
"password",
|
|
7640
|
+
"pass",
|
|
7641
|
+
"token",
|
|
7642
|
+
"secret",
|
|
7643
|
+
"apiKey",
|
|
7644
|
+
"api_key"
|
|
7645
|
+
]);
|
|
7646
|
+
MASK_KEYS = /* @__PURE__ */ new Set([
|
|
7647
|
+
"serialNumber",
|
|
7648
|
+
"serial",
|
|
7649
|
+
"uid",
|
|
7650
|
+
"mac",
|
|
7651
|
+
"ssid",
|
|
7652
|
+
"wifiPassword",
|
|
7653
|
+
"userName",
|
|
7654
|
+
"username",
|
|
7655
|
+
"user"
|
|
7656
|
+
]);
|
|
7657
|
+
IPV4_RE = /\b(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\b/g;
|
|
7658
|
+
MAC_RE = /\b([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}\b/g;
|
|
7227
7659
|
}
|
|
7228
7660
|
});
|
|
7229
7661
|
|
|
@@ -14680,7 +15112,7 @@ function computeDeviceCapabilities(params) {
|
|
|
14680
15112
|
const ptzControlRaw = supportItem ? supportItem.ptzControl : void 0;
|
|
14681
15113
|
const supportExplicitlyDefinesPtz = ptzTypeRaw !== void 0 || ptzControlRaw !== void 0;
|
|
14682
15114
|
const ptzExplicitlyDisabledBySupportItem = supportExplicitlyDefinesPtz && !isTruthyNumberLike(ptzTypeRaw) && !isTruthyNumberLike(ptzControlRaw);
|
|
14683
|
-
const hasPtzFromSupportItem = isTruthyNumberLike(ptzTypeRaw)
|
|
15115
|
+
const hasPtzFromSupportItem = isTruthyNumberLike(ptzTypeRaw);
|
|
14684
15116
|
const ptzDisabledBySupport = (ptzMode === "none" || ptzMode === "0") && !hasPtzFromSupportItem;
|
|
14685
15117
|
const hasBatteryFromSupport = supportItem ? isTruthyNumberLike(supportItem.battery) : false;
|
|
14686
15118
|
const ptzPresetRaw = supportItem ? supportItem.ptzPreset : void 0;
|
|
@@ -14744,6 +15176,17 @@ function computeDeviceCapabilities(params) {
|
|
|
14744
15176
|
if (ptzMode !== void 0) result.ptzMode = ptzMode;
|
|
14745
15177
|
return result;
|
|
14746
15178
|
}
|
|
15179
|
+
function xmlIndicatesFloodlight(xml) {
|
|
15180
|
+
if (/(<FloodlightTask\b|<FloodlightManual\b|<FloodlightStatusList\b)/i.test(
|
|
15181
|
+
xml
|
|
15182
|
+
)) {
|
|
15183
|
+
return true;
|
|
15184
|
+
}
|
|
15185
|
+
if (/<WhiteLed\b/i.test(xml)) {
|
|
15186
|
+
return /(<brightness_cur>|<bright>|<LightingSchedule\b)/i.test(xml);
|
|
15187
|
+
}
|
|
15188
|
+
return false;
|
|
15189
|
+
}
|
|
14747
15190
|
|
|
14748
15191
|
// src/reolink/baichuan/utils/abilityInfo.ts
|
|
14749
15192
|
init_xml();
|
|
@@ -23780,9 +24223,7 @@ ${stderr}`)
|
|
|
23780
24223
|
`probeFloodlightSupportByCmd289: received XML for channel ${ch}:
|
|
23781
24224
|
${xml}`
|
|
23782
24225
|
);
|
|
23783
|
-
return
|
|
23784
|
-
xml
|
|
23785
|
-
);
|
|
24226
|
+
return xmlIndicatesFloodlight(xml);
|
|
23786
24227
|
} catch {
|
|
23787
24228
|
return false;
|
|
23788
24229
|
}
|