@stoprocent/noble 1.18.2 → 1.19.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.
@@ -105,7 +105,13 @@ NobleBindings.prototype.updateRssi = function (peripheralUuid) {
105
105
  };
106
106
 
107
107
  NobleBindings.prototype.init = function () {
108
- this.onSigIntBinded = this.onSigInt.bind(this);
108
+ /* Add exit handlers after `init()` has completed. If no adaptor
109
+ is present it can throw an exception - in which case we don't
110
+ want to try and clear up afterwards (issue #502) */
111
+ this._sigIntHandler = this.onSigInt.bind(this);
112
+ this._exitHandler = this.stop.bind(this);
113
+ process.on('SIGINT', this._sigIntHandler);
114
+ process.on('exit', this._exitHandler);
109
115
 
110
116
  this._gap.on('scanParametersSet', this.onScanParametersSet.bind(this));
111
117
  this._gap.on('scanStart', this.onScanStart.bind(this));
@@ -122,18 +128,12 @@ NobleBindings.prototype.init = function () {
122
128
  this._hci.on('aclDataPkt', this.onAclDataPkt.bind(this));
123
129
 
124
130
  this._hci.init();
125
-
126
- /* Add exit handlers after `init()` has completed. If no adaptor
127
- is present it can throw an exception - in which case we don't
128
- want to try and clear up afterwards (issue #502) */
129
- process.on('SIGINT', this.onSigIntBinded);
130
- process.on('exit', this.stop.bind(this));
131
131
  };
132
132
 
133
133
  NobleBindings.prototype.onSigInt = function () {
134
134
  const sigIntListeners = process.listeners('SIGINT');
135
135
 
136
- if (sigIntListeners[sigIntListeners.length - 1] === this.onSigIntBinded) {
136
+ if (sigIntListeners[sigIntListeners.length - 1] === this._sigIntHandler) {
137
137
  // we are the last listener, so exit
138
138
  // this will trigger onExit, and clean up
139
139
  process.exit(1);
@@ -141,6 +141,9 @@ NobleBindings.prototype.onSigInt = function () {
141
141
  };
142
142
 
143
143
  NobleBindings.prototype.stop = function () {
144
+ process.removeListener('exit', this._exitHandler);
145
+ process.removeListener('SIGINT', this._sigIntHandler);
146
+
144
147
  this.stopScanning();
145
148
  for (const handle in this._aclStreams) {
146
149
  this._hci.disconnect(handle);
@@ -153,6 +156,14 @@ NobleBindings.prototype.onStateChange = function (state) {
153
156
  if (this._state === state) {
154
157
  return;
155
158
  }
159
+
160
+ // If we are powered on and we are powered off, disconnect all connections
161
+ if (this._state === 'poweredOn' && state === 'poweredOff') {
162
+ for (const handle in this._handles) {
163
+ this.onDisconnComplete(handle, 0x03); // Hardward Failure
164
+ }
165
+ }
166
+
156
167
  this._state = state;
157
168
 
158
169
  if (state === 'unauthorized') {
@@ -182,7 +182,6 @@ Gatt.prototype.onAclStreamEnd = function () {
182
182
 
183
183
  Gatt.prototype.writeAtt = function (data) {
184
184
  debug(`${this._address}: write: ${data.toString('hex')}`);
185
-
186
185
  this._aclStream.write(ATT_CID, data);
187
186
  };
188
187
 
@@ -104,18 +104,19 @@ const Hci = function (options) {
104
104
  this._isExtended = 'extended' in options && options.extended;
105
105
  this._state = null;
106
106
  this._bindParams = 'bindParams' in options ? options.bindParams : undefined;
107
-
108
107
  this._handleBuffers = {};
109
-
110
108
  this._aclBuffers = undefined;
111
109
  this._resolveAclBuffers = undefined;
110
+
112
111
  const aclBuffersPromise = new Promise((resolve) => {
113
112
  this._resolveAclBuffers = resolve;
114
113
  });
114
+
115
115
  this.getAclBuffers = async function () {
116
116
  if (this._aclBuffers) return this._aclBuffers;
117
117
  return await aclBuffersPromise;
118
118
  }.bind(this);
119
+
119
120
  this.setAclBuffers = function (length, num) {
120
121
  if (this._aclBuffers) {
121
122
  this._aclBuffers.length = length;
@@ -130,7 +131,6 @@ const Hci = function (options) {
130
131
  }.bind(this);
131
132
 
132
133
  this._aclConnections = new Map();
133
-
134
134
  this._aclQueue = [];
135
135
 
136
136
  this._deviceId = options.deviceId != null
@@ -926,32 +926,28 @@ Hci.prototype.processCmdCompleteEvent = function (cmd, status, result) {
926
926
  this.setLeEventMask();
927
927
  this.readLocalVersion();
928
928
  this.readBdAddr();
929
- } else if (cmd === LE_READ_LOCAL_SUPPORTED_FEATURES) {
930
- if (status === 0) {
931
- // Set _isExtended based on leExtendedAdvertising bit (12)
932
- this._isExtended = !!(result.readUInt32LE(0) & (1 << 12));
929
+ } else if (cmd === LE_READ_LOCAL_SUPPORTED_FEATURES && status === 0) {
930
+ // Set _isExtended based on leExtendedAdvertising bit (12)
931
+ this._isExtended = !!(result.readUInt32LE(0) & (1 << 12));
933
932
 
934
- this.emit('leFeatures', result);
933
+ this.emit('leFeatures', result);
935
934
 
936
- if (this._isExtended) {
937
- this.setCodedPhySupport();
938
- }
939
- this.setEventMask();
940
- this.setLeEventMask();
941
- this.readLocalVersion();
942
- this.writeLeHostSupported();
943
- this.readLeHostSupported();
944
- this.readLeBufferSize();
945
- this.readBdAddr();
935
+ if (this._isExtended) {
936
+ this.setCodedPhySupport();
946
937
  }
947
- } else if (cmd === READ_LE_HOST_SUPPORTED_CMD) {
948
- if (status === 0) {
949
- const le = result.readUInt8(0);
950
- const simul = result.readUInt8(1);
938
+ this.setEventMask();
939
+ this.setLeEventMask();
940
+ this.readLocalVersion();
941
+ this.writeLeHostSupported();
942
+ this.readLeHostSupported();
943
+ this.readLeBufferSize();
944
+ this.readBdAddr();
945
+ } else if (cmd === READ_LE_HOST_SUPPORTED_CMD && status === 0) {
946
+ const le = result.readUInt8(0);
947
+ const simul = result.readUInt8(1);
951
948
 
952
- debug(`\t\t\tle = ${le}`);
953
- debug(`\t\t\tsimul = ${simul}`);
954
- }
949
+ debug(`\t\t\tle = ${le}`);
950
+ debug(`\t\t\tsimul = ${simul}`);
955
951
  } else if (cmd === READ_LOCAL_VERSION_CMD) {
956
952
  const hciVer = result.readUInt8(0);
957
953
  const hciRev = result.readUInt16LE(1);
@@ -1289,6 +1285,11 @@ Hci.prototype.processCmdStatusEvent = function (cmd, status) {
1289
1285
  };
1290
1286
 
1291
1287
  Hci.prototype.onStateChange = function (state) {
1288
+ // If we are powered on and we are powered off, clean up
1289
+ if (this._state === 'poweredOn' && state === 'poweredOff') {
1290
+ this._aclConnections.clear();
1291
+ this._aclQueue = [];
1292
+ }
1292
1293
  this._state = state;
1293
1294
  };
1294
1295
 
package/lib/noble.js CHANGED
@@ -14,11 +14,8 @@ function Noble (bindings) {
14
14
  this.address = 'unknown';
15
15
  this._state = 'unknown';
16
16
  this._bindings = bindings;
17
- this._peripherals = {};
18
- this._services = {};
19
- this._characteristics = {};
20
- this._descriptors = {};
21
- this._discoveredPeripheralUUids = {};
17
+
18
+ this._cleanupPeriperals();
22
19
 
23
20
  this._bindings.on('stateChange', this.onStateChange.bind(this));
24
21
  this._bindings.on('addressChange', this.onAddressChange.bind(this));
@@ -56,7 +53,6 @@ function Noble (bindings) {
56
53
  this.on('newListener', (event) => {
57
54
  if (event === 'stateChange' && !this.initialized) {
58
55
  this.initialized = true;
59
-
60
56
  process.nextTick(() => {
61
57
  try {
62
58
  this._bindings.init();
@@ -73,7 +69,6 @@ function Noble (bindings) {
73
69
  get: function () {
74
70
  if (!this.initialized) {
75
71
  this.initialized = true;
76
-
77
72
  this._bindings.init();
78
73
  }
79
74
  return this._state;
@@ -84,11 +79,23 @@ function Noble (bindings) {
84
79
 
85
80
  util.inherits(Noble, events.EventEmitter);
86
81
 
82
+ Noble.prototype._cleanupPeriperals = function () {
83
+ this._peripherals = {};
84
+ this._services = {};
85
+ this._characteristics = {};
86
+ this._descriptors = {};
87
+ this._discoveredPeripheralUUids = {};
88
+ };
89
+
87
90
  Noble.prototype.onStateChange = function (state) {
88
91
  debug(`stateChange ${state}`);
89
92
 
90
- this._state = state;
93
+ // If the state is poweredOff and the previous state was poweredOn, clean up the peripherals
94
+ if (state === 'poweredOff' && this._state === 'poweredOn') {
95
+ this._cleanupPeriperals();
96
+ }
91
97
 
98
+ this._state = state;
92
99
  this.emit('stateChange', state);
93
100
  };
94
101
 
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "license": "MIT",
7
7
  "name": "@stoprocent/noble",
8
8
  "description": "A Node.js BLE (Bluetooth Low Energy) central library.",
9
- "version": "1.18.2",
9
+ "version": "1.19.0",
10
10
  "repository": {
11
11
  "type": "git",
12
12
  "url": "https://github.com/stoprocent/noble.git"
@@ -34,7 +34,7 @@
34
34
  "node-gyp-build": "^4.8.1"
35
35
  },
36
36
  "optionalDependencies": {
37
- "@stoprocent/bluetooth-hci-socket": "^1.4.4"
37
+ "@stoprocent/bluetooth-hci-socket": "^1.5.1"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@commitlint/cli": "^19.3.0",
@@ -78,13 +78,13 @@ describe('hci-socket bindings', () => {
78
78
  describe('onSigInt', () => {
79
79
  it('should exit', () => {
80
80
  const sigIntListeners = process.listeners('SIGINT');
81
- bindings.onSigIntBinded = sigIntListeners[sigIntListeners.length - 1];
81
+ bindings._sigIntHandler = sigIntListeners[sigIntListeners.length - 1];
82
82
  bindings.onSigInt();
83
83
  assert.calledOnceWithExactly(process.exit, 1);
84
84
  });
85
85
 
86
86
  it('should not exit', () => {
87
- bindings.onSigIntBinded = sinon.spy();
87
+ bindings._sigIntHandler = sinon.spy();
88
88
  bindings.onSigInt();
89
89
  assert.notCalled(process.exit);
90
90
  });
@@ -292,7 +292,9 @@ describe('hci-socket bindings', () => {
292
292
  bindings._gap.stopScanning = fake.resolves(null);
293
293
  bindings._hci.reset = fake.resolves(null);
294
294
  bindings._hci.stop = fake.resolves(null);
295
-
295
+ bindings._sigIntHandler = fake.resolves(null);
296
+ bindings._exitHandler = fake.resolves(null);
297
+
296
298
  bindings.stop();
297
299
 
298
300
  assert.calledOnce(bindings._gap.stopScanning);
@@ -305,6 +307,8 @@ describe('hci-socket bindings', () => {
305
307
  bindings._hci.disconnect = fake.resolves(null);
306
308
  bindings._hci.reset = fake.resolves(null);
307
309
  bindings._hci.stop = fake.resolves(null);
310
+ bindings._sigIntHandler = fake.resolves(null);
311
+ bindings._exitHandler = fake.resolves(null);
308
312
 
309
313
  bindings._aclStreams = [1, 2, 3];
310
314