incyclist-services 1.0.53 → 1.0.55

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.
@@ -0,0 +1,2 @@
1
+ export * from './types';
2
+ export * from './json';
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./types"), exports);
18
+ __exportStar(require("./json"), exports);
@@ -0,0 +1,19 @@
1
+ import { EventLogger } from "gd-eventlog";
2
+ import { IRepositoryBinding, JSONObject } from "../types";
3
+ export declare class JsonRepository {
4
+ protected static _instances: {
5
+ [x: string]: JsonRepository;
6
+ };
7
+ protected static _defaultBinding: IRepositoryBinding;
8
+ static create(repoName: string): JsonRepository;
9
+ static setBinding(binding: IRepositoryBinding): void;
10
+ protected binding: IRepositoryBinding;
11
+ protected name: string;
12
+ protected db: string;
13
+ protected logger: EventLogger;
14
+ constructor(repoName: string, binding?: IRepositoryBinding);
15
+ protected open(): Promise<boolean>;
16
+ protected close(): Promise<boolean>;
17
+ protected write(objectName: string, data: JSONObject): Promise<boolean>;
18
+ protected read(objectName: string): Promise<JSONObject>;
19
+ }
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.JsonRepository = void 0;
13
+ const gd_eventlog_1 = require("gd-eventlog");
14
+ class JsonRepository {
15
+ static create(repoName) {
16
+ if (JsonRepository._instances[repoName])
17
+ return JsonRepository._instances[repoName];
18
+ JsonRepository._instances[repoName] = new JsonRepository(repoName);
19
+ return JsonRepository._instances[repoName];
20
+ }
21
+ static setBinding(binding) {
22
+ JsonRepository._defaultBinding = binding;
23
+ }
24
+ constructor(repoName, binding) {
25
+ this.name = repoName;
26
+ this.binding = binding || JsonRepository._defaultBinding;
27
+ this.logger = new gd_eventlog_1.EventLogger(`Repo-${this.name}`);
28
+ }
29
+ open() {
30
+ return __awaiter(this, void 0, void 0, function* () {
31
+ if (!this.binding)
32
+ throw new Error('no binding specified');
33
+ try {
34
+ const existing = yield this.binding.get(this.name);
35
+ if (existing) {
36
+ return true;
37
+ }
38
+ return yield this.binding.create(this.name);
39
+ }
40
+ catch (err) {
41
+ return false;
42
+ }
43
+ });
44
+ }
45
+ close() {
46
+ return __awaiter(this, void 0, void 0, function* () {
47
+ if (!this.binding)
48
+ throw new Error('no binding specified');
49
+ this.binding.release(this.name);
50
+ return true;
51
+ });
52
+ }
53
+ write(objectName, data) {
54
+ if (!this.binding)
55
+ throw new Error('no binding specified');
56
+ const success = this.binding.write(objectName, data);
57
+ if (!success) {
58
+ }
59
+ return success;
60
+ }
61
+ read(objectName) {
62
+ if (!this.binding)
63
+ throw new Error('no binding specified');
64
+ try {
65
+ const data = this.binding.read(objectName);
66
+ if (!data) {
67
+ }
68
+ return data;
69
+ }
70
+ catch (err) {
71
+ }
72
+ }
73
+ }
74
+ exports.JsonRepository = JsonRepository;
75
+ JsonRepository._instances = {};
File without changes
File without changes
@@ -0,0 +1,10 @@
1
+ export type JSONObject = string | number | boolean | {
2
+ [x: string]: JSONObject;
3
+ } | Array<JSONObject>;
4
+ export interface IRepositoryBinding {
5
+ create(name: string): Promise<boolean>;
6
+ get(name: string): Promise<boolean>;
7
+ release(name: string): Promise<boolean>;
8
+ read(resourceName: string): Promise<JSONObject>;
9
+ write(resourceName: string, data: JSONObject): Promise<boolean>;
10
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -18,11 +18,12 @@ export declare class DeviceAccessService extends EventEmitter {
18
18
  constructor();
19
19
  protected logEvent(event: any): void;
20
20
  setDefaultInterfaceProperties(props: InterfaceAccessProps): void;
21
- enableInterface(ifaceName: string, binding?: any, props?: InterfaceAccessProps): void;
22
- disableInterface(ifaceName: string, avalailable?: boolean): void;
21
+ enableInterface(ifaceName: string, binding?: any, props?: InterfaceAccessProps): Promise<void>;
22
+ disableInterface(ifaceName: string, avalailable?: boolean): Promise<void>;
23
23
  setInterfaceProperties(ifaceName: string, props: InterfaceAccessProps): void;
24
24
  getInterfaceInfo(ifaceName: string): InterfaceInfo;
25
25
  enrichWithAccessState(interfaces: InterfaceSetting[]): EnrichedInterfaceSetting[];
26
+ initInterface(ifaceName: string, binding: any, props?: InterfaceAccessProps): void;
26
27
  protected getInterface(ifaceName: string): IncyclistInterface;
27
28
  connect(ifaceName?: string): Promise<boolean>;
28
29
  private getScanTimeout;
@@ -44,55 +44,67 @@ class DeviceAccessService extends events_1.default {
44
44
  this.defaultProps = props;
45
45
  }
46
46
  enableInterface(ifaceName, binding, props = {}) {
47
- const existing = this.interfaces[ifaceName];
48
- if (!binding && !existing) {
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 });
51
- }
52
- if (!existing) {
53
- const properties = (0, clone_1.default)(this.defaultProps);
54
- (0, merge_1.merge)(properties, props);
55
- const info = { name: ifaceName, interface: incyclist_devices_1.InterfaceFactory.create(ifaceName, { binding }), enabled: true, isScanning: false, properties, state: 'unknown' };
56
- this.interfaces[ifaceName] = info;
57
- info.interface.setBinding(binding);
58
- const keys = Object.keys(this.interfaces);
59
- const interfaces = keys.map(name => (Object.assign(Object.assign({}, this.interfaces[name]), { name })));
60
- this.emit('interface-changed', ifaceName, this.interfaces[ifaceName], interfaces);
61
- }
62
- else {
63
- if (this.isScanning(ifaceName)) {
64
- this.logEvent({ message: 'Illegal State, enable Interface cannot be called during an ongoing scan' });
65
- return;
47
+ var _a;
48
+ return __awaiter(this, void 0, void 0, function* () {
49
+ try {
50
+ if (binding)
51
+ this.initInterface(ifaceName, binding, props);
52
+ const existing = this.interfaces[ifaceName];
53
+ if (!binding && !existing) {
54
+ this.logEvent({ message: 'Interface has not been initialized with binding', interface: ifaceName });
55
+ this.emit('interface-changed', ifaceName, { name: ifaceName, state: 'unavailable', isScanning: false });
56
+ }
57
+ if (this.isScanning(ifaceName)) {
58
+ this.logEvent({ message: 'Illegal State, enable Interface cannot be called during an ongoing scan' });
59
+ return;
60
+ }
61
+ if (existing.enabled && ((existing.state === 'connected' && ((_a = existing === null || existing === void 0 ? void 0 : existing.interface) === null || _a === void 0 ? void 0 : _a.isConnected())) || existing.state === 'connecting')) {
62
+ return;
63
+ }
64
+ existing.enabled = true;
65
+ const state = existing.interface.isConnected() ? 'connected' : 'disconnected';
66
+ existing.state = state;
67
+ (0, merge_1.merge)(existing.properties || this.defaultProps, props);
68
+ this.emit('interface-changed', ifaceName, Object.assign({}, existing));
69
+ if (!existing.interface.isConnected()) {
70
+ this.emit('interface-changed', ifaceName, Object.assign(Object.assign({}, existing), { state: 'connecting' }));
71
+ const conected = yield this.connect(ifaceName);
72
+ const state = conected ? 'connected' : 'disconnected';
73
+ this.emit('interface-changed', ifaceName, Object.assign(Object.assign({}, existing), { state }));
74
+ }
66
75
  }
67
- if (binding)
68
- existing.interface.setBinding(binding);
69
- existing.enabled = true;
70
- (0, merge_1.merge)(existing.properties || this.defaultProps, props);
71
- this.emit('interface-changed', ifaceName, this.interfaces[ifaceName]);
72
- }
76
+ catch (err) {
77
+ this.logEvent({ message: 'Error', fn: 'enableInterface', error: err.message, stack: err.stack });
78
+ }
79
+ });
73
80
  }
74
81
  disableInterface(ifaceName, avalailable = true) {
75
- const existing = this.interfaces[ifaceName];
76
- if (!existing)
77
- return;
78
- if (this.isScanning(ifaceName)) {
79
- const info = this.interfaces[ifaceName];
80
- info.interface.stopScan().then((stopped) => {
81
- this.emit('interface-changed', ifaceName, this.interfaces[ifaceName]);
82
- info.isScanning = !stopped;
83
- if (stopped)
84
- this.disableInterface(ifaceName);
85
- });
86
- return;
87
- }
88
- existing.enabled = false;
89
- if (!avalailable) {
90
- existing.state = 'unavailable';
91
- existing.unavailable = true;
92
- this.emit('interface-changed', ifaceName, { name: ifaceName, state: 'unavailable', isScanning: false });
93
- return;
94
- }
95
- this.emit('interface-changed', ifaceName, this.interfaces[ifaceName]);
82
+ return __awaiter(this, void 0, void 0, function* () {
83
+ const existing = this.interfaces[ifaceName];
84
+ if (!existing)
85
+ return;
86
+ if (this.isScanning(ifaceName)) {
87
+ try {
88
+ const info = this.interfaces[ifaceName];
89
+ const stopped = yield info.interface.stopScan();
90
+ info.isScanning = !stopped;
91
+ this.emit('interface-changed', ifaceName, this.interfaces[ifaceName]);
92
+ if (stopped)
93
+ this.disableInterface(ifaceName);
94
+ }
95
+ catch (err) {
96
+ this.logEvent({ message: 'Error', fn: 'disableInterface', error: err.message, stack: err.stack });
97
+ }
98
+ }
99
+ existing.enabled = false;
100
+ yield this.disconnect(ifaceName);
101
+ if (!avalailable) {
102
+ existing.state = 'unavailable';
103
+ existing.unavailable = true;
104
+ this.emit('interface-changed', ifaceName, { name: ifaceName, state: 'unavailable', isScanning: false });
105
+ return;
106
+ }
107
+ });
96
108
  }
97
109
  setInterfaceProperties(ifaceName, props) {
98
110
  if (this.isScanning(ifaceName)) {
@@ -132,34 +144,60 @@ class DeviceAccessService extends events_1.default {
132
144
  return enriched;
133
145
  });
134
146
  }
147
+ initInterface(ifaceName, binding, props = {}) {
148
+ const existing = this.interfaces[ifaceName];
149
+ if (!existing) {
150
+ const properties = (0, clone_1.default)(this.defaultProps);
151
+ (0, merge_1.merge)(properties, props);
152
+ const info = { name: ifaceName, interface: incyclist_devices_1.InterfaceFactory.create(ifaceName, { binding }), enabled: false, isScanning: false, properties, state: 'unknown' };
153
+ this.interfaces[ifaceName] = info;
154
+ info.interface.setBinding(binding);
155
+ const keys = Object.keys(this.interfaces);
156
+ const interfaces = keys.map(name => (Object.assign(Object.assign({}, this.interfaces[name]), { name })));
157
+ this.emit('interface-changed', ifaceName, this.interfaces[ifaceName], interfaces);
158
+ }
159
+ else {
160
+ const info = existing;
161
+ info.interface.setBinding(binding);
162
+ }
163
+ }
135
164
  getInterface(ifaceName) {
136
165
  const info = this.interfaces[ifaceName];
137
166
  return info === null || info === void 0 ? void 0 : info.interface;
138
167
  }
139
168
  connect(ifaceName) {
169
+ var _a;
140
170
  return __awaiter(this, void 0, void 0, function* () {
141
- if (!ifaceName) {
142
- const interfaces = Object.keys(this.interfaces);
143
- interfaces.forEach(name => { if (name)
144
- this.connect(name); });
145
- return;
171
+ try {
172
+ if (!ifaceName) {
173
+ const interfaces = Object.keys(this.interfaces);
174
+ interfaces.forEach(name => { if (name)
175
+ this.connect(name); });
176
+ return;
177
+ }
178
+ if (((_a = this.interfaces[ifaceName]) === null || _a === void 0 ? void 0 : _a.enabled) === false)
179
+ return;
180
+ const impl = this.getInterface(ifaceName);
181
+ if (!impl) {
182
+ this.emit('interface-changed', ifaceName, { name: ifaceName, state: 'unavailable', isScanning: false });
183
+ this.interfaces[ifaceName].state = 'unavailable';
184
+ return false;
185
+ }
186
+ const prevState = this.interfaces[ifaceName].state;
187
+ if (prevState === 'connected')
188
+ return true;
189
+ this.interfaces[ifaceName].state = 'connecting';
190
+ this.emit('interface-changed', ifaceName, Object.assign(Object.assign({}, this.interfaces[ifaceName]), { state: 'connecting' }));
191
+ const connected = yield impl.connect();
192
+ const state = connected ? 'connected' : 'disconnected';
193
+ this.interfaces[ifaceName].state = state;
194
+ this.emit('interface-changed', ifaceName, this.interfaces[ifaceName]);
195
+ return connected;
146
196
  }
147
- const impl = this.getInterface(ifaceName);
148
- if (!impl) {
149
- this.emit('interface-changed', ifaceName, { name: ifaceName, state: 'unavailable', isScanning: false });
150
- this.interfaces[ifaceName].state = 'unavailable';
197
+ catch (err) {
198
+ this.logEvent({ message: 'Error', fn: 'connect', error: err.message, stack: err.stack });
151
199
  return false;
152
200
  }
153
- const prevState = this.interfaces[ifaceName].state;
154
- if (prevState === 'connected')
155
- return true;
156
- this.interfaces[ifaceName].state = 'connecting';
157
- this.emit('interface-changed', ifaceName, this.interfaces[ifaceName]);
158
- const connected = yield impl.connect();
159
- const state = connected ? 'connected' : 'disconnected';
160
- this.interfaces[ifaceName].state = state;
161
- this.emit('interface-changed', ifaceName, this.interfaces[ifaceName]);
162
- return connected;
163
201
  });
164
202
  }
165
203
  getScanTimeout(propsTimeout, interfaceSettingsTimeout) {
@@ -187,11 +225,11 @@ class DeviceAccessService extends events_1.default {
187
225
  return true;
188
226
  const prevState = this.interfaces[ifaceName].state;
189
227
  this.interfaces[ifaceName].state = 'disconnecting';
190
- this.emit('interface-changed', ifaceName, this.interfaces[ifaceName]);
228
+ this.emit('interface-changed', ifaceName, Object.assign({}, this.interfaces[ifaceName]));
191
229
  const disconnected = yield impl.disconnect();
192
230
  const state = disconnected ? 'disconnected' : prevState;
193
231
  this.interfaces[ifaceName].state = state;
194
- this.emit('interface-changed', ifaceName, this.interfaces[ifaceName]);
232
+ this.emit('interface-changed', ifaceName, Object.assign({}, this.interfaces[ifaceName]));
195
233
  return disconnected;
196
234
  });
197
235
  }
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import { DeviceData, DeviceSettings, IncyclistCapability, IncyclistDeviceAdapter } from "incyclist-devices";
2
3
  import { EnrichedInterfaceSetting } from "../access";
3
4
  import { RideServiceCheckFilter } from "../ride";
@@ -38,10 +39,18 @@ export interface PairingState {
38
39
  canStartRide?: boolean;
39
40
  adapters?: Array<AdapterInfo>;
40
41
  }
42
+ export interface DeleteListEntry {
43
+ capability: IncyclistCapability;
44
+ udid: string;
45
+ }
41
46
  export interface InternalPairingState extends PairingState {
42
47
  initialized: boolean;
43
48
  stopRequested?: boolean;
44
49
  stopped?: boolean;
50
+ waiting?: boolean;
51
+ deleted: Array<DeleteListEntry>;
52
+ scanTo?: NodeJS.Timeout;
53
+ tsPrevStart?: number;
45
54
  check?: {
46
55
  promise: Promise<boolean>;
47
56
  };
@@ -5,8 +5,6 @@ import { DeviceData, IncyclistCapability, IncyclistDeviceAdapter } from "incycli
5
5
  import { AdapterStateInfo, DeviceRideService } from "../ride";
6
6
  import { IncyclistService } from "../../base/service";
7
7
  import { EnrichedInterfaceSetting } from "../access";
8
- export declare const mappedCapability: (c: CapabilityInformation) => CapabilityData;
9
- export declare const mappedCapabilities: (capabilities: DeviceConfigurationInfo) => Array<CapabilityData>;
10
8
  export interface Services {
11
9
  configuration?: DeviceConfigurationService;
12
10
  access?: DeviceAccessService;
@@ -95,6 +93,7 @@ export declare class DevicePairingService extends IncyclistService {
95
93
  protected getCapabilitiesUsingInterface(name: string): CapabilityData[];
96
94
  protected getEnabedInterfaces(): EnrichedInterfaceSetting[];
97
95
  protected getDisabledInterfaces(): EnrichedInterfaceSetting[];
96
+ protected getPairingInterfaces(): Array<string>;
98
97
  protected getDeviceAdapter(udid: string): IncyclistDeviceAdapter;
99
98
  protected stopAdaptersWithCapability(capability: IncyclistCapability | CapabilityData, udid?: string): Promise<void>;
100
99
  protected pauseAdapters(adapters: AdapterInfo[], enforced?: boolean): void;
@@ -106,5 +105,10 @@ export declare class DevicePairingService extends IncyclistService {
106
105
  protected isPairing(): boolean;
107
106
  protected _stopDeviceSelection(changed: boolean): Promise<void>;
108
107
  private numberOfSelectedCababilities;
108
+ protected addToDeletedList(capability: IncyclistCapability | CapabilityData, udid: string): void;
109
+ protected removeFromDeletedList(capability: IncyclistCapability | CapabilityData, udid: string): void;
110
+ protected isOnDeletedList(c: IncyclistCapability | CapabilityData, udid: string): boolean;
111
+ mappedCapability(c: CapabilityInformation): CapabilityData;
112
+ protected mappedCapabilities(capabilities: DeviceConfigurationInfo): Array<CapabilityData>;
109
113
  }
110
114
  export declare const useDevicePairing: () => DevicePairingService;
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.useDevicePairing = exports.DevicePairingService = exports.mappedCapabilities = exports.mappedCapability = void 0;
15
+ exports.useDevicePairing = exports.DevicePairingService = void 0;
16
16
  const service_1 = require("../access/service");
17
17
  const configuration_1 = require("../configuration");
18
18
  const incyclist_devices_1 = require("incyclist-devices");
@@ -26,28 +26,6 @@ const Units = [
26
26
  { capability: incyclist_devices_1.IncyclistCapability.Speed, unit: 'km/h', value: 'speed', decimals: 1 },
27
27
  { capability: incyclist_devices_1.IncyclistCapability.Cadence, unit: 'rpm', value: 'cadence', decimals: 0 },
28
28
  ];
29
- const mappedCapability = (c) => {
30
- var _a, _b, _c;
31
- const { devices } = c;
32
- const mapped = Object.assign({}, c);
33
- mapped.deviceNames = devices.map(d => d.name).join(';');
34
- mapped.selected = (_a = devices.find(d => d.selected)) === null || _a === void 0 ? void 0 : _a.udid;
35
- mapped.deviceName = (_b = devices.find(d => d.selected)) === null || _b === void 0 ? void 0 : _b.name;
36
- mapped.interface = (_c = devices.find(d => d.selected)) === null || _c === void 0 ? void 0 : _c.interface;
37
- mapped.devices = devices;
38
- return mapped;
39
- };
40
- exports.mappedCapability = mappedCapability;
41
- const mappedCapabilities = (capabilities) => {
42
- const caps = [];
43
- const ci = capabilities ? Object.keys(capabilities) || [] : [];
44
- ci.forEach(name => {
45
- const c = capabilities[name];
46
- caps.push((0, exports.mappedCapability)(c));
47
- });
48
- return caps;
49
- };
50
- exports.mappedCapabilities = mappedCapabilities;
51
29
  const getInterfaceSettings = (ifName, v) => {
52
30
  if (!v)
53
31
  return {};
@@ -62,7 +40,7 @@ class DevicePairingService extends service_2.IncyclistService {
62
40
  constructor(services) {
63
41
  super('Pairing');
64
42
  this.settings = {};
65
- this.state = { initialized: false };
43
+ this.state = { initialized: false, deleted: [] };
66
44
  this.deviceSelectState = null;
67
45
  this.onPairingStartedHandler = this.onPairingStarted.bind(this);
68
46
  this.onPairingSuccessHandler = this.onPairingSuccess.bind(this);
@@ -81,6 +59,10 @@ class DevicePairingService extends service_2.IncyclistService {
81
59
  }
82
60
  start(onStateChanged) {
83
61
  return __awaiter(this, void 0, void 0, function* () {
62
+ if (this.state.stopped) {
63
+ this.state.stopped = false;
64
+ this.state.deleted = [];
65
+ }
84
66
  try {
85
67
  if (this.settings.onStateChanged) {
86
68
  this.settings.onStateChanged = onStateChanged;
@@ -89,7 +71,9 @@ class DevicePairingService extends service_2.IncyclistService {
89
71
  }
90
72
  yield this.waitForInit();
91
73
  const { capabilities, interfaces } = this.configuration.load();
92
- this.state.capabilities = (0, exports.mappedCapabilities)(capabilities);
74
+ const state = Object.assign({}, this.state);
75
+ delete state.adapters;
76
+ this.state.capabilities = this.mappedCapabilities(capabilities);
93
77
  this.state.interfaces = this.access.enrichWithAccessState(interfaces);
94
78
  this.state.canStartRide = this.configuration.canStartRide();
95
79
  this.state.stopRequested = false;
@@ -129,6 +113,11 @@ class DevicePairingService extends service_2.IncyclistService {
129
113
  this.removeConfigHandlers();
130
114
  this.settings = {};
131
115
  this.state.initialized = false;
116
+ this.state.waiting = false;
117
+ this.state.check = null;
118
+ this.state.scan = null;
119
+ this.state.stopRequested = false;
120
+ this.state.stopped = true;
132
121
  }
133
122
  catch (err) {
134
123
  this.logError(err, 'stop');
@@ -140,7 +129,7 @@ class DevicePairingService extends service_2.IncyclistService {
140
129
  const capabilityData = this.getCapability(capability);
141
130
  this.settings = Object.assign(this.settings || {}, { onDeviceSelectStateChanged, capabilityForScan: capability });
142
131
  const devices = (capabilityData === null || capabilityData === void 0 ? void 0 : capabilityData.devices) || [];
143
- const available = devices.filter(d => this.isInterfaceEnabled(d.interface));
132
+ const available = devices.filter(d => this.isInterfaceEnabled(d.interface)).filter(d => !this.isOnDeletedList(capability, d.udid));
144
133
  const startScan = () => __awaiter(this, void 0, void 0, function* () {
145
134
  if (devices.length > 0)
146
135
  yield this.stopAdaptersWithCapability(capability);
@@ -246,15 +235,6 @@ class DevicePairingService extends service_2.IncyclistService {
246
235
  if (!changed)
247
236
  return;
248
237
  this.configuration.setInterfaceSettings(name, settings);
249
- if (settings.enabled) {
250
- this.connectInterface(name);
251
- }
252
- else {
253
- this.stopAdaptersOnInterface(name);
254
- this.disconnectInterface(name);
255
- }
256
- this.emitStateChange();
257
- yield this.restart();
258
238
  }
259
239
  catch (err) {
260
240
  this.logError(err, 'changeInterfaceSettings');
@@ -263,8 +243,34 @@ class DevicePairingService extends service_2.IncyclistService {
263
243
  }
264
244
  restart() {
265
245
  return __awaiter(this, void 0, void 0, function* () {
266
- yield this._stop();
267
- this.run();
246
+ const wasActive = this.isPairing() || this.isScanning();
247
+ if (this.state.scanTo) {
248
+ clearTimeout(this.state.scanTo);
249
+ delete this.state.scanTo;
250
+ this.state.waiting = true;
251
+ }
252
+ else {
253
+ yield this._stop();
254
+ }
255
+ if (this.state.tsPrevStart) {
256
+ if (this.state.tsPrevStart === -1) {
257
+ return;
258
+ }
259
+ const timeSincePrev = Date.now() - this.state.tsPrevStart;
260
+ if (timeSincePrev < 3000) {
261
+ this.state.tsPrevStart = -1;
262
+ yield (0, utils_1.sleep)(3000 - timeSincePrev);
263
+ }
264
+ }
265
+ if (wasActive) {
266
+ yield this.rideService.stop();
267
+ yield (0, utils_1.sleep)(500);
268
+ this.run();
269
+ }
270
+ if (this.state.waiting) {
271
+ this.state.waiting = false;
272
+ this.run();
273
+ }
268
274
  });
269
275
  }
270
276
  _stop() {
@@ -273,6 +279,8 @@ class DevicePairingService extends service_2.IncyclistService {
273
279
  yield this.stopPairing();
274
280
  if (this.isScanning())
275
281
  yield this.stopScanning();
282
+ this.state.capabilities.forEach(c => c.connectState = 'waiting');
283
+ this.state.waiting = true;
276
284
  });
277
285
  }
278
286
  getCapability(capability) {
@@ -284,14 +292,14 @@ class DevicePairingService extends service_2.IncyclistService {
284
292
  const c = this.getCapability(capability);
285
293
  if (!c)
286
294
  return false;
287
- return c.selected !== udid;
295
+ return c.selected !== udid && !this.isOnDeletedList(capability, udid);
288
296
  }
289
297
  getCapabilityDevice(capability, udid) {
290
298
  const c = this.getCapability(capability);
291
299
  if (!(c === null || c === void 0 ? void 0 : c.devices))
292
300
  return;
293
301
  if (udid) {
294
- return c.devices.find(d => d.udid === udid);
302
+ return c.devices.find(d => d.udid === udid && !this.isOnDeletedList(capability, udid));
295
303
  }
296
304
  else {
297
305
  return c.devices.find(d => d.selected);
@@ -301,7 +309,7 @@ class DevicePairingService extends service_2.IncyclistService {
301
309
  return __awaiter(this, void 0, void 0, function* () {
302
310
  if (this.state.initialized)
303
311
  return;
304
- this.state.capabilities = (0, exports.mappedCapabilities)(capabilitiesLoaded);
312
+ this.state.capabilities = this.mappedCapabilities(capabilitiesLoaded);
305
313
  this.state.canStartRide = this.configuration.canStartRide();
306
314
  this.state.interfaces = this.access.enrichWithAccessState(interfacesLoaded);
307
315
  this.state.initialized = true;
@@ -337,6 +345,8 @@ class DevicePairingService extends service_2.IncyclistService {
337
345
  delete state.scan;
338
346
  delete state.initialized;
339
347
  delete state.props;
348
+ delete state.deleted;
349
+ delete state.waiting;
340
350
  return state;
341
351
  }
342
352
  emitStateChange(newState) {
@@ -378,6 +388,7 @@ class DevicePairingService extends service_2.IncyclistService {
378
388
  current.port = settings.port;
379
389
  current.protocol = settings.protocol;
380
390
  this.emitStateChange();
391
+ this.restart();
381
392
  }
382
393
  catch (err) {
383
394
  this.logError(err, 'onInterfaceConfigChanged()');
@@ -404,7 +415,7 @@ class DevicePairingService extends service_2.IncyclistService {
404
415
  keys.forEach(key => {
405
416
  const newCap = newCapabilities[key];
406
417
  const current = capabilities.find(c => c.capability === key);
407
- this.mergeState(current, (0, exports.mappedCapability)(newCap));
418
+ this.mergeState(current, this.mappedCapability(newCap));
408
419
  });
409
420
  this.checkCanStart();
410
421
  }
@@ -420,9 +431,12 @@ class DevicePairingService extends service_2.IncyclistService {
420
431
  const current = getInterfaceSettings(ifName, prev);
421
432
  const changed = (current.state !== ifDetails.state || current.isScanning !== ifDetails.isScanning || current.enabled !== ifDetails.enabled);
422
433
  if (!changed) {
434
+ console.log('~~~ DEUBUG: if change, no change', ifName, ifDetails);
423
435
  return;
424
436
  }
437
+ this.logEvent({ message: 'interface state changed', interface: ifName, state: ifDetails.state });
425
438
  try {
439
+ let restartScan = false;
426
440
  if (interfacesNew) {
427
441
  const getData = (i) => ({ name: i.name, enabled: i.enabled, state: i.state });
428
442
  if (!prev)
@@ -443,10 +457,15 @@ class DevicePairingService extends service_2.IncyclistService {
443
457
  else if (ifDetails.state !== 'unavailable' && current.state === 'unavailable') {
444
458
  this.enableAdaptersOnInterface(ifName);
445
459
  }
460
+ else if (ifDetails.state === 'connected' && current.state !== 'connected' && !this.isPairing()) {
461
+ restartScan = true;
462
+ }
446
463
  if (changedIdx !== -1) {
447
464
  prev[changedIdx].isScanning = ifDetails.isScanning;
448
465
  prev[changedIdx].state = ifDetails.state;
449
466
  }
467
+ if (restartScan)
468
+ this.restart();
450
469
  this.emitStateChange({ interfaces: this.state.interfaces });
451
470
  }
452
471
  }
@@ -467,7 +486,7 @@ class DevicePairingService extends service_2.IncyclistService {
467
486
  ci.forEach(c => {
468
487
  var _a;
469
488
  const { devices = [], disabled } = c;
470
- const deviceNames = devices.map(d => d.name).join(';');
489
+ const deviceNames = devices.filter(d => !this.isOnDeletedList(c.capability, d.udid)).map(d => d.name).join(';');
471
490
  const selected = (_a = devices.find(d => d.selected)) === null || _a === void 0 ? void 0 : _a.name;
472
491
  this.logEvent({ message: 'capability info', capability: c.capability, devices: deviceNames, selected, disabled });
473
492
  });
@@ -577,6 +596,8 @@ class DevicePairingService extends service_2.IncyclistService {
577
596
  return;
578
597
  capabilities.forEach(c => {
579
598
  var _a;
599
+ if (this.isOnDeletedList(c, udid))
600
+ return;
580
601
  const unitInfo = Units.find(ui => ui.capability === c.capability);
581
602
  const device = this.getCapabilityDevice(c, udid);
582
603
  if (unitInfo) {
@@ -619,6 +640,8 @@ class DevicePairingService extends service_2.IncyclistService {
619
640
  markConnected(adapter, udid) {
620
641
  const capabilites = adapter.getCapabilities();
621
642
  capabilites.forEach(c => {
643
+ if (this.isOnDeletedList(c, udid))
644
+ return;
622
645
  const info = this.getCapability(c);
623
646
  if (!info) {
624
647
  this.logEvent({ message: 'warning: capabability not found', c, caps: this.state.capabilities });
@@ -710,7 +733,7 @@ class DevicePairingService extends service_2.IncyclistService {
710
733
  run(props = {}) {
711
734
  return __awaiter(this, void 0, void 0, function* () {
712
735
  this.emit('run');
713
- if (this.isPairing() || this.isScanning()) {
736
+ if (this.isPairing() || this.isScanning() || !this.state.waiting) {
714
737
  yield this._stop();
715
738
  }
716
739
  if (this.state.stopRequested || this.state.stopped) {
@@ -743,14 +766,19 @@ class DevicePairingService extends service_2.IncyclistService {
743
766
  startPairing(adapters, props) {
744
767
  return __awaiter(this, void 0, void 0, function* () {
745
768
  this.emit('pairing-start');
746
- const isReady = !this.state.interfaces.find(i => i.enabled && i.state === 'connecting');
769
+ const requiredInterfaces = this.getPairingInterfaces();
770
+ const busyRequired = this.state.interfaces
771
+ .filter(i => requiredInterfaces.includes(i.name))
772
+ .find(i => i.enabled && i.state !== 'connected' && i.state !== 'unavailable');
773
+ const isReady = busyRequired === undefined;
747
774
  if (!isReady) {
748
775
  setTimeout(() => {
749
- this.run();
776
+ if (!this.isPairing() && !this.isScanning())
777
+ this.run();
750
778
  }, 1000);
751
779
  return;
752
780
  }
753
- this.logEvent({ message: 'Start Pairing', adapters, props });
781
+ this.state.tsPrevStart = Date.now();
754
782
  this.processConnectedDevices(adapters);
755
783
  const selected = this.state.capabilities.map(c => c.selected);
756
784
  const target = adapters.filter(ai => !ai.adapter.isStarted() && selected.includes(ai.udid));
@@ -759,12 +787,14 @@ class DevicePairingService extends service_2.IncyclistService {
759
787
  const promise = this.rideService.startAdapters(selectedAdapters, 'pair');
760
788
  this.state.check = { promise };
761
789
  this.onPairingStarted();
790
+ this.logEvent({ message: 'Start Pairing', adapters, props });
762
791
  yield this.state.check.promise;
763
792
  if (this.state.check)
764
793
  delete this.state.check;
765
794
  this.emit('pairing-done');
766
795
  if (!this.checkPairingSuccess()) {
767
796
  this.logEvent({ message: 'Pairing done', adapters, props });
797
+ yield this.rideService.stop();
768
798
  yield (0, utils_1.sleep)(this.getPairingRetryDelay());
769
799
  if (!this.state.scan)
770
800
  this.run();
@@ -787,25 +817,24 @@ class DevicePairingService extends service_2.IncyclistService {
787
817
  }
788
818
  startScanning(adapters, props) {
789
819
  return __awaiter(this, void 0, void 0, function* () {
790
- const interfaces = this.state.interfaces.filter(i => this.isInterfaceEnabled(i)) || [].map(i => i.name);
820
+ const interfaces = this.state.interfaces.filter(i => this.isInterfaceEnabled(i) && i.state === 'connected')
821
+ .map(i => i.name);
791
822
  if (interfaces.length === 0) {
792
- setTimeout(() => {
793
- this.run();
823
+ if (this.state.scanTo)
824
+ return;
825
+ this.state.scanTo = setTimeout(() => {
826
+ delete this.state.scanTo;
827
+ if (!this.isPairing() && !this.isScanning())
828
+ this.run();
794
829
  }, 1000);
795
830
  return;
796
831
  }
797
832
  this.emit('scanning-start');
798
- const isReady = !this.state.interfaces.find(i => i.enabled && i.state === 'connecting');
799
- if (!isReady) {
800
- setTimeout(() => {
801
- this.run();
802
- }, 1000);
803
- return;
804
- }
805
- this.logEvent({ message: 'Start Scanning', props });
833
+ this.state.tsPrevStart = Date.now();
834
+ this.logEvent({ message: 'Start Scanning', interfaces: interfaces.join(','), props });
806
835
  this.initScanningCallbacks();
807
836
  const timeout = props.enforcedScan ? 1000 * 60 * 60 : undefined;
808
- const promise = this.access.scan({ excludeDisabled: true }, { includeKnown: props.enforcedScan, timeout });
837
+ const promise = this.access.scan({ interfaces, excludeDisabled: true }, { includeKnown: props.enforcedScan, timeout });
809
838
  this.state.scan = { promise, adapters: [] };
810
839
  this.onPairingStarted();
811
840
  try {
@@ -919,7 +948,9 @@ class DevicePairingService extends service_2.IncyclistService {
919
948
  const impactedCapabilties = this.getCapabilitiesUsingInterface(name);
920
949
  const enabledInterfaces = this.getEnabedInterfaces().filter(i => i.name !== name).map(i => i.name);
921
950
  impactedCapabilties.forEach(c => {
922
- const available = c.devices.filter(d => d.interface !== name && enabledInterfaces.includes(d.interface));
951
+ const available = c.devices
952
+ .filter(d => d.interface !== name && enabledInterfaces.includes(d.interface))
953
+ .filter(d => !this.isOnDeletedList(c, d.udid));
923
954
  if (!(available === null || available === void 0 ? void 0 : available.length)) {
924
955
  this.configuration.unselect(c.capability, true);
925
956
  }
@@ -932,7 +963,9 @@ class DevicePairingService extends service_2.IncyclistService {
932
963
  const impactedCapabilties = this.state.capabilities.filter(c => !c.selected);
933
964
  const enabledInterfaces = this.getEnabedInterfaces().filter(i => i.name !== name).map(i => i.name);
934
965
  impactedCapabilties.forEach(c => {
935
- const available = c.devices.filter(d => d.interface === name || enabledInterfaces.includes(d.interface));
966
+ const available = c.devices
967
+ .filter(d => d.interface === name || enabledInterfaces.includes(d.interface))
968
+ .filter(d => !this.isOnDeletedList(c, d.udid));
936
969
  if ((available === null || available === void 0 ? void 0 : available.length) > 0) {
937
970
  this.configuration.select(available[0].udid, c.capability, { emit: true });
938
971
  }
@@ -950,6 +983,15 @@ class DevicePairingService extends service_2.IncyclistService {
950
983
  getDisabledInterfaces() {
951
984
  return this.state.interfaces.filter(i => !i.enabled);
952
985
  }
986
+ getPairingInterfaces() {
987
+ const interfaces = this.state.capabilities.map(ci => ci.interface);
988
+ const selected = [];
989
+ interfaces.forEach(i => {
990
+ if (!selected.includes(i))
991
+ selected.push(i);
992
+ });
993
+ return selected;
994
+ }
953
995
  getDeviceAdapter(udid) {
954
996
  const { adapters = [] } = this.state;
955
997
  const target = adapters.find(ai => ai.udid === udid);
@@ -1029,6 +1071,7 @@ class DevicePairingService extends service_2.IncyclistService {
1029
1071
  c.connectState = undefined;
1030
1072
  }
1031
1073
  this.configuration.delete(udid, capability, shouldEmit);
1074
+ this.addToDeletedList(capability, udid);
1032
1075
  this.emitStateChange({ capabilities: this.state.capabilities });
1033
1076
  }
1034
1077
  isScanning() {
@@ -1056,6 +1099,44 @@ class DevicePairingService extends service_2.IncyclistService {
1056
1099
  numberOfSelectedCababilities(udid) {
1057
1100
  return (this.state.capabilities || []).map(c => c.selected === udid ? 1 : 0).reduce((a, c) => a + c, 0);
1058
1101
  }
1102
+ addToDeletedList(capability, udid) {
1103
+ if (this.isOnDeletedList(capability, udid))
1104
+ return;
1105
+ const c = this.getCapability(capability);
1106
+ this.state.deleted.push({ capability: c.capability, udid });
1107
+ }
1108
+ removeFromDeletedList(capability, udid) {
1109
+ const c = this.getCapability(capability);
1110
+ const idx = this.state.deleted.findIndex(e => e.capability === c.capability && e.udid === udid);
1111
+ if (idx === -1)
1112
+ return;
1113
+ this.state.deleted.splice(idx, 1);
1114
+ }
1115
+ isOnDeletedList(c, udid) {
1116
+ const capability = this.getCapability(c);
1117
+ return this.state.deleted.find(e => e.capability === capability.capability && e.udid === udid) !== undefined;
1118
+ }
1119
+ mappedCapability(c) {
1120
+ var _a, _b, _c;
1121
+ const { devices } = c;
1122
+ const mapped = Object.assign({}, c);
1123
+ const available = devices.filter(d => !this.isOnDeletedList(c.capability, d.udid));
1124
+ mapped.deviceNames = available.map(d => d.name).join(';');
1125
+ mapped.selected = (_a = available.find(d => d.selected)) === null || _a === void 0 ? void 0 : _a.udid;
1126
+ mapped.deviceName = (_b = devices.find(d => d.selected)) === null || _b === void 0 ? void 0 : _b.name;
1127
+ mapped.interface = (_c = devices.find(d => d.selected)) === null || _c === void 0 ? void 0 : _c.interface;
1128
+ mapped.devices = devices;
1129
+ return mapped;
1130
+ }
1131
+ mappedCapabilities(capabilities) {
1132
+ const caps = [];
1133
+ const ci = capabilities ? Object.keys(capabilities) || [] : [];
1134
+ ci.forEach(name => {
1135
+ const c = capabilities[name];
1136
+ caps.push(this.mappedCapability(c));
1137
+ });
1138
+ return caps;
1139
+ }
1059
1140
  }
1060
1141
  exports.DevicePairingService = DevicePairingService;
1061
1142
  const useDevicePairing = () => DevicePairingService.getInstance();
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "incyclist-services",
3
- "version": "1.0.53",
3
+ "version": "1.0.55",
4
4
  "peerDependencies": {
5
- "gd-eventlog": "^0.1.24"
5
+ "gd-eventlog": "^0.1.26"
6
6
  },
7
7
  "devDependencies": {
8
8
  "@types/jest": "^29.5.4",
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "axios": "^1.6.1",
42
- "incyclist-devices": "^2.1.21",
42
+ "incyclist-devices": "^2.1.22",
43
43
  "uuid": "^9.0.0"
44
44
  }
45
45
  }