Switching setVariable to a query and fixing error hangling in query mechanism

This commit is contained in:
David Négrier 2021-07-05 18:29:34 +02:00
parent c30de8c6db
commit bf17ad4567
6 changed files with 49 additions and 43 deletions

View File

@ -50,7 +50,6 @@ export type IframeEventMap = {
getState: undefined; getState: undefined;
registerMenuCommand: MenuItemRegisterEvent; registerMenuCommand: MenuItemRegisterEvent;
setTiles: SetTilesEvent; setTiles: SetTilesEvent;
setVariable: SetVariableEvent;
}; };
export interface IframeEvent<T extends keyof IframeEventMap> { export interface IframeEvent<T extends keyof IframeEventMap> {
type: T; type: T;
@ -93,6 +92,10 @@ export type IframeQueryMap = {
query: undefined, query: undefined,
answer: MapDataEvent, answer: MapDataEvent,
}, },
setVariable: {
query: SetVariableEvent,
answer: void
}
} }
export interface IframeQuery<T extends keyof IframeQueryMap> { export interface IframeQuery<T extends keyof IframeQueryMap> {

View File

@ -105,9 +105,6 @@ class IframeListener {
private readonly _setTilesStream: Subject<SetTilesEvent> = new Subject(); private readonly _setTilesStream: Subject<SetTilesEvent> = new Subject();
public readonly setTilesStream = this._setTilesStream.asObservable(); public readonly setTilesStream = this._setTilesStream.asObservable();
private readonly _setVariableStream: Subject<SetVariableEvent> = new Subject();
public readonly setVariableStream = this._setVariableStream.asObservable();
private readonly iframes = new Set<HTMLIFrameElement>(); private readonly iframes = new Set<HTMLIFrameElement>();
private readonly iframeCloseCallbacks = new Map<HTMLIFrameElement, (() => void)[]>(); private readonly iframeCloseCallbacks = new Map<HTMLIFrameElement, (() => void)[]>();
private readonly scripts = new Map<string, HTMLIFrameElement>(); private readonly scripts = new Map<string, HTMLIFrameElement>();
@ -171,13 +168,7 @@ class IframeListener {
return; return;
} }
Promise.resolve(answerer(query.data)).then((value) => { const errorHandler = (reason: any) => {
iframe?.contentWindow?.postMessage({
id: queryId,
type: query.type,
data: value
}, '*');
}).catch(reason => {
console.error('An error occurred while responding to an iFrame query.', reason); console.error('An error occurred while responding to an iFrame query.', reason);
let reasonMsg: string; let reasonMsg: string;
if (reason instanceof Error) { if (reason instanceof Error) {
@ -191,8 +182,31 @@ class IframeListener {
type: query.type, type: query.type,
error: reasonMsg error: reasonMsg
} as IframeErrorAnswerEvent, '*'); } as IframeErrorAnswerEvent, '*');
}); };
try {
Promise.resolve(answerer(query.data)).then((value) => {
iframe?.contentWindow?.postMessage({
id: queryId,
type: query.type,
data: value
}, '*');
}).catch(errorHandler);
} catch (reason) {
errorHandler(reason);
}
if (isSetVariableIframeEvent(payload.query)) {
// Let's dispatch the message to the other iframes
for (iframe of this.iframes) {
if (iframe.contentWindow !== message.source) {
iframe.contentWindow?.postMessage({
'type': 'setVariable',
'data': payload.query.data
}, '*');
}
}
}
} else if (isIframeEventWrapper(payload)) { } else if (isIframeEventWrapper(payload)) {
if (payload.type === "showLayer" && isLayerEvent(payload.data)) { if (payload.type === "showLayer" && isLayerEvent(payload.data)) {
this._showLayerStream.next(payload.data); this._showLayerStream.next(payload.data);
@ -246,18 +260,6 @@ class IframeListener {
handleMenuItemRegistrationEvent(payload.data); handleMenuItemRegistrationEvent(payload.data);
} else if (payload.type == "setTiles" && isSetTilesEvent(payload.data)) { } else if (payload.type == "setTiles" && isSetTilesEvent(payload.data)) {
this._setTilesStream.next(payload.data); this._setTilesStream.next(payload.data);
} else if (isSetVariableIframeEvent(payload)) {
this._setVariableStream.next(payload.data);
// Let's dispatch the message to the other iframes
for (iframe of this.iframes) {
if (iframe.contentWindow !== message.source) {
iframe.contentWindow?.postMessage({
'type': 'setVariable',
'data': payload.data
}, '*');
}
}
} }
} }
}, },

