Make SessionLoader a function

There's no point in it being a React component.
This commit is contained in:
Richard van der Hoff 2016-08-10 11:33:58 +01:00
parent 24841cc5c4
commit 26c7c9e994
4 changed files with 123 additions and 179 deletions

View file

@ -14,19 +14,120 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import q from 'q';
import MatrixClientPeg from './MatrixClientPeg';
import Notifier from './Notifier'
import UserActivity from './UserActivity';
import Presence from './Presence';
import dis from './dispatcher';
/**
* Called at startup, to attempt to build a logged-in Matrix session. It tries
* a number of things:
*
* 0. if it looks like we are in the middle of a registration process, it does
* nothing.
*
* 1. if we have a guest access token in the query params, it uses that.
*
* 2. if an access token is stored in local storage (from a previous session),
* it uses that.
*
* 3. it attempts to auto-register as a guest user.
*
* If any of steps 1-3 are successful, it will call {setLoggedIn}, which in
* turn will raise on_logged_in and will_start_client events.
*
* It returns a promise which resolves when the above process completes.
*
* @param {object} opts.queryParams: string->string map of the query-parameters
* extracted from the #-fragment of the starting URI.
*
* @param {boolean} opts.enableGuest: set to true to enable guest access tokens
* and auto-guest registrations.
*
* @params {string} opts.hsUrl: homeserver URL. Only used if enableGuest is
* true; defines the HS to register against.
*
* @params {string} opts.isUrl: homeserver URL. Only used if enableGuest is
* true; defines the IS to use.
*
*/
export function loadSession(opts) {
const queryParams = opts.queryParams || {};
let enableGuest = opts.enableGuest || false;
const hsUrl = opts.hsUrl;
const isUrl = opts.isUrl;
if (queryParams.client_secret && queryParams.sid) {
// this happens during email validation: the email contains a link to the
// IS, which in turn redirects back to vector. We let MatrixChat create a
// Registration component which completes the next stage of registration.
console.log("Not registering as guest: registration already in progress.");
return q();
}
if (!hsUrl) {
console.warn("Cannot enable guest access: can't determine HS URL to use");
enableGuest = false;
}
if (enableGuest &&
queryParams.guest_user_id &&
queryParams.guest_access_token
) {
console.log("Using guest access credentials");
setLoggedIn({
userId: queryParams.guest_user_id,
accessToken: queryParams.guest_access_token,
homeserverUrl: hsUrl,
identityServerUrl: isUrl,
guest: true,
});
return q();
}
if (MatrixClientPeg.get() && MatrixClientPeg.get().credentials) {
console.log("Using existing credentials");
setLoggedIn(MatrixClientPeg.getCredentials());
return q();
}
if (enableGuest) {
return _registerAsGuest(hsUrl, isUrl);
}
// fall back to login screen
return q();
}
function _registerAsGuest(hsUrl, isUrl) {
console.log("Doing guest login on %s", hsUrl);
MatrixClientPeg.replaceUsingUrls(hsUrl, isUrl);
return MatrixClientPeg.get().registerGuest().then((creds) => {
console.log("Registered as guest: %s", creds.user_id);
setLoggedIn({
userId: creds.user_id,
accessToken: creds.access_token,
homeserverUrl: hsUrl,
identityServerUrl: isUrl,
guest: true,
});
}, (err) => {
console.error("Failed to register as guest: " + err + " " + err.data);
});
}
/**
* Transitions to a logged-in state using the given credentials
* @param {MatrixClientCreds} credentials The credentials to use
*/
function setLoggedIn(credentials) {
export function setLoggedIn(credentials) {
credentials.guest = Boolean(credentials.guest);
console.log("onLoggedIn => %s (guest=%s) hs=%s",
console.log("setLoggedIn => %s (guest=%s) hs=%s",
credentials.userId, credentials.guest,
credentials.homeserverUrl);
MatrixClientPeg.replaceUsingCreds(credentials);
@ -39,7 +140,7 @@ function setLoggedIn(credentials) {
/**
* Logs the current session out and transitions to the logged-out state
*/
function logout() {
export function logout() {
if (MatrixClientPeg.get().isGuest()) {
// logout doesn't work for guest sessions
// Also we sometimes want to re-log in a guest session
@ -67,7 +168,7 @@ function logout() {
* Starts the matrix client and all other react-sdk services that
* listen for events while a session is logged in.
*/
function startMatrixClient() {
export function startMatrixClient() {
// 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
@ -85,7 +186,7 @@ function startMatrixClient() {
* Stops a running client and all related services, used after
* a session has been logged out / ended.
*/
function onLoggedOut() {
export function onLoggedOut() {
if (window.localStorage) {
const hsUrl = window.localStorage.getItem("mx_hs_url");
const isUrl = window.localStorage.getItem("mx_is_url");
@ -112,7 +213,3 @@ function _stopMatrixClient() {
MatrixClientPeg.get().removeAllListeners();
MatrixClientPeg.unset();
}
module.exports = {
setLoggedIn, logout, startMatrixClient, onLoggedOut
};

View file

@ -39,7 +39,6 @@ module.exports.components['structures.login.ForgotPassword'] = require('./compon
module.exports.components['structures.login.Login'] = require('./components/structures/login/Login');
module.exports.components['structures.login.PostRegistration'] = require('./components/structures/login/PostRegistration');
module.exports.components['structures.login.Registration'] = require('./components/structures/login/Registration');
module.exports.components['structures.login.SessionLoader'] = require('./components/structures/login/SessionLoader');
module.exports.components['views.avatars.BaseAvatar'] = require('./components/views/avatars/BaseAvatar');
module.exports.components['views.avatars.MemberAvatar'] = require('./components/views/avatars/MemberAvatar');
module.exports.components['views.avatars.RoomAvatar'] = require('./components/views/avatars/RoomAvatar');

View file

@ -26,7 +26,6 @@ var UserActivity = require("../../UserActivity");
var Presence = require("../../Presence");
var dis = require("../../dispatcher");
var SessionLoader = require("./login/SessionLoader");
var Login = require("./login/Login");
var Registration = require("./login/Registration");
var PostRegistration = require("./login/PostRegistration");
@ -145,14 +144,11 @@ module.exports = React.createClass({
if (this.props.config.sync_timeline_limit) {
MatrixClientPeg.opts.initialSyncLimit = this.props.config.sync_timeline_limit;
}
// register our dispatcher listener here rather than in
// componentDidMount so that we hear about any actions raised during
// the loading process.
this.dispatcherRef = dis.register(this.onAction);
},
componentDidMount: function() {
this.dispatcherRef = dis.register(this.onAction);
this.focusComposer = false;
// scrollStateMap is a map from room id to the scroll state returned by
// RoomView.getScrollState()
@ -171,6 +167,17 @@ module.exports = React.createClass({
window.addEventListener('resize', this.handleResize);
this.handleResize();
Lifecycle.loadSession({
queryParams: this.props.startingQueryParams,
enableGuest: this.props.enableGuest,
hsUrl: this.getDefaultHsUrl(),
isUrl: this.getDefaultIsUrl(),
}).done(()=>{
// stuff this through the dispatcher so that it happens
// after the on_logged_in action.
dis.dispatch({action: 'load_completed'});
});
},
componentWillUnmount: function() {
@ -990,18 +997,11 @@ module.exports = React.createClass({
// "; logged_in="+this.state.logged_in+"; ready="+this.state.ready);
if (this.state.loading) {
var Spinner = sdk.getComponent('elements.Spinner');
return (
<SessionLoader
queryParams={this.props.startingQueryParams}
enableGuest={this.props.enableGuest}
hsUrl={this.getCurrentHsUrl()}
isUrl={this.getCurrentIsUrl()}
onLoggedIn={Lifecycle.setLoggedIn}
// stuff this through the dispatcher so that it happens
// after the on_logged_in action.
onComplete={()=>{dis.dispatch({action: 'load_completed'});}}
/>
<div className="mx_MatrixChat_splash">
<Spinner />
</div>
);
}
// needs to be before normal PageTypes as you are logged in technically

View file

@ -1,152 +0,0 @@
/*
Copyright 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 React from 'react';
import q from 'q';
import dis from '../../../dispatcher';
import sdk from '../../../index';
import MatrixClientPeg from '../../../MatrixClientPeg';
import Lifecycle from '../../../Lifecycle';
/**
* A react component which is only used when the application first starts.
*
* Its job is to attempt to build a logged-in Matrix session. It tries a number
* of things:
*
* 0. if it looks like we are in the middle of a registration process, it does
* nothing.
*
* 1. if we have a guest access token in the query params, it uses that.
*
* 2. if an access token is stored in local storage (from a previous session),
* it uses that.
*
* 3. it attempts to auto-register as a guest user.
*
* If any of steps 1-3 are successful, it will call onLoggedIn (which is
* typically Lifecycle.setLoggedIn, which in turn will raise on_logged_in and
* will_start_client events).
*
* Finally, it calls onComplete, which makes MatrixChat move into its normal processing.
*/
export default class SessionLoader extends React.Component {
constructor(props, context) {
super(props, context);
}
componentDidMount() {
this._loadSession().done(() => {
this.props.onComplete();
});
}
componentWillReceiveProps(nextProps) {
if (nextProps.hsUrl != this.props.hsUrl ||
nextProps.isUrl != this.props.isUrl
) {
throw new Error("changing servers on a SessionLoader is not supported");
};
}
_loadSession() {
if (this.props.queryParams.client_secret && this.props.queryParams.sid) {
// this happens during email validation: the email contains a link to the
// IS, which in turn redirects back to vector. We let MatrixChat create a
// Registration component which completes the next stage of registration.
console.log("Not registering as guest: registration already in progress.");
return q();
}
let enableGuest = false;
if (this.props.enableGuest) {
if (!this.props.hsUrl) {
console.warn("Cannot enable guest access: can't determine HS URL to use");
}
else {
enableGuest = true;
}
}
if (enableGuest &&
this.props.queryParams.guest_user_id &&
this.props.queryParams.guest_access_token
) {
console.log("Using guest access credentials");
this.props.onLoggedIn({
userId: this.props.queryParams.guest_user_id,
accessToken: this.props.queryParams.guest_access_token,
homeserverUrl: this.props.hsUrl,
identityServerUrl: this.props.isUrl,
guest: true,
});
return q();
}
if (MatrixClientPeg.get() && MatrixClientPeg.get().credentials) {
console.log("Using existing credentials");
this.props.onLoggedIn(MatrixClientPeg.getCredentials());
return q();
}
if (enableGuest) {
return this._registerAsGuest();
}
// fall back to login screen
return q();
}
_registerAsGuest() {
var hsUrl = this.props.hsUrl;
var isUrl = this.props.isUrl;
console.log("Doing guest login on %s", hsUrl);
MatrixClientPeg.replaceUsingUrls(hsUrl, isUrl);
return MatrixClientPeg.get().registerGuest().then((creds) => {
console.log("Registered as guest: %s", creds.user_id);
this.props.onLoggedIn({
userId: creds.user_id,
accessToken: creds.access_token,
homeserverUrl: hsUrl,
identityServerUrl: isUrl,
guest: true,
});
}, (err) => {
console.error("Failed to register as guest: " + err + " " + err.data);
});
}
render() {
const Spinner = sdk.getComponent('elements.Spinner');
return (
<div className="mx_MatrixChat_splash">
<Spinner />
</div>
);
}
}
SessionLoader.propTypes = {
queryParams: React.PropTypes.object.isRequired,
enableGuest: React.PropTypes.bool,
hsUrl: React.PropTypes.string,
isUrl: React.PropTypes.string,
onLoggedIn: React.PropTypes.func.isRequired,
onComplete: React.PropTypes.func.isRequired,
};