This repository has been archived by the owner on Jul 15, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 171
/
Copy pathindex.ts
113 lines (106 loc) · 3.29 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import { EMPTY, merge } from "rxjs";
import type { Observable } from "rxjs";
import { catchError } from "rxjs/operators";
import Transport from "@ledgerhq/hw-transport";
type Discovery = Observable<{
type: "add" | "remove";
id: string;
name: string;
}>;
// NB open/close/disconnect semantic will have to be refined...
export type TransportModule = {
// unique transport name that identify the transport module
id: string;
// open a device by an id, this id must be unique across all modules
// you can typically prefix it with `something|` that identify it globally
// returns falsy if the transport module can't handle this id
// here, open means we want to START doing something with the transport
open: (id: string) => Promise<Transport> | null | undefined;
// here, close means we want to STOP doing something with the transport
close?: (
transport: Transport,
id: string
) => Promise<void> | null | undefined;
// disconnect/interrupt a device connection globally
// returns falsy if the transport module can't handle this id
disconnect: (id: string) => Promise<void> | null | undefined;
// here, setAllowAutoDisconnect determines whether an autodisconnect can
// happen at this time or not. Currently only used by TransportNodeHid
setAllowAutoDisconnect?: (
transport: Transport,
id: string,
allow: boolean
) => Promise<void> | null | undefined;
// optional observable that allows to discover a transport
discovery?: Discovery;
};
const modules: TransportModule[] = [];
export const registerTransportModule = (module: TransportModule) => {
modules.push(module);
};
export const discoverDevices = (
accept: (module: TransportModule) => boolean = () => true
): Discovery => {
const all: Discovery[] = [];
for (let i = 0; i < modules.length; i++) {
const m = modules[i];
if (m.discovery && accept(m)) {
all.push(m.discovery);
}
}
return merge(
...all.map((o) =>
o.pipe(
catchError((e) => {
console.warn(`One Transport provider failed: ${e}`);
return EMPTY;
})
)
)
);
};
export const open = (deviceId: string): Promise<Transport> => {
for (let i = 0; i < modules.length; i++) {
const m = modules[i];
const p = m.open(deviceId);
if (p) return p;
}
return Promise.reject(new Error(`Can't find handler to open ${deviceId}`));
};
export const close = (
transport: Transport,
deviceId: string
): Promise<void> => {
for (let i = 0; i < modules.length; i++) {
const m = modules[i];
const p = m.close && m.close(transport, deviceId);
if (p) return p;
}
// fallback on an actual close
return transport.close();
};
export const setAllowAutoDisconnect = (
transport: Transport,
deviceId: string,
allow: boolean
): Promise<void> | null | undefined => {
for (let i = 0; i < modules.length; i++) {
const m = modules[i];
const p =
m.setAllowAutoDisconnect &&
m.setAllowAutoDisconnect(transport, deviceId, allow);
if (p) return p;
}
};
export const disconnect = (deviceId: string): Promise<void> => {
for (let i = 0; i < modules.length; i++) {
const dis = modules[i].disconnect;
const p = dis(deviceId);
if (p) {
return p;
}
}
return Promise.reject(
new Error(`Can't find handler to disconnect ${deviceId}`)
);
};