From 550eac1e00d908d1737cd31b9dac1adffe851311 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Fri, 13 Apr 2018 01:29:24 +0100 Subject: [PATCH] switch to use getUpdateCheckStatusEnum via field rather than export --- src/VectorConferenceHandler.js | 138 ++++++++++++++++++ .../views/globals/UpdateCheckBar.js | 20 ++- 2 files changed, 150 insertions(+), 8 deletions(-) create mode 100644 src/VectorConferenceHandler.js diff --git a/src/VectorConferenceHandler.js b/src/VectorConferenceHandler.js new file mode 100644 index 00000000000..19081726b29 --- /dev/null +++ b/src/VectorConferenceHandler.js @@ -0,0 +1,138 @@ +/* +Copyright 2015, 2016 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +"use strict"; + +import Promise from 'bluebird'; +var Matrix = require("matrix-js-sdk"); +var Room = Matrix.Room; +var CallHandler = require('./CallHandler'); + +// FIXME: this is Riot (Vector) specific code, but will be removed shortly when +// we switch over to jitsi entirely for video conferencing. + +// FIXME: This currently forces Vector to try to hit the matrix.org AS for conferencing. +// This is bad because it prevents people running their own ASes from being used. +// This isn't permanent and will be customisable in the future: see the proposal +// at docs/conferencing.md for more info. +var USER_PREFIX = "fs_"; +var DOMAIN = "matrix.org"; + +function ConferenceCall(matrixClient, groupChatRoomId) { + this.client = matrixClient; + this.groupRoomId = groupChatRoomId; + this.confUserId = module.exports.getConferenceUserIdForRoom(this.groupRoomId); +} + +ConferenceCall.prototype.setup = function() { + var self = this; + return this._joinConferenceUser().then(function() { + return self._getConferenceUserRoom(); + }).then(function(room) { + // return a call for *this* room to be placed. We also tack on + // confUserId to speed up lookups (else we'd need to loop every room + // looking for a 1:1 room with this conf user ID!) + var call = Matrix.createNewMatrixCall(self.client, room.roomId); + call.confUserId = self.confUserId; + call.groupRoomId = self.groupRoomId; + return call; + }); +}; + +ConferenceCall.prototype._joinConferenceUser = function() { + // Make sure the conference user is in the group chat room + var groupRoom = this.client.getRoom(this.groupRoomId); + if (!groupRoom) { + return Promise.reject("Bad group room ID"); + } + var member = groupRoom.getMember(this.confUserId); + if (member && member.membership === "join") { + return Promise.resolve(); + } + return this.client.invite(this.groupRoomId, this.confUserId); +}; + +ConferenceCall.prototype._getConferenceUserRoom = function() { + // Use an existing 1:1 with the conference user; else make one + var rooms = this.client.getRooms(); + var confRoom = null; + for (var i = 0; i < rooms.length; i++) { + var confUser = rooms[i].getMember(this.confUserId); + if (confUser && confUser.membership === "join" && + rooms[i].getJoinedMembers().length === 2) { + confRoom = rooms[i]; + break; + } + } + if (confRoom) { + return Promise.resolve(confRoom); + } + return this.client.createRoom({ + preset: "private_chat", + invite: [this.confUserId] + }).then(function(res) { + return new Room(res.room_id); + }); +}; + +/** + * Check if this user ID is in fact a conference bot. + * @param {string} userId The user ID to check. + * @return {boolean} True if it is a conference bot. + */ +module.exports.isConferenceUser = function(userId) { + if (userId.indexOf("@" + USER_PREFIX) !== 0) { + return false; + } + var base64part = userId.split(":")[0].substring(1 + USER_PREFIX.length); + if (base64part) { + var decoded = new Buffer(base64part, "base64").toString(); + // ! $STUFF : $STUFF + return /^!.+:.+/.test(decoded); + } + return false; +}; + +module.exports.getConferenceUserIdForRoom = function(roomId) { + // abuse browserify's core node Buffer support (strip padding ='s) + var base64RoomId = new Buffer(roomId).toString("base64").replace(/=/g, ""); + return "@" + USER_PREFIX + base64RoomId + ":" + DOMAIN; +}; + +module.exports.createNewMatrixCall = function(client, roomId) { + var confCall = new ConferenceCall( + client, roomId + ); + return confCall.setup(); +}; + +module.exports.getConferenceCallForRoom = function(roomId) { + // search for a conference 1:1 call for this group chat room ID + var activeCall = CallHandler.getAnyActiveCall(); + if (activeCall && activeCall.confUserId) { + var thisRoomConfUserId = module.exports.getConferenceUserIdForRoom( + roomId + ); + if (thisRoomConfUserId === activeCall.confUserId) { + return activeCall; + } + } + return null; +}; + +module.exports.ConferenceCall = ConferenceCall; + +module.exports.slot = 'conference'; diff --git a/src/components/views/globals/UpdateCheckBar.js b/src/components/views/globals/UpdateCheckBar.js index b169054c5c9..4397b3313e8 100644 --- a/src/components/views/globals/UpdateCheckBar.js +++ b/src/components/views/globals/UpdateCheckBar.js @@ -19,14 +19,8 @@ limitations under the License. import React from 'react'; import { _t } from '../../../languageHandler'; import PlatformPeg from '../../../PlatformPeg'; -import {updateCheckStatusEnum} from '../../../vector/platform/VectorBasePlatform'; import AccessibleButton from '../../../components/views/elements/AccessibleButton'; -const doneStatuses = [ - updateCheckStatusEnum.ERROR, - updateCheckStatusEnum.NOTAVAILABLE, -]; - export default React.createClass({ propTypes: { status: React.PropTypes.oneOf(Object.values(updateCheckStatusEnum)).isRequired, @@ -42,6 +36,7 @@ export default React.createClass({ }, getStatusText: function() { + const updateCheckStatusEnum = PlatformPeg.get().getUpdateCheckStatusEnum(); switch(this.props.status) { case updateCheckStatusEnum.ERROR: return _t('Error encountered (%(errorDetail)s).', { errorDetail: this.props.detail }); @@ -52,8 +47,7 @@ export default React.createClass({ case updateCheckStatusEnum.DOWNLOADING: return _t('Downloading update...'); } - } - , + }, hideToolbar: function() { PlatformPeg.get().stopUpdateCheck(); @@ -63,6 +57,16 @@ export default React.createClass({ const message = this.getStatusText(); const warning = _t('Warning'); + if (!'getUpdateCheckStatusEnum' in PlatformPeg.get()) { + return
; + } + + const updateCheckStatusEnum = PlatformPeg.get().getUpdateCheckStatusEnum(); + const doneStatuses = [ + updateCheckStatusEnum.ERROR, + updateCheckStatusEnum.NOTAVAILABLE, + ]; + let image; if (doneStatuses.includes(this.props.status)) { image = {warning}/;