Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Start to factor out session-loading magic #397

Merged
merged 2 commits into from
Aug 10, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 108 additions & 9 deletions src/Lifecycle.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,122 @@ 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)", credentials.userId, credentials.guest);
console.log("setLoggedIn => %s (guest=%s) hs=%s",
credentials.userId, credentials.guest,
credentials.homeserverUrl);
MatrixClientPeg.replaceUsingCreds(credentials);

dis.dispatch({action: 'on_logged_in'});
Expand All @@ -37,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
Expand Down Expand Up @@ -65,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
Expand All @@ -83,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");
Expand All @@ -110,7 +213,3 @@ function _stopMatrixClient() {
MatrixClientPeg.get().removeAllListeners();
MatrixClientPeg.unset();
}

module.exports = {
setLoggedIn, logout, startMatrixClient, onLoggedOut
};
116 changes: 43 additions & 73 deletions src/components/structures/MatrixChat.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,30 +65,24 @@ module.exports = React.createClass({

getInitialState: function() {
var s = {
loading: true,
screen: undefined,

// If we are viewing a room by alias, this contains the alias
currentRoomAlias: null,

// The ID of the room we're viewing. This is either populated directly
// in the case where we view a room by ID or by RoomView when it resolves
// what ID an alias points at.
currentRoomId: null,
logged_in: !!(MatrixClientPeg.get() && MatrixClientPeg.get().credentials),
logged_in: false,
collapse_lhs: false,
collapse_rhs: false,
ready: false,
width: 10000,
sideOpacity: 1.0,
middleOpacity: 1.0,
};
if (s.logged_in) {
if (MatrixClientPeg.get().getRooms().length) {
s.page_type = this.PageTypes.RoomView;
} else {
// we don't need to default to the directoy here
// as we'll go there anyway after syncing
// s.page_type = this.PageTypes.RoomDirectory;
}
}
return s;
},

Expand Down Expand Up @@ -153,59 +147,15 @@ module.exports = React.createClass({
},

componentDidMount: function() {
let clientStarted = false;

this._autoRegisterAsGuest = false;
if (this.props.enableGuest) {
if (!this.getCurrentHsUrl()) {
console.error("Cannot enable guest access: can't determine HS URL to use");
}
else if (this.props.startingQueryParams.client_secret && this.props.startingQueryParams.sid) {
console.log("Not registering as guest; registration.");
this._autoRegisterAsGuest = false;
}
else if (this.props.startingQueryParams.guest_user_id &&
this.props.startingQueryParams.guest_access_token)
{
this._autoRegisterAsGuest = false;
Lifecycle.setLoggedIn({
userId: this.props.startingQueryParams.guest_user_id,
accessToken: this.props.startingQueryParams.guest_access_token,
homeserverUrl: this.getDefaultHsUrl(),
identityServerUrl: this.getDefaultIsUrl(),
guest: true
});
clientStarted = true;
}
else {
this._autoRegisterAsGuest = true;
}
}

this.dispatcherRef = dis.register(this.onAction);
if (this.state.logged_in) {
// 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;
if (!clientStarted) {
Lifecycle.startMatrixClient();
}
}

this.focusComposer = false;
// scrollStateMap is a map from room id to the scroll state returned by
// RoomView.getScrollState()
this.scrollStateMap = {};
document.addEventListener("keydown", this.onKeyDown);
window.addEventListener("focus", this.onFocus);

if (this.state.logged_in) {
this.notifyNewScreen('');
} else if (this._autoRegisterAsGuest) {
this._registerAsGuest();
} else {
this.notifyNewScreen('login');
}

// this can technically be done anywhere but doing this here keeps all
// the routing url path logic together.
if (this.onAliasClick) {
Expand All @@ -217,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() {
Expand All @@ -243,7 +204,6 @@ module.exports = React.createClass({
MatrixClientPeg.replaceUsingUrls(hsUrl, isUrl);
MatrixClientPeg.get().registerGuest().done(function(creds) {
console.log("Registered as guest: %s", creds.user_id);
self._setAutoRegisterAsGuest(false);
Lifecycle.setLoggedIn({
userId: creds.user_id,
accessToken: creds.access_token,
Expand All @@ -260,15 +220,9 @@ module.exports = React.createClass({
});
}
console.error("Failed to register as guest: " + err + " " + err.data);
self._setAutoRegisterAsGuest(false);
});
},

_setAutoRegisterAsGuest: function(shouldAutoRegister) {
this._autoRegisterAsGuest = shouldAutoRegister;
this.forceUpdate();
},

onAction: function(payload) {
var roomIndexDelta = 1;

Expand Down Expand Up @@ -479,6 +433,9 @@ module.exports = React.createClass({
case 'will_start_client':
this._onWillStartClient();
break;
case 'load_completed':
this._onLoadCompleted();
break;
}
},

Expand Down Expand Up @@ -589,6 +546,13 @@ module.exports = React.createClass({
this.scrollStateMap[roomId] = state;
},

/**
* Called when the sessionloader has finished
*/
_onLoadCompleted: function() {
this.setState({loading: false});
},

/**
* Called when a new logged in session has started
*/
Expand Down Expand Up @@ -1029,8 +993,19 @@ module.exports = React.createClass({

// work out the HS URL prompts we should show for

// console.log("rendering; loading="+this.state.loading+"; screen="+this.state.screen +
// "; logged_in="+this.state.logged_in+"; ready="+this.state.ready);

if (this.state.loading) {
var Spinner = sdk.getComponent('elements.Spinner');
return (
<div className="mx_MatrixChat_splash">
<Spinner />
</div>
);
}
// needs to be before normal PageTypes as you are logged in technically
if (this.state.screen == 'post_registration') {
else if (this.state.screen == 'post_registration') {
return (
<PostRegistration
onComplete={this.onFinishPostRegistration} />
Expand Down Expand Up @@ -1101,20 +1076,15 @@ module.exports = React.createClass({
</div>
</div>
);
} else if (this.state.logged_in || (!this.state.logged_in && this._autoRegisterAsGuest)) {
} else if (this.state.logged_in) {
// we think we are logged in, but are still waiting for the /sync to complete
var Spinner = sdk.getComponent('elements.Spinner');
var logoutLink;
if (this.state.logged_in) {
logoutLink = (
<a href="#" className="mx_MatrixChat_splashButtons" onClick={ this.onLogoutClick }>
Logout
</a>
);
}
return (
<div className="mx_MatrixChat_splash">
<Spinner />
{logoutLink}
<a href="#" className="mx_MatrixChat_splashButtons" onClick={ this.onLogoutClick }>
Logout
</a>
</div>
);
} else if (this.state.screen == 'register') {
Expand Down
Loading