Simplify & refactor some widget stuff

* ScalarMessaging onMessage was getting the current room ID by listening
  for view_and remembering the room id or alias, and so having to look up
  the alias if it was alias. We have RoomViewStore for this.
 * Move waitForUserWidget into WidgetUtils
 * s/require/import/
This commit is contained in:
David Baker 2018-06-13 10:39:52 +01:00
parent e858cf3bcb
commit 1cb794753e
2 changed files with 106 additions and 133 deletions

View file

@ -1,6 +1,7 @@
/* /*
Copyright 2016 OpenMarket Ltd Copyright 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd Copyright 2017 Vector Creations Ltd
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -231,11 +232,12 @@ Example:
} }
*/ */
const SdkConfig = require('./SdkConfig'); import SdkConfig from './SdkConfig';
const MatrixClientPeg = require("./MatrixClientPeg"); import MatrixClientPeg from './MatrixClientPeg';
const MatrixEvent = require("matrix-js-sdk").MatrixEvent; import { MatrixEvent } from 'matrix-js-sdk';
const dis = require("./dispatcher"); import dis from './dispatcher';
const Widgets = require('./utils/widgets'); import Widgets from './utils/widgets';
import RoomViewStore from './stores/RoomViewStore';
import { _t } from './languageHandler'; import { _t } from './languageHandler';
function sendResponse(event, res) { function sendResponse(event, res) {
@ -286,51 +288,6 @@ function inviteUser(event, roomId, userId) {
}); });
} }
/**
* Returns a promise that resolves when a widget with the given
* ID has been added as a user widget (ie. the accountData event
* arrives) or rejects after a timeout
*
* @param {string} widgetId The ID of the widget to wait for
* @param {boolean} add True to wait for the widget to be added,
* false to wait for it to be deleted.
* @returns {Promise} that resolves when the widget is available
*/
function waitForUserWidget(widgetId, add) {
return new Promise((resolve, reject) => {
const currentAccountDataEvent = MatrixClientPeg.get().getAccountData('m.widgets');
// Tests an account data event, returning true if it's in the state
// we're waiting for it to be in
function eventInIntendedState(ev) {
if (!ev || !currentAccountDataEvent.getContent()) return false;
if (add) {
return ev.getContent()[widgetId] !== undefined;
} else {
return ev.getContent()[widgetId] === undefined;
}
}
if (eventInIntendedState(currentAccountDataEvent)) {
resolve();
return;
}
function onAccountData(ev) {
if (eventInIntendedState(currentAccountDataEvent)) {
MatrixClientPeg.get().removeListener('accountData', onAccountData);
clearTimeout(timerId);
resolve();
}
}
const timerId = setTimeout(() => {
MatrixClientPeg.get().removeListener('accountData', onAccountData);
reject(new Error("Timed out waiting for widget ID " + widgetId + " to appear"));
}, 10000);
MatrixClientPeg.get().on('accountData', onAccountData);
});
}
function setWidget(event, roomId) { function setWidget(event, roomId) {
const widgetId = event.data.widget_id; const widgetId = event.data.widget_id;
const widgetType = event.data.type; const widgetType = event.data.type;
@ -637,19 +594,6 @@ function returnStateEvent(event, roomId, eventType, stateKey) {
sendResponse(event, stateEvent.getContent()); sendResponse(event, stateEvent.getContent());
} }
let currentRoomId = null;
let currentRoomAlias = null;
// Listen for when a room is viewed
dis.register(onAction);
function onAction(payload) {
if (payload.action !== "view_room") {
return;
}
currentRoomId = payload.room_id;
currentRoomAlias = payload.room_alias;
}
const onMessage = function(event) { const onMessage = function(event) {
if (!event.origin) { // stupid chrome if (!event.origin) { // stupid chrome
event.origin = event.originalEvent.origin; event.origin = event.originalEvent.origin;
@ -700,80 +644,63 @@ const onMessage = function(event) {
return; return;
} }
} }
let promise = Promise.resolve(currentRoomId);
if (!currentRoomId) { if (roomId !== RoomViewStore.getRoomId()) {
if (!currentRoomAlias) { sendError(event, _t('Room %(roomId)s not visible', {roomId: roomId}));
sendError(event, _t('Must be viewing a room')); return;
return;
}
// no room ID but there is an alias, look it up.
console.log("Looking up alias " + currentRoomAlias);
promise = MatrixClientPeg.get().getRoomIdForAlias(currentRoomAlias).then((res) => {
return res.room_id;
});
} }
promise.then((viewingRoomId) => { // Get and set room-based widgets
if (roomId !== viewingRoomId) { if (event.data.action === "get_widgets") {
sendError(event, _t('Room %(roomId)s not visible', {roomId: roomId})); getWidgets(event, roomId);
return; return;
} } else if (event.data.action === "set_widget") {
setWidget(event, roomId);
return;
}
// Get and set room-based widgets // These APIs don't require userId
if (event.data.action === "get_widgets") { if (event.data.action === "join_rules_state") {
getWidgets(event, roomId); getJoinRules(event, roomId);
return; return;
} else if (event.data.action === "set_widget") { } else if (event.data.action === "set_plumbing_state") {
setWidget(event, roomId); setPlumbingState(event, roomId, event.data.status);
return; return;
} } else if (event.data.action === "get_membership_count") {
getMembershipCount(event, roomId);
return;
} else if (event.data.action === "get_room_enc_state") {
getRoomEncState(event, roomId);
return;
} else if (event.data.action === "can_send_event") {
canSendEvent(event, roomId);
return;
}
// These APIs don't require userId if (!userId) {
if (event.data.action === "join_rules_state") { sendError(event, _t('Missing user_id in request'));
getJoinRules(event, roomId); return;
return; }
} else if (event.data.action === "set_plumbing_state") { switch (event.data.action) {
setPlumbingState(event, roomId, event.data.status); case "membership_state":
return; getMembershipState(event, roomId, userId);
} else if (event.data.action === "get_membership_count") { break;
getMembershipCount(event, roomId); case "invite":
return; inviteUser(event, roomId, userId);
} else if (event.data.action === "get_room_enc_state") { break;
getRoomEncState(event, roomId); case "bot_options":
return; botOptions(event, roomId, userId);
} else if (event.data.action === "can_send_event") { break;
canSendEvent(event, roomId); case "set_bot_options":
return; setBotOptions(event, roomId, userId);
} break;
case "set_bot_power":
if (!userId) { setBotPower(event, roomId, userId, event.data.level);
sendError(event, _t('Missing user_id in request')); break;
return; default:
} console.warn("Unhandled postMessage event with action '" + event.data.action +"'");
switch (event.data.action) { break;
case "membership_state": }
getMembershipState(event, roomId, userId);
break;
case "invite":
inviteUser(event, roomId, userId);
break;
case "bot_options":
botOptions(event, roomId, userId);
break;
case "set_bot_options":
setBotOptions(event, roomId, userId);
break;
case "set_bot_power":
setBotPower(event, roomId, userId, event.data.level);
break;
default:
console.warn("Unhandled postMessage event with action '" + event.data.action +"'");
break;
}
}, (err) => {
console.error(err);
sendError(event, _t('Failed to lookup current room') + '.');
});
}; };
let listenerCount = 0; let listenerCount = 0;

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2017 Vector Creations Ltd Copyright 2017 Vector Creations Ltd
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -90,4 +91,49 @@ export default class WidgetUtils {
} }
return false; return false;
} }
/**
* Returns a promise that resolves when a widget with the given
* ID has been added as a user widget (ie. the accountData event
* arrives) or rejects after a timeout
*
* @param {string} widgetId The ID of the widget to wait for
* @param {boolean} add True to wait for the widget to be added,
* false to wait for it to be deleted.
* @returns {Promise} that resolves when the widget is available
*/
static waitForUserWidget(widgetId, add) {
return new Promise((resolve, reject) => {
const currentAccountDataEvent = MatrixClientPeg.get().getAccountData('m.widgets');
// Tests an account data event, returning true if it's in the state
// we're waiting for it to be in
function eventInIntendedState(ev) {
if (!ev || !currentAccountDataEvent.getContent()) return false;
if (add) {
return ev.getContent()[widgetId] !== undefined;
} else {
return ev.getContent()[widgetId] === undefined;
}
}
if (eventInIntendedState(currentAccountDataEvent)) {
resolve();
return;
}
function onAccountData(ev) {
if (eventInIntendedState(currentAccountDataEvent)) {
MatrixClientPeg.get().removeListener('accountData', onAccountData);
clearTimeout(timerId);
resolve();
}
}
const timerId = setTimeout(() => {
MatrixClientPeg.get().removeListener('accountData', onAccountData);
reject(new Error("Timed out waiting for widget ID " + widgetId + " to appear"));
}, 10000);
MatrixClientPeg.get().on('accountData', onAccountData);
});
}
} }