incyclist-services 1.0.36 → 1.0.38

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.
Files changed (68) hide show
  1. package/LICENSE +21 -21
  2. package/README.MD +29 -28
  3. package/lib/devices/access/index.d.ts +0 -0
  4. package/lib/devices/access/index.js +0 -0
  5. package/lib/devices/access/mock.d.ts +4 -0
  6. package/lib/devices/access/mock.js +10 -0
  7. package/lib/devices/access/model.d.ts +5 -0
  8. package/lib/devices/access/model.js +0 -0
  9. package/lib/devices/access/service.d.ts +8 -2
  10. package/lib/devices/access/service.js +59 -22
  11. package/lib/devices/configuration/index.d.ts +0 -0
  12. package/lib/devices/configuration/index.js +0 -0
  13. package/lib/devices/configuration/mock.d.ts +4 -0
  14. package/lib/devices/configuration/mock.js +16 -0
  15. package/lib/devices/configuration/model/app/index.d.ts +1 -0
  16. package/lib/devices/configuration/model/app/index.js +0 -0
  17. package/lib/devices/configuration/model/index.d.ts +0 -0
  18. package/lib/devices/configuration/model/index.js +0 -0
  19. package/lib/devices/configuration/model/repository/index.d.ts +0 -0
  20. package/lib/devices/configuration/model/repository/index.js +0 -0
  21. package/lib/devices/configuration/model/repository/legacy.d.ts +0 -0
  22. package/lib/devices/configuration/model/repository/legacy.js +0 -0
  23. package/lib/devices/configuration/model/service/index.d.ts +0 -0
  24. package/lib/devices/configuration/model/service/index.js +0 -0
  25. package/lib/devices/configuration/service.d.ts +6 -1
  26. package/lib/devices/configuration/service.js +58 -22
  27. package/lib/devices/index.d.ts +1 -0
  28. package/lib/devices/index.js +1 -0
  29. package/lib/devices/pairing/index.d.ts +2 -0
  30. package/lib/devices/pairing/index.js +18 -0
  31. package/lib/devices/pairing/model.d.ts +59 -0
  32. package/lib/devices/pairing/model.js +2 -0
  33. package/lib/devices/pairing/service.d.ts +88 -0
  34. package/lib/devices/pairing/service.js +809 -0
  35. package/lib/devices/ride/index.d.ts +0 -0
  36. package/lib/devices/ride/index.js +0 -0
  37. package/lib/devices/ride/model.d.ts +8 -1
  38. package/lib/devices/ride/model.js +0 -0
  39. package/lib/devices/ride/service.d.ts +5 -11
  40. package/lib/devices/ride/service.js +8 -5
  41. package/lib/index.d.ts +0 -0
  42. package/lib/index.js +0 -0
  43. package/lib/settings/index.d.ts +0 -0
  44. package/lib/settings/index.js +0 -0
  45. package/lib/settings/user/bindings/index.d.ts +0 -0
  46. package/lib/settings/user/bindings/index.js +0 -0
  47. package/lib/settings/user/bindings/json.d.ts +0 -0
  48. package/lib/settings/user/bindings/json.js +0 -0
  49. package/lib/settings/user/bindings/types.d.ts +0 -0
  50. package/lib/settings/user/bindings/types.js +0 -0
  51. package/lib/settings/user/mock.d.ts +4 -0
  52. package/lib/settings/user/mock.js +46 -0
  53. package/lib/settings/user/service.d.ts +1 -1
  54. package/lib/settings/user/service.js +2 -1
  55. package/lib/utils/clone.d.ts +0 -0
  56. package/lib/utils/clone.js +0 -0
  57. package/lib/utils/index.d.ts +0 -0
  58. package/lib/utils/index.js +0 -0
  59. package/lib/utils/logging.d.ts +0 -0
  60. package/lib/utils/logging.js +0 -0
  61. package/lib/utils/merge.d.ts +0 -0
  62. package/lib/utils/merge.js +0 -0
  63. package/lib/utils/sleep.d.ts +0 -0
  64. package/lib/utils/sleep.js +0 -0
  65. package/lib/utils/valid.d.ts +0 -0
  66. package/lib/utils/valid.js +0 -0
  67. package/package.json +44 -43
  68. package/lib/devices/consume/service.js +0 -19
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2023 Incyclist
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Incyclist
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.MD CHANGED
@@ -1,28 +1,29 @@
1
- # incyclist-services
2
-
3
- This Library contains the business logic used by the React components of the [Incyclist](https://incyclist.com) Indoor Cycling App.
4
-
5
- Incyclist uses React to render the App Front-End for PC platforms ( Windows, Mac. Linux). It is planned that in the future, React Native will be used to render the Front-Ends for other platforms ( Android, IOS, AppleTV,...)
6
-
7
- All Services will be accessed by the Front-End using
8
-
9
- ```
10
- import {useXXX, initXXX} from {incyclist-devices}
11
-
12
- ```
13
-
14
- - useXXX can be used to consume a Service (e.g. `useDeviceConfiguration()` )
15
- - initXXX can be used to perform a lazy initialization of the Service (e.g. `initUserSettings(binding)` )
16
-
17
- where XXX represents the Service name
18
-
19
- The following Services are currently implemented in this library:
20
-
21
- ## Settings
22
- - [UserSettings](./doc/classes/UserSettingsService.md): manages the user settings
23
-
24
-
25
- ## Devices
26
- - [DeviceConfiguration](./doc/classes/DeviceConfigurationService.md): manages the user configuration of scanned/added/selected devices
27
- - [DeviceAccess](./doc/classes/DeviceAccessService.md): manages the basic communication to the device (setting up interfacs, scanning,... )
28
- - [Device](./src/devices/device/README.MD): allows the Front-End to communicate with a device (reading, writing data)
1
+ # incyclist-services
2
+
3
+ This Library contains the business logic used by the React components of the [Incyclist](https://incyclist.com) Indoor Cycling App.
4
+
5
+ Incyclist uses React to render the App Front-End for PC platforms ( Windows, Mac. Linux). It is planned that in the future, React Native will be used to render the Front-Ends for other platforms ( Android, IOS, AppleTV,...)
6
+
7
+ All Services will be accessed by the Front-End using
8
+
9
+ ```
10
+ import {useXXX, initXXX} from {incyclist-devices}
11
+
12
+ ```
13
+
14
+ - useXXX can be used to consume a Service (e.g. `useDeviceConfiguration()` )
15
+ - initXXX can be used to perform a lazy initialization of the Service (e.g. `initUserSettings(binding)` )
16
+
17
+ where XXX represents the Service name
18
+
19
+ The following Services are currently implemented in this library:
20
+
21
+ ## Settings
22
+ - [UserSettings](./doc/classes/UserSettingsService.md): manages the user settings
23
+
24
+
25
+ ## Devices
26
+ - [DeviceConfiguration](./doc/classes/DeviceConfigurationService.md): manages the user configuration of scanned/added/selected devices
27
+ - [DeviceAccess](./doc/classes/DeviceAccessService.md): manages the basic communication to the device (setting up interfacs, scanning,... )
28
+ - [Device](./src/devices/device/README.MD): allows the Front-End to communicate with a device (reading, writing data)
29
+ - [DevicePairing](./doc/classes/DevicePairingService.md): implements the business logic og the DevicePairing screens
File without changes
File without changes
@@ -0,0 +1,4 @@
1
+ import { DeviceAccessService } from "./service";
2
+ export default class DeviceAccessMock extends DeviceAccessService {
3
+ constructor();
4
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const service_1 = require("./service");
4
+ class DeviceAccessMock extends service_1.DeviceAccessService {
5
+ constructor() {
6
+ super();
7
+ service_1.DeviceAccessService._instance = this;
8
+ }
9
+ }
10
+ exports.default = DeviceAccessMock;
@@ -1,4 +1,5 @@
1
1
  import { DeviceSettings, IncyclistCapability } from "incyclist-devices";
2
+ import { InterfaceSetting } from "../configuration";
2
3
  export type InterfaceState = 'connected' | 'disconnected' | 'unknown' | 'connecting' | 'disconnecting' | 'unavailable';
3
4
  export type ScanState = 'start-requested' | 'started' | 'stop-requested' | 'stopped' | 'idle';
4
5
  export interface InterfaceInfo {
@@ -18,6 +19,10 @@ export interface InterfaceAccessProps {
18
19
  export interface InterfaceList {
19
20
  [index: string]: InterfaceInfo;
20
21
  }
22
+ export interface EnrichedInterfaceSetting extends InterfaceSetting {
23
+ state: InterfaceState;
24
+ isScanning: boolean;
25
+ }
21
26
  export interface ScanFilter {
22
27
  interfaces?: string[];
23
28
  capabilities?: (IncyclistCapability | 'bike')[];
File without changes
@@ -2,7 +2,8 @@
2
2
  import EventEmitter from "events";
3
3
  import { EventLogger } from "gd-eventlog";
4
4
  import { DeviceSettings, IncyclistInterface } from "incyclist-devices";
5
- import { InterfaceList, ScanFilter, InterfaceInfo, InterfaceAccessProps, ScanState, ScanForNewFilter } from "./model";
5
+ import { InterfaceSetting } from "../configuration";
6
+ import { InterfaceList, ScanFilter, InterfaceInfo, InterfaceAccessProps, ScanState, ScanForNewFilter, EnrichedInterfaceSetting } from "./model";
6
7
  interface InternalScanState {
7
8
  promises: (Promise<DeviceSettings[]>)[];
8
9
  interfaces: IncyclistInterface[];
@@ -21,10 +22,15 @@ export declare class DeviceAccessService extends EventEmitter {
21
22
  disableInterface(ifaceName: string, avalailable?: boolean): void;
22
23
  setInterfaceProperties(ifaceName: string, props: InterfaceAccessProps): void;
23
24
  getInterfaceInfo(ifaceName: string): InterfaceInfo;
25
+ enrichWithAccessState(interfaces: InterfaceSetting[]): EnrichedInterfaceSetting[];
24
26
  protected getInterface(ifaceName: string): IncyclistInterface;
25
27
  connect(ifaceName?: string): Promise<boolean>;
28
+ private getScanTimeout;
26
29
  disconnect(ifaceName?: string): Promise<boolean>;
27
- scan(filter?: ScanFilter): Promise<DeviceSettings[]>;
30
+ scan(filter?: ScanFilter, props?: {
31
+ timeout?: number;
32
+ includeKnown?: boolean;
33
+ }): Promise<DeviceSettings[]>;
28
34
  scanForNew(filter?: ScanForNewFilter, maxDevices?: number, timeout?: number): Promise<DeviceSettings[] | DeviceSettings>;
29
35
  getPaths(ifaceName: string): Promise<string[]>;
30
36
  getProtocols(ifaceName: string): string[];
@@ -46,7 +46,8 @@ class DeviceAccessService extends events_1.default {
46
46
  enableInterface(ifaceName, binding, props = {}) {
47
47
  const existing = this.interfaces[ifaceName];
48
48
  if (!binding && !existing) {
49
- throw new Error('Interface has not been initialized with binding');
49
+ this.logEvent({ message: 'Interface has not been initialized with binding', interface: ifaceName });
50
+ this.emit('interface-changed', ifaceName, { name: ifaceName, state: 'unavailable', isScanning: false });
50
51
  }
51
52
  if (!existing) {
52
53
  const properties = (0, clone_1.default)(this.defaultProps);
@@ -60,7 +61,8 @@ class DeviceAccessService extends events_1.default {
60
61
  }
61
62
  else {
62
63
  if (this.isScanning(ifaceName)) {
63
- throw new Error('Illegal State, enable Interface cannot be called during an ongoing scan');
64
+ this.logEvent({ message: 'Illegal State, enable Interface cannot be called during an ongoing scan' });
65
+ return;
64
66
  }
65
67
  if (binding)
66
68
  existing.interface.setBinding(binding);
@@ -115,6 +117,21 @@ class DeviceAccessService extends events_1.default {
115
117
  getInterfaceInfo(ifaceName) {
116
118
  return this.interfaces[ifaceName];
117
119
  }
120
+ enrichWithAccessState(interfaces) {
121
+ return interfaces.map(i => {
122
+ const info = this.interfaces[i.name];
123
+ const enriched = Object.assign({}, i);
124
+ if (!info) {
125
+ enriched.state = 'unavailable';
126
+ enriched.isScanning = false;
127
+ }
128
+ else {
129
+ enriched.state = info.state;
130
+ enriched.isScanning = info.isScanning;
131
+ }
132
+ return enriched;
133
+ });
134
+ }
118
135
  getInterface(ifaceName) {
119
136
  const info = this.interfaces[ifaceName];
120
137
  return info === null || info === void 0 ? void 0 : info.interface;
@@ -130,6 +147,7 @@ class DeviceAccessService extends events_1.default {
130
147
  const impl = this.getInterface(ifaceName);
131
148
  if (!impl) {
132
149
  this.emit('interface-changed', ifaceName, { name: ifaceName, state: 'unavailable', isScanning: false });
150
+ this.interfaces[ifaceName].state = 'unavailable';
133
151
  return false;
134
152
  }
135
153
  const prevState = this.interfaces[ifaceName].state;
@@ -144,6 +162,17 @@ class DeviceAccessService extends events_1.default {
144
162
  return connected;
145
163
  });
146
164
  }
165
+ getScanTimeout(propsTimeout, interfaceSettingsTimeout) {
166
+ if (propsTimeout) {
167
+ if (propsTimeout === -1)
168
+ return undefined;
169
+ else
170
+ return propsTimeout;
171
+ }
172
+ else {
173
+ return interfaceSettingsTimeout;
174
+ }
175
+ }
147
176
  disconnect(ifaceName) {
148
177
  return __awaiter(this, void 0, void 0, function* () {
149
178
  if (!ifaceName) {
@@ -166,11 +195,13 @@ class DeviceAccessService extends events_1.default {
166
195
  return disconnected;
167
196
  });
168
197
  }
169
- scan(filter = {}) {
198
+ scan(filter = {}, props = {}) {
199
+ var _a, _b, _c;
170
200
  return __awaiter(this, void 0, void 0, function* () {
171
- this.logEvent({ message: 'device scan start', filter });
201
+ this.logEvent({ message: 'device scan start', filter, props });
172
202
  const detected = [];
173
203
  const onDataHandlers = {};
204
+ const { includeKnown = false } = props;
174
205
  if (!this.isScanning()) {
175
206
  this.emitScanStateChange('start-requested');
176
207
  this.scanState = {
@@ -192,17 +223,19 @@ class DeviceAccessService extends events_1.default {
192
223
  }
193
224
  };
194
225
  const onDevice = (deviceSettings) => __awaiter(this, void 0, void 0, function* () {
195
- if (adapters.find(a => a.isEqual(deviceSettings))) {
196
- return;
197
- }
198
- if (filter.profile && deviceSettings.profile !== filter.profile) {
199
- return;
200
- }
201
- if (filter.protocol && deviceSettings.protocol !== filter.protocol) {
202
- return;
203
- }
204
- if (filter.protocols && !filter.protocols.includes(deviceSettings.protocol)) {
205
- return;
226
+ if (!includeKnown) {
227
+ if (adapters.find(a => a.isEqual(deviceSettings))) {
228
+ return;
229
+ }
230
+ if (filter.profile && deviceSettings.profile !== filter.profile) {
231
+ return;
232
+ }
233
+ if (filter.protocol && deviceSettings.protocol !== filter.protocol) {
234
+ return;
235
+ }
236
+ if (filter.protocols && !filter.protocols.includes(deviceSettings.protocol)) {
237
+ return;
238
+ }
206
239
  }
207
240
  const adapter = incyclist_devices_1.AdapterFactory.create(deviceSettings);
208
241
  if (filter.capabilities) {
@@ -227,17 +260,18 @@ class DeviceAccessService extends events_1.default {
227
260
  const ifaceName = i.getName();
228
261
  const info = this.interfaces[ifaceName];
229
262
  info.isScanning = true;
230
- const props = info.properties || this.defaultProps;
231
- const { scanTimeout, port, protocol } = props;
232
- const properties = ifaceName === 'tcpip' || ifaceName === 'serial' ? { timeout: scanTimeout, port: port === null || port === void 0 ? void 0 : port.toString(), protocol } : { timeout: scanTimeout };
263
+ const scanProps = info.properties || this.defaultProps;
264
+ const { scanTimeout, port, protocol } = scanProps;
265
+ const timeout = this.getScanTimeout(props.timeout, scanTimeout);
266
+ const properties = ifaceName === 'tcpip' || ifaceName === 'serial' ? { timeout, port: port === null || port === void 0 ? void 0 : port.toString(), protocol } : { timeout: scanTimeout };
233
267
  this.scanState.promises.push(i.scan(properties));
234
268
  });
235
269
  this.emitScanStateChange('started');
236
270
  try {
237
- if (this.scanState.promises.length === 0) {
238
- this.scanState.promises.push(this.dummyScan());
271
+ if (((_a = this.scanState) === null || _a === void 0 ? void 0 : _a.promises.length) === 0) {
272
+ (_b = this.scanState) === null || _b === void 0 ? void 0 : _b.promises.push(this.dummyScan());
239
273
  }
240
- yield Promise.allSettled(this.scanState.promises);
274
+ yield Promise.allSettled((_c = this.scanState) === null || _c === void 0 ? void 0 : _c.promises);
241
275
  }
242
276
  catch (err) {
243
277
  this.logEvent({ message: 'device scan finished with errors', filter, error: err.message, stack: err.stack });
@@ -250,6 +284,7 @@ class DeviceAccessService extends events_1.default {
250
284
  if (i.getName() === 'tcpip')
251
285
  this.interfaces[i.getName()];
252
286
  });
287
+ adapters.forEach(adapter => adapter.removeAllListeners('data'));
253
288
  this.emitScanStateChange('stopped');
254
289
  this.logEvent({ message: 'device scan finished', filter, detected });
255
290
  return detected;
@@ -355,13 +390,15 @@ class DeviceAccessService extends events_1.default {
355
390
  this.logEvent({ message: 'stop device scan finished with errors', error: err.message, stack: err.stack });
356
391
  return false;
357
392
  }
358
- this.scanState.promises = [];
393
+ this.scanState = null;
359
394
  this.emitScanStateChange('stopped');
360
395
  this.logEvent({ message: 'stop device scan finished', stopScanresult: result });
361
396
  return true;
362
397
  });
363
398
  }
364
399
  isScanning(ifaceName) {
400
+ if (!this.scanState)
401
+ return false;
365
402
  if (!ifaceName)
366
403
  return this.scanState !== null && this.scanState.promises !== null && this.scanState.promises.length > 0;
367
404
  else
File without changes
File without changes
@@ -0,0 +1,4 @@
1
+ import { DeviceConfigurationService } from "./service";
2
+ export default class DeviceConfigurationMock extends DeviceConfigurationService {
3
+ constructor(settings: any);
4
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const mock_1 = __importDefault(require("../../settings/user/mock"));
7
+ const service_1 = require("./service");
8
+ class DeviceConfigurationMock extends service_1.DeviceConfigurationService {
9
+ constructor(settings) {
10
+ const svc = new mock_1.default(settings);
11
+ super();
12
+ this.userSettings = svc;
13
+ service_1.DeviceConfigurationService._instance = this;
14
+ }
15
+ }
16
+ exports.default = DeviceConfigurationMock;
@@ -3,6 +3,7 @@ export type ExtendedIncyclistCapability = IncyclistCapability | 'bike';
3
3
  export interface DeviceInformation {
4
4
  udid: string;
5
5
  name: string;
6
+ interface: string;
6
7
  selected: boolean;
7
8
  mode?: string;
8
9
  modeSetting?: any;
File without changes
File without changes
File without changes
File without changes
@@ -1,5 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import { IncyclistCapability, IncyclistDeviceAdapter } from "incyclist-devices";
3
+ import { UserSettingsService } from "../../settings";
3
4
  import { AdapterInfo, DeviceConfigurationInfo, DeviceConfigurationSettings, DeviceModeInfo, ExtendedIncyclistCapability, IncyclistDeviceSettings, InterfaceSetting, LegacySettings } from "./model";
4
5
  import EventEmitter from "events";
5
6
  import { EventLogger } from "gd-eventlog";
@@ -15,7 +16,7 @@ export declare class DeviceConfigurationService extends EventEmitter {
15
16
  protected static _instance: DeviceConfigurationService;
16
17
  static getInstance(): DeviceConfigurationService;
17
18
  settings: DeviceConfigurationSettings;
18
- userSettings: any;
19
+ userSettings: UserSettingsService;
19
20
  adapters: DeviceAdapterList;
20
21
  protected logger: EventLogger;
21
22
  constructor();
@@ -31,6 +32,10 @@ export declare class DeviceConfigurationService extends EventEmitter {
31
32
  protected getDeviceConfigurationInfo(): DeviceConfigurationInfo;
32
33
  protected emitCapabiltyChanged(capability?: ExtendedIncyclistCapability): void;
33
34
  protected emitInitialized(): void;
35
+ load(): {
36
+ capabilities: DeviceConfigurationInfo;
37
+ interfaces: Array<InterfaceSetting>;
38
+ };
34
39
  disableCapability(cability: ExtendedIncyclistCapability, disabled?: boolean): void;
35
40
  select(udid: string, capability: ExtendedIncyclistCapability, props?: {
36
41
  noRecursive?: boolean;