Skip to content

Commit

Permalink
Wait briefly for a broadcast message before attempting to connect (th…
Browse files Browse the repository at this point in the history
  • Loading branch information
lgrahl authored Dec 18, 2019
1 parent 2c24cd6 commit dfdf4a6
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 18 deletions.
69 changes: 54 additions & 15 deletions src/partials/welcome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import GlobalConnectionState = threema.GlobalConnectionState;
import DisconnectReason = threema.DisconnectReason;

class WelcomeController {
private static BROADCAST_DELAY = 100;
private static REDIRECT_DELAY = 500;

// Angular services
Expand Down Expand Up @@ -262,18 +263,33 @@ class WelcomeController {
resume: false,
});

// Set up the broadcast channel that checks whether we're already connected in another tab
this.setupBroadcastChannel(this.webClientService.salty.keyStore.publicKeyHex);

// Initialize QR code params
this.$scope.$watch(() => this.password, () => {
const payload = this.webClientService.buildQrCodePayload(this.password.length > 0);
this.qrCode = this.buildQrCode(payload);
this.passwordStrength = scorePassword(this.password);
});

// Start webclient
this.start();
// Set up the broadcast channel that checks whether we're already connected in another tab
this.setupBroadcastChannel(this.webClientService.salty.keyStore.publicKeyHex, 0)
.then((result) => {
this.$scope.$apply(() => {
switch (result) {
case 'already_open':
this.log.warn('Session already connected in another tab or window');
break;
case 'no_answer':
this.start();
break;
}
});
})
.catch((error) => {
this.$scope.$apply(() => {
this.log.warn('Unable to set up broadcast channel:', error);
this.start();
});
});
}

/**
Expand Down Expand Up @@ -301,24 +317,43 @@ class WelcomeController {
const keyStore = new saltyrtcClient.KeyStore(decrypted.ownSecretKey);

// Set up the broadcast channel that checks whether we're already connected in another tab
this.setupBroadcastChannel(keyStore.publicKeyHex);

// Reconnect
this.reconnect(keyStore, decrypted);
this.setupBroadcastChannel(keyStore.publicKeyHex, WelcomeController.BROADCAST_DELAY)
.then((result) => {
this.$scope.$apply(() => {
switch (result) {
case 'already_open':
this.log.warn('Session already connected in another tab or window');
break;
case 'no_answer':
this.log.debug('No broadcast received indicating that a session is already open');
this.reconnect(keyStore, decrypted);
break;
}
});
})
.catch((error) => {
this.$scope.$apply(() => {
this.log.warn('Unable to set up broadcast channel:', error);
this.reconnect(keyStore, decrypted);
});
});
}

/**
* Set up a `BroadcastChannel` to check if there are other tabs running on
* the same session.
* the same session. Resolves when either an `already_connected` message has
* been received or a timeout of `delayMs` has been elapsed.
*
* The `publicKeyHex` parameter is the hex-encoded public key of the keystore
* used to establish the SaltyRTC connection.
*/
private setupBroadcastChannel(publicKeyHex: string) {
private setupBroadcastChannel(publicKeyHex: string, delayMs: number): Future<'already_open' | 'no_answer'> {
const future: Future<'already_open' | 'no_answer'> = new Future();

// Check for broadcast support in the browser
if (!('BroadcastChannel' in this.$window)) {
// No BroadcastChannel support in this browser
this.log.warn('BroadcastChannel not supported in this browser');
return;
future.reject('BroadcastChannel not supported in this browser');
return future;
}

// Config constants
Expand Down Expand Up @@ -351,7 +386,7 @@ class WelcomeController {
// Another tab notified us that the session we're trying to connect to
// is already active.
if (message.key === publicKeyHex && this.stateService.connectionBuildupState !== 'done') {
this.log.error('Session already connected in another tab or window');
future.resolve('already_open');
this.timeoutService.register(() => {
this.stateService.updateConnectionBuildupState('already_connected');
this.stateService.state = GlobalConnectionState.Error;
Expand All @@ -370,6 +405,10 @@ class WelcomeController {
type: TYPE_PUBLIC_KEY,
key: publicKeyHex,
}));

// Resolve after the specified delay without an `already_connected` response
setTimeout(() => future.resolve('no_answer'), delayMs);
return future;
}

/**
Expand Down
7 changes: 4 additions & 3 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"compilerOptions": {
"target": "ES2017",
"module": "esNext",
"moduleResolution": "node",
"lib": ["DOM", "ESNext"],
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Node",
"removeComments": true
},
"exclude": [
Expand Down

0 comments on commit dfdf4a6

Please sign in to comment.