Make WidgetAPI an EventEmitter + use for terminate + cleanups
Use EventEmitter for emitting events, rename terminate event code, plus misc cleanups from review. Signed-off-by: Pauli Virtanen <pav@iki.fi>
This commit is contained in:
parent
352ea29d17
commit
cf4137d4b2
3 changed files with 28 additions and 25 deletions
|
@ -89,8 +89,6 @@ export default class WidgetMessaging {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells the widget that it should terminate now.
|
* Tells the widget that it should terminate now.
|
||||||
* It is not necessarily called in all instances before the widget is removed,
|
|
||||||
* and the client may force termination with a timeout.
|
|
||||||
* @returns {Promise<*>} Resolves when widget has acknowledged the message.
|
* @returns {Promise<*>} Resolves when widget has acknowledged the message.
|
||||||
*/
|
*/
|
||||||
terminate() {
|
terminate() {
|
||||||
|
|
|
@ -346,7 +346,7 @@ export default class AppTile extends React.Component {
|
||||||
_endWidgetActions() {
|
_endWidgetActions() {
|
||||||
let promise;
|
let promise;
|
||||||
|
|
||||||
if (this._hasCapability('m.receive_terminate')) {
|
if (this._hasCapability('im.vector.receive_terminate')) {
|
||||||
// Wait for widget to terminate within a timeout
|
// Wait for widget to terminate within a timeout
|
||||||
const timeout = 2000;
|
const timeout = 2000;
|
||||||
const messaging = ActiveWidgetStore.getWidgetMessaging(this.props.app.id);
|
const messaging = ActiveWidgetStore.getWidgetMessaging(this.props.app.id);
|
||||||
|
@ -396,20 +396,20 @@ export default class AppTile extends React.Component {
|
||||||
this.setState({deleting: true});
|
this.setState({deleting: true});
|
||||||
|
|
||||||
this._endWidgetActions().then(() => {
|
this._endWidgetActions().then(() => {
|
||||||
WidgetUtils.setRoomWidget(
|
return WidgetUtils.setRoomWidget(
|
||||||
this.props.room.roomId,
|
this.props.room.roomId,
|
||||||
this.props.app.id,
|
this.props.app.id,
|
||||||
).catch((e) => {
|
);
|
||||||
console.error('Failed to delete widget', e);
|
}).catch((e) => {
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
console.error('Failed to delete widget', e);
|
||||||
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
|
|
||||||
Modal.createTrackedDialog('Failed to remove widget', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to remove widget', '', ErrorDialog, {
|
||||||
title: _t('Failed to remove widget'),
|
title: _t('Failed to remove widget'),
|
||||||
description: _t('An error ocurred whilst trying to remove the widget from the room'),
|
description: _t('An error ocurred whilst trying to remove the widget from the room'),
|
||||||
});
|
|
||||||
}).finally(() => {
|
|
||||||
this.setState({deleting: false});
|
|
||||||
});
|
});
|
||||||
|
}).finally(() => {
|
||||||
|
this.setState({deleting: false});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,12 +18,13 @@ limitations under the License.
|
||||||
// https://github.com/turt2live/matrix-dimension/blob/4f92d560266635e5a3c824606215b84e8c0b19f5/web/app/shared/services/scalar/scalar-widget.api.ts
|
// https://github.com/turt2live/matrix-dimension/blob/4f92d560266635e5a3c824606215b84e8c0b19f5/web/app/shared/services/scalar/scalar-widget.api.ts
|
||||||
|
|
||||||
import { randomString } from "matrix-js-sdk/src/randomstring";
|
import { randomString } from "matrix-js-sdk/src/randomstring";
|
||||||
|
import { EventEmitter } from "events";
|
||||||
|
|
||||||
export enum Capability {
|
export enum Capability {
|
||||||
Screenshot = "m.capability.screenshot",
|
Screenshot = "m.capability.screenshot",
|
||||||
Sticker = "m.sticker",
|
Sticker = "m.sticker",
|
||||||
AlwaysOnScreen = "m.always_on_screen",
|
AlwaysOnScreen = "m.always_on_screen",
|
||||||
ReceiveTerminate = "m.receive_terminate",
|
ReceiveTerminate = "im.vector.receive_terminate",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum KnownWidgetActions {
|
export enum KnownWidgetActions {
|
||||||
|
@ -64,14 +65,17 @@ export interface FromWidgetRequest extends WidgetRequest {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles Riot <--> Widget interactions for embedded/standalone widgets.
|
* Handles Riot <--> Widget interactions for embedded/standalone widgets.
|
||||||
|
*
|
||||||
|
* Emitted events:
|
||||||
|
* - terminate(wait): client requested the widget to terminate.
|
||||||
|
* Call the argument 'wait(promise)' to postpone the finalization until
|
||||||
|
* the given promise resolves.
|
||||||
*/
|
*/
|
||||||
export class WidgetApi {
|
export class WidgetApi extends EventEmitter {
|
||||||
private origin: string;
|
private origin: string;
|
||||||
private inFlightRequests: { [requestId: string]: (reply: FromWidgetRequest) => void } = {};
|
private inFlightRequests: { [requestId: string]: (reply: FromWidgetRequest) => void } = {};
|
||||||
private readyPromise: Promise<any>;
|
private readyPromise: Promise<any>;
|
||||||
private readyPromiseResolve: () => void;
|
private readyPromiseResolve: () => void;
|
||||||
private terminatePromise: Promise<any>;
|
|
||||||
private terminatePromiseResolve: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set this to true if your widget is expecting a ready message from the client. False otherwise (default).
|
* Set this to true if your widget is expecting a ready message from the client. False otherwise (default).
|
||||||
|
@ -79,10 +83,11 @@ export class WidgetApi {
|
||||||
public expectingExplicitReady = false;
|
public expectingExplicitReady = false;
|
||||||
|
|
||||||
constructor(currentUrl: string, private widgetId: string, private requestedCapabilities: string[]) {
|
constructor(currentUrl: string, private widgetId: string, private requestedCapabilities: string[]) {
|
||||||
|
super();
|
||||||
|
|
||||||
this.origin = new URL(currentUrl).origin;
|
this.origin = new URL(currentUrl).origin;
|
||||||
|
|
||||||
this.readyPromise = new Promise<any>(resolve => this.readyPromiseResolve = resolve);
|
this.readyPromise = new Promise<any>(resolve => this.readyPromiseResolve = resolve);
|
||||||
this.terminatePromise = new Promise<any>(resolve => this.terminatePromiseResolve = resolve);
|
|
||||||
|
|
||||||
window.addEventListener("message", event => {
|
window.addEventListener("message", event => {
|
||||||
if (event.origin !== this.origin) return; // ignore: invalid origin
|
if (event.origin !== this.origin) return; // ignore: invalid origin
|
||||||
|
@ -104,11 +109,15 @@ export class WidgetApi {
|
||||||
// Automatically acknowledge so we can move on
|
// Automatically acknowledge so we can move on
|
||||||
this.replyToRequest(<ToWidgetRequest>payload, {});
|
this.replyToRequest(<ToWidgetRequest>payload, {});
|
||||||
} else if (payload.action === KnownWidgetActions.Terminate) {
|
} else if (payload.action === KnownWidgetActions.Terminate) {
|
||||||
// Reply after resolving
|
// Finalization needs to be async, so postpone with a promise
|
||||||
this.terminatePromise.then(() => {
|
let finalizePromise = Promise.resolve();
|
||||||
|
const wait = promise => {
|
||||||
|
finalizePromise = finalizePromise.then(value => promise);
|
||||||
|
}
|
||||||
|
this.emit('terminate', wait);
|
||||||
|
Promise.resolve(finalizePromise).then(() => {
|
||||||
this.replyToRequest(<ToWidgetRequest>payload, {});
|
this.replyToRequest(<ToWidgetRequest>payload, {});
|
||||||
});
|
});
|
||||||
this.terminatePromiseResolve();
|
|
||||||
} else {
|
} else {
|
||||||
console.warn(`[WidgetAPI] Got unexpected action: ${payload.action}`);
|
console.warn(`[WidgetAPI] Got unexpected action: ${payload.action}`);
|
||||||
}
|
}
|
||||||
|
@ -127,10 +136,6 @@ export class WidgetApi {
|
||||||
return this.readyPromise;
|
return this.readyPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addTerminateCallback(action) {
|
|
||||||
this.terminatePromise = this.terminatePromise.then(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private replyToRequest(payload: ToWidgetRequest, reply: any) {
|
private replyToRequest(payload: ToWidgetRequest, reply: any) {
|
||||||
if (!window.parent) return;
|
if (!window.parent) return;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue