From 3df746ef143a02103272081f384280961bc18b81 Mon Sep 17 00:00:00 2001 From: wmwragg Date: Wed, 27 Jul 2016 14:16:17 +0100 Subject: [PATCH] Revert merge up from develop --- package.json | 10 +- src/GuestAccess.js | 51 ------- src/MatrixClientPeg.js | 171 +++++++++++++---------- src/TabComplete.js | 7 +- src/components/structures/RoomView.js | 18 ++- src/components/views/rooms/MemberInfo.js | 8 +- src/ratelimitedfunc.js | 8 ++ 7 files changed, 130 insertions(+), 143 deletions(-) delete mode 100644 src/GuestAccess.js diff --git a/package.json b/package.json index cd81ad7c56..60fc45db77 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "reskindex": "./reskindex.js" }, "scripts": { - "reskindex": "reskindex -h header", + "reskindex": "./reskindex.js -h header", "build": "babel src -d lib --source-maps --stage 1", "start": "babel src -w -d lib --source-maps --stage 1", "lint": "eslint src/", @@ -42,10 +42,10 @@ "matrix-js-sdk": "matrix-org/matrix-js-sdk#develop", "optimist": "^0.6.1", "q": "^1.4.1", - "react": "^15.0.1", - "react-addons-css-transition-group": "^15.1.0", - "react-dom": "^15.0.1", - "react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#c3d942e", + "react": "^15.2.1", + "react-addons-css-transition-group": "^15.2.1", + "react-dom": "^15.2.1", + "react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#dbf0abf", "sanitize-html": "^1.11.1", "velocity-vector": "vector-im/velocity#059e3b2", "whatwg-fetch": "^1.0.0" diff --git a/src/GuestAccess.js b/src/GuestAccess.js deleted file mode 100644 index ef48d23ded..0000000000 --- a/src/GuestAccess.js +++ /dev/null @@ -1,51 +0,0 @@ -/* -Copyright 2015 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. -*/ -const IS_GUEST_KEY = "matrix-is-guest"; - -class GuestAccess { - - constructor(localStorage) { - this.localStorage = localStorage; - try { - this._isGuest = localStorage.getItem(IS_GUEST_KEY) === "true"; - } - catch (e) {} // don't care - } - - setPeekedRoom(roomId) { - // we purposefully do not persist this to local storage as peeking is - // entirely transient. - this._peekedRoomId = roomId; - } - - getPeekedRoom() { - return this._peekedRoomId; - } - - isGuest() { - return this._isGuest; - } - - markAsGuest(isGuest) { - try { - this.localStorage.setItem(IS_GUEST_KEY, JSON.stringify(isGuest)); - } catch (e) {} // ignore. If they don't do LS, they'll just get a new account. - this._isGuest = isGuest; - this._peekedRoomId = null; - } -} - -module.exports = GuestAccess; diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js index 7c1c5b34d7..ce4b5ba743 100644 --- a/src/MatrixClientPeg.js +++ b/src/MatrixClientPeg.js @@ -16,13 +16,9 @@ limitations under the License. 'use strict'; -// A thing that holds your Matrix Client -var Matrix = require("matrix-js-sdk"); -var GuestAccess = require("./GuestAccess"); +import Matrix from 'matrix-js-sdk'; -let matrixClient: MatrixClient = null; - -var localStorage = window.localStorage; +const localStorage = window.localStorage; function deviceId() { // XXX: is Math.random()'s deterministicity a problem here? @@ -35,82 +31,42 @@ function deviceId() { return id; } -function createClientForPeg(hs_url, is_url, user_id, access_token, guestAccess) { - var opts = { - baseUrl: hs_url, - idBaseUrl: is_url, - accessToken: access_token, - userId: user_id, - timelineSupport: true, - }; - - if (localStorage) { - opts.sessionStore = new Matrix.WebStorageSessionStore(localStorage); - opts.deviceId = deviceId(); - } - - matrixClient = Matrix.createClient(opts); - - // we're going to add eventlisteners for each matrix event tile, so the - // potential number of event listeners is quite high. - matrixClient.setMaxListeners(500); - - if (guestAccess) { - console.log("Guest: %s", guestAccess.isGuest()); - matrixClient.setGuest(guestAccess.isGuest()); - var peekedRoomId = guestAccess.getPeekedRoom(); - if (peekedRoomId) { - console.log("Peeking in room %s", peekedRoomId); - matrixClient.peekInRoom(peekedRoomId); - } - } -} - -if (localStorage) { - var hs_url = localStorage.getItem("mx_hs_url"); - var is_url = localStorage.getItem("mx_is_url") || 'https://matrix.org'; - var access_token = localStorage.getItem("mx_access_token"); - var user_id = localStorage.getItem("mx_user_id"); - var guestAccess = new GuestAccess(localStorage); - if (access_token && user_id && hs_url) { - console.log("Restoring session for %s", user_id); - createClientForPeg(hs_url, is_url, user_id, access_token, guestAccess); - } - else { - console.log("Session not found."); - } -} - -class MatrixClient { - - constructor(guestAccess) { - this.guestAccess = guestAccess; +/** + * Wrapper object for handling the js-sdk Matrix Client object in the react-sdk + * Handles the creation/initialisation of client objects. + * This module provides a singleton instance of this class so the 'current' + * Matrix Client object is available easily. + */ +class MatrixClientPeg { + constructor() { + this.matrixClient = null; } get(): MatrixClient { - return matrixClient; + return this.matrixClient; } unset() { - matrixClient = null; + this.matrixClient = null; } - // FIXME, XXX: this all seems very convoluted :( - // - // Why do we have this peg wrapper rather than just MatrixClient.get()? - // Why do we name MatrixClient as MatrixClientPeg when we export it? - // - // -matthew - + /** + * Replace this MatrixClientPeg's client with a client instance that has + * Home Server / Identity Server URLs but no credentials + */ replaceUsingUrls(hs_url, is_url) { - this.replaceClient(hs_url, is_url); + this._replaceClient(hs_url, is_url); } + /** + * Replace this MatrixClientPeg's client with a client instance that has + * Home Server / Identity Server URLs and active credentials + */ replaceUsingAccessToken(hs_url, is_url, user_id, access_token, isGuest) { - this.replaceClient(hs_url, is_url, user_id, access_token, isGuest); + this._replaceClient(hs_url, is_url, user_id, access_token, isGuest); } - replaceClient(hs_url, is_url, user_id, access_token, isGuest) { + _replaceClient(hs_url, is_url, user_id, access_token, isGuest) { if (localStorage) { try { localStorage.clear(); @@ -118,15 +74,19 @@ class MatrixClient { console.warn("Error clearing local storage", e); } } - this.guestAccess.markAsGuest(Boolean(isGuest)); - createClientForPeg(hs_url, is_url, user_id, access_token, this.guestAccess); + this._createClient(hs_url, is_url, user_id, access_token, isGuest); + if (localStorage) { try { localStorage.setItem("mx_hs_url", hs_url); localStorage.setItem("mx_is_url", is_url); - localStorage.setItem("mx_user_id", user_id); - localStorage.setItem("mx_access_token", access_token); - console.log("Session persisted for %s", user_id); + + if (user_id !== undefined && access_token !== undefined) { + localStorage.setItem("mx_user_id", user_id); + localStorage.setItem("mx_access_token", access_token); + localStorage.setItem("mx_is_guest", JSON.stringify(isGuest)); + console.log("Session persisted for %s", user_id); + } } catch (e) { console.warn("Error using local storage: can't persist session!", e); } @@ -134,9 +94,68 @@ class MatrixClient { console.warn("No local storage available: can't persist session!"); } } + + getCredentials() { + return [ + this.matrixClient.baseUrl, + this.matrixClient.idBaseUrl, + this.matrixClient.credentials.userId, + this.matrixClient.getAccessToken(), + this.matrixClient.isGuest(), + ]; + } + + tryRestore() { + if (localStorage) { + const hs_url = localStorage.getItem("mx_hs_url"); + const is_url = localStorage.getItem("mx_is_url") || 'https://matrix.org'; + const access_token = localStorage.getItem("mx_access_token"); + const user_id = localStorage.getItem("mx_user_id"); + + let is_guest; + if (localStorage.getItem("mx_is_guest") !== null) { + is_guest = localStorage.getItem("mx_is_guest") === "true"; + } else { + // legacy key name + is_guest = localStorage.getItem("matrix-is-guest") === "true"; + } + + if (access_token && user_id && hs_url) { + console.log("Restoring session for %s", user_id); + this._createClient(hs_url, is_url, user_id, access_token); + this.matrixClient.setGuest(is_guest); + } else { + console.log("Session not found."); + } + } + } + + _createClient(hs_url, is_url, user_id, access_token, isGuest) { + var opts = { + baseUrl: hs_url, + idBaseUrl: is_url, + accessToken: access_token, + userId: user_id, + timelineSupport: true, + }; + + if (localStorage) { + opts.sessionStore = new Matrix.WebStorageSessionStore(localStorage); + opts.deviceId = deviceId(); + } + + this.matrixClient = Matrix.createClient(opts); + + // we're going to add eventlisteners for each matrix event tile, so the + // potential number of event listeners is quite high. + this.matrixClient.setMaxListeners(500); + + this.matrixClient.setGuest(Boolean(isGuest)); + } } -if (!global.mxMatrixClient) { - global.mxMatrixClient = new MatrixClient(new GuestAccess(localStorage)); +if (!global.mxMatrixClientPeg) { + global.mxMatrixClientPeg = new MatrixClientPeg(); + global.mxMatrixClientPeg.tryRestore(); } -module.exports = global.mxMatrixClient; +module.exports = global.mxMatrixClientPeg; diff --git a/src/TabComplete.js b/src/TabComplete.js index 0ec0b77802..65441c9381 100644 --- a/src/TabComplete.js +++ b/src/TabComplete.js @@ -341,7 +341,12 @@ class TabComplete { } if (a.kind == 'member') { - return this.memberTabOrder[b.member.userId] - this.memberTabOrder[a.member.userId]; + let orderA = this.memberTabOrder[a.member.userId]; + let orderB = this.memberTabOrder[b.member.userId]; + if (orderA === undefined) orderA = -1; + if (orderB === undefined) orderB = -1; + + return orderB - orderA; } // anything else we have no ordering for diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index accf96f349..9fbdb51f11 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -493,6 +493,17 @@ module.exports = React.createClass({ return; } + if (this.props.ConferenceHandler && + member.userId === this.props.ConferenceHandler.getConferenceUserIdForRoom(member.roomId)) { + this._updateConfCallNotification(); + } + + this._updateRoomMembers(); + }, + + // rate limited because a power level change will emit an event for every + // member in the room. + _updateRoomMembers: new rate_limited_func(function() { // a member state changed in this room, refresh the tab complete list this.tabComplete.loadEntries(this.state.room); this._updateAutoComplete(); @@ -506,12 +517,7 @@ module.exports = React.createClass({ joining: false }); } - - if (this.props.ConferenceHandler && - member.userId === this.props.ConferenceHandler.getConferenceUserIdForRoom(member.roomId)) { - this._updateConfCallNotification(); - } - }, + }, 500), _hasUnsentMessages: function(room) { return this._getUnsentMessages(room).length > 0; diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js index c439f8b40c..07a7b9398d 100644 --- a/src/components/views/rooms/MemberInfo.js +++ b/src/components/views/rooms/MemberInfo.js @@ -406,14 +406,14 @@ module.exports = React.createClass({ this.props.onFinished(); } else { - self.setState({ updating: self.state.updating + 1 }); + this.setState({ updating: this.state.updating + 1 }); createRoom({ createOpts: { invite: [this.props.member.userId], }, - }).finally(function() { - self.props.onFinished(); - self.setState({ updating: self.state.updating - 1 }); + }).finally(() => { + this.props.onFinished(); + this.setState({ updating: this.state.updating - 1 }); }).done(); } }, diff --git a/src/ratelimitedfunc.js b/src/ratelimitedfunc.js index 453669b477..ed892f4eac 100644 --- a/src/ratelimitedfunc.js +++ b/src/ratelimitedfunc.js @@ -14,6 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ +/** + * 'debounces' a function to only execute every n milliseconds. + * Useful when react-sdk gets many, many events but only wants + * to update the interface once for all of them. + * + * Note that the function must not take arguments, since the args + * could be different for each invocarion of the function. + */ module.exports = function(f, minIntervalMs) { this.lastCall = 0; this.scheduledCall = undefined;