View File

@ -119,9 +119,9 @@ export class WorkadventureRoomCommands extends IframeApiContribution<Workadventu
}); });
} }
saveVariable(key : string, value : unknown): void { saveVariable(key : string, value : unknown): Promise<void> {
variables.set(key, value); variables.set(key, value);
sendToWorkadventure({ return queryWorkadventure({
type: 'setVariable', type: 'setVariable',
data: { data: {
key, key,

View File

@ -14,7 +14,6 @@ interface Variable {
export class SharedVariablesManager { export class SharedVariablesManager {
private _variables = new Map<string, unknown>(); private _variables = new Map<string, unknown>();
private iframeListenerSubscription: Subscription;
private variableObjects: Map<string, Variable>; private variableObjects: Map<string, Variable>;
constructor(private roomConnection: RoomConnection, private gameMap: GameMap) { constructor(private roomConnection: RoomConnection, private gameMap: GameMap) {
@ -28,7 +27,7 @@ export class SharedVariablesManager {
} }
// When a variable is modified from an iFrame // When a variable is modified from an iFrame
this.iframeListenerSubscription = iframeListener.setVariableStream.subscribe((event) => { iframeListener.registerAnswerer('setVariable', (event) => {
const key = event.key; const key = event.key;
if (!this.variableObjects.has(key)) { if (!this.variableObjects.has(key)) {
@ -75,7 +74,7 @@ export class SharedVariablesManager {
} }
public close(): void { public close(): void {
this.iframeListenerSubscription.unsubscribe(); iframeListener.unregisterAnswerer('setVariable');
} }
get variables(): Map<string, unknown> { get variables(): Map<string, unknown> {

View File

@ -192,7 +192,18 @@ window.addEventListener(
console.debug(payload); console.debug(payload);
if (isIframeAnswerEvent(payload)) { if (isIframeErrorAnswerEvent(payload)) {
const queryId = payload.id;
const payloadError = payload.error;
const resolver = answerPromises.get(queryId);
if (resolver === undefined) {
throw new Error('In Iframe API, got an error answer for a question that we have no track of.');
}
resolver.reject(new Error(payloadError));
answerPromises.delete(queryId);
} else if (isIframeAnswerEvent(payload)) {
const queryId = payload.id; const queryId = payload.id;
const payloadData = payload.data; const payloadData = payload.data;
@ -202,17 +213,6 @@ window.addEventListener(
} }
resolver.resolve(payloadData); resolver.resolve(payloadData);
answerPromises.delete(queryId);
} else if (isIframeErrorAnswerEvent(payload)) {
const queryId = payload.id;
const payloadError = payload.error;
const resolver = answerPromises.get(queryId);
if (resolver === undefined) {
throw new Error('In Iframe API, got an error answer for a question that we have no track of.');
}
resolver.reject(payloadError);
answerPromises.delete(queryId); answerPromises.delete(queryId);
} else if (isIframeResponseEventWrapper(payload)) { } else if (isIframeResponseEventWrapper(payload)) {
const payloadData = payload.data; const payloadData = payload.data;

View File

@ -2,8 +2,10 @@ WA.onInit().then(() => {
console.log('Trying to read variable "doorOpened" whose default property is true. This should display "true".'); console.log('Trying to read variable "doorOpened" whose default property is true. This should display "true".');
console.log('doorOpened', WA.room.loadVariable('doorOpened')); console.log('doorOpened', WA.room.loadVariable('doorOpened'));
console.log('Trying to set variable "not_exists". This should display an error in the console.') console.log('Trying to set variable "not_exists". This should display an error in the console, followed by a log saying the error was caught.')
WA.room.saveVariable('not_exists', 'foo'); WA.room.saveVariable('not_exists', 'foo').catch((e) => {
console.log('Successfully caught error: ', e);
});
console.log('Trying to set variable "config". This should work.'); console.log('Trying to set variable "config". This should work.');
WA.room.saveVariable('config', {'foo': 'bar'}); WA.room.saveVariable('config', {'foo': 'bar'});