@mega-yfue/eufy-sdk 0.3.0-beta.0 → 0.3.0-beta.2
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/index.js +94 -24
- package/dist/index.js.map +3 -3
- package/dist/transport/p2p/p2p-session.d.ts +12 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5813,6 +5813,7 @@ var LIGHT_SWITCH_JSON_TYPES = /* @__PURE__ */ new Set([
|
|
|
5813
5813
|
DeviceType.CAMERA_4G_S330
|
|
5814
5814
|
]);
|
|
5815
5815
|
var LIGHT_SWITCH_INT_STRING_TYPES = /* @__PURE__ */ new Set([
|
|
5816
|
+
DeviceType.FLOODLIGHT_CAMERA_8423,
|
|
5816
5817
|
DeviceType.INDOOR_OUTDOOR_CAMERA_1080P_NO_LIGHT,
|
|
5817
5818
|
DeviceType.INDOOR_OUTDOOR_CAMERA_2K,
|
|
5818
5819
|
DeviceType.INDOOR_OUTDOOR_CAMERA_1080P,
|
|
@@ -15139,6 +15140,7 @@ var LIVE_START_RETRANSMIT_MS = 150;
|
|
|
15139
15140
|
var LIVE_START_ACK_DEADLINE_MS = 3e3;
|
|
15140
15141
|
var SEQUENCE_LOOKBACK = 32768;
|
|
15141
15142
|
var STALE_RETRANSMIT_DEPTH = 1024;
|
|
15143
|
+
var PUNCH_PROBE_SOCKETS = 7;
|
|
15142
15144
|
var MAX_TRACED_DATAGRAM_GAPS = 8;
|
|
15143
15145
|
var CMD_SET_PAYLOAD = 1350;
|
|
15144
15146
|
var CMD_NOTIFY_PAYLOAD = 1351;
|
|
@@ -15200,8 +15202,12 @@ var P2PSession = class _P2PSession extends EventEmitter2 {
|
|
|
15200
15202
|
lookupTimer;
|
|
15201
15203
|
heartbeatTimer;
|
|
15202
15204
|
connectTimer;
|
|
15203
|
-
/**
|
|
15204
|
-
|
|
15205
|
+
/** Extra sockets registered alongside {@link socket} while connecting; see {@link PUNCH_PROBE_SOCKETS}. */
|
|
15206
|
+
probeSockets = [];
|
|
15207
|
+
/** Cloud lookup inputs resolved once for a connection. */
|
|
15208
|
+
cloudLookup;
|
|
15209
|
+
/** Local outbound IPv4 reported inside LOOKUP_WITH_KEY requests. */
|
|
15210
|
+
selfHost;
|
|
15205
15211
|
/** In-flight multi-datagram frame per data channel (see onData). */
|
|
15206
15212
|
pendingByDataType = /* @__PURE__ */ new Map();
|
|
15207
15213
|
/** Last datagram sequence number seen per dataType — used to detect a lost/reordered datagram
|
|
@@ -15496,7 +15502,7 @@ var P2PSession = class _P2PSession extends EventEmitter2 {
|
|
|
15496
15502
|
}
|
|
15497
15503
|
const socket = dgram.createSocket("udp4");
|
|
15498
15504
|
this.socket = socket;
|
|
15499
|
-
socket.on("message", (msg, rinfo) => this.onMessage(msg, rinfo));
|
|
15505
|
+
socket.on("message", (msg, rinfo) => this.onMessage(msg, rinfo, socket));
|
|
15500
15506
|
socket.on("error", (e) => this.emit("error", e));
|
|
15501
15507
|
await new Promise((resolve) => {
|
|
15502
15508
|
socket.bind(() => {
|
|
@@ -15507,15 +15513,20 @@ var P2PSession = class _P2PSession extends EventEmitter2 {
|
|
|
15507
15513
|
resolve();
|
|
15508
15514
|
});
|
|
15509
15515
|
});
|
|
15510
|
-
const boundPort = socket.address().port;
|
|
15511
15516
|
void _P2PSession.detectLocalIp().then((host) => {
|
|
15512
15517
|
if (host && !this.closed)
|
|
15513
|
-
this.
|
|
15518
|
+
this.selfHost = host;
|
|
15514
15519
|
});
|
|
15520
|
+
const { dskKey, cloudAddresses } = this.cfg;
|
|
15521
|
+
this.cloudLookup = dskKey && cloudAddresses?.length ? { key: dskKey, addresses: cloudAddresses } : void 0;
|
|
15522
|
+
if (this.cloudLookup)
|
|
15523
|
+
await this.startPunchProbes();
|
|
15524
|
+
if (this.closed)
|
|
15525
|
+
return;
|
|
15515
15526
|
this.trace({
|
|
15516
15527
|
phase: "lookup-channels",
|
|
15517
15528
|
local: !this.cfg.noBroadcast || this.cfg.localAddress !== void 0,
|
|
15518
|
-
cloud: this.
|
|
15529
|
+
cloud: this.cloudLookup !== void 0
|
|
15519
15530
|
});
|
|
15520
15531
|
this.sendLookups();
|
|
15521
15532
|
this.lookupTimer = setInterval(() => this.sendLookups(), LOOKUP_RETRY_MS);
|
|
@@ -15593,14 +15604,20 @@ var P2PSession = class _P2PSession extends EventEmitter2 {
|
|
|
15593
15604
|
this.send({ host: "255.255.255.255", port: LOCAL_LOOKUP_PORT }, RequestMessageType.LOCAL_LOOKUP, localPayload);
|
|
15594
15605
|
if (this.cfg.localAddress)
|
|
15595
15606
|
this.send({ host: this.cfg.localAddress, port: LOCAL_LOOKUP_PORT }, RequestMessageType.LOCAL_LOOKUP, localPayload);
|
|
15596
|
-
|
|
15597
|
-
|
|
15598
|
-
const
|
|
15599
|
-
|
|
15600
|
-
|
|
15601
|
-
this.logger.debug(`[p2p] ${this.cfg.stationSn} sendLookups: cloud -> ${this.cfg.cloudAddresses.map((a) => `${a.host}:${a.port}`).join(", ")} self=${this.selfAddress?.host}:${this.selfAddress?.port}`);
|
|
15607
|
+
const lookup2 = this.cloudLookup;
|
|
15608
|
+
if (lookup2) {
|
|
15609
|
+
for (const socket of [this.socket, ...this.probeSockets])
|
|
15610
|
+
this.sendCloudLookup(socket, lookup2);
|
|
15611
|
+
this.logger.debug(`[p2p] ${this.cfg.stationSn} sendLookups: cloud -> ${lookup2.addresses.map((a) => `${a.host}:${a.port}`).join(", ")} self=${this.selfHost ?? "unknown"}`);
|
|
15602
15612
|
}
|
|
15603
15613
|
}
|
|
15614
|
+
/** Register a bound socket's own port with each configured cloud lookup address. */
|
|
15615
|
+
sendCloudLookup(socket, lookup2) {
|
|
15616
|
+
const payload = this.selfHost ? buildLookupWithKeyPayload(this.cfg.p2pDid, this.selfHost, socket.address().port, lookup2.key) : buildLookupWithKeyPayload2(this.cfg.p2pDid, lookup2.key);
|
|
15617
|
+
const type = this.selfHost ? RequestMessageType.LOOKUP_WITH_KEY : RequestMessageType.LOOKUP_WITH_KEY2;
|
|
15618
|
+
for (const addr of lookup2.addresses)
|
|
15619
|
+
this.send(addr, type, payload, socket);
|
|
15620
|
+
}
|
|
15604
15621
|
/**
|
|
15605
15622
|
* Route one inbound UDP datagram by its message type, tracing every non-DATA one and any type this session
|
|
15606
15623
|
* does not model.
|
|
@@ -15612,28 +15629,30 @@ var P2PSession = class _P2PSession extends EventEmitter2 {
|
|
|
15612
15629
|
* recur across later probes of it. Correlate an unmodelled type against a WORKING session before reading it
|
|
15613
15630
|
* as a cause.
|
|
15614
15631
|
*/
|
|
15615
|
-
onMessage(msg, rinfo) {
|
|
15632
|
+
onMessage(msg, rinfo, socket = this.socket) {
|
|
15633
|
+
if (!socket)
|
|
15634
|
+
return;
|
|
15616
15635
|
if (!hasHeader(msg, ResponseMessageType.DATA)) {
|
|
15617
15636
|
this.logger.debug(`[p2p] ${this.cfg.stationSn} <<< ${rinfo.address}:${rinfo.port} header=${msg.subarray(0, 2).toString("hex")} len=${msg.length}`);
|
|
15618
15637
|
}
|
|
15619
15638
|
if (hasHeader(msg, ResponseMessageType.LOCAL_LOOKUP_RESP)) {
|
|
15620
15639
|
if (!this.connected)
|
|
15621
|
-
this.beginCheckCam({ host: rinfo.address, port: rinfo.port });
|
|
15640
|
+
this.beginCheckCam({ host: rinfo.address, port: rinfo.port }, socket);
|
|
15622
15641
|
} else if (hasHeader(msg, ResponseMessageType.LOOKUP_ADDR) || hasHeader(msg, ResponseMessageType.LOOKUP_ADDR2)) {
|
|
15623
15642
|
if (!this.connected) {
|
|
15624
15643
|
const addr = parseLookupAddr(msg);
|
|
15625
15644
|
this.logger.debug(`[p2p] ${this.cfg.stationSn} LOOKUP_ADDR -> ${addr.host}:${addr.port}`);
|
|
15626
15645
|
if (addr.host !== "0.0.0.0")
|
|
15627
|
-
this.beginCheckCam(addr);
|
|
15646
|
+
this.beginCheckCam(addr, socket);
|
|
15628
15647
|
}
|
|
15629
15648
|
} else if (hasHeader(msg, ResponseMessageType.CAM_ID) || hasHeader(msg, ResponseMessageType.TURN_SERVER_CAM_ID)) {
|
|
15630
|
-
this.onConnected({ host: rinfo.address, port: rinfo.port });
|
|
15649
|
+
this.onConnected({ host: rinfo.address, port: rinfo.port }, socket);
|
|
15631
15650
|
} else if (hasHeader(msg, ResponseMessageType.PONG)) {
|
|
15632
15651
|
this.lastPongData = msg.length > 4 ? msg.subarray(4) : void 0;
|
|
15633
15652
|
this.lastPongAt = Date.now();
|
|
15634
15653
|
this.pathStaleTraced = false;
|
|
15635
15654
|
} else if (hasHeader(msg, ResponseMessageType.PING)) {
|
|
15636
|
-
this.send({ host: rinfo.address, port: rinfo.port }, RequestMessageType.PONG);
|
|
15655
|
+
this.send({ host: rinfo.address, port: rinfo.port }, RequestMessageType.PONG, void 0, socket);
|
|
15637
15656
|
} else if (hasHeader(msg, ResponseMessageType.ACK)) {
|
|
15638
15657
|
this.onAck(msg);
|
|
15639
15658
|
} else if (hasHeader(msg, ResponseMessageType.DATA)) {
|
|
@@ -15643,17 +15662,67 @@ var P2PSession = class _P2PSession extends EventEmitter2 {
|
|
|
15643
15662
|
this.logger.debug(`[p2p] ${this.cfg.stationSn} UNHANDLED payload hex: ${msg.toString("hex")}`);
|
|
15644
15663
|
}
|
|
15645
15664
|
}
|
|
15646
|
-
beginCheckCam(addr) {
|
|
15665
|
+
beginCheckCam(addr, socket) {
|
|
15647
15666
|
this.logger.debug(`[p2p] ${this.cfg.stationSn} beginCheckCam -> ${addr.host}:${addr.port} (+/-3)`);
|
|
15648
15667
|
const payload = buildCheckCamPayload(this.cfg.p2pDid);
|
|
15649
|
-
this.send(addr, RequestMessageType.CHECK_CAM, payload);
|
|
15668
|
+
this.send(addr, RequestMessageType.CHECK_CAM, payload, socket);
|
|
15650
15669
|
for (let p = addr.port - 3; p <= addr.port + 3; p++)
|
|
15651
15670
|
if (p !== addr.port && p > 0)
|
|
15652
|
-
this.send({ host: addr.host, port: p }, RequestMessageType.CHECK_CAM, payload);
|
|
15671
|
+
this.send({ host: addr.host, port: p }, RequestMessageType.CHECK_CAM, payload, socket);
|
|
15672
|
+
}
|
|
15673
|
+
/** Bind additional UDP source ports before the first cloud lookup. */
|
|
15674
|
+
async startPunchProbes() {
|
|
15675
|
+
await Promise.all(Array.from({ length: PUNCH_PROBE_SOCKETS }, async () => {
|
|
15676
|
+
const probe = dgram.createSocket("udp4");
|
|
15677
|
+
probe.on("error", (error) => this.logger.warn("[p2p] lookup socket error", error.message));
|
|
15678
|
+
probe.on("message", (msg, rinfo) => this.onMessage(msg, rinfo, probe));
|
|
15679
|
+
this.probeSockets.push(probe);
|
|
15680
|
+
await new Promise((resolve) => {
|
|
15681
|
+
let settled = false;
|
|
15682
|
+
const finish = (bound) => {
|
|
15683
|
+
if (settled)
|
|
15684
|
+
return;
|
|
15685
|
+
settled = true;
|
|
15686
|
+
probe.off("error", onError);
|
|
15687
|
+
probe.off("close", onClose);
|
|
15688
|
+
if (!bound) {
|
|
15689
|
+
this.probeSockets = this.probeSockets.filter((socket) => socket !== probe);
|
|
15690
|
+
try {
|
|
15691
|
+
probe.close();
|
|
15692
|
+
} catch {
|
|
15693
|
+
}
|
|
15694
|
+
}
|
|
15695
|
+
resolve();
|
|
15696
|
+
};
|
|
15697
|
+
const onError = () => finish(false);
|
|
15698
|
+
const onClose = () => finish(false);
|
|
15699
|
+
probe.once("error", onError);
|
|
15700
|
+
probe.once("close", onClose);
|
|
15701
|
+
probe.bind(() => finish(true));
|
|
15702
|
+
});
|
|
15703
|
+
}));
|
|
15653
15704
|
}
|
|
15654
|
-
|
|
15705
|
+
/** Close all lookup sockets except the one that completed the handshake. */
|
|
15706
|
+
stopPunchProbes(winner) {
|
|
15707
|
+
for (const probe of this.probeSockets) {
|
|
15708
|
+
if (probe === winner)
|
|
15709
|
+
continue;
|
|
15710
|
+
probe.removeAllListeners("message");
|
|
15711
|
+
probe.close();
|
|
15712
|
+
}
|
|
15713
|
+
this.probeSockets = [];
|
|
15714
|
+
}
|
|
15715
|
+
onConnected(addr, socket) {
|
|
15655
15716
|
if (this.connected)
|
|
15656
15717
|
return;
|
|
15718
|
+
this.stopPunchProbes(socket);
|
|
15719
|
+
if (this.socket !== socket) {
|
|
15720
|
+
this.socket?.removeAllListeners();
|
|
15721
|
+
this.socket?.close();
|
|
15722
|
+
socket.removeAllListeners("error");
|
|
15723
|
+
socket.on("error", (error) => this.emit("error", error));
|
|
15724
|
+
this.socket = socket;
|
|
15725
|
+
}
|
|
15657
15726
|
this.connected = true;
|
|
15658
15727
|
this.connectedAtMs = Date.now();
|
|
15659
15728
|
this.connecting = false;
|
|
@@ -16540,11 +16609,11 @@ var P2PSession = class _P2PSession extends EventEmitter2 {
|
|
|
16540
16609
|
}
|
|
16541
16610
|
this.emit("data", frame);
|
|
16542
16611
|
}
|
|
16543
|
-
send(addr, type, payload) {
|
|
16544
|
-
if (!
|
|
16612
|
+
send(addr, type, payload, socket = this.socket) {
|
|
16613
|
+
if (!socket)
|
|
16545
16614
|
return;
|
|
16546
16615
|
const packet = frameMessage(type, payload);
|
|
16547
|
-
|
|
16616
|
+
socket.send(packet, addr.port, addr.host, (err) => {
|
|
16548
16617
|
if (err)
|
|
16549
16618
|
this.logger.warn(`[p2p] send err ${addr.host}:${addr.port}`, err.message);
|
|
16550
16619
|
});
|
|
@@ -16553,6 +16622,7 @@ var P2PSession = class _P2PSession extends EventEmitter2 {
|
|
|
16553
16622
|
if (this.closed)
|
|
16554
16623
|
return;
|
|
16555
16624
|
this.closed = true;
|
|
16625
|
+
this.stopPunchProbes();
|
|
16556
16626
|
this.connectionGeneration += 1;
|
|
16557
16627
|
this.level2Key = void 0;
|
|
16558
16628
|
this.level2Seq = 0;
|