generated from My-Templates/TypeScript-Library
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbrowser-tab-ipc.ts
111 lines (97 loc) · 4.08 KB
/
browser-tab-ipc.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
import {AbstractTransport} from './abstract-transport';
import {ConnectionOptions} from './connection-options';
import {ConnectionState} from './connection-state';
import {DefaultStorageExpiredTime, DefaultStorageKeyPrefix, EventConnected, EventConnectionError, EventDisconnected, EventMessage} from './const';
import {transportFabric} from './transport-fabric';
import {TransportType} from './transport-type.enum';
export class BrowserTabIPC extends AbstractTransport {
public static defaultWorkerUri = '//lopatnov.github.io/browser-tab-ipc/dist/ipc-worker.js';
private options: ConnectionOptions = {};
private transport?: AbstractTransport;
constructor(options?: ConnectionOptions) {
super();
this.extendOptions(options);
}
get transportType(): TransportType | undefined {
return this.transport?.transportType;
}
private extendOptions(options?: ConnectionOptions) {
this.options = {...this.options, ...options};
this.options.transportTypes = this.initTransportTypes(options);
this.options.sharedWorkerUri = this.options.sharedWorkerUri || BrowserTabIPC.defaultWorkerUri;
this.options.storageKey = this.options.storageKey || DefaultStorageKeyPrefix;
this.options.storageExpiredTime = this.options.storageExpiredTime || DefaultStorageExpiredTime;
}
private initTransportTypes(options?: ConnectionOptions) {
if (!options?.transportTypes || (Array.isArray(options?.transportTypes) && !options!.transportTypes.length)) {
return [TransportType.broadcastChannel, TransportType.sharedWorker, TransportType.sessionStorage];
} else if (Array.isArray(options?.transportTypes) && options!.transportTypes.length) {
return options.transportTypes;
} else {
return [options.transportTypes as TransportType];
}
}
public connect(options?: ConnectionOptions): Promise<ConnectionState> {
this.extendOptions(options);
return this.connectTransport(this.options).then((state) => {
this.subscribeTransport();
return state;
});
}
private connectTransport(options: ConnectionOptions, index = 0): Promise<ConnectionState> {
if (!Array.isArray(options.transportTypes) || !options.transportTypes.length || index >= options.transportTypes.length || !options.transportTypes[index]) {
return this.failConnect();
}
this.transport = transportFabric(options.transportTypes[index]);
return this.transport.connect(options).catch((error) => {
++index;
if (Array.isArray(options.transportTypes) && index < options.transportTypes!.length) {
return this.connectTransport(options, index);
}
throw error;
});
}
private subscribeTransport() {
this.transport!.connected((state) => this.onConnected(state));
this.transport!.connectionError((state) => this.onConnectionError(state));
this.transport!.disconnected((state) => this.onDisconnected(state));
this.transport!.message((content) => this.onMessage(content));
}
private unsubscribeTransport() {
this.transport?.removeAllListeners(EventConnected);
this.transport?.removeAllListeners(EventConnectionError);
this.transport?.removeAllListeners(EventDisconnected);
this.transport?.removeAllListeners(EventMessage);
}
private failConnect() {
const reason: ConnectionState = {
type: null,
error: 'Network transport not found',
connected: false,
};
this.onConnectionError(reason);
return Promise.reject(reason);
}
public disconnect(): Promise<ConnectionState> {
try {
this.unsubscribeTransport();
return this.transport?.disconnect() ?? Promise.reject(new Error('Undefined connection'));
} catch (error) {
return Promise.reject(error);
} finally {
this.unsubscribeEvents();
}
}
private unsubscribeEvents() {
this.removeAllListeners(EventConnected);
this.removeAllListeners(EventConnectionError);
this.removeAllListeners(EventDisconnected);
this.removeAllListeners(EventMessage);
}
public postMessage(message: any): Promise<void> {
if (!this.transport) {
this.connect();
}
return this.transport!.postMessage(message);
}
}