@openfin/core 31.74.6 → 31.74.8
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/OpenFin.d.ts +68 -16
- package/src/api/api-exposer/api-consumer.d.ts +28 -0
- package/src/api/api-exposer/api-consumer.js +28 -0
- package/src/api/api-exposer/api-exposer.d.ts +35 -0
- package/src/api/api-exposer/api-exposer.js +38 -0
- package/src/api/api-exposer/decorators.d.ts +10 -0
- package/src/api/api-exposer/decorators.js +18 -0
- package/src/api/api-exposer/index.d.ts +4 -0
- package/src/api/api-exposer/index.js +20 -0
- package/src/api/api-exposer/strategies/index.d.ts +1 -0
- package/src/api/api-exposer/strategies/index.js +17 -0
- package/src/api/api-exposer/strategies/openfin-channels/channels-consumer.d.ts +14 -0
- package/src/api/api-exposer/strategies/openfin-channels/channels-consumer.js +20 -0
- package/src/api/api-exposer/strategies/openfin-channels/channels-exposer.d.ts +20 -0
- package/src/api/api-exposer/strategies/openfin-channels/channels-exposer.js +23 -0
- package/src/api/api-exposer/strategies/openfin-channels/index.d.ts +2 -0
- package/src/api/api-exposer/strategies/openfin-channels/index.js +18 -0
- package/src/api/application/Factory.js +1 -2
- package/src/api/application/Instance.js +23 -5
- package/src/api/base.d.ts +1 -2
- package/src/api/events/base.d.ts +0 -3
- package/src/api/events/system.d.ts +2 -2
- package/src/api/events/view.d.ts +6 -3
- package/src/api/events/webcontents.d.ts +2 -0
- package/src/api/events/window.d.ts +21 -13
- package/src/api/interappbus/channel/index.js +1 -1
- package/src/api/interappbus/channel/protocols/classic/strategy.js +24 -6
- package/src/api/interappbus/index.js +1 -1
- package/src/api/interop/InteropBroker.js +6 -2
- package/src/api/interop/fdc3/PrivateChannelClient.d.ts +1 -0
- package/src/api/interop/fdc3/PrivateChannelClient.js +15 -7
- package/src/api/interop/fdc3/PrivateChannelProvider.d.ts +16 -2
- package/src/api/interop/fdc3/PrivateChannelProvider.js +80 -28
- package/src/api/interop/fdc3/fdc3-1.2.js +53 -5
- package/src/api/interop/fdc3/fdc3-2.0.d.ts +11 -10
- package/src/api/interop/fdc3/fdc3-2.0.js +18 -19
- package/src/api/interop/fdc3/shapes/fdc3v2.d.ts +1 -1
- package/src/api/interop/fdc3/utils.d.ts +17 -0
- package/src/api/interop/fdc3/utils.js +75 -21
- package/src/api/interop/utils.d.ts +0 -1
- package/src/api/interop/utils.js +1 -9
- package/src/api/platform/Factory.d.ts +2 -1
- package/src/api/platform/Factory.js +5 -9
- package/src/api/platform/Instance.d.ts +6 -5
- package/src/api/platform/Instance.js +1 -0
- package/src/api/platform/layout/Factory.js +16 -6
- package/src/api/platform/layout/Instance.d.ts +6 -0
- package/src/api/platform/layout/Instance.js +26 -1
- package/src/api/platform/layout/controllers/layout-content-cache.d.ts +9 -0
- package/src/api/platform/layout/controllers/layout-content-cache.js +54 -0
- package/src/api/platform/layout/controllers/layout-entities-controller.d.ts +117 -0
- package/src/api/platform/layout/controllers/layout-entities-controller.js +270 -0
- package/src/api/platform/layout/controllers/tab-drag-controller.d.ts +2 -1
- package/src/api/platform/layout/entities/layout-entities.d.ts +144 -0
- package/src/api/platform/layout/entities/layout-entities.js +216 -0
- package/src/api/platform/layout/entities/shapes.d.ts +6 -0
- package/src/api/platform/layout/entities/shapes.js +2 -0
- package/src/api/platform/layout/layout.constants.d.ts +1 -0
- package/src/api/platform/layout/layout.constants.js +4 -0
- package/src/api/platform/layout/shapes.d.ts +3 -0
- package/src/api/platform/layout/utils/layout-traversal.d.ts +4 -0
- package/src/api/platform/layout/utils/layout-traversal.js +65 -0
- package/src/api/platform/provider.d.ts +2 -1
- package/src/api/view/Instance.d.ts +13 -3
- package/src/api/view/Instance.js +41 -4
- package/src/api/webcontents/main.d.ts +1 -22
- package/src/mock.d.ts +1 -1
- package/src/mock.js +5 -2
- package/src/transport/transport.d.ts +7 -3
- package/src/transport/transport.js +10 -11
- package/src/transport/wire.d.ts +1 -0
- package/src/util/channel-api-relay.d.ts +13 -0
- package/src/util/channel-api-relay.js +47 -0
- package/src/util/lazy.d.ts +16 -0
- package/src/util/lazy.js +26 -0
- package/src/util/ref-counter.d.ts +1 -1
- package/src/util/ref-counter.js +3 -2
- package/src/util/reversible-map.d.ts +11 -0
- package/src/util/reversible-map.js +49 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type * as OpenFin from '../../OpenFin';
|
|
2
2
|
import { NamedEvent, PropagatedEvent } from './base';
|
|
3
|
-
import { PropagatedViewEvent } from './view';
|
|
3
|
+
import { BaseViewEvent, PropagatedViewEvent, AttachedEvent as ViewAttachedEvent } from './view';
|
|
4
4
|
import { NonPropagatedWebContentsEvent, WillPropagateWebContentsEvent } from './webcontents';
|
|
5
5
|
export type AlertRequestedEvent = NamedEvent & {
|
|
6
6
|
type: 'alert-requested';
|
|
@@ -84,11 +84,9 @@ export type WillMoveOrResizeEvent = NamedEvent & {
|
|
|
84
84
|
export type PerformanceReportEvent = Performance & NamedEvent & {
|
|
85
85
|
type: 'performance-report';
|
|
86
86
|
};
|
|
87
|
-
export type ViewDetachedEvent = NamedEvent & {
|
|
87
|
+
export type ViewDetachedEvent = NamedEvent & BaseViewEvent & {
|
|
88
88
|
type: 'view-detached';
|
|
89
89
|
previousTarget: OpenFin.Identity;
|
|
90
|
-
target: OpenFin.Identity;
|
|
91
|
-
viewIdentity: OpenFin.Identity;
|
|
92
90
|
};
|
|
93
91
|
export type InputEvent = {
|
|
94
92
|
inputType: 'keyUp' | 'keyDown';
|
|
@@ -101,6 +99,18 @@ export type InputEvent = {
|
|
|
101
99
|
repeat: boolean;
|
|
102
100
|
command?: string;
|
|
103
101
|
};
|
|
102
|
+
export type LayoutInitializedEvent = NamedEvent & {
|
|
103
|
+
type: 'layout-initialized';
|
|
104
|
+
ofViews: (OpenFin.Identity & {
|
|
105
|
+
entityType: 'view';
|
|
106
|
+
})[];
|
|
107
|
+
};
|
|
108
|
+
export type LayoutReadyEvent = NamedEvent & {
|
|
109
|
+
type: 'layout-ready';
|
|
110
|
+
views: (OpenFin.Identity & {
|
|
111
|
+
success: boolean;
|
|
112
|
+
})[];
|
|
113
|
+
};
|
|
104
114
|
/**
|
|
105
115
|
* A Window event that does not propagate to (republish on) parent topics.
|
|
106
116
|
*/
|
|
@@ -141,12 +151,6 @@ export type WindowHotkeyEvent = InputEvent & NamedEvent & {
|
|
|
141
151
|
export type WindowInitializedEvent = NamedEvent & {
|
|
142
152
|
type: 'initialized';
|
|
143
153
|
};
|
|
144
|
-
export type LayoutInitializedEvent = NamedEvent & {
|
|
145
|
-
type: 'layout-initialized';
|
|
146
|
-
};
|
|
147
|
-
export type LayoutReadyEvent = NamedEvent & {
|
|
148
|
-
type: 'layout-ready';
|
|
149
|
-
};
|
|
150
154
|
export type MaximizedEvent = NamedEvent & {
|
|
151
155
|
type: 'maximized';
|
|
152
156
|
};
|
|
@@ -180,13 +184,17 @@ export type WillMoveEvent = WillMoveOrResizeEvent & {
|
|
|
180
184
|
export type WillResizeEvent = WillMoveOrResizeEvent & {
|
|
181
185
|
type: 'will-resize';
|
|
182
186
|
};
|
|
187
|
+
/**
|
|
188
|
+
* A propagated view event that is re-propagated from window.
|
|
189
|
+
*/
|
|
190
|
+
export type PropagatedViewAttachedEvent = PropagatedEvent<'view', ViewAttachedEvent>;
|
|
183
191
|
/**
|
|
184
192
|
* A Window event that does propagate to (republish on) parent topics.
|
|
185
193
|
*/
|
|
186
|
-
export type WillPropagateWindowEvent = WillPropagateWebContentsEvent |
|
|
194
|
+
export type WillPropagateWindowEvent = WillPropagateWebContentsEvent | PropagatedViewAttachedEvent | ViewDetachedEvent | AuthRequestedEvent | BeginUserBoundsChangingEvent | BoundsChangedEvent | BoundsChangingEvent | WindowCloseRequestedEvent | WindowClosedEvent | WindowClosingEvent | DisabledMovementBoundsChangedEvent | DisabledMovementBoundsChangingEvent | EmbeddedEvent | EndUserBoundsChangingEvent | ExternalProcessExitedEvent | ExternalProcessStartedEvent | HiddenEvent | WindowHotkeyEvent | WindowInitializedEvent | LayoutInitializedEvent | LayoutReadyEvent | MaximizedEvent | MinimizedEvent | WindowOptionsChangedEvent | PerformanceReportEvent | PreloadScriptsStateChangedEvent | PreloadScriptsStateChangingEvent | ReloadedEvent | WindowRestoredEvent | WindowShowRequestedEvent | WindowShownEvent | UserMovementDisabledEvent | UserMovementEnabledEvent | WillMoveEvent | WillRedirectEvent | WillResizeEvent;
|
|
187
195
|
export type WindowEvent = {
|
|
188
196
|
topic: 'window';
|
|
189
|
-
} & (WillPropagateWindowEvent | NonPropagatedWindowEvent);
|
|
197
|
+
} & (WillPropagateWindowEvent | NonPropagatedWindowEvent | PropagatedViewEvent);
|
|
190
198
|
export type WindowEventType = WindowEvent['type'];
|
|
191
|
-
export type PropagatedWindowEvent = PropagatedEvent<'window', WillPropagateWindowEvent
|
|
199
|
+
export type PropagatedWindowEvent = PropagatedEvent<'window', Exclude<WillPropagateWindowEvent, WindowCloseRequestedEvent>>;
|
|
192
200
|
export type PropagatedWindowEventType = PropagatedWindowEvent['type'];
|
|
@@ -62,7 +62,7 @@ class Channel extends base_1.EmitterBase {
|
|
|
62
62
|
if (entityType === 'iframe') {
|
|
63
63
|
// @ts-expect-error
|
|
64
64
|
// TODO: type this correctly (frame types are broken)
|
|
65
|
-
|
|
65
|
+
connectionUrl = (await this.fin.me.getInfo()).url;
|
|
66
66
|
}
|
|
67
67
|
else if (entityType === 'window' || entityType === 'view') {
|
|
68
68
|
connectionUrl = (await this.fin.me.getInfo()).url;
|
|
@@ -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,7 +26,11 @@ 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) => {
|
|
33
|
+
var _a;
|
|
30
34
|
const to = __classPrivateFieldGet(this, _ClassicStrategy_endpointIdentityMap, "f").get(endpointId);
|
|
31
35
|
if (!to) {
|
|
32
36
|
throw new Error(`Could not locate routing info for endpoint ${endpointId}`);
|
|
@@ -38,20 +42,27 @@ class ClassicStrategy {
|
|
|
38
42
|
delete cleanId.endpointId;
|
|
39
43
|
}
|
|
40
44
|
delete cleanId.isLocalEndpointId;
|
|
41
|
-
|
|
45
|
+
// grab the promise before awaiting it to save in our pending messages map
|
|
46
|
+
const p = __classPrivateFieldGet(this, _ClassicStrategy_wire, "f")
|
|
42
47
|
.sendAction('send-channel-message', {
|
|
43
48
|
...cleanId,
|
|
44
49
|
providerIdentity: this.providerIdentity,
|
|
45
50
|
action,
|
|
46
51
|
payload
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
});
|
|
53
|
+
(_a = __classPrivateFieldGet(this, _ClassicStrategy_pendingMessagesByEndpointId, "f").get(endpointId)) === null || _a === void 0 ? void 0 : _a.add(p);
|
|
54
|
+
const raw = await p.catch((error) => {
|
|
55
|
+
throw new Error(error.message);
|
|
56
|
+
}).finally(() => {
|
|
57
|
+
var _a;
|
|
58
|
+
// clean up the pending promise
|
|
59
|
+
(_a = __classPrivateFieldGet(this, _ClassicStrategy_pendingMessagesByEndpointId, "f").get(endpointId)) === null || _a === void 0 ? void 0 : _a.delete(p);
|
|
50
60
|
});
|
|
51
61
|
return raw.payload.data.result;
|
|
52
62
|
};
|
|
53
63
|
this.close = async () => {
|
|
54
64
|
this.messageReceiver.removeEndpoint(this.providerIdentity.channelId, this.endpointId);
|
|
65
|
+
[...__classPrivateFieldGet(this, _ClassicStrategy_endpointIdentityMap, "f").keys()].forEach((id) => this.closeEndpoint(id));
|
|
55
66
|
__classPrivateFieldSet(this, _ClassicStrategy_endpointIdentityMap, new Map(), "f");
|
|
56
67
|
};
|
|
57
68
|
__classPrivateFieldSet(this, _ClassicStrategy_wire, wire, "f");
|
|
@@ -63,13 +74,20 @@ class ClassicStrategy {
|
|
|
63
74
|
this.messageReceiver.addEndpoint(listener, this.providerIdentity.channelId, this.endpointId);
|
|
64
75
|
}
|
|
65
76
|
async closeEndpoint(endpointId) {
|
|
77
|
+
const id = __classPrivateFieldGet(this, _ClassicStrategy_endpointIdentityMap, "f").get(endpointId);
|
|
66
78
|
__classPrivateFieldGet(this, _ClassicStrategy_endpointIdentityMap, "f").delete(endpointId);
|
|
79
|
+
const pendingSet = __classPrivateFieldGet(this, _ClassicStrategy_pendingMessagesByEndpointId, "f").get(endpointId);
|
|
80
|
+
pendingSet === null || pendingSet === void 0 ? void 0 : pendingSet.forEach((p) => {
|
|
81
|
+
const errorMsg = `Channel connection with identity uuid: ${id === null || id === void 0 ? void 0 : id.uuid} / name: ${id === null || id === void 0 ? void 0 : id.name} / endpointId: ${endpointId} no longer connected.`;
|
|
82
|
+
p.cancel(new Error(errorMsg));
|
|
83
|
+
});
|
|
67
84
|
}
|
|
68
85
|
isEndpointConnected(endpointId) {
|
|
69
86
|
return __classPrivateFieldGet(this, _ClassicStrategy_endpointIdentityMap, "f").has(endpointId);
|
|
70
87
|
}
|
|
71
88
|
addEndpoint(endpointId, payload) {
|
|
72
89
|
__classPrivateFieldGet(this, _ClassicStrategy_endpointIdentityMap, "f").set(endpointId, payload.endpointIdentity);
|
|
90
|
+
__classPrivateFieldGet(this, _ClassicStrategy_pendingMessagesByEndpointId, "f").set(endpointId, new Set());
|
|
73
91
|
}
|
|
74
92
|
isValidEndpointPayload(payload) {
|
|
75
93
|
var _a, _b;
|
|
@@ -78,6 +96,6 @@ class ClassicStrategy {
|
|
|
78
96
|
}
|
|
79
97
|
}
|
|
80
98
|
exports.ClassicStrategy = ClassicStrategy;
|
|
81
|
-
_ClassicStrategy_wire = new WeakMap(), _ClassicStrategy_endpointIdentityMap = new WeakMap();
|
|
99
|
+
_ClassicStrategy_wire = new WeakMap(), _ClassicStrategy_endpointIdentityMap = new WeakMap(), _ClassicStrategy_pendingMessagesByEndpointId = new WeakMap();
|
|
82
100
|
// Arbitrarily starting at 5 to leave the door open to backfilling pre endpointId etc.
|
|
83
101
|
exports.ClassicInfo = { version: 5, minimumVersion: 0, type: 'classic' };
|
|
@@ -17,7 +17,7 @@ class InterApplicationBus extends base_1.Base {
|
|
|
17
17
|
subscriberAdded: 'subscriber-added',
|
|
18
18
|
subscriberRemoved: 'subscriber-removed'
|
|
19
19
|
};
|
|
20
|
-
this.refCounter = new ref_counter_1.
|
|
20
|
+
this.refCounter = new ref_counter_1.RefCounter();
|
|
21
21
|
this.Channel = new index_1.Channel(wire);
|
|
22
22
|
this.emitter = new events_1.EventEmitter();
|
|
23
23
|
wire.registerMessageHandler(this.onmessage.bind(this));
|
|
@@ -5,6 +5,7 @@ const base_1 = require("../base");
|
|
|
5
5
|
const SessionContextGroupBroker_1 = require("./SessionContextGroupBroker");
|
|
6
6
|
const utils_1 = require("./utils");
|
|
7
7
|
const lodash_1 = require("lodash");
|
|
8
|
+
const PrivateChannelProvider_1 = require("./fdc3/PrivateChannelProvider");
|
|
8
9
|
let contextGroups = [
|
|
9
10
|
{
|
|
10
11
|
id: 'green',
|
|
@@ -1009,8 +1010,6 @@ class InteropBroker extends base_1.Base {
|
|
|
1009
1010
|
});
|
|
1010
1011
|
this.clientDisconnected(clientIdentity);
|
|
1011
1012
|
});
|
|
1012
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1013
|
-
// @ts-ignore
|
|
1014
1013
|
channel.beforeAction(async (action, payload, clientIdentity) => {
|
|
1015
1014
|
var _a, _b;
|
|
1016
1015
|
if (!(await this.isActionAuthorized(action, payload, clientIdentity))) {
|
|
@@ -1052,6 +1051,11 @@ class InteropBroker extends base_1.Base {
|
|
|
1052
1051
|
channel.register('fdc3v2GetInfo', async (payload, clientIdentity) => {
|
|
1053
1052
|
return this.fdc3HandleGetInfo.bind(this)(payload, clientIdentity);
|
|
1054
1053
|
});
|
|
1054
|
+
channel.register('createPrivateChannelProvider', async (payload) => {
|
|
1055
|
+
const { channelId } = payload;
|
|
1056
|
+
const channelProvider = await this.fin.InterApplicationBus.Channel.create(channelId);
|
|
1057
|
+
PrivateChannelProvider_1.PrivateChannelProvider.init(channelProvider, channelId);
|
|
1058
|
+
});
|
|
1055
1059
|
}
|
|
1056
1060
|
/**
|
|
1057
1061
|
* Can be used to completely prevent a connection. Return false to prevent connections. Allows all connections by default.
|
|
@@ -14,6 +14,7 @@ export declare class PrivateChannelClient {
|
|
|
14
14
|
onAddContextListener(handler: (contextType?: string) => void): Listener;
|
|
15
15
|
onDisconnect(handler: () => void): Listener;
|
|
16
16
|
onUnsubscribe(handler: (contextType?: string) => void): Listener;
|
|
17
|
+
cleanUpAllSubs(): Promise<void>;
|
|
17
18
|
disconnect(): Promise<void>;
|
|
18
19
|
}
|
|
19
20
|
export {};
|
|
@@ -69,14 +69,22 @@ class PrivateChannelClient {
|
|
|
69
69
|
this.client.dispatch(`onUnsubscribeHandlerAdded`, { handlerId });
|
|
70
70
|
return listener;
|
|
71
71
|
}
|
|
72
|
-
async
|
|
73
|
-
const listenerUnsubscribers = Array.from(this.listeners.
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
async cleanUpAllSubs() {
|
|
73
|
+
const listenerUnsubscribers = Array.from(this.listeners.keys());
|
|
74
|
+
listenerUnsubscribers.forEach((handlerId) => {
|
|
75
|
+
this.client.remove(handlerId);
|
|
76
|
+
this.listeners.delete(handlerId);
|
|
76
77
|
});
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
}
|
|
79
|
+
async disconnect() {
|
|
80
|
+
try {
|
|
81
|
+
await this.client.dispatch('clientDisconnecting');
|
|
82
|
+
await this.cleanUpAllSubs();
|
|
83
|
+
await this.client.disconnect();
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
throw new Error(error.message);
|
|
87
|
+
}
|
|
80
88
|
}
|
|
81
89
|
}
|
|
82
90
|
exports.PrivateChannelClient = PrivateChannelClient;
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type * as OpenFin from '../../../OpenFin';
|
|
2
|
-
|
|
2
|
+
type ChannelProvider = OpenFin.ChannelProvider;
|
|
3
3
|
type HandlerId = string;
|
|
4
|
+
type ContextType = string;
|
|
5
|
+
interface PrivateChannelClientState {
|
|
6
|
+
clientIdentity: OpenFin.ClientIdentity;
|
|
7
|
+
handlerIdsByContextTypes: Map<ContextType, HandlerId[]>;
|
|
8
|
+
globalHandler: HandlerId | undefined;
|
|
9
|
+
onAddContextListenerHandlerId: HandlerId | undefined;
|
|
10
|
+
onUnsubscribeHandlerId: HandlerId | undefined;
|
|
11
|
+
onDisconnectHandlerId: HandlerId | undefined;
|
|
12
|
+
}
|
|
4
13
|
export declare class PrivateChannelProvider {
|
|
5
14
|
id: string;
|
|
6
15
|
private provider;
|
|
@@ -35,7 +44,12 @@ export declare class PrivateChannelProvider {
|
|
|
35
44
|
onUnsubscribeHandlerAdded(payload: {
|
|
36
45
|
handlerId: HandlerId;
|
|
37
46
|
}, id: OpenFin.ClientIdentity): void;
|
|
38
|
-
|
|
47
|
+
removeClient(disconnectingClientIdentity: OpenFin.ClientIdentity): void;
|
|
48
|
+
fireOnDisconnectForOtherClients(disconnectingClientIdentity: OpenFin.ClientIdentity): Promise<void>;
|
|
49
|
+
unsubscribeAll(clientIdentity: OpenFin.ClientIdentity): Promise<void>;
|
|
50
|
+
handleClientDisconnecting(disconnectingClientIdentity: OpenFin.ClientIdentity): Promise<void>;
|
|
39
51
|
registerNewClient(clientIdentity: OpenFin.ClientIdentity): void;
|
|
52
|
+
getConnectedClients(): Promise<PrivateChannelClientState[]>;
|
|
53
|
+
static init(channelProvider: OpenFin.ChannelProvider, id: string): PrivateChannelProvider;
|
|
40
54
|
}
|
|
41
55
|
export {};
|
|
@@ -11,7 +11,15 @@ class PrivateChannelProvider {
|
|
|
11
11
|
this.contextByContextType = new Map();
|
|
12
12
|
this.lastContext = undefined;
|
|
13
13
|
this.provider.onConnection((clientIdentity) => this.registerNewClient(clientIdentity));
|
|
14
|
-
this.provider.onDisconnection((clientIdentity) =>
|
|
14
|
+
this.provider.onDisconnection(async (clientIdentity) => {
|
|
15
|
+
const { endpointId } = clientIdentity;
|
|
16
|
+
if (this.clients.has(endpointId)) {
|
|
17
|
+
await this.handleClientDisconnecting(clientIdentity);
|
|
18
|
+
}
|
|
19
|
+
if ((await this.provider.getAllClientInfo()).length === 0) {
|
|
20
|
+
this.provider.destroy();
|
|
21
|
+
}
|
|
22
|
+
});
|
|
15
23
|
}
|
|
16
24
|
getClientState(id) {
|
|
17
25
|
return this.clients.get(id.endpointId);
|
|
@@ -25,7 +33,9 @@ class PrivateChannelProvider {
|
|
|
25
33
|
this.provider.register('onAddContextHandlerAdded', this.onAddContextHandlerAdded.bind(this));
|
|
26
34
|
this.provider.register('onDisconnectHandlerAdded', this.onDisconnectHandlerAdded.bind(this));
|
|
27
35
|
this.provider.register('onUnsubscribeHandlerAdded', this.onUnsubscribeHandlerAdded.bind(this));
|
|
28
|
-
this.provider.register('clientDisconnecting',
|
|
36
|
+
this.provider.register('clientDisconnecting', (payload, clientIdentity) => {
|
|
37
|
+
this.handleClientDisconnecting(clientIdentity);
|
|
38
|
+
});
|
|
29
39
|
}
|
|
30
40
|
broadcast(payload, broadcasterClientIdentity) {
|
|
31
41
|
const { context } = payload;
|
|
@@ -74,16 +84,9 @@ class PrivateChannelProvider {
|
|
|
74
84
|
if (contextType) {
|
|
75
85
|
const currentHandlersList = senderClientState.handlerIdsByContextTypes.get(contextType) || [];
|
|
76
86
|
senderClientState.handlerIdsByContextTypes.set(contextType, [...currentHandlersList, handlerId]);
|
|
77
|
-
const currContext = this.contextByContextType.get(contextType);
|
|
78
|
-
if (currContext) {
|
|
79
|
-
this.provider.dispatch(senderClientIdentity, handlerId, currContext);
|
|
80
|
-
}
|
|
81
87
|
}
|
|
82
88
|
else {
|
|
83
89
|
senderClientState.globalHandler = handlerId;
|
|
84
|
-
if (this.lastContext) {
|
|
85
|
-
this.provider.dispatch(senderClientIdentity, handlerId, this.lastContext);
|
|
86
|
-
}
|
|
87
90
|
}
|
|
88
91
|
Array.from(this.clients.values()).forEach((currClientState) => {
|
|
89
92
|
if (currClientState.clientIdentity.endpointId !== senderClientIdentity.endpointId &&
|
|
@@ -110,17 +113,18 @@ class PrivateChannelProvider {
|
|
|
110
113
|
}
|
|
111
114
|
}
|
|
112
115
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
// getting only valid client connections here, it is possible we haven't removed a disconnected client from the map yet
|
|
117
|
+
// so we need to ensure we don't dispatch to any disconnected client
|
|
118
|
+
// TODO: Take a look at our client disconnection logic and see if we can handle client disconnection cleanly
|
|
119
|
+
const clientsToDispatchTo = await this.getConnectedClients();
|
|
120
|
+
const dispatchPromises = clientsToDispatchTo.map(async (otherClientState) => {
|
|
121
|
+
const { clientIdentity, clientIdentity: { endpointId }, onUnsubscribeHandlerId } = otherClientState;
|
|
122
|
+
if (endpointId !== removingClientIdentity.endpointId && onUnsubscribeHandlerId) {
|
|
123
|
+
await this.provider.dispatch(clientIdentity, onUnsubscribeHandlerId, contextType);
|
|
120
124
|
}
|
|
121
|
-
}
|
|
125
|
+
});
|
|
122
126
|
try {
|
|
123
|
-
await Promise.all(
|
|
127
|
+
await Promise.all(dispatchPromises);
|
|
124
128
|
}
|
|
125
129
|
catch (error) {
|
|
126
130
|
console.error(`Problem when attempting to dispatch to onUnsubscribeHandlers. Error: ${error} Removing Client: ${handlerId}. uuid: ${removingClientIdentity.uuid}. name: ${removingClientIdentity.name}. endpointId: ${removingClientIdentity.endpointId}`);
|
|
@@ -181,32 +185,68 @@ class PrivateChannelProvider {
|
|
|
181
185
|
}
|
|
182
186
|
clientState.onUnsubscribeHandlerId = handlerId;
|
|
183
187
|
}
|
|
184
|
-
|
|
188
|
+
removeClient(disconnectingClientIdentity) {
|
|
185
189
|
const disconnectingClientState = this.getClientState(disconnectingClientIdentity);
|
|
186
190
|
if (!disconnectingClientState) {
|
|
187
191
|
throw new Error(`Client with Identity: ${disconnectingClientIdentity.uuid} ${disconnectingClientIdentity.name}, tried to call disconnect, is not connected to this Private Channel`);
|
|
188
192
|
}
|
|
189
193
|
disconnectingClientState.handlerIdsByContextTypes.clear();
|
|
190
194
|
this.clients.delete(disconnectingClientIdentity.endpointId);
|
|
191
|
-
|
|
195
|
+
}
|
|
196
|
+
async fireOnDisconnectForOtherClients(disconnectingClientIdentity) {
|
|
192
197
|
// TODO: call onDisconnect Handler of the other client only.
|
|
193
198
|
// CURRENTLY, just calling the onDisconnect handler for all the other clients. Once we limit it to just one other client, we can eliminate all the iteration code.
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
199
|
+
const { endpointId } = disconnectingClientIdentity;
|
|
200
|
+
// getting only valid client connections here, it is possible we haven't removed a disconnected client from the map yet
|
|
201
|
+
// so we need to ensure we don't dispatch to any disconnected client
|
|
202
|
+
// TODO: Take a look at our client disconnection logic and see if we can handle client disconnection cleanly
|
|
203
|
+
const clientsToDispatchTo = await this.getConnectedClients();
|
|
204
|
+
const dispatchPromises = clientsToDispatchTo.map(async (otherClientState) => {
|
|
205
|
+
const { clientIdentity: { endpointId: otherClientEndpointId }, onDisconnectHandlerId } = otherClientState;
|
|
206
|
+
if (otherClientEndpointId !== endpointId && onDisconnectHandlerId) {
|
|
207
|
+
await this.provider.dispatch(otherClientState.clientIdentity, onDisconnectHandlerId);
|
|
200
208
|
}
|
|
201
|
-
}
|
|
209
|
+
});
|
|
202
210
|
try {
|
|
203
|
-
await Promise.all(
|
|
211
|
+
await Promise.all(dispatchPromises);
|
|
204
212
|
}
|
|
205
213
|
catch (error) {
|
|
206
214
|
console.error(`Problem when attempting to dispatch to onDisconnectHandlers. Error: ${error} Disconnecting Client: uuid: ${disconnectingClientIdentity.uuid}. name: ${disconnectingClientIdentity.name}. endpointId: ${disconnectingClientIdentity.endpointId}`);
|
|
207
215
|
throw new Error(error);
|
|
208
216
|
}
|
|
209
217
|
}
|
|
218
|
+
async unsubscribeAll(clientIdentity) {
|
|
219
|
+
const { endpointId } = clientIdentity;
|
|
220
|
+
const state = this.clients.get(endpointId);
|
|
221
|
+
if (state) {
|
|
222
|
+
const contextTypeHandlerIds = Array.from(state.handlerIdsByContextTypes.values()).flat();
|
|
223
|
+
const globalHandlerId = state.globalHandler;
|
|
224
|
+
if (contextTypeHandlerIds.length > 0) {
|
|
225
|
+
const unsubPromises = contextTypeHandlerIds.map(async (handlerId) => {
|
|
226
|
+
return this.contextHandlerRemoved({ handlerId }, clientIdentity);
|
|
227
|
+
});
|
|
228
|
+
try {
|
|
229
|
+
await Promise.all(unsubPromises);
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
console.error(error.message);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (globalHandlerId) {
|
|
236
|
+
try {
|
|
237
|
+
await this.contextHandlerRemoved({ handlerId: globalHandlerId }, clientIdentity);
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
console.error(error.message);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async handleClientDisconnecting(disconnectingClientIdentity) {
|
|
246
|
+
await this.unsubscribeAll(disconnectingClientIdentity);
|
|
247
|
+
this.removeClient(disconnectingClientIdentity);
|
|
248
|
+
await this.fireOnDisconnectForOtherClients(disconnectingClientIdentity);
|
|
249
|
+
}
|
|
210
250
|
registerNewClient(clientIdentity) {
|
|
211
251
|
if (!this.clients.has(clientIdentity.endpointId)) {
|
|
212
252
|
const clientSubscriptionState = {
|
|
@@ -220,5 +260,17 @@ class PrivateChannelProvider {
|
|
|
220
260
|
this.clients.set(clientIdentity.endpointId, clientSubscriptionState);
|
|
221
261
|
}
|
|
222
262
|
}
|
|
263
|
+
async getConnectedClients() {
|
|
264
|
+
const allClientInfo = await this.provider.getAllClientInfo();
|
|
265
|
+
return Array.from(this.clients.values()).filter((clientState) => {
|
|
266
|
+
const { uuid, name } = clientState.clientIdentity;
|
|
267
|
+
return allClientInfo.some((clientInfo) => {
|
|
268
|
+
return name === clientInfo.name && uuid === clientInfo.uuid;
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
static init(channelProvider, id) {
|
|
273
|
+
return new PrivateChannelProvider(channelProvider, id);
|
|
274
|
+
}
|
|
223
275
|
}
|
|
224
276
|
exports.PrivateChannelProvider = PrivateChannelProvider;
|
|
@@ -4,6 +4,7 @@ const base_1 = require("../../base");
|
|
|
4
4
|
const utils_1 = require("./utils");
|
|
5
5
|
const utils_2 = require("../utils");
|
|
6
6
|
const InteropClient_1 = require("../InteropClient");
|
|
7
|
+
const lodash_1 = require("lodash");
|
|
7
8
|
/**
|
|
8
9
|
* @typedef { object } Listener
|
|
9
10
|
* @summary Listener object returned by addContextListener and addIntentListener
|
|
@@ -169,11 +170,15 @@ class Fdc3Module extends base_1.Base {
|
|
|
169
170
|
}
|
|
170
171
|
catch (error) {
|
|
171
172
|
if (error.message === utils_2.BROKER_ERRORS.joinSessionContextGroupWithJoinContextGroup) {
|
|
172
|
-
|
|
173
|
+
console.error('The Channel you have tried to join is an App Channel. Custom Channels can only be defined by the Interop Broker through code or manifest configuration. Please use getOrCreateChannel.');
|
|
173
174
|
}
|
|
174
175
|
else {
|
|
175
|
-
|
|
176
|
+
console.error(error.message);
|
|
176
177
|
}
|
|
178
|
+
if (error.message.startsWith('Attempting to join a context group that does not exist')) {
|
|
179
|
+
throw new Error(utils_1.ChannelError.NoChannelFound);
|
|
180
|
+
}
|
|
181
|
+
throw new Error(utils_1.ChannelError.AccessDenied);
|
|
177
182
|
}
|
|
178
183
|
}
|
|
179
184
|
/**
|
|
@@ -317,8 +322,19 @@ class Fdc3Module extends base_1.Base {
|
|
|
317
322
|
this.wire.sendAction('fdc3-get-or-create-channel').catch((e) => {
|
|
318
323
|
// we do not want to expose this error, just continue if this analytics-only call fails
|
|
319
324
|
});
|
|
320
|
-
const
|
|
321
|
-
|
|
325
|
+
const systemChannels = await this.getSystemChannels();
|
|
326
|
+
const userChannel = systemChannels.find((channel) => channel.id === channelId);
|
|
327
|
+
if (userChannel) {
|
|
328
|
+
return { ...userChannel, type: 'system', ...(0, utils_1.getUnsupportedChannelApis)() };
|
|
329
|
+
}
|
|
330
|
+
try {
|
|
331
|
+
const sessionContextGroup = await this.fin.me.interop.joinSessionContextGroup(channelId);
|
|
332
|
+
return (0, utils_1.buildAppChannelObject)(sessionContextGroup);
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
console.error(error.message);
|
|
336
|
+
throw new Error(utils_1.ChannelError.CreationFailed);
|
|
337
|
+
}
|
|
322
338
|
}
|
|
323
339
|
/**
|
|
324
340
|
* Returns metadata relating to the FDC3 object and its provider, including the supported version of the FDC3 specification and the name of the provider of the implementation.
|
|
@@ -378,7 +394,39 @@ class Fdc3Module extends base_1.Base {
|
|
|
378
394
|
return {
|
|
379
395
|
...currentContextGroupInfo,
|
|
380
396
|
type: 'system',
|
|
381
|
-
addContextListener:
|
|
397
|
+
addContextListener: (contextType, handler) => {
|
|
398
|
+
let realHandler;
|
|
399
|
+
let realType;
|
|
400
|
+
if (typeof contextType === 'function') {
|
|
401
|
+
console.warn('addContextListener(handler) has been deprecated. Please use addContextListener(null, handler)');
|
|
402
|
+
realHandler = contextType;
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
realHandler = handler;
|
|
406
|
+
if (typeof contextType === 'string') {
|
|
407
|
+
realType = contextType;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
const listener = (async () => {
|
|
411
|
+
let first = true;
|
|
412
|
+
const currentContext = await this.fin.me.interop.getCurrentContext(realType);
|
|
413
|
+
const wrappedHandler = (context, contextMetadata) => {
|
|
414
|
+
if (first) {
|
|
415
|
+
first = false;
|
|
416
|
+
if ((0, lodash_1.isEqual)(currentContext, context)) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
// eslint-disable-next-line consistent-return
|
|
421
|
+
return realHandler(context, contextMetadata);
|
|
422
|
+
};
|
|
423
|
+
return this.fin.me.interop.addContextHandler(wrappedHandler, realType);
|
|
424
|
+
})();
|
|
425
|
+
return {
|
|
426
|
+
...listener,
|
|
427
|
+
unsubscribe: () => listener.then((l) => l.unsubscribe())
|
|
428
|
+
};
|
|
429
|
+
},
|
|
382
430
|
broadcast: this.broadcast.bind(this),
|
|
383
431
|
getCurrentContext: async (contextType) => {
|
|
384
432
|
const context = await this.fin.me.interop.getCurrentContext(contextType);
|
|
@@ -171,14 +171,14 @@ export default class Fdc3Module2 extends Base implements FDC3v2.DesktopAgent {
|
|
|
171
171
|
* Find all the available instances for a particular application.
|
|
172
172
|
* @param { AppIdentifier } app
|
|
173
173
|
* @returns { Promise<Array<AppIdentifier>> }
|
|
174
|
-
* @tutorial findInstances
|
|
174
|
+
* @tutorial fdc3v2.findInstances
|
|
175
175
|
*/
|
|
176
176
|
findInstances(app: FDC3v2.AppIdentifier): Promise<Array<FDC3v2.AppIdentifier>>;
|
|
177
177
|
/**
|
|
178
178
|
* Retrieves the AppMetadata for an AppIdentifier, which provides additional metadata (such as icons, a title and description) from the App Directory record for the application, that may be used for display purposes.
|
|
179
179
|
* @param { AppIdentifier } app
|
|
180
180
|
* @returns { Promise<AppMetadata(2)> }
|
|
181
|
-
* @tutorial getAppMetadata
|
|
181
|
+
* @tutorial fdc3v2.getAppMetadata
|
|
182
182
|
*/
|
|
183
183
|
getAppMetadata(app: FDC3v2.AppIdentifier): Promise<FDC3v2.AppMetadata>;
|
|
184
184
|
/**
|
|
@@ -210,7 +210,7 @@ export default class Fdc3Module2 extends Base implements FDC3v2.DesktopAgent {
|
|
|
210
210
|
* @param { Context } context
|
|
211
211
|
* @param { string } [resultType] The type of result returned for any intent specified during resolution.
|
|
212
212
|
* @returns { Promise<Array<AppIntent(2)>> }
|
|
213
|
-
* @tutorial findIntentsByContext
|
|
213
|
+
* @tutorial fdc3v2.findIntentsByContext
|
|
214
214
|
*/
|
|
215
215
|
findIntentsByContext(context: FDC3v2.Context, resultType?: string): Promise<Array<FDC3v2.AppIntent>>;
|
|
216
216
|
/**
|
|
@@ -219,7 +219,7 @@ export default class Fdc3Module2 extends Base implements FDC3v2.DesktopAgent {
|
|
|
219
219
|
* @param { Context } context Context associated with the Intent
|
|
220
220
|
* @param { AppIdentifier | TargetApp } [app]
|
|
221
221
|
* @returns { Promise<IntentResolution(2)> }
|
|
222
|
-
* @tutorial raiseIntent
|
|
222
|
+
* @tutorial fdc3v2.raiseIntent
|
|
223
223
|
*/
|
|
224
224
|
raiseIntent(intent: string, context: FDC3v2.Context, app?: FDC3v2.AppIdentifier | FDC3v1.TargetApp): Promise<FDC3v2.IntentResolution>;
|
|
225
225
|
/**
|
|
@@ -227,7 +227,7 @@ export default class Fdc3Module2 extends Base implements FDC3v2.DesktopAgent {
|
|
|
227
227
|
* @param { Context } context Context associated with the Intent
|
|
228
228
|
* @param { AppIdentifier | TargetApp } [app]
|
|
229
229
|
* @returns { Promise<IntentResolution(2)> }
|
|
230
|
-
* @tutorial raiseIntentForContext
|
|
230
|
+
* @tutorial fdc3v2.raiseIntentForContext
|
|
231
231
|
*/
|
|
232
232
|
raiseIntentForContext(context: FDC3v2.Context, app?: FDC3v2.AppIdentifier | FDC3v1.TargetApp): Promise<FDC3v2.IntentResolution>;
|
|
233
233
|
/**
|
|
@@ -244,17 +244,17 @@ export default class Fdc3Module2 extends Base implements FDC3v2.DesktopAgent {
|
|
|
244
244
|
* @returns { Promise<Channel> }
|
|
245
245
|
* @tutorial fdc3.getOrCreateChannel
|
|
246
246
|
*/
|
|
247
|
-
getOrCreateChannel(channelId: string): Promise<
|
|
247
|
+
getOrCreateChannel(channelId: string): Promise<FDC3v2.Channel>;
|
|
248
248
|
/**
|
|
249
249
|
* Returns a Channel with an auto-generated identity that is intended for private communication between applications. Primarily used to create channels that will be returned to other applications via an IntentResolution for a raised intent.
|
|
250
250
|
* @returns { Promise<PrivateChannel> }
|
|
251
|
-
* @tutorial createPrivateChannel
|
|
251
|
+
* @tutorial fdc3v2.createPrivateChannel
|
|
252
252
|
*/
|
|
253
253
|
createPrivateChannel(): Promise<FDC3v2.PrivateChannel>;
|
|
254
254
|
/**
|
|
255
255
|
* Retrieves a list of the User Channels available for the app to join.
|
|
256
256
|
* @returns { Promise<Channel[]>}
|
|
257
|
-
* @tutorial getUserChannels
|
|
257
|
+
* @tutorial fdc3v2.getUserChannels
|
|
258
258
|
*/
|
|
259
259
|
getUserChannels(): Promise<Array<FDC3v1.SystemChannel>>;
|
|
260
260
|
/**
|
|
@@ -268,7 +268,7 @@ export default class Fdc3Module2 extends Base implements FDC3v2.DesktopAgent {
|
|
|
268
268
|
* Join an app to a specified User channel.
|
|
269
269
|
* @param { string } channelId Channel name
|
|
270
270
|
* @returns { Promise<void> }
|
|
271
|
-
* @tutorial joinUserChannel
|
|
271
|
+
* @tutorial fdc3v2.joinUserChannel
|
|
272
272
|
*/
|
|
273
273
|
joinUserChannel(channelId: string): Promise<void>;
|
|
274
274
|
/**
|
|
@@ -282,6 +282,7 @@ export default class Fdc3Module2 extends Base implements FDC3v2.DesktopAgent {
|
|
|
282
282
|
/**
|
|
283
283
|
* Returns the Channel object for the current User channel membership
|
|
284
284
|
* @returns { Promise<FDC3.Channel | null> }
|
|
285
|
+
* @tutorial fdc3.getCurrentChannel
|
|
285
286
|
*/
|
|
286
287
|
getCurrentChannel(): Promise<FDC3v2.Channel | null>;
|
|
287
288
|
/**
|
|
@@ -294,7 +295,7 @@ export default class Fdc3Module2 extends Base implements FDC3v2.DesktopAgent {
|
|
|
294
295
|
* Retrieves information about the FDC3 implementation, including the supported version of the FDC3 specification, the name of the provider of the implementation, its own version number, details of whether optional API features are implemented and the metadata of the calling application according to the desktop agent.
|
|
295
296
|
* fdc3HandleGetInfo must be overridden in the InteropBroker so that the ImplementationMetadata will have the appMetadata info.
|
|
296
297
|
* @returns { Promise<ImplementationMetadata(2)> }
|
|
297
|
-
* @tutorial getInfo
|
|
298
|
+
* @tutorial fdc3v2.getInfo
|
|
298
299
|
*/
|
|
299
300
|
getInfo(): Promise<FDC3v2.ImplementationMetadata>;
|
|
300
301
|
}
|