@openfin/core 30.74.12 → 30.74.13
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.
- package/package.json +1 -1
- package/src/api/interappbus/channel/client.d.ts +2 -2
- package/src/api/interappbus/channel/index.d.ts +4 -4
- package/src/api/interappbus/channel/index.js +94 -57
- package/src/api/interappbus/channel/protocols/classic/strategy.js +5 -2
- package/src/transport/transport.d.ts +11 -3
- package/src/transport/transport.js +18 -4
package/package.json
CHANGED
|
@@ -4,9 +4,9 @@ import { Transport } from '../../../transport/transport';
|
|
|
4
4
|
import { AnyStrategy } from './protocols/strategy-types';
|
|
5
5
|
declare type ProviderIdentity = OpenFin.ProviderIdentity;
|
|
6
6
|
declare type DisconnectionListener = (providerIdentity: ProviderIdentity) => any;
|
|
7
|
-
|
|
7
|
+
export declare type RoutingInfo = ProviderIdentity & {
|
|
8
8
|
endpointId: string;
|
|
9
|
-
}
|
|
9
|
+
};
|
|
10
10
|
export default class ChannelClient extends ChannelBase {
|
|
11
11
|
#private;
|
|
12
12
|
private disconnectListener;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type * as OpenFin from '../../../OpenFin';
|
|
2
|
-
import
|
|
3
|
-
import { ChannelProvider } from './provider';
|
|
2
|
+
import { Message, Transport } from '../../../transport/transport';
|
|
4
3
|
import { EmitterBase } from '../../base';
|
|
5
|
-
import { Transport, Message } from '../../../transport/transport';
|
|
6
4
|
import { ChannelEvent } from '../../events/channel';
|
|
5
|
+
import ChannelClient from './client';
|
|
6
|
+
import { ChannelProvider } from './provider';
|
|
7
7
|
declare type ProviderIdentity = OpenFin.ProviderIdentity;
|
|
8
8
|
declare type Identity = OpenFin.Identity;
|
|
9
9
|
export interface ChannelMessage extends Message<any> {
|
|
@@ -15,10 +15,10 @@ export interface ChannelMessage extends Message<any> {
|
|
|
15
15
|
export declare class Channel extends EmitterBase<ChannelEvent> {
|
|
16
16
|
#private;
|
|
17
17
|
constructor(wire: Transport);
|
|
18
|
-
private channelExists;
|
|
19
18
|
getAllChannels(): Promise<ProviderIdentity[]>;
|
|
20
19
|
onChannelConnect(listener: (...args: any[]) => void): Promise<void>;
|
|
21
20
|
onChannelDisconnect(listener: (...args: any[]) => void): Promise<void>;
|
|
21
|
+
private safeConnect;
|
|
22
22
|
connect(channelName: string, options?: OpenFin.ChannelConnectOptions): Promise<ChannelClient>;
|
|
23
23
|
create(channelName: string, options?: OpenFin.ChannelCreateOptions): Promise<ChannelProvider>;
|
|
24
24
|
}
|
|
@@ -14,12 +14,25 @@ var _Channel_connectionManager, _Channel_internalEmitter, _Channel_readyToConnec
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.Channel = void 0;
|
|
16
16
|
/* eslint-disable no-console */
|
|
17
|
-
const client_1 = require("./client");
|
|
18
|
-
const provider_1 = require("./provider");
|
|
19
|
-
const base_1 = require("../../base");
|
|
20
|
-
const connection_manager_1 = require("./connection-manager");
|
|
21
17
|
const events_1 = require("events");
|
|
22
18
|
const lazy_1 = require("../../../util/lazy");
|
|
19
|
+
const base_1 = require("../../base");
|
|
20
|
+
const client_1 = require("./client");
|
|
21
|
+
const connection_manager_1 = require("./connection-manager");
|
|
22
|
+
const provider_1 = require("./provider");
|
|
23
|
+
function retryDelay(count) {
|
|
24
|
+
const interval = 500; // base delay
|
|
25
|
+
const steps = 10; // How many retries to do before incrementing the delay
|
|
26
|
+
const base = 2; // How much to multiply the previous delay by
|
|
27
|
+
const max = 30000; // max delay
|
|
28
|
+
const step = Math.floor(count / steps);
|
|
29
|
+
const delay = Math.min(max, interval * base ** step);
|
|
30
|
+
return new Promise((resolve) => {
|
|
31
|
+
setTimeout(() => {
|
|
32
|
+
resolve(false);
|
|
33
|
+
}, delay);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
23
36
|
class Channel extends base_1.EmitterBase {
|
|
24
37
|
constructor(wire) {
|
|
25
38
|
super(wire, 'channel');
|
|
@@ -38,10 +51,6 @@ class Channel extends base_1.EmitterBase {
|
|
|
38
51
|
}));
|
|
39
52
|
__classPrivateFieldSet(this, _Channel_connectionManager, new connection_manager_1.ConnectionManager(wire), "f");
|
|
40
53
|
}
|
|
41
|
-
async channelExists(channelName) {
|
|
42
|
-
const channels = await this.getAllChannels();
|
|
43
|
-
return channels.some((providerIdentity) => providerIdentity.channelName === channelName);
|
|
44
|
-
}
|
|
45
54
|
async getAllChannels() {
|
|
46
55
|
return this.wire.sendAction('get-all-channels').then(({ payload }) => payload.data);
|
|
47
56
|
}
|
|
@@ -51,6 +60,57 @@ class Channel extends base_1.EmitterBase {
|
|
|
51
60
|
async onChannelDisconnect(listener) {
|
|
52
61
|
await this.on('disconnected', listener);
|
|
53
62
|
}
|
|
63
|
+
async safeConnect(channelName, shouldWait, connectPayload) {
|
|
64
|
+
const retryInfo = { count: 0 };
|
|
65
|
+
/* eslint-disable no-await-in-loop, no-constant-condition */
|
|
66
|
+
do {
|
|
67
|
+
// setup a listener and a connected promise to await in case we connect before the channel is ready
|
|
68
|
+
let connectedListener = () => undefined;
|
|
69
|
+
const connectedPromise = new Promise((resolve) => {
|
|
70
|
+
connectedListener = (payload) => {
|
|
71
|
+
if (channelName === payload.channelName) {
|
|
72
|
+
resolve(true);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
__classPrivateFieldGet(this, _Channel_internalEmitter, "f").on('connected', connectedListener);
|
|
76
|
+
});
|
|
77
|
+
try {
|
|
78
|
+
if (retryInfo.count > 0) {
|
|
79
|
+
// Wait before retrying
|
|
80
|
+
// Delay returns false connectedPromise returns true so we can know if a retry is due to connected event
|
|
81
|
+
retryInfo.gotConnectedEvent = await Promise.race([retryDelay(retryInfo.count), connectedPromise]);
|
|
82
|
+
const result = await this.wire.sendAction('connect-to-channel', { ...connectPayload, retryInfo });
|
|
83
|
+
// log only if there was a retry
|
|
84
|
+
console.log(`Successfully connected to channelName: ${channelName}`);
|
|
85
|
+
return result.payload.data;
|
|
86
|
+
}
|
|
87
|
+
// Send retryInfo to the core for debug log inclusion
|
|
88
|
+
const sentMessagePromise = this.wire.sendAction('connect-to-channel', connectPayload);
|
|
89
|
+
// Save messageId from the first connection attempt
|
|
90
|
+
retryInfo.originalMessageId = sentMessagePromise.messageId;
|
|
91
|
+
const result = await sentMessagePromise;
|
|
92
|
+
return result.payload.data;
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (!error.message.includes('internal-nack')) {
|
|
96
|
+
// Not an internal nack, break the loop
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
if (shouldWait && retryInfo.count === 0) {
|
|
100
|
+
// start waiting on the next iteration, warn the user
|
|
101
|
+
console.warn(`No channel found for channelName: ${channelName}. Waiting for connection...`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
retryInfo.count += 1;
|
|
106
|
+
// in case of other errors, remove our listener
|
|
107
|
+
__classPrivateFieldGet(this, _Channel_internalEmitter, "f").removeListener('connected', connectedListener);
|
|
108
|
+
}
|
|
109
|
+
} while (shouldWait); // If we're waiting we retry the above loop
|
|
110
|
+
// Should wait was false, no channel was found.
|
|
111
|
+
throw new Error(`No channel found for channelName: ${channelName}.`);
|
|
112
|
+
/* eslint-enable no-await-in-loop, no-constant-condition */
|
|
113
|
+
}
|
|
54
114
|
async connect(channelName, options = {}) {
|
|
55
115
|
// Make sure we don't connect before listeners are set up
|
|
56
116
|
// This also errors if we're not in OpenFin, ensuring we don't run unnecessary code
|
|
@@ -59,58 +119,35 @@ class Channel extends base_1.EmitterBase {
|
|
|
59
119
|
throw new Error('Please provide a channelName string to connect to a channel.');
|
|
60
120
|
}
|
|
61
121
|
const opts = { wait: true, ...this.wire.environment.getDefaultChannelOptions().connect, ...options };
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
console.warn(`Channel not found for channelName: ${channelName}, waiting for channel connection.`);
|
|
67
|
-
await new Promise((resolve) => {
|
|
68
|
-
const connectedListener = (payload) => {
|
|
69
|
-
if (channelName === payload.channelName) {
|
|
70
|
-
__classPrivateFieldGet(this, _Channel_internalEmitter, "f").removeListener('connected', connectedListener);
|
|
71
|
-
resolve();
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
__classPrivateFieldGet(this, _Channel_internalEmitter, "f").on('connected', connectedListener);
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
try {
|
|
79
|
-
const { offer, rtc: rtcPacket } = await __classPrivateFieldGet(this, _Channel_connectionManager, "f").createClientOffer(opts);
|
|
80
|
-
const connectionUrl = (await this.fin.me.getInfo()).url;
|
|
81
|
-
const { payload: { data: routingInfo } } = await this.wire.sendAction('connect-to-channel', {
|
|
82
|
-
channelName,
|
|
83
|
-
...opts,
|
|
84
|
-
offer,
|
|
85
|
-
connectionUrl
|
|
86
|
-
});
|
|
87
|
-
const strategy = await __classPrivateFieldGet(this, _Channel_connectionManager, "f").createClientStrategy(rtcPacket, routingInfo);
|
|
88
|
-
const channel = new client_1.default(routingInfo, this.wire, strategy);
|
|
89
|
-
// It is the client's responsibility to handle endpoint disconnection to the provider.
|
|
90
|
-
// If the endpoint dies, the client will force a disconnection through the core.
|
|
91
|
-
// The provider does not care about endpoint disconnection.
|
|
92
|
-
strategy.onEndpointDisconnect(routingInfo.channelId, async () => {
|
|
93
|
-
try {
|
|
94
|
-
await channel.sendDisconnectAction();
|
|
95
|
-
}
|
|
96
|
-
catch (error) {
|
|
97
|
-
console.warn(`Something went wrong during disconnect for client with uuid: ${routingInfo.uuid} / name: ${routingInfo.name} / endpointId: ${routingInfo.endpointId}.`);
|
|
98
|
-
}
|
|
99
|
-
finally {
|
|
100
|
-
client_1.default.handleProviderDisconnect(routingInfo);
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
return channel;
|
|
122
|
+
const { offer, rtc: rtcPacket } = await __classPrivateFieldGet(this, _Channel_connectionManager, "f").createClientOffer(opts);
|
|
123
|
+
let connectionUrl;
|
|
124
|
+
if (this.fin.me.isFrame || this.fin.me.isView || this.fin.me.isWindow) {
|
|
125
|
+
connectionUrl = (await this.fin.me.getInfo()).url;
|
|
104
126
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
127
|
+
const connectPayload = {
|
|
128
|
+
channelName,
|
|
129
|
+
...opts,
|
|
130
|
+
offer,
|
|
131
|
+
connectionUrl
|
|
132
|
+
};
|
|
133
|
+
const routingInfo = await this.safeConnect(channelName, opts.wait, connectPayload);
|
|
134
|
+
const strategy = await __classPrivateFieldGet(this, _Channel_connectionManager, "f").createClientStrategy(rtcPacket, routingInfo);
|
|
135
|
+
const channel = new client_1.default(routingInfo, this.wire, strategy);
|
|
136
|
+
// It is the client's responsibility to handle endpoint disconnection to the provider.
|
|
137
|
+
// If the endpoint dies, the client will force a disconnection through the core.
|
|
138
|
+
// The provider does not care about endpoint disconnection.
|
|
139
|
+
strategy.onEndpointDisconnect(routingInfo.channelId, async () => {
|
|
140
|
+
try {
|
|
141
|
+
await channel.sendDisconnectAction();
|
|
109
142
|
}
|
|
110
|
-
|
|
111
|
-
|
|
143
|
+
catch (error) {
|
|
144
|
+
console.warn(`Something went wrong during disconnect for client with uuid: ${routingInfo.uuid} / name: ${routingInfo.name} / endpointId: ${routingInfo.endpointId}.`);
|
|
112
145
|
}
|
|
113
|
-
|
|
146
|
+
finally {
|
|
147
|
+
client_1.default.handleProviderDisconnect(routingInfo);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
return channel;
|
|
114
151
|
}
|
|
115
152
|
async create(channelName, options) {
|
|
116
153
|
if (!channelName) {
|
|
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
11
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
12
|
};
|
|
13
|
-
var _ClassicStrategy_wire, _ClassicStrategy_endpointIdentityMap;
|
|
13
|
+
var _ClassicStrategy_wire, _ClassicStrategy_endpointIdentityMap, _ClassicStrategy_pendingMessagesByEndpointId;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.ClassicInfo = exports.ClassicStrategy = void 0;
|
|
16
16
|
/*
|
|
@@ -26,6 +26,9 @@ class ClassicStrategy {
|
|
|
26
26
|
// Store full endpointIdentity by endpointId of all known endpoints for this strategy instance.
|
|
27
27
|
// (clients will only have 1: the provider, the provider will have all clients)
|
|
28
28
|
_ClassicStrategy_endpointIdentityMap.set(this, new Map());
|
|
29
|
+
// Store a set of cancellable promises to be able to reject them when client
|
|
30
|
+
// connection problems occur
|
|
31
|
+
_ClassicStrategy_pendingMessagesByEndpointId.set(this, new Map());
|
|
29
32
|
this.send = async (endpointId, action, payload) => {
|
|
30
33
|
const to = __classPrivateFieldGet(this, _ClassicStrategy_endpointIdentityMap, "f").get(endpointId);
|
|
31
34
|
if (!to) {
|
|
@@ -78,6 +81,6 @@ class ClassicStrategy {
|
|
|
78
81
|
}
|
|
79
82
|
}
|
|
80
83
|
exports.ClassicStrategy = ClassicStrategy;
|
|
81
|
-
_ClassicStrategy_wire = new WeakMap(), _ClassicStrategy_endpointIdentityMap = new WeakMap();
|
|
84
|
+
_ClassicStrategy_wire = new WeakMap(), _ClassicStrategy_endpointIdentityMap = new WeakMap(), _ClassicStrategy_pendingMessagesByEndpointId = new WeakMap();
|
|
82
85
|
// Arbitrarily starting at 5 to leave the door open to backfilling pre endpointId etc.
|
|
83
86
|
exports.ClassicInfo = { version: 5, minimumVersion: 0, type: 'classic' };
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
2
3
|
import { EventEmitter } from 'events';
|
|
3
4
|
import type * as OpenFin from '../OpenFin';
|
|
4
5
|
import { ExistingConnectConfig, InternalConnectConfig, RemoteConfig, Wire, WireConstructor } from './wire';
|
|
5
6
|
import { Environment } from '../environment/environment';
|
|
7
|
+
import { RuntimeErrorPayload } from './transport-errors';
|
|
6
8
|
import EventAggregator from '../api/events/eventAggregator';
|
|
7
9
|
import { EntityTypeHelpers } from '../api/me';
|
|
8
10
|
import { ProtocolMap } from '../shapes/protocol';
|
|
9
11
|
import { NamedEvent } from '../api/events/base';
|
|
10
12
|
import { ErrorPlainObject } from '../util/errors';
|
|
11
13
|
declare type EntityType = OpenFin.EntityType;
|
|
14
|
+
declare type SendActionResponse<T extends keyof ProtocolMap> = Message<{
|
|
15
|
+
data: ProtocolMap[T]['response'];
|
|
16
|
+
} & ProtocolMap[T]['specialResponse']>;
|
|
12
17
|
export declare type MessageHandler = (data: any) => boolean;
|
|
18
|
+
export declare type SentMessage<Value> = Promise<Value> & {
|
|
19
|
+
cancel: (reason?: any) => void;
|
|
20
|
+
messageId: ReturnType<Environment['getNextMessageId']>;
|
|
21
|
+
};
|
|
13
22
|
export declare class Transport<MeType extends EntityType = EntityType> extends EventEmitter {
|
|
14
23
|
#private;
|
|
15
24
|
protected wireListeners: Map<number, {
|
|
@@ -31,9 +40,8 @@ export declare class Transport<MeType extends EntityType = EntityType> extends E
|
|
|
31
40
|
private connectRemote;
|
|
32
41
|
connectByPort(config: ExistingConnectConfig): Promise<void>;
|
|
33
42
|
private authorize;
|
|
34
|
-
sendAction<T extends keyof ProtocolMap = string>(action: T, payload?: ProtocolMap[T]['request'], uncorrelated?: boolean):
|
|
35
|
-
|
|
36
|
-
} & ProtocolMap[T]['specialResponse']>>;
|
|
43
|
+
sendAction<T extends keyof ProtocolMap = string>(action: T, payload?: ProtocolMap[T]['request'], uncorrelated?: boolean): SentMessage<SendActionResponse<T>>;
|
|
44
|
+
protected nackHandler(payloadOrMessage: RuntimeErrorPayload | string, reject: Function, callSites?: NodeJS.CallSite[]): void;
|
|
37
45
|
ferryAction(origData: any): Promise<Message<any>>;
|
|
38
46
|
registerMessageHandler(handler: MessageHandler): void;
|
|
39
47
|
protected addWireListener(id: number, resolve: Function, reject: Function, uncorrelated: boolean): void;
|
|
@@ -101,17 +101,31 @@ class Transport extends events_1.EventEmitter {
|
|
|
101
101
|
sendAction(action, payload = {}, uncorrelated = false
|
|
102
102
|
// specialResponse type is only used for 'requestAuthorization'
|
|
103
103
|
) {
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
105
|
+
let cancel = () => { };
|
|
106
|
+
// We want the callsite from the caller of this function, not from here.
|
|
107
|
+
const messageId = this.environment.getNextMessageId();
|
|
108
|
+
const prom = new Promise((resolve, reject) => {
|
|
109
|
+
cancel = reject;
|
|
106
110
|
const msg = {
|
|
107
111
|
action,
|
|
108
112
|
payload,
|
|
109
|
-
messageId
|
|
113
|
+
messageId
|
|
110
114
|
};
|
|
111
115
|
const wire = __classPrivateFieldGet(this, _Transport_wire, "f");
|
|
112
|
-
this.addWireListener(
|
|
116
|
+
this.addWireListener(messageId, resolve, reject, uncorrelated);
|
|
113
117
|
return wire.send(msg).catch(reject);
|
|
114
118
|
});
|
|
119
|
+
return Object.assign(prom, { cancel, messageId });
|
|
120
|
+
}
|
|
121
|
+
nackHandler(payloadOrMessage, reject, callSites) {
|
|
122
|
+
if (typeof payloadOrMessage === 'string') {
|
|
123
|
+
// NOTE: this is for backwards compatibility to support plain string rejections
|
|
124
|
+
reject(payloadOrMessage);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
reject(new transport_errors_1.RuntimeError(payloadOrMessage));
|
|
128
|
+
}
|
|
115
129
|
}
|
|
116
130
|
ferryAction(origData) {
|
|
117
131
|
return new Promise((resolve, reject) => {
|