Call the logout API when we log out

Also try to refactor some of the login/logout code out of MatrixChat and into a separate Lifecycle.js. This still isn't great, but it at least gets some code out of MatrixClient.
This commit is contained in:
David Baker 2016-08-02 14:04:20 +01:00
parent 215b32b377
commit db9750a7e3
4 changed files with 176 additions and 72 deletions

View file

@ -181,11 +181,11 @@ function _onAction(payload) {
console.error("Unknown conf call type: %s", payload.type);
}
}
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
switch (payload.action) {
case 'place_call':
if (module.exports.getAnyActiveCall()) {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Existing Call",
description: "You are already in a call."
@ -195,6 +195,7 @@ function _onAction(payload) {
// if the runtime env doesn't do VoIP, whine.
if (!MatrixClientPeg.get().supportsVoip()) {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "VoIP is unsupported",
description: "You cannot place VoIP calls in this browser."
@ -210,7 +211,7 @@ function _onAction(payload) {
var members = room.getJoinedMembers();
if (members.length <= 1) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
description: "You cannot place a call with yourself."
});
@ -236,11 +237,13 @@ function _onAction(payload) {
case 'place_conference_call':
console.log("Place conference call in %s", payload.room_id);
if (!ConferenceHandler) {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
description: "Conference calls are not supported in this client"
});
}
else if (!MatrixClientPeg.get().supportsVoip()) {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "VoIP is unsupported",
description: "You cannot place VoIP calls in this browser."

98
src/Lifecycle.js Normal file
View file

@ -0,0 +1,98 @@
/*
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.
*/
import MatrixClientPeg from './MatrixClientPeg';
import Notifier from './Notifier'
import UserActivity from './UserActivity';
import Presence from './Presence';
import dis from './dispatcher';
function login(credentials, options) {
credentials.guest = Boolean(credentials.guest);
console.log("onLoggedIn => %s (guest=%s)", credentials.userId, credentials.guest);
MatrixClientPeg.replaceUsingAccessToken(
credentials.homeserverUrl, credentials.identityServerUrl,
credentials.userId, credentials.accessToken, credentials.guest
);
dis.dispatch({action: 'on_logged_in'});
startMatrixClient(options);
}
function logout() {
if (MatrixClientPeg.get().isGuest()) {
// logout doesn't work for guest sessions
// Also we sometimes want to re-log in a guest session
// if we abort the login
_onLoggedOut();
return;
}
return MatrixClientPeg.get().logout().then(_onLoggedOut,
// Just throwing an error here is going to be very unhelpful
// if you're trying to log out because your server's down and
// you want to log into a different server, so just forget the
// access token. It's annoying that this will leave the access
// token still valid, but we should fix this by having access
// tokens expire (and if you really think you've been compromised,
// change your password).
_onLoggedOut
);
}
function startMatrixClient(options) {
// dispatch this before starting the matrix client: it's used
// to add listeners for the 'sync' event so otherwise we'd have
// a race condition (and we need to dispatch synchronously for this
// to work).
dis.dispatch({action: 'will_start_client'}, true);
Notifier.start();
UserActivity.start();
Presence.start();
MatrixClientPeg.get().startClient(MatrixClientPeg.opts);
}
function _onLoggedOut() {
if (window.localStorage) {
const hsUrl = window.localStorage.getItem("mx_hs_url");
const isUrl = window.localStorage.getItem("mx_is_url");
window.localStorage.clear();
// preserve our HS & IS URLs for convenience
// N.B. we cache them in hsUrl/isUrl and can't really inline them
// as getCurrentHsUrl() may call through to localStorage.
if (hsUrl) window.localStorage.setItem("mx_hs_url", hsUrl);
if (isUrl) window.localStorage.setItem("mx_is_url", isUrl);
}
_stopMatrixClient();
dis.dispatch({action: 'on_logged_out'});
}
// stop all the background processes related to the current client
function _stopMatrixClient() {
Notifier.stop();
UserActivity.stop();
Presence.stop();
MatrixClientPeg.get().stopClient();
MatrixClientPeg.get().removeAllListeners();
MatrixClientPeg.unset();
}
module.exports = {
login, logout, startMatrixClient
};

View file

@ -40,6 +40,14 @@ function deviceId() {
class MatrixClientPeg {
constructor() {
this.matrixClient = null;
// These are the default options used when Lifecycle.js
// starts the client. These can be altered when the
// 'will_start_client' event is dispatched.
this.opts = {
pendingEventOrdering: "detached",
initialSyncLimit: 20,
};
}
get(): MatrixClient {
@ -96,13 +104,13 @@ class MatrixClientPeg {
}
getCredentials() {
return [
this.matrixClient.baseUrl,
this.matrixClient.idBaseUrl,
this.matrixClient.credentials.userId,
this.matrixClient.getAccessToken(),
this.matrixClient.isGuest(),
];
return {
homeserverUrl: this.matrixClient.baseUrl,
identityServerUrl: this.matrixClient.idBaseUrl,
userId: this.matrixClient.credentials.userId,
accessToken: this.matrixClient.getAccessToken(),
guest: this.matrixClient.isGuest(),
};
}
tryRestore() {

View file

@ -36,6 +36,7 @@ var sdk = require('../../index');
var MatrixTools = require('../../MatrixTools');
var linkifyMatrix = require("../../linkify-matrix");
var KeyCode = require('../../KeyCode');
var Lifecycle = require('../../Lifecycle');
var createRoom = require("../../createRoom");
@ -140,6 +141,7 @@ module.exports = React.createClass({
componentWillMount: function() {
this.favicon = new Favico({animation: 'none'});
this.guestCreds = null;
},
componentDidMount: function() {
@ -156,7 +158,7 @@ module.exports = React.createClass({
this.props.startingQueryParams.guest_access_token)
{
this._autoRegisterAsGuest = false;
this.onLoggedIn({
this._onHaveCredentials({
userId: this.props.startingQueryParams.guest_user_id,
accessToken: this.props.startingQueryParams.guest_access_token,
homeserverUrl: this.getDefaultHsUrl(),
@ -174,7 +176,7 @@ module.exports = React.createClass({
// Don't auto-register as a guest. This applies if you refresh the page on a
// logged in client THEN hit the Sign Out button.
this._autoRegisterAsGuest = false;
this.startMatrixClient();
Lifecycle.startMatrixClient();
}
this.focusComposer = false;
// scrollStateMap is a map from room id to the scroll state returned by
@ -229,7 +231,7 @@ module.exports = React.createClass({
MatrixClientPeg.get().registerGuest().done(function(creds) {
console.log("Registered as guest: %s", creds.user_id);
self._setAutoRegisterAsGuest(false);
self.onLoggedIn({
self._onHaveCredentials({
userId: creds.user_id,
accessToken: creds.access_token,
homeserverUrl: hsUrl,
@ -260,34 +262,10 @@ module.exports = React.createClass({
var self = this;
switch (payload.action) {
case 'logout':
var guestCreds;
if (MatrixClientPeg.get().isGuest()) {
guestCreds = { // stash our guest creds so we can backout if needed
userId: MatrixClientPeg.get().credentials.userId,
accessToken: MatrixClientPeg.get().getAccessToken(),
homeserverUrl: MatrixClientPeg.get().getHomeserverUrl(),
identityServerUrl: MatrixClientPeg.get().getIdentityServerUrl(),
guest: true
}
this.guestCreds = MatrixClientPeg.getCredentials();
}
if (window.localStorage) {
var hsUrl = this.getCurrentHsUrl();
var isUrl = this.getCurrentIsUrl();
window.localStorage.clear();
// preserve our HS & IS URLs for convenience
// N.B. we cache them in hsUrl/isUrl and can't really inline them
// as getCurrentHsUrl() may call through to localStorage.
window.localStorage.setItem("mx_hs_url", hsUrl);
window.localStorage.setItem("mx_is_url", isUrl);
}
this._stopMatrixClient();
this.notifyNewScreen('login');
this.replaceState({
logged_in: false,
ready: false,
guestCreds: guestCreds,
});
Lifecycle.logout();
break;
case 'start_registration':
var newState = payload.params || {};
@ -313,7 +291,6 @@ module.exports = React.createClass({
if (this.state.logged_in) return;
this.replaceState({
screen: 'login',
guestCreds: this.state.guestCreds,
});
this.notifyNewScreen('login');
break;
@ -323,17 +300,14 @@ module.exports = React.createClass({
});
break;
case 'start_upgrade_registration':
// stash our guest creds so we can backout if needed
if (MatrixClientPeg.get().isGuest()) {
this.guestCreds = MatrixClientPeg.getCredentials();
}
this.replaceState({
screen: "register",
upgradeUsername: MatrixClientPeg.get().getUserIdLocalpart(),
guestAccessToken: MatrixClientPeg.get().getAccessToken(),
guestCreds: { // stash our guest creds so we can backout if needed
userId: MatrixClientPeg.get().credentials.userId,
accessToken: MatrixClientPeg.get().getAccessToken(),
homeserverUrl: MatrixClientPeg.get().getHomeserverUrl(),
identityServerUrl: MatrixClientPeg.get().getIdentityServerUrl(),
guest: true
}
});
this.notifyNewScreen('register');
break;
@ -482,6 +456,15 @@ module.exports = React.createClass({
middleOpacity: payload.middleOpacity,
});
break;
case 'on_logged_in':
this._onLoggedIn();
break;
case 'on_logged_out':
this._onLoggedOut();
break;
case 'will_start_client':
this._onWillStartClient();
break;
}
},
@ -592,23 +575,40 @@ module.exports = React.createClass({
this.scrollStateMap[roomId] = state;
},
onLoggedIn: function(credentials) {
credentials.guest = Boolean(credentials.guest);
console.log("onLoggedIn => %s (guest=%s)", credentials.userId, credentials.guest);
MatrixClientPeg.replaceUsingAccessToken(
credentials.homeserverUrl, credentials.identityServerUrl,
credentials.userId, credentials.accessToken, credentials.guest
);
this.setState({
screen: undefined,
logged_in: true
_doLogin(creds) {
Lifecycle.login(creds, {
syncTimelineLimit: this.props.config.sync_timeline_limit,
});
this.startMatrixClient();
this.notifyNewScreen('');
},
startMatrixClient: function() {
_onHaveCredentials: function(credentials) {
credentials.guest = Boolean(credentials.guest);
Lifecycle.login(credentials);
},
_onLoggedIn: function(credentials) {
this.guestCreds = null;
this.setState({
screen: undefined,
logged_in: true,
});
},
_onLoggedOut: function() {
this.notifyNewScreen('login');
this.replaceState({
logged_in: false,
ready: false,
});
},
_onWillStartClient() {
var cli = MatrixClientPeg.get();
if (this.props.config.sync_timeline_limit) {
MatrixClientPeg.opts.initialSyncLimit = this.props.config.sync_timeline_limit;
}
var self = this;
cli.on('sync', function(state, prevState) {
self.updateFavicon(state, prevState);
@ -675,13 +675,6 @@ module.exports = React.createClass({
action: 'logout'
});
});
Notifier.start();
UserActivity.start();
Presence.start();
cli.startClient({
pendingEventOrdering: "detached",
initialSyncLimit: this.props.config.sync_timeline_limit || 20,
});
},
// stop all the background processes related to the current client
@ -919,12 +912,14 @@ module.exports = React.createClass({
onReturnToGuestClick: function() {
// reanimate our guest login
this.onLoggedIn(this.state.guestCreds);
this.setState({ guestCreds: null });
if (this.guestCreds) {
this._onHaveCredentials(this.guestCreds);
this.guestCreds = null;
}
},
onRegistered: function(credentials) {
this.onLoggedIn(credentials);
this._onHaveCredentials(credentials);
// do post-registration stuff
// This now goes straight to user settings
// We use _setPage since if we wait for
@ -1130,7 +1125,7 @@ module.exports = React.createClass({
onLoggedIn={this.onRegistered}
onLoginClick={this.onLoginClick}
onRegisterClick={this.onRegisterClick}
onCancelClick={ this.state.guestCreds ? this.onReturnToGuestClick : null }
onCancelClick={this.guestCreds ? this.onReturnToGuestClick : null}
/>
);
} else if (this.state.screen == 'forgot_password') {
@ -1146,7 +1141,7 @@ module.exports = React.createClass({
} else {
return (
<Login
onLoggedIn={this.onLoggedIn}
onLoggedIn={this._onHaveCredentials}
onRegisterClick={this.onRegisterClick}
defaultHsUrl={this.getDefaultHsUrl()}
defaultIsUrl={this.getDefaultIsUrl()}
@ -1155,7 +1150,7 @@ module.exports = React.createClass({
fallbackHsUrl={this.getFallbackHsUrl()}
onForgotPasswordClick={this.onForgotPasswordClick}
onLoginAsGuestClick={this.props.enableGuest && this.props.config && this._registerAsGuest.bind(this, true)}
onCancelClick={ this.state.guestCreds ? this.onReturnToGuestClick : null }
onCancelClick={this.guestCreds ? this.onReturnToGuestClick : null}
/>
);
}