hap-nodejs 1.0.0-beta.7 → 1.0.0
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/README.md +7 -3
- package/dist/accessories/AirConditioner_accessory.js +24 -24
- package/dist/accessories/AirConditioner_accessory.js.map +1 -1
- package/dist/accessories/AppleTVRemote_accessory.js +23 -23
- package/dist/accessories/AppleTVRemote_accessory.js.map +1 -1
- package/dist/accessories/Camera_accessory.js +295 -380
- package/dist/accessories/Camera_accessory.js.map +1 -1
- package/dist/accessories/Fan_accessory.js +15 -21
- package/dist/accessories/Fan_accessory.js.map +1 -1
- package/dist/accessories/GarageDoorOpener_accessory.js +12 -12
- package/dist/accessories/GarageDoorOpener_accessory.js.map +1 -1
- package/dist/accessories/Light-AdaptiveLighting_accessory.js +31 -21
- package/dist/accessories/Light-AdaptiveLighting_accessory.js.map +1 -1
- package/dist/accessories/Light_accessory.js +45 -48
- package/dist/accessories/Light_accessory.js.map +1 -1
- package/dist/accessories/Lock_accessory.js +11 -11
- package/dist/accessories/Lock_accessory.js.map +1 -1
- package/dist/accessories/MotionSensor_accessory.js +8 -8
- package/dist/accessories/MotionSensor_accessory.js.map +1 -1
- package/dist/accessories/Outlet_accessory.js +10 -10
- package/dist/accessories/Outlet_accessory.js.map +1 -1
- package/dist/accessories/SmartSpeaker_accessory.js +11 -11
- package/dist/accessories/SmartSpeaker_accessory.js.map +1 -1
- package/dist/accessories/Sprinkler_accessory.js +19 -19
- package/dist/accessories/Sprinkler_accessory.js.map +1 -1
- package/dist/accessories/TV_accessory.js +17 -17
- package/dist/accessories/TV_accessory.js.map +1 -1
- package/dist/accessories/TemperatureSensor_accessory.js +6 -6
- package/dist/accessories/TemperatureSensor_accessory.js.map +1 -1
- package/dist/accessories/Wi-FiRouter_accessory.js +3 -3
- package/dist/accessories/Wi-FiRouter_accessory.js.map +1 -1
- package/dist/accessories/Wi-FiSatellite_accessory.js +4 -4
- package/dist/accessories/Wi-FiSatellite_accessory.js.map +1 -1
- package/dist/accessories/gstreamer-audioProducer.js +45 -55
- package/dist/accessories/gstreamer-audioProducer.js.map +1 -1
- package/dist/accessories/types.js +2 -2
- package/dist/accessories/types.js.map +1 -1
- package/dist/index.d.ts +0 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -31
- package/dist/index.js.map +1 -1
- package/dist/internal-types.d.ts +4 -4
- package/dist/internal-types.d.ts.map +1 -1
- package/dist/internal-types.js +10 -6
- package/dist/internal-types.js.map +1 -1
- package/dist/lib/Accessory.d.ts +19 -74
- package/dist/lib/Accessory.d.ts.map +1 -1
- package/dist/lib/Accessory.js +775 -1155
- package/dist/lib/Accessory.js.map +1 -1
- package/dist/lib/Advertiser.d.ts +5 -6
- package/dist/lib/Advertiser.d.ts.map +1 -1
- package/dist/lib/Advertiser.js +402 -521
- package/dist/lib/Advertiser.js.map +1 -1
- package/dist/lib/Bridge.js +6 -10
- package/dist/lib/Bridge.js.map +1 -1
- package/dist/lib/Characteristic.d.ts +31 -93
- package/dist/lib/Characteristic.d.ts.map +1 -1
- package/dist/lib/Characteristic.js +1474 -668
- package/dist/lib/Characteristic.js.map +1 -1
- package/dist/lib/HAPServer.d.ts +10 -22
- package/dist/lib/HAPServer.d.ts.map +1 -1
- package/dist/lib/HAPServer.js +224 -286
- package/dist/lib/HAPServer.js.map +1 -1
- package/dist/lib/Service.d.ts +9 -27
- package/dist/lib/Service.d.ts.map +1 -1
- package/dist/lib/Service.js +476 -314
- package/dist/lib/Service.js.map +1 -1
- package/dist/lib/camera/RTPProxy.d.ts +0 -2
- package/dist/lib/camera/RTPProxy.d.ts.map +1 -1
- package/dist/lib/camera/RTPProxy.js +112 -104
- package/dist/lib/camera/RTPProxy.js.map +1 -1
- package/dist/lib/camera/RTPStreamManagement.d.ts +2 -67
- package/dist/lib/camera/RTPStreamManagement.d.ts.map +1 -1
- package/dist/lib/camera/RTPStreamManagement.js +272 -292
- package/dist/lib/camera/RTPStreamManagement.js.map +1 -1
- package/dist/lib/camera/RecordingManagement.d.ts +0 -1
- package/dist/lib/camera/RecordingManagement.d.ts.map +1 -1
- package/dist/lib/camera/RecordingManagement.js +325 -392
- package/dist/lib/camera/RecordingManagement.js.map +1 -1
- package/dist/lib/camera/index.d.ts +0 -1
- package/dist/lib/camera/index.d.ts.map +1 -1
- package/dist/lib/camera/index.js +1 -2
- package/dist/lib/camera/index.js.map +1 -1
- package/dist/lib/controller/AdaptiveLightingController.d.ts +19 -4
- package/dist/lib/controller/AdaptiveLightingController.d.ts.map +1 -1
- package/dist/lib/controller/AdaptiveLightingController.js +220 -221
- package/dist/lib/controller/AdaptiveLightingController.js.map +1 -1
- package/dist/lib/controller/CameraController.d.ts +0 -6
- package/dist/lib/controller/CameraController.d.ts.map +1 -1
- package/dist/lib/controller/CameraController.js +192 -258
- package/dist/lib/controller/CameraController.js.map +1 -1
- package/dist/lib/controller/Controller.d.ts +1 -1
- package/dist/lib/controller/Controller.d.ts.map +1 -1
- package/dist/lib/controller/Controller.js +3 -3
- package/dist/lib/controller/Controller.js.map +1 -1
- package/dist/lib/controller/DoorbellController.js +38 -39
- package/dist/lib/controller/DoorbellController.js.map +1 -1
- package/dist/lib/controller/RemoteController.d.ts +4 -20
- package/dist/lib/controller/RemoteController.d.ts.map +1 -1
- package/dist/lib/controller/RemoteController.js +351 -424
- package/dist/lib/controller/RemoteController.js.map +1 -1
- package/dist/lib/controller/index.js +1 -1
- package/dist/lib/datastream/DataStreamManagement.js +57 -58
- package/dist/lib/datastream/DataStreamManagement.js.map +1 -1
- package/dist/lib/datastream/DataStreamParser.d.ts +0 -1
- package/dist/lib/datastream/DataStreamParser.d.ts.map +1 -1
- package/dist/lib/datastream/DataStreamParser.js +261 -306
- package/dist/lib/datastream/DataStreamParser.js.map +1 -1
- package/dist/lib/datastream/DataStreamServer.d.ts +0 -8
- package/dist/lib/datastream/DataStreamServer.d.ts.map +1 -1
- package/dist/lib/datastream/DataStreamServer.js +262 -275
- package/dist/lib/datastream/DataStreamServer.js.map +1 -1
- package/dist/lib/datastream/index.js +1 -1
- package/dist/lib/definitions/CharacteristicDefinitions.d.ts +50 -40
- package/dist/lib/definitions/CharacteristicDefinitions.d.ts.map +1 -1
- package/dist/lib/definitions/CharacteristicDefinitions.js +2059 -2754
- package/dist/lib/definitions/CharacteristicDefinitions.js.map +1 -1
- package/dist/lib/definitions/ServiceDefinitions.d.ts +14 -8
- package/dist/lib/definitions/ServiceDefinitions.d.ts.map +1 -1
- package/dist/lib/definitions/ServiceDefinitions.js +834 -1053
- package/dist/lib/definitions/ServiceDefinitions.js.map +1 -1
- package/dist/lib/definitions/generate-definitions.js +383 -679
- package/dist/lib/definitions/generate-definitions.js.map +1 -1
- package/dist/lib/definitions/generator-configuration.d.ts.map +1 -1
- package/dist/lib/definitions/generator-configuration.js +163 -35
- package/dist/lib/definitions/generator-configuration.js.map +1 -1
- package/dist/lib/definitions/index.js +1 -1
- package/dist/lib/model/AccessoryInfo.d.ts +0 -1
- package/dist/lib/model/AccessoryInfo.d.ts.map +1 -1
- package/dist/lib/model/AccessoryInfo.js +102 -137
- package/dist/lib/model/AccessoryInfo.js.map +1 -1
- package/dist/lib/model/ControllerStorage.js +86 -89
- package/dist/lib/model/ControllerStorage.js.map +1 -1
- package/dist/lib/model/HAPStorage.js +15 -16
- package/dist/lib/model/HAPStorage.js.map +1 -1
- package/dist/lib/model/IdentifierCache.js +49 -49
- package/dist/lib/model/IdentifierCache.js.map +1 -1
- package/dist/lib/tv/AccessControlManagement.d.ts +0 -1
- package/dist/lib/tv/AccessControlManagement.d.ts.map +1 -1
- package/dist/lib/tv/AccessControlManagement.js +43 -46
- package/dist/lib/tv/AccessControlManagement.js.map +1 -1
- package/dist/lib/util/checkName.d.ts +8 -0
- package/dist/lib/util/checkName.d.ts.map +1 -0
- package/dist/lib/util/checkName.js +17 -0
- package/dist/lib/util/checkName.js.map +1 -0
- package/dist/lib/util/clone.js +6 -29
- package/dist/lib/util/clone.js.map +1 -1
- package/dist/lib/util/color-utils.js +8 -12
- package/dist/lib/util/color-utils.js.map +1 -1
- package/dist/lib/util/eventedhttp.d.ts +5 -9
- package/dist/lib/util/eventedhttp.d.ts.map +1 -1
- package/dist/lib/util/eventedhttp.js +306 -405
- package/dist/lib/util/eventedhttp.js.map +1 -1
- package/dist/lib/util/hapCrypto.d.ts +0 -1
- package/dist/lib/util/hapCrypto.d.ts.map +1 -1
- package/dist/lib/util/hapCrypto.js +39 -41
- package/dist/lib/util/hapCrypto.js.map +1 -1
- package/dist/lib/util/hapStatusError.js +9 -12
- package/dist/lib/util/hapStatusError.js.map +1 -1
- package/dist/lib/util/net-utils.d.ts.map +1 -1
- package/dist/lib/util/net-utils.js +34 -54
- package/dist/lib/util/net-utils.js.map +1 -1
- package/dist/lib/util/once.js +4 -10
- package/dist/lib/util/once.js.map +1 -1
- package/dist/lib/util/promise-utils.d.ts +0 -1
- package/dist/lib/util/promise-utils.d.ts.map +1 -1
- package/dist/lib/util/promise-utils.js +10 -16
- package/dist/lib/util/promise-utils.js.map +1 -1
- package/dist/lib/util/request-util.js +8 -10
- package/dist/lib/util/request-util.js.map +1 -1
- package/dist/lib/util/time.d.ts +0 -1
- package/dist/lib/util/time.d.ts.map +1 -1
- package/dist/lib/util/time.js +7 -8
- package/dist/lib/util/time.js.map +1 -1
- package/dist/lib/util/tlv.d.ts +0 -28
- package/dist/lib/util/tlv.d.ts.map +1 -1
- package/dist/lib/util/tlv.js +83 -126
- package/dist/lib/util/tlv.js.map +1 -1
- package/dist/lib/util/uuid.d.ts +0 -10
- package/dist/lib/util/uuid.d.ts.map +1 -1
- package/dist/lib/util/uuid.js +22 -40
- package/dist/lib/util/uuid.js.map +1 -1
- package/dist/types.d.ts +0 -35
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +29 -28
- package/dist/BridgedCore.d.ts +0 -2
- package/dist/BridgedCore.d.ts.map +0 -1
- package/dist/BridgedCore.js +0 -43
- package/dist/BridgedCore.js.map +0 -1
- package/dist/Core.d.ts +0 -2
- package/dist/Core.d.ts.map +0 -1
- package/dist/Core.js +0 -52
- package/dist/Core.js.map +0 -1
- package/dist/lib/AccessoryLoader.d.ts +0 -28
- package/dist/lib/AccessoryLoader.d.ts.map +0 -1
- package/dist/lib/AccessoryLoader.js +0 -167
- package/dist/lib/AccessoryLoader.js.map +0 -1
- package/dist/lib/camera/Camera.d.ts +0 -44
- package/dist/lib/camera/Camera.d.ts.map +0 -1
- package/dist/lib/camera/Camera.js +0 -36
- package/dist/lib/camera/Camera.js.map +0 -1
package/dist/lib/Advertiser.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ResolvedAdvertiser = exports.AvahiAdvertiser = exports.DBusInvokeError = exports.BonjourHAPAdvertiser = exports.CiaoAdvertiser = exports.AdvertiserEvent = exports.PairingFeatureFlag = exports.StatusFlag = void 0;
|
|
4
|
-
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
5
|
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
|
6
6
|
/// <reference path="../../@types/bonjour-hap.d.ts" />
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
const ciao_1 = tslib_1.__importDefault(require("@homebridge/ciao"));
|
|
8
|
+
const dbus_native_1 = tslib_1.__importDefault(require("@homebridge/dbus-native"));
|
|
9
|
+
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
10
|
+
const bonjour_hap_1 = tslib_1.__importDefault(require("bonjour-hap"));
|
|
11
|
+
const crypto_1 = tslib_1.__importDefault(require("crypto"));
|
|
12
|
+
const debug_1 = tslib_1.__importDefault(require("debug"));
|
|
13
|
+
const events_1 = require("events");
|
|
14
|
+
const promise_utils_1 = require("./util/promise-utils");
|
|
15
|
+
const debug = (0, debug_1.default)("HAP-NodeJS:Advertiser");
|
|
16
16
|
/**
|
|
17
17
|
* This enum lists all bitmasks for all known status flags.
|
|
18
18
|
* When the bit for the given bitmask is set, it represents the state described by the name.
|
|
@@ -24,7 +24,7 @@ var StatusFlag;
|
|
|
24
24
|
StatusFlag[StatusFlag["NOT_PAIRED"] = 1] = "NOT_PAIRED";
|
|
25
25
|
StatusFlag[StatusFlag["NOT_JOINED_WIFI"] = 2] = "NOT_JOINED_WIFI";
|
|
26
26
|
StatusFlag[StatusFlag["PROBLEM_DETECTED"] = 4] = "PROBLEM_DETECTED";
|
|
27
|
-
})(StatusFlag
|
|
27
|
+
})(StatusFlag || (exports.StatusFlag = StatusFlag = {}));
|
|
28
28
|
/**
|
|
29
29
|
* This enum lists all bitmasks for all known pairing feature flags.
|
|
30
30
|
* When the bit for the given bitmask is set, it represents the state described by the name.
|
|
@@ -35,7 +35,7 @@ var PairingFeatureFlag;
|
|
|
35
35
|
(function (PairingFeatureFlag) {
|
|
36
36
|
PairingFeatureFlag[PairingFeatureFlag["SUPPORTS_HARDWARE_AUTHENTICATION"] = 1] = "SUPPORTS_HARDWARE_AUTHENTICATION";
|
|
37
37
|
PairingFeatureFlag[PairingFeatureFlag["SUPPORTS_SOFTWARE_AUTHENTICATION"] = 2] = "SUPPORTS_SOFTWARE_AUTHENTICATION";
|
|
38
|
-
})(PairingFeatureFlag
|
|
38
|
+
})(PairingFeatureFlag || (exports.PairingFeatureFlag = PairingFeatureFlag = {}));
|
|
39
39
|
/**
|
|
40
40
|
* @group Advertiser
|
|
41
41
|
*/
|
|
@@ -46,7 +46,7 @@ var AdvertiserEvent;
|
|
|
46
46
|
* was automatically changed due to some naming conflicts on the network.
|
|
47
47
|
*/
|
|
48
48
|
AdvertiserEvent["UPDATED_NAME"] = "updated-name";
|
|
49
|
-
})(AdvertiserEvent
|
|
49
|
+
})(AdvertiserEvent || (exports.AdvertiserEvent = AdvertiserEvent = {}));
|
|
50
50
|
/**
|
|
51
51
|
* Advertiser uses mdns to broadcast the presence of an Accessory to the local network.
|
|
52
52
|
*
|
|
@@ -57,155 +57,155 @@ var AdvertiserEvent;
|
|
|
57
57
|
*
|
|
58
58
|
* @group Advertiser
|
|
59
59
|
*/
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
60
|
+
class CiaoAdvertiser extends events_1.EventEmitter {
|
|
61
|
+
static protocolVersion = "1.1";
|
|
62
|
+
static protocolVersionService = "1.1.0";
|
|
63
|
+
accessoryInfo;
|
|
64
|
+
setupHash;
|
|
65
|
+
responder;
|
|
66
|
+
advertisedService;
|
|
67
|
+
constructor(accessoryInfo, responderOptions, serviceOptions) {
|
|
68
|
+
super();
|
|
69
|
+
this.accessoryInfo = accessoryInfo;
|
|
70
|
+
this.setupHash = CiaoAdvertiser.computeSetupHash(accessoryInfo);
|
|
71
|
+
this.responder = ciao_1.default.getResponder({
|
|
72
|
+
...responderOptions,
|
|
73
|
+
});
|
|
74
|
+
this.advertisedService = this.responder.createService({
|
|
75
|
+
name: this.accessoryInfo.displayName,
|
|
76
|
+
type: "hap" /* ServiceType.HAP */,
|
|
77
|
+
txt: CiaoAdvertiser.createTxt(accessoryInfo, this.setupHash),
|
|
78
|
+
// host will default now to <displayName>.local, spaces replaced with dashes
|
|
79
|
+
...serviceOptions,
|
|
80
|
+
});
|
|
81
|
+
this.advertisedService.on("name-change" /* ServiceEvent.NAME_CHANGED */, this.emit.bind(this, "updated-name" /* AdvertiserEvent.UPDATED_NAME */));
|
|
82
|
+
debug(`Preparing Advertiser for '${this.accessoryInfo.displayName}' using ciao backend!`);
|
|
83
|
+
}
|
|
84
|
+
initPort(port) {
|
|
73
85
|
this.advertisedService.updatePort(port);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
debug(
|
|
86
|
+
}
|
|
87
|
+
startAdvertising() {
|
|
88
|
+
debug(`Starting to advertise '${this.accessoryInfo.displayName}' using ciao backend!`);
|
|
77
89
|
return this.advertisedService.advertise();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
90
|
+
}
|
|
91
|
+
updateAdvertisement(silent) {
|
|
92
|
+
const txt = CiaoAdvertiser.createTxt(this.accessoryInfo, this.setupHash);
|
|
81
93
|
debug("Updating txt record (txt: %o, silent: %d)", txt, silent);
|
|
82
94
|
this.advertisedService.updateTxt(txt, silent);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
case 1:
|
|
92
|
-
// advertisedService.destroy(); is called implicitly via the shutdown call
|
|
93
|
-
_a.sent();
|
|
94
|
-
this.removeAllListeners();
|
|
95
|
-
return [2 /*return*/];
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
};
|
|
100
|
-
CiaoAdvertiser.createTxt = function (accessoryInfo, setupHash) {
|
|
101
|
-
var statusFlags = [];
|
|
95
|
+
}
|
|
96
|
+
async destroy() {
|
|
97
|
+
// advertisedService.destroy(); is called implicitly via the shutdown call
|
|
98
|
+
await this.responder.shutdown();
|
|
99
|
+
this.removeAllListeners();
|
|
100
|
+
}
|
|
101
|
+
static createTxt(accessoryInfo, setupHash) {
|
|
102
|
+
const statusFlags = [];
|
|
102
103
|
if (!accessoryInfo.paired()) {
|
|
103
104
|
statusFlags.push(1 /* StatusFlag.NOT_PAIRED */);
|
|
104
105
|
}
|
|
105
106
|
return {
|
|
106
|
-
"c#": accessoryInfo.getConfigVersion(),
|
|
107
|
-
ff: CiaoAdvertiser.ff(),
|
|
108
|
-
id: accessoryInfo.username,
|
|
109
|
-
md: accessoryInfo.model,
|
|
110
|
-
pv: CiaoAdvertiser.protocolVersion,
|
|
111
|
-
"s#": 1,
|
|
112
|
-
sf: CiaoAdvertiser.sf
|
|
107
|
+
"c#": accessoryInfo.getConfigVersion(), // current configuration number
|
|
108
|
+
ff: CiaoAdvertiser.ff(), // pairing feature flags
|
|
109
|
+
id: accessoryInfo.username, // device id
|
|
110
|
+
md: accessoryInfo.model, // model name
|
|
111
|
+
pv: CiaoAdvertiser.protocolVersion, // protocol version
|
|
112
|
+
"s#": 1, // current state number (must be 1)
|
|
113
|
+
sf: CiaoAdvertiser.sf(...statusFlags), // status flags
|
|
113
114
|
ci: accessoryInfo.category,
|
|
114
115
|
sh: setupHash,
|
|
115
116
|
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
}
|
|
118
|
+
static computeSetupHash(accessoryInfo) {
|
|
119
|
+
const hash = crypto_1.default.createHash("sha512");
|
|
119
120
|
hash.update(accessoryInfo.setupID + accessoryInfo.username.toUpperCase());
|
|
120
121
|
return hash.digest().slice(0, 4).toString("base64");
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
flags[_i] = arguments[_i];
|
|
126
|
-
}
|
|
127
|
-
var value = 0;
|
|
128
|
-
flags.forEach(function (flag) { return value |= flag; });
|
|
122
|
+
}
|
|
123
|
+
static ff(...flags) {
|
|
124
|
+
let value = 0;
|
|
125
|
+
flags.forEach(flag => value |= flag);
|
|
129
126
|
return value;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
flags[_i] = arguments[_i];
|
|
135
|
-
}
|
|
136
|
-
var value = 0;
|
|
137
|
-
flags.forEach(function (flag) { return value |= flag; });
|
|
127
|
+
}
|
|
128
|
+
static sf(...flags) {
|
|
129
|
+
let value = 0;
|
|
130
|
+
flags.forEach(flag => value |= flag);
|
|
138
131
|
return value;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
CiaoAdvertiser.protocolVersionService = "1.1.0";
|
|
142
|
-
return CiaoAdvertiser;
|
|
143
|
-
}(events_1.EventEmitter));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
144
134
|
exports.CiaoAdvertiser = CiaoAdvertiser;
|
|
145
135
|
/**
|
|
146
136
|
* Advertiser base on the legacy "bonjour-hap" library.
|
|
147
137
|
*
|
|
148
138
|
* @group Advertiser
|
|
149
139
|
*/
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
140
|
+
class BonjourHAPAdvertiser extends events_1.EventEmitter {
|
|
141
|
+
accessoryInfo;
|
|
142
|
+
setupHash;
|
|
143
|
+
serviceOptions;
|
|
144
|
+
bonjour;
|
|
145
|
+
advertisement;
|
|
146
|
+
port;
|
|
147
|
+
destroyed = false;
|
|
148
|
+
constructor(accessoryInfo, serviceOptions) {
|
|
149
|
+
super();
|
|
150
|
+
this.accessoryInfo = accessoryInfo;
|
|
151
|
+
this.setupHash = CiaoAdvertiser.computeSetupHash(accessoryInfo);
|
|
152
|
+
this.serviceOptions = serviceOptions;
|
|
153
|
+
this.bonjour = (0, bonjour_hap_1.default)();
|
|
154
|
+
debug(`Preparing Advertiser for '${this.accessoryInfo.displayName}' using bonjour-hap backend!`);
|
|
155
|
+
}
|
|
156
|
+
initPort(port) {
|
|
163
157
|
this.port = port;
|
|
164
|
-
}
|
|
165
|
-
|
|
158
|
+
}
|
|
159
|
+
startAdvertising() {
|
|
166
160
|
(0, assert_1.default)(!this.destroyed, "Can't advertise on a destroyed bonjour instance!");
|
|
167
161
|
if (this.port == null) {
|
|
168
162
|
throw new Error("Tried starting bonjour-hap advertisement without initializing port!");
|
|
169
163
|
}
|
|
170
|
-
debug(
|
|
164
|
+
debug(`Starting to advertise '${this.accessoryInfo.displayName}' using bonjour-hap backend!`);
|
|
171
165
|
if (this.advertisement) {
|
|
172
166
|
this.destroy();
|
|
173
167
|
}
|
|
174
|
-
|
|
175
|
-
this.advertisement = this.bonjour.publish(
|
|
168
|
+
const hostname = this.accessoryInfo.username.replace(/:/ig, "_") + ".local";
|
|
169
|
+
this.advertisement = this.bonjour.publish({
|
|
170
|
+
name: this.accessoryInfo.displayName,
|
|
171
|
+
type: "hap",
|
|
172
|
+
port: this.port,
|
|
173
|
+
txt: CiaoAdvertiser.createTxt(this.accessoryInfo, this.setupHash),
|
|
174
|
+
host: hostname,
|
|
175
|
+
addUnsafeServiceEnumerationRecord: true,
|
|
176
|
+
...this.serviceOptions,
|
|
177
|
+
});
|
|
176
178
|
return (0, promise_utils_1.PromiseTimeout)(1);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
|
|
179
|
+
}
|
|
180
|
+
updateAdvertisement(silent) {
|
|
181
|
+
const txt = CiaoAdvertiser.createTxt(this.accessoryInfo, this.setupHash);
|
|
180
182
|
debug("Updating txt record (txt: %o, silent: %d)", txt, silent);
|
|
181
183
|
if (this.advertisement) {
|
|
182
184
|
this.advertisement.updateTxt(txt, silent);
|
|
183
185
|
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
var _this = this;
|
|
186
|
+
}
|
|
187
|
+
destroy() {
|
|
187
188
|
if (this.advertisement) {
|
|
188
|
-
this.advertisement.stop(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
189
|
+
this.advertisement.stop(() => {
|
|
190
|
+
this.advertisement.destroy();
|
|
191
|
+
this.advertisement = undefined;
|
|
192
|
+
this.bonjour.destroy();
|
|
192
193
|
});
|
|
193
194
|
}
|
|
194
195
|
else {
|
|
195
196
|
this.bonjour.destroy();
|
|
196
197
|
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
}(events_1.EventEmitter));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
200
|
exports.BonjourHAPAdvertiser = BonjourHAPAdvertiser;
|
|
201
201
|
function messageBusConnectionResult(bus) {
|
|
202
|
-
return new Promise(
|
|
203
|
-
|
|
202
|
+
return new Promise((resolve, reject) => {
|
|
203
|
+
const errorHandler = (error) => {
|
|
204
204
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
205
205
|
bus.connection.removeListener("connect", connectHandler);
|
|
206
206
|
reject(error);
|
|
207
207
|
};
|
|
208
|
-
|
|
208
|
+
const connectHandler = () => {
|
|
209
209
|
bus.connection.removeListener("error", errorHandler);
|
|
210
210
|
resolve();
|
|
211
211
|
};
|
|
@@ -216,29 +216,34 @@ function messageBusConnectionResult(bus) {
|
|
|
216
216
|
/**
|
|
217
217
|
* @group Advertiser
|
|
218
218
|
*/
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
219
|
+
class DBusInvokeError extends Error {
|
|
220
|
+
errorName;
|
|
221
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
222
|
+
constructor(errorObject) {
|
|
223
|
+
super();
|
|
224
|
+
Object.setPrototypeOf(this, DBusInvokeError.prototype);
|
|
225
|
+
this.name = "DBusInvokeError";
|
|
226
|
+
this.errorName = errorObject.name;
|
|
226
227
|
if (Array.isArray(errorObject.message) && errorObject.message.length === 1) {
|
|
227
|
-
|
|
228
|
+
this.message = errorObject.message[0];
|
|
228
229
|
}
|
|
229
230
|
else {
|
|
230
|
-
|
|
231
|
+
this.message = errorObject.message.toString();
|
|
231
232
|
}
|
|
232
|
-
return _this;
|
|
233
233
|
}
|
|
234
|
-
|
|
235
|
-
}(Error));
|
|
234
|
+
}
|
|
236
235
|
exports.DBusInvokeError = DBusInvokeError;
|
|
237
236
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
238
237
|
function dbusInvoke(bus, destination, path, dbusInterface, member, others) {
|
|
239
|
-
return new Promise(
|
|
240
|
-
|
|
241
|
-
|
|
238
|
+
return new Promise((resolve, reject) => {
|
|
239
|
+
const command = {
|
|
240
|
+
destination,
|
|
241
|
+
path,
|
|
242
|
+
interface: dbusInterface,
|
|
243
|
+
member,
|
|
244
|
+
...(others || {}),
|
|
245
|
+
};
|
|
246
|
+
bus.invoke(command, (err, result) => {
|
|
242
247
|
if (err) {
|
|
243
248
|
reject(new DBusInvokeError(err));
|
|
244
249
|
}
|
|
@@ -273,220 +278,167 @@ var AvahiServerState;
|
|
|
273
278
|
*
|
|
274
279
|
* @group Advertiser
|
|
275
280
|
*/
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
281
|
+
class AvahiAdvertiser extends events_1.EventEmitter {
|
|
282
|
+
accessoryInfo;
|
|
283
|
+
setupHash;
|
|
284
|
+
port;
|
|
285
|
+
bus;
|
|
286
|
+
avahiServerInterface;
|
|
287
|
+
path;
|
|
288
|
+
stateChangeHandler;
|
|
289
|
+
constructor(accessoryInfo) {
|
|
290
|
+
super();
|
|
291
|
+
this.accessoryInfo = accessoryInfo;
|
|
292
|
+
this.setupHash = CiaoAdvertiser.computeSetupHash(accessoryInfo);
|
|
293
|
+
debug(`Preparing Advertiser for '${this.accessoryInfo.displayName}' using Avahi backend!`);
|
|
294
|
+
this.bus = dbus_native_1.default.systemBus();
|
|
295
|
+
this.stateChangeHandler = this.handleStateChangedEvent.bind(this);
|
|
296
|
+
}
|
|
297
|
+
createTxt() {
|
|
288
298
|
return Object
|
|
289
299
|
.entries(CiaoAdvertiser.createTxt(this.accessoryInfo, this.setupHash))
|
|
290
|
-
.map(
|
|
291
|
-
}
|
|
292
|
-
|
|
300
|
+
.map((el) => Buffer.from(el[0] + "=" + el[1]));
|
|
301
|
+
}
|
|
302
|
+
initPort(port) {
|
|
293
303
|
this.port = port;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
return [4 /*yield*/, AvahiAdvertiser.avahiInvoke(this.bus, "/", "Server", "EntryGroupNew")];
|
|
318
|
-
case 3:
|
|
319
|
-
_b.path = (_c.sent());
|
|
320
|
-
return [4 /*yield*/, AvahiAdvertiser.avahiInvoke(this.bus, this.path, "EntryGroup", "AddService", {
|
|
321
|
-
body: [
|
|
322
|
-
-1,
|
|
323
|
-
-1,
|
|
324
|
-
0,
|
|
325
|
-
this.accessoryInfo.displayName,
|
|
326
|
-
"_hap._tcp",
|
|
327
|
-
"",
|
|
328
|
-
"",
|
|
329
|
-
this.port,
|
|
330
|
-
this.createTxt(), // txt
|
|
331
|
-
],
|
|
332
|
-
signature: "iiussssqaay",
|
|
333
|
-
})];
|
|
334
|
-
case 4:
|
|
335
|
-
_c.sent();
|
|
336
|
-
return [4 /*yield*/, AvahiAdvertiser.avahiInvoke(this.bus, this.path, "EntryGroup", "Commit")];
|
|
337
|
-
case 5:
|
|
338
|
-
_c.sent();
|
|
339
|
-
return [2 /*return*/];
|
|
340
|
-
}
|
|
341
|
-
});
|
|
304
|
+
}
|
|
305
|
+
async startAdvertising() {
|
|
306
|
+
if (this.port == null) {
|
|
307
|
+
throw new Error("Tried starting Avahi advertisement without initializing port!");
|
|
308
|
+
}
|
|
309
|
+
if (!this.bus) {
|
|
310
|
+
throw new Error("Tried to start Avahi advertisement on a destroyed advertiser!");
|
|
311
|
+
}
|
|
312
|
+
debug(`Starting to advertise '${this.accessoryInfo.displayName}' using Avahi backend!`);
|
|
313
|
+
this.path = await AvahiAdvertiser.avahiInvoke(this.bus, "/", "Server", "EntryGroupNew");
|
|
314
|
+
await AvahiAdvertiser.avahiInvoke(this.bus, this.path, "EntryGroup", "AddService", {
|
|
315
|
+
body: [
|
|
316
|
+
-1, // interface
|
|
317
|
+
-1, // protocol
|
|
318
|
+
0, // flags
|
|
319
|
+
this.accessoryInfo.displayName, // name
|
|
320
|
+
"_hap._tcp", // type
|
|
321
|
+
"", // domain
|
|
322
|
+
"", // host
|
|
323
|
+
this.port, // port
|
|
324
|
+
this.createTxt(), // txt
|
|
325
|
+
],
|
|
326
|
+
signature: "iiussssqaay",
|
|
342
327
|
});
|
|
343
|
-
|
|
328
|
+
await AvahiAdvertiser.avahiInvoke(this.bus, this.path, "EntryGroup", "Commit");
|
|
329
|
+
try {
|
|
330
|
+
if (!this.avahiServerInterface) {
|
|
331
|
+
this.avahiServerInterface = await AvahiAdvertiser.avahiInterface(this.bus, "Server");
|
|
332
|
+
this.avahiServerInterface.on("StateChanged", this.stateChangeHandler);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
catch (error) {
|
|
336
|
+
// We have some problem on Synology https://github.com/homebridge/HAP-NodeJS/issues/993
|
|
337
|
+
console.warn("Failed to create listener for avahi-daemon server state. The system will not be notified about restarts of avahi-daemon " +
|
|
338
|
+
"and will therefore stay undiscoverable in those instances. Error message: " + error);
|
|
339
|
+
if (error.stack) {
|
|
340
|
+
debug("Detailed error: " + error.stack);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
344
|
/**
|
|
345
345
|
* Event handler for the `StateChanged` event of the `org.freedesktop.Avahi.Server` DBus interface.
|
|
346
346
|
*
|
|
347
347
|
* This is called once the state of the running avahi-daemon changes its running state.
|
|
348
348
|
* @param state - The state the server changed into {@see AvahiServerState}.
|
|
349
349
|
*/
|
|
350
|
-
|
|
350
|
+
handleStateChangedEvent(state) {
|
|
351
351
|
if (state === 2 /* AvahiServerState.RUNNING */ && this.path) {
|
|
352
352
|
debug("Found Avahi daemon to have restarted!");
|
|
353
353
|
this.startAdvertising()
|
|
354
|
-
.catch(
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
debug("Updating txt record (txt: %o, silent: %d)", CiaoAdvertiser.createTxt(this.accessoryInfo, this.setupHash), silent);
|
|
371
|
-
_a.label = 1;
|
|
372
|
-
case 1:
|
|
373
|
-
_a.trys.push([1, 3, , 4]);
|
|
374
|
-
return [4 /*yield*/, AvahiAdvertiser.avahiInvoke(this.bus, this.path, "EntryGroup", "UpdateServiceTxt", {
|
|
375
|
-
body: [-1, -1, 0, this.accessoryInfo.displayName, "_hap._tcp", "", this.createTxt()],
|
|
376
|
-
signature: "iiusssaay",
|
|
377
|
-
})];
|
|
378
|
-
case 2:
|
|
379
|
-
_a.sent();
|
|
380
|
-
return [3 /*break*/, 4];
|
|
381
|
-
case 3:
|
|
382
|
-
error_1 = _a.sent();
|
|
383
|
-
console.error("Failed to update avahi advertisement: " + error_1);
|
|
384
|
-
return [3 /*break*/, 4];
|
|
385
|
-
case 4: return [2 /*return*/];
|
|
386
|
-
}
|
|
387
|
-
});
|
|
388
|
-
});
|
|
389
|
-
};
|
|
390
|
-
AvahiAdvertiser.prototype.destroy = function () {
|
|
391
|
-
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
392
|
-
var error_2;
|
|
393
|
-
return tslib_1.__generator(this, function (_a) {
|
|
394
|
-
switch (_a.label) {
|
|
395
|
-
case 0:
|
|
396
|
-
if (!this.bus) {
|
|
397
|
-
throw new Error("Tried to destroy Avahi advertisement on a destroyed advertiser!");
|
|
398
|
-
}
|
|
399
|
-
if (!this.path) return [3 /*break*/, 5];
|
|
400
|
-
_a.label = 1;
|
|
401
|
-
case 1:
|
|
402
|
-
_a.trys.push([1, 3, , 4]);
|
|
403
|
-
return [4 /*yield*/, AvahiAdvertiser.avahiInvoke(this.bus, this.path, "EntryGroup", "Free")];
|
|
404
|
-
case 2:
|
|
405
|
-
_a.sent();
|
|
406
|
-
return [3 /*break*/, 4];
|
|
407
|
-
case 3:
|
|
408
|
-
error_2 = _a.sent();
|
|
409
|
-
// Typically, this fails if e.g. avahi service was stopped in the meantime.
|
|
410
|
-
debug("Destroying Avahi advertisement failed: " + error_2);
|
|
411
|
-
return [3 /*break*/, 4];
|
|
412
|
-
case 4:
|
|
413
|
-
this.path = undefined;
|
|
414
|
-
_a.label = 5;
|
|
415
|
-
case 5:
|
|
416
|
-
if (this.avahiServerInterface) {
|
|
417
|
-
this.avahiServerInterface.removeListener("StateChanged", this.stateChangeHandler);
|
|
418
|
-
this.avahiServerInterface = undefined;
|
|
419
|
-
}
|
|
420
|
-
this.bus.connection.stream.destroy();
|
|
421
|
-
this.bus = undefined;
|
|
422
|
-
return [2 /*return*/];
|
|
423
|
-
}
|
|
424
|
-
});
|
|
425
|
-
});
|
|
426
|
-
};
|
|
427
|
-
AvahiAdvertiser.isAvailable = function () {
|
|
428
|
-
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
429
|
-
var bus, error_3, version, error_4;
|
|
430
|
-
return tslib_1.__generator(this, function (_a) {
|
|
431
|
-
switch (_a.label) {
|
|
432
|
-
case 0:
|
|
433
|
-
bus = dbus_native_1.default.systemBus();
|
|
434
|
-
_a.label = 1;
|
|
435
|
-
case 1:
|
|
436
|
-
_a.trys.push([1, , 9, 10]);
|
|
437
|
-
_a.label = 2;
|
|
438
|
-
case 2:
|
|
439
|
-
_a.trys.push([2, 4, , 5]);
|
|
440
|
-
return [4 /*yield*/, messageBusConnectionResult(bus)];
|
|
441
|
-
case 3:
|
|
442
|
-
_a.sent();
|
|
443
|
-
return [3 /*break*/, 5];
|
|
444
|
-
case 4:
|
|
445
|
-
error_3 = _a.sent();
|
|
446
|
-
debug("Avahi/DBus classified unavailable due to missing dbus interface!");
|
|
447
|
-
return [2 /*return*/, false];
|
|
448
|
-
case 5:
|
|
449
|
-
_a.trys.push([5, 7, , 8]);
|
|
450
|
-
return [4 /*yield*/, this.avahiInvoke(bus, "/", "Server", "GetVersionString")];
|
|
451
|
-
case 6:
|
|
452
|
-
version = _a.sent();
|
|
453
|
-
debug("Detected Avahi over DBus interface running version '%s'.", version);
|
|
454
|
-
return [3 /*break*/, 8];
|
|
455
|
-
case 7:
|
|
456
|
-
error_4 = _a.sent();
|
|
457
|
-
debug("Avahi/DBus classified unavailable due to missing avahi interface!");
|
|
458
|
-
return [2 /*return*/, false];
|
|
459
|
-
case 8: return [2 /*return*/, true];
|
|
460
|
-
case 9:
|
|
461
|
-
bus.connection.stream.destroy();
|
|
462
|
-
return [7 /*endfinally*/];
|
|
463
|
-
case 10: return [2 /*return*/];
|
|
464
|
-
}
|
|
354
|
+
.catch(reason => console.error("Could not (re-)create mDNS advertisement. The HAP-Server won't be discoverable: " + reason));
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
async updateAdvertisement(silent) {
|
|
358
|
+
if (!this.bus) {
|
|
359
|
+
throw new Error("Tried to update Avahi advertisement on a destroyed advertiser!");
|
|
360
|
+
}
|
|
361
|
+
if (!this.path) {
|
|
362
|
+
debug("Tried to update advertisement without a valid `path`!");
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
debug("Updating txt record (txt: %o, silent: %d)", CiaoAdvertiser.createTxt(this.accessoryInfo, this.setupHash), silent);
|
|
366
|
+
try {
|
|
367
|
+
await AvahiAdvertiser.avahiInvoke(this.bus, this.path, "EntryGroup", "UpdateServiceTxt", {
|
|
368
|
+
body: [-1, -1, 0, this.accessoryInfo.displayName, "_hap._tcp", "", this.createTxt()],
|
|
369
|
+
signature: "iiusssaay",
|
|
465
370
|
});
|
|
466
|
-
}
|
|
467
|
-
|
|
371
|
+
}
|
|
372
|
+
catch (error) {
|
|
373
|
+
console.error("Failed to update avahi advertisement: " + error);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
async destroy() {
|
|
377
|
+
if (!this.bus) {
|
|
378
|
+
throw new Error("Tried to destroy Avahi advertisement on a destroyed advertiser!");
|
|
379
|
+
}
|
|
380
|
+
if (this.path) {
|
|
381
|
+
try {
|
|
382
|
+
await AvahiAdvertiser.avahiInvoke(this.bus, this.path, "EntryGroup", "Free");
|
|
383
|
+
}
|
|
384
|
+
catch (error) {
|
|
385
|
+
// Typically, this fails if e.g. avahi service was stopped in the meantime.
|
|
386
|
+
debug("Destroying Avahi advertisement failed: " + error);
|
|
387
|
+
}
|
|
388
|
+
this.path = undefined;
|
|
389
|
+
}
|
|
390
|
+
if (this.avahiServerInterface) {
|
|
391
|
+
this.avahiServerInterface.removeListener("StateChanged", this.stateChangeHandler);
|
|
392
|
+
this.avahiServerInterface = undefined;
|
|
393
|
+
}
|
|
394
|
+
this.bus.connection.stream.destroy();
|
|
395
|
+
this.bus = undefined;
|
|
396
|
+
}
|
|
397
|
+
static async isAvailable() {
|
|
398
|
+
const bus = dbus_native_1.default.systemBus();
|
|
399
|
+
try {
|
|
400
|
+
try {
|
|
401
|
+
await messageBusConnectionResult(bus);
|
|
402
|
+
}
|
|
403
|
+
catch (error) {
|
|
404
|
+
debug("Avahi/DBus classified unavailable due to missing dbus interface!");
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
try {
|
|
408
|
+
const version = await this.avahiInvoke(bus, "/", "Server", "GetVersionString");
|
|
409
|
+
debug("Detected Avahi over DBus interface running version '%s'.", version);
|
|
410
|
+
}
|
|
411
|
+
catch (error) {
|
|
412
|
+
debug("Avahi/DBus classified unavailable due to missing avahi interface!");
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
return true;
|
|
416
|
+
}
|
|
417
|
+
finally {
|
|
418
|
+
bus.connection.stream.destroy();
|
|
419
|
+
}
|
|
420
|
+
}
|
|
468
421
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
469
|
-
|
|
470
|
-
return dbusInvoke(bus, "org.freedesktop.Avahi", path,
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
return new Promise(
|
|
422
|
+
static avahiInvoke(bus, path, dbusInterface, member, others) {
|
|
423
|
+
return dbusInvoke(bus, "org.freedesktop.Avahi", path, `org.freedesktop.Avahi.${dbusInterface}`, member, others);
|
|
424
|
+
}
|
|
425
|
+
static avahiInterface(bus, dbusInterface) {
|
|
426
|
+
return new Promise((resolve, reject) => {
|
|
474
427
|
bus
|
|
475
428
|
.getService("org.freedesktop.Avahi")
|
|
476
|
-
.getInterface("/", "org.freedesktop.Avahi." + dbusInterface,
|
|
429
|
+
.getInterface("/", "org.freedesktop.Avahi." + dbusInterface, (error, iface) => {
|
|
477
430
|
if (error || !iface) {
|
|
478
|
-
reject(error
|
|
431
|
+
reject(error ?? new Error("Interface not present!"));
|
|
479
432
|
}
|
|
480
433
|
else {
|
|
481
434
|
resolve(iface);
|
|
482
435
|
}
|
|
483
436
|
});
|
|
484
437
|
});
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
}(events_1.EventEmitter));
|
|
438
|
+
}
|
|
439
|
+
}
|
|
488
440
|
exports.AvahiAdvertiser = AvahiAdvertiser;
|
|
489
|
-
|
|
441
|
+
const RESOLVED_PERMISSIONS_ERRORS = [
|
|
490
442
|
"org.freedesktop.DBus.Error.AccessDenied",
|
|
491
443
|
"org.freedesktop.DBus.Error.AuthFailed",
|
|
492
444
|
"org.freedesktop.DBus.Error.InteractiveAuthorizationRequired",
|
|
@@ -497,217 +449,146 @@ var RESOLVED_PERMISSIONS_ERRORS = [
|
|
|
497
449
|
*
|
|
498
450
|
* @group Advertiser
|
|
499
451
|
*/
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
452
|
+
class ResolvedAdvertiser extends events_1.EventEmitter {
|
|
453
|
+
accessoryInfo;
|
|
454
|
+
setupHash;
|
|
455
|
+
port;
|
|
456
|
+
bus;
|
|
457
|
+
path;
|
|
458
|
+
constructor(accessoryInfo) {
|
|
459
|
+
super();
|
|
460
|
+
this.accessoryInfo = accessoryInfo;
|
|
461
|
+
this.setupHash = CiaoAdvertiser.computeSetupHash(accessoryInfo);
|
|
462
|
+
this.bus = dbus_native_1.default.systemBus();
|
|
463
|
+
debug(`Preparing Advertiser for '${this.accessoryInfo.displayName}' using systemd-resolved backend!`);
|
|
464
|
+
}
|
|
465
|
+
createTxt() {
|
|
511
466
|
return Object
|
|
512
467
|
.entries(CiaoAdvertiser.createTxt(this.accessoryInfo, this.setupHash))
|
|
513
|
-
.map(
|
|
514
|
-
}
|
|
515
|
-
|
|
468
|
+
.map((el) => [el[0].toString(), Buffer.from(el[1].toString())]);
|
|
469
|
+
}
|
|
470
|
+
initPort(port) {
|
|
516
471
|
this.port = port;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
this.accessoryInfo.displayName,
|
|
539
|
-
"_hap._tcp",
|
|
540
|
-
this.port,
|
|
541
|
-
0,
|
|
542
|
-
0,
|
|
543
|
-
[this.createTxt()], // txt_datas
|
|
544
|
-
],
|
|
545
|
-
signature: "sssqqqaa{say}",
|
|
546
|
-
})];
|
|
547
|
-
case 2:
|
|
548
|
-
_a.path = _b.sent();
|
|
549
|
-
return [3 /*break*/, 4];
|
|
550
|
-
case 3:
|
|
551
|
-
error_5 = _b.sent();
|
|
552
|
-
if (error_5 instanceof DBusInvokeError) {
|
|
553
|
-
if (RESOLVED_PERMISSIONS_ERRORS.includes(error_5.errorName)) {
|
|
554
|
-
error_5.message = "Permissions issue. See https://homebridge.io/w/mDNS-Options for more info. ".concat(error_5.message);
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
throw error_5;
|
|
558
|
-
case 4: return [2 /*return*/];
|
|
559
|
-
}
|
|
560
|
-
});
|
|
561
|
-
});
|
|
562
|
-
};
|
|
563
|
-
ResolvedAdvertiser.prototype.updateAdvertisement = function (silent) {
|
|
564
|
-
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
565
|
-
return tslib_1.__generator(this, function (_a) {
|
|
566
|
-
switch (_a.label) {
|
|
567
|
-
case 0:
|
|
568
|
-
if (!this.bus) {
|
|
569
|
-
throw new Error("Tried to update systemd-resolved advertisement on a destroyed advertiser!");
|
|
570
|
-
}
|
|
571
|
-
debug("Updating txt record (txt: %o, silent: %d)", CiaoAdvertiser.createTxt(this.accessoryInfo, this.setupHash), silent);
|
|
572
|
-
// Currently, systemd-resolved has no way to update an existing record.
|
|
573
|
-
return [4 /*yield*/, this.stopAdvertising()];
|
|
574
|
-
case 1:
|
|
575
|
-
// Currently, systemd-resolved has no way to update an existing record.
|
|
576
|
-
_a.sent();
|
|
577
|
-
return [4 /*yield*/, this.startAdvertising()];
|
|
578
|
-
case 2:
|
|
579
|
-
_a.sent();
|
|
580
|
-
return [2 /*return*/];
|
|
581
|
-
}
|
|
472
|
+
}
|
|
473
|
+
async startAdvertising() {
|
|
474
|
+
if (this.port == null) {
|
|
475
|
+
throw new Error("Tried starting systemd-resolved advertisement without initializing port!");
|
|
476
|
+
}
|
|
477
|
+
if (!this.bus) {
|
|
478
|
+
throw new Error("Tried to start systemd-resolved advertisement on a destroyed advertiser!");
|
|
479
|
+
}
|
|
480
|
+
debug(`Starting to advertise '${this.accessoryInfo.displayName}' using systemd-resolved backend!`);
|
|
481
|
+
try {
|
|
482
|
+
this.path = await ResolvedAdvertiser.managerInvoke(this.bus, "RegisterService", {
|
|
483
|
+
body: [
|
|
484
|
+
this.accessoryInfo.displayName, // name
|
|
485
|
+
this.accessoryInfo.displayName, // name_template
|
|
486
|
+
"_hap._tcp", // type
|
|
487
|
+
this.port, // service_port
|
|
488
|
+
0, // service_priority
|
|
489
|
+
0, // service_weight
|
|
490
|
+
[this.createTxt()], // txt_datas
|
|
491
|
+
],
|
|
492
|
+
signature: "sssqqqaa{say}",
|
|
582
493
|
});
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
return tslib_1.__generator(this, function (_a) {
|
|
589
|
-
switch (_a.label) {
|
|
590
|
-
case 0:
|
|
591
|
-
if (!this.bus) {
|
|
592
|
-
throw new Error("Tried to destroy systemd-resolved advertisement on a destroyed advertiser!");
|
|
593
|
-
}
|
|
594
|
-
if (!this.path) return [3 /*break*/, 5];
|
|
595
|
-
_a.label = 1;
|
|
596
|
-
case 1:
|
|
597
|
-
_a.trys.push([1, 3, , 4]);
|
|
598
|
-
return [4 /*yield*/, ResolvedAdvertiser.managerInvoke(this.bus, "UnregisterService", {
|
|
599
|
-
body: [this.path],
|
|
600
|
-
signature: "o",
|
|
601
|
-
})];
|
|
602
|
-
case 2:
|
|
603
|
-
_a.sent();
|
|
604
|
-
return [3 /*break*/, 4];
|
|
605
|
-
case 3:
|
|
606
|
-
error_6 = _a.sent();
|
|
607
|
-
// Typically, this fails if e.g. systemd-resolved service was stopped in the meantime.
|
|
608
|
-
debug("Destroying systemd-resolved advertisement failed: " + error_6);
|
|
609
|
-
return [3 /*break*/, 4];
|
|
610
|
-
case 4:
|
|
611
|
-
this.path = undefined;
|
|
612
|
-
_a.label = 5;
|
|
613
|
-
case 5: return [2 /*return*/];
|
|
494
|
+
}
|
|
495
|
+
catch (error) {
|
|
496
|
+
if (error instanceof DBusInvokeError) {
|
|
497
|
+
if (RESOLVED_PERMISSIONS_ERRORS.includes(error.errorName)) {
|
|
498
|
+
error.message = `Permissions issue. See https://homebridge.io/w/mDNS-Options for more info. ${error.message}`;
|
|
614
499
|
}
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
500
|
+
}
|
|
501
|
+
throw error;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
async updateAdvertisement(silent) {
|
|
505
|
+
if (!this.bus) {
|
|
506
|
+
throw new Error("Tried to update systemd-resolved advertisement on a destroyed advertiser!");
|
|
507
|
+
}
|
|
508
|
+
debug("Updating txt record (txt: %o, silent: %d)", CiaoAdvertiser.createTxt(this.accessoryInfo, this.setupHash), silent);
|
|
509
|
+
// Currently, systemd-resolved has no way to update an existing record.
|
|
510
|
+
await this.stopAdvertising();
|
|
511
|
+
await this.startAdvertising();
|
|
512
|
+
}
|
|
513
|
+
async stopAdvertising() {
|
|
514
|
+
if (!this.bus) {
|
|
515
|
+
throw new Error("Tried to destroy systemd-resolved advertisement on a destroyed advertiser!");
|
|
516
|
+
}
|
|
517
|
+
if (this.path) {
|
|
518
|
+
try {
|
|
519
|
+
await ResolvedAdvertiser.managerInvoke(this.bus, "UnregisterService", {
|
|
520
|
+
body: [this.path],
|
|
521
|
+
signature: "o",
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
catch (error) {
|
|
525
|
+
// Typically, this fails if e.g. systemd-resolved service was stopped in the meantime.
|
|
526
|
+
debug("Destroying systemd-resolved advertisement failed: " + error);
|
|
527
|
+
}
|
|
528
|
+
this.path = undefined;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
async destroy() {
|
|
532
|
+
if (!this.bus) {
|
|
533
|
+
throw new Error("Tried to destroy systemd-resolved advertisement on a destroyed advertiser!");
|
|
534
|
+
}
|
|
535
|
+
await this.stopAdvertising();
|
|
536
|
+
this.bus.connection.stream.destroy();
|
|
537
|
+
this.bus = undefined;
|
|
538
|
+
}
|
|
539
|
+
static async isAvailable() {
|
|
540
|
+
const bus = dbus_native_1.default.systemBus();
|
|
541
|
+
try {
|
|
542
|
+
try {
|
|
543
|
+
await messageBusConnectionResult(bus);
|
|
544
|
+
}
|
|
545
|
+
catch (error) {
|
|
546
|
+
debug("systemd-resolved/DBus classified unavailable due to missing dbus interface!");
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
try {
|
|
550
|
+
// Ensure that systemd-resolved is accessible.
|
|
551
|
+
await this.managerInvoke(bus, "ResolveHostname", {
|
|
552
|
+
body: [0, "127.0.0.1", 0, 0],
|
|
553
|
+
signature: "isit",
|
|
554
|
+
});
|
|
555
|
+
debug("Detected systemd-resolved over DBus interface running version.");
|
|
556
|
+
}
|
|
557
|
+
catch (error) {
|
|
558
|
+
debug("systemd-resolved/DBus classified unavailable due to missing systemd-resolved interface!");
|
|
559
|
+
return false;
|
|
560
|
+
}
|
|
561
|
+
try {
|
|
562
|
+
const mdnsStatus = await this.resolvedInvoke(bus, "org.freedesktop.DBus.Properties", "Get", {
|
|
563
|
+
body: ["org.freedesktop.resolve1.Manager", "MulticastDNS"],
|
|
564
|
+
signature: "ss",
|
|
565
|
+
});
|
|
566
|
+
if (mdnsStatus[0][0].type !== "s") {
|
|
567
|
+
throw new Error("Invalid type for MulticastDNS");
|
|
632
568
|
}
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
ResolvedAdvertiser.isAvailable = function () {
|
|
637
|
-
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
638
|
-
var bus, error_7, error_8, mdnsStatus, error_9;
|
|
639
|
-
return tslib_1.__generator(this, function (_a) {
|
|
640
|
-
switch (_a.label) {
|
|
641
|
-
case 0:
|
|
642
|
-
bus = dbus_native_1.default.systemBus();
|
|
643
|
-
_a.label = 1;
|
|
644
|
-
case 1:
|
|
645
|
-
_a.trys.push([1, , 12, 13]);
|
|
646
|
-
_a.label = 2;
|
|
647
|
-
case 2:
|
|
648
|
-
_a.trys.push([2, 4, , 5]);
|
|
649
|
-
return [4 /*yield*/, messageBusConnectionResult(bus)];
|
|
650
|
-
case 3:
|
|
651
|
-
_a.sent();
|
|
652
|
-
return [3 /*break*/, 5];
|
|
653
|
-
case 4:
|
|
654
|
-
error_7 = _a.sent();
|
|
655
|
-
debug("systemd-resolved/DBus classified unavailable due to missing dbus interface!");
|
|
656
|
-
return [2 /*return*/, false];
|
|
657
|
-
case 5:
|
|
658
|
-
_a.trys.push([5, 7, , 8]);
|
|
659
|
-
// Ensure that systemd-resolved is accessible.
|
|
660
|
-
return [4 /*yield*/, this.managerInvoke(bus, "ResolveHostname", {
|
|
661
|
-
body: [0, "127.0.0.1", 0, 0],
|
|
662
|
-
signature: "isit",
|
|
663
|
-
})];
|
|
664
|
-
case 6:
|
|
665
|
-
// Ensure that systemd-resolved is accessible.
|
|
666
|
-
_a.sent();
|
|
667
|
-
debug("Detected systemd-resolved over DBus interface running version.");
|
|
668
|
-
return [3 /*break*/, 8];
|
|
669
|
-
case 7:
|
|
670
|
-
error_8 = _a.sent();
|
|
671
|
-
debug("systemd-resolved/DBus classified unavailable due to missing systemd-resolved interface!");
|
|
672
|
-
return [2 /*return*/, false];
|
|
673
|
-
case 8:
|
|
674
|
-
_a.trys.push([8, 10, , 11]);
|
|
675
|
-
return [4 /*yield*/, this.resolvedInvoke(bus, "org.freedesktop.DBus.Properties", "Get", {
|
|
676
|
-
body: ["org.freedesktop.resolve1.Manager", "MulticastDNS"],
|
|
677
|
-
signature: "ss",
|
|
678
|
-
})];
|
|
679
|
-
case 9:
|
|
680
|
-
mdnsStatus = _a.sent();
|
|
681
|
-
if (mdnsStatus[0][0].type !== "s") {
|
|
682
|
-
throw new Error("Invalid type for MulticastDNS");
|
|
683
|
-
}
|
|
684
|
-
if (mdnsStatus[1][0] !== "yes") {
|
|
685
|
-
debug("systemd-resolved/DBus classified unavailable because MulticastDNS is not enabled!");
|
|
686
|
-
return [2 /*return*/, false];
|
|
687
|
-
}
|
|
688
|
-
return [3 /*break*/, 11];
|
|
689
|
-
case 10:
|
|
690
|
-
error_9 = _a.sent();
|
|
691
|
-
debug("systemd-resolved/DBus classified unavailable due to failure checking system status: " + error_9);
|
|
692
|
-
return [2 /*return*/, false];
|
|
693
|
-
case 11: return [2 /*return*/, true];
|
|
694
|
-
case 12:
|
|
695
|
-
bus.connection.stream.destroy();
|
|
696
|
-
return [7 /*endfinally*/];
|
|
697
|
-
case 13: return [2 /*return*/];
|
|
569
|
+
if (mdnsStatus[1][0] !== "yes") {
|
|
570
|
+
debug("systemd-resolved/DBus classified unavailable because MulticastDNS is not enabled!");
|
|
571
|
+
return false;
|
|
698
572
|
}
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
|
|
573
|
+
}
|
|
574
|
+
catch (error) {
|
|
575
|
+
debug("systemd-resolved/DBus classified unavailable due to failure checking system status: " + error);
|
|
576
|
+
return false;
|
|
577
|
+
}
|
|
578
|
+
return true;
|
|
579
|
+
}
|
|
580
|
+
finally {
|
|
581
|
+
bus.connection.stream.destroy();
|
|
582
|
+
}
|
|
583
|
+
}
|
|
702
584
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
703
|
-
|
|
585
|
+
static resolvedInvoke(bus, dbusInterface, member, others) {
|
|
704
586
|
return dbusInvoke(bus, "org.freedesktop.resolve1", "/org/freedesktop/resolve1", dbusInterface, member, others);
|
|
705
|
-
}
|
|
587
|
+
}
|
|
706
588
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
707
|
-
|
|
589
|
+
static managerInvoke(bus, member, others) {
|
|
708
590
|
return this.resolvedInvoke(bus, "org.freedesktop.resolve1.Manager", member, others);
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
}(events_1.EventEmitter));
|
|
591
|
+
}
|
|
592
|
+
}
|
|
712
593
|
exports.ResolvedAdvertiser = ResolvedAdvertiser;
|
|
713
594
|
//# sourceMappingURL=Advertiser.js.map
|