Skip to content

Commit 82645cc

Browse files
committed
feat(connection): Adds token refresh and cancel resume.
1 parent a189bca commit 82645cc

File tree

6 files changed

+153
-59
lines changed

6 files changed

+153
-59
lines changed

JitsiConference.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4435,7 +4435,14 @@ export default class JitsiConference extends Listenable {
44354435
*/
44364436
public joinLobby(displayName: string, email: string): Promise<void> {
44374437
if (this.room) {
4438-
return this.room.getLobby().join(displayName, email);
4438+
if (!this.room.getLobby()?.lobbyRoom?.joined) {
4439+
return this.room.getLobby().join(displayName, email);
4440+
} else {
4441+
logger.warn('Already joined the lobby');
4442+
4443+
return Promise.resolve();
4444+
}
4445+
44394446
}
44404447

44414448
return Promise.reject(new Error('The conference not started'));

JitsiConnection.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,17 @@ export default class JitsiConnection {
156156
* This method allows renewal of the tokens if they are expiring.
157157
* @param token - The new token.
158158
*/
159-
setToken(token: string): void {
159+
refreshToken(token: string): Promise<void> {
160160
this.token = token;
161+
162+
return this._xmpp.refreshToken(this.token);
163+
}
164+
165+
/**
166+
* Cancels the connection resume process if it is in progress.
167+
*/
168+
cancelResume() {
169+
this.xmpp.cancelResume();
161170
}
162171

163172
/**

JitsiConnectionEvents.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ export enum JitsiConnectionEvents {
4040
*/
4141
CONNECTION_REDIRECTED = 'connection.redirected',
4242

43+
/**
44+
* The connection will try to resume.
45+
*/
46+
CONNECTION_RESUMING = 'connection.resuming',
47+
4348
/**
4449
* Indicates that the display name is required over this connection and need to be supplied when
4550
* joining the room.
@@ -59,5 +64,6 @@ export const CONNECTION_DISCONNECTED = JitsiConnectionEvents.CONNECTION_DISCONNE
5964
export const CONNECTION_ESTABLISHED = JitsiConnectionEvents.CONNECTION_ESTABLISHED;
6065
export const CONNECTION_FAILED = JitsiConnectionEvents.CONNECTION_FAILED;
6166
export const CONNECTION_REDIRECTED = JitsiConnectionEvents.CONNECTION_REDIRECTED;
67+
export const CONNECTION_RESUMING = JitsiConnectionEvents.CONNECTION_RESUMING;
6268
export const DISPLAY_NAME_REQUIRED = JitsiConnectionEvents.DISPLAY_NAME_REQUIRED;
6369
export const PROPERTIES_UPDATED = JitsiConnectionEvents.PROPERTIES_UPDATED;

modules/xmpp/ResumeTask.ts

Lines changed: 41 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -55,40 +55,64 @@ export default class ResumeTask {
5555
}
5656

5757
/**
58-
* Cancels the delayed resume task.
58+
* Removes network online listener for the NETWORK_INFO_EVENT event.
5959
*
6060
* @private
6161
* @returns {void}
6262
*/
63-
private _cancelResume(): void {
63+
private _removeNetworkOnlineListener(): void {
64+
if (this._networkOnlineListener) {
65+
this._networkOnlineListener();
66+
this._networkOnlineListener = null;
67+
}
68+
}
69+
70+
/**
71+
* Schedules a delayed timeout which will execute the resume action.
72+
* @private
73+
* @returns {void}
74+
*/
75+
private _scheduleResume(): void {
6476
if (this._resumeTimeout) {
65-
logger.info('Canceling connection resume task');
66-
clearTimeout(this._resumeTimeout);
67-
this._resumeTimeout = undefined;
68-
this._retryDelay = undefined;
77+
// NO-OP
78+
return;
6979
}
80+
81+
// The retry delay will be:
82+
// 1st retry: 1.5s - 3s
83+
// 2nd retry: 3s - 9s
84+
// 3rd and next retry: 4.5s - 27s
85+
this._retryDelay = getJitterDelay(
86+
/* retry */ this._resumeRetryN,
87+
/* minDelay */ this._resumeRetryN * 1500,
88+
3
89+
);
90+
91+
logger.info(`Will try to resume the XMPP connection in ${this.retryDelay}ms`);
92+
93+
this._resumeTimeout = setTimeout(() => this.resumeConnection(), this.retryDelay);
7094
}
7195

7296
/**
73-
* Removes network online listener for the NETWORK_INFO_EVENT event.
97+
* Cancels the delayed resume task.
7498
*
75-
* @private
7699
* @returns {void}
77100
*/
78-
private _removeNetworkOnlineListener(): void {
79-
if (this._networkOnlineListener) {
80-
this._networkOnlineListener();
81-
this._networkOnlineListener = null;
101+
cancelResume(): void {
102+
if (this._resumeTimeout) {
103+
logger.info('Canceling connection resume task');
104+
clearTimeout(this._resumeTimeout);
105+
this._resumeTimeout = undefined;
106+
this._retryDelay = undefined;
82107
}
83108
}
84109

85110
/**
86111
* Resumes the XMPP connection using the stream management plugin.
87112
*
88-
* @private
89113
* @returns {void}
90114
*/
91-
private _resumeConnection(): void {
115+
resumeConnection(): void {
92116
this._resumeTimeout = undefined;
93117

94118
const { streamManagement } = this._stropheConn;
@@ -126,40 +150,14 @@ export default class ResumeTask {
126150
}
127151
}
128152

129-
/**
130-
* Schedules a delayed timeout which will execute the resume action.
131-
* @private
132-
* @returns {void}
133-
*/
134-
private _scheduleResume(): void {
135-
if (this._resumeTimeout) {
136-
// NO-OP
137-
return;
138-
}
139-
140-
// The retry delay will be:
141-
// 1st retry: 1.5s - 3s
142-
// 2nd retry: 3s - 9s
143-
// 3rd and next retry: 4.5s - 27s
144-
this._retryDelay = getJitterDelay(
145-
/* retry */ this._resumeRetryN,
146-
/* minDelay */ this._resumeRetryN * 1500,
147-
3
148-
);
149-
150-
logger.info(`Will try to resume the XMPP connection in ${this.retryDelay}ms`);
151-
152-
this._resumeTimeout = setTimeout(() => this._resumeConnection(), this.retryDelay);
153-
}
154-
155153
/**
156154
* Cancels the retry task. It's called by {@link XmppConnection} when it's no longer interested in reconnecting for
157155
* example when the disconnect method is called.
158156
*
159157
* @returns {void}
160158
*/
161159
cancel(): void {
162-
this._cancelResume();
160+
this.cancelResume();
163161
this._removeNetworkOnlineListener();
164162
this._resumeRetryN = 0;
165163
}
@@ -170,7 +168,7 @@ export default class ResumeTask {
170168
* @returns {void}
171169
*/
172170
schedule(): void {
173-
this._cancelResume();
171+
this.cancelResume();
174172
this._removeNetworkOnlineListener();
175173

176174
this._resumeRetryN += 1;
@@ -181,7 +179,7 @@ export default class ResumeTask {
181179
if (isOnline) {
182180
this._scheduleResume();
183181
} else {
184-
this._cancelResume();
182+
this.cancelResume();
185183
}
186184
}
187185
) as () => void;

modules/xmpp/XmppConnection.ts

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,15 @@ interface IInternalOptions {
8282
websocketKeepAliveUrl?: string;
8383
}
8484

85+
const TOKEN_REFRESH = 'token_refresh';
86+
87+
/**
88+
* Adds one more status to Strophe.Status enum.
89+
*/
90+
enum ExtendedStatus {
91+
RESUMING = 15
92+
}
93+
8594
/**
8695
* The lib-jitsi-meet layer for {@link Strophe.Connection}.
8796
* @internal
@@ -128,7 +137,7 @@ export default class XmppConnection extends Listenable {
128137
* @returns {Strophe.Status}
129138
*/
130139
static get Status() {
131-
return Strophe.Status;
140+
return { ...Strophe.Status, ...ExtendedStatus };
132141
}
133142

134143
/**
@@ -395,8 +404,6 @@ export default class XmppConnection extends Listenable {
395404
_stropheConnectionCb(targetCallback: IConnectionStatusCallback, status: Strophe.Status, condition?: string, element?: Element): void {
396405
this._status = status;
397406

398-
let blockCallback = false;
399-
400407
if (status === Strophe.Status.CONNECTED || status === Strophe.Status.ATTACHED) {
401408
this._maybeEnableStreamResume();
402409

@@ -421,17 +428,24 @@ export default class XmppConnection extends Listenable {
421428
} else if (status === Strophe.Status.DISCONNECTED) {
422429
this.ping.stopInterval();
423430

424-
// FIXME add RECONNECTING state instead of blocking the DISCONNECTED update
425-
blockCallback = this._tryResumingConnection();
426-
if (!blockCallback) {
427-
clearTimeout(this._wsKeepAlive);
431+
// if resumption is scheduled skip disconnecting state event fire
432+
if (this._tryResumingConnection(condition === TOKEN_REFRESH)) {
433+
434+
if (condition !== TOKEN_REFRESH) {
435+
// let's fire event that status changed to resuming
436+
// we do not fire it on refresh, as consumers should get
437+
// the event and execute refresh with a new token
438+
this.eventEmitter.emit(XmppConnection.Events.CONN_STATUS_CHANGED, ExtendedStatus.RESUMING);
439+
}
440+
441+
return;
428442
}
429-
}
430443

431-
if (!blockCallback) {
432-
targetCallback(status, condition, element);
433-
this.eventEmitter.emit(XmppConnection.Events.CONN_STATUS_CHANGED, status);
444+
clearTimeout(this._wsKeepAlive);
434445
}
446+
447+
targetCallback(status, condition, element);
448+
this.eventEmitter.emit(XmppConnection.Events.CONN_STATUS_CHANGED, status);
435449
}
436450

437451
/**
@@ -758,14 +772,22 @@ export default class XmppConnection extends Listenable {
758772
* the token is present it means the connection can be resumed.
759773
*
760774
* @private
761-
* @returns {boolean}
775+
* @returns {boolean} - Whether a resume attempt was scheduled or executed.
762776
*/
763-
_tryResumingConnection(): boolean {
777+
_tryResumingConnection(force = false): boolean {
764778
const { streamManagement } = this._stropheConn;
765779
const resumeToken = streamManagement?.getResumeToken();
766780

767781
if (resumeToken) {
768-
this._resumeTask.schedule();
782+
if (force) {
783+
logger.info('Trying to resume XMPP connection immediately due to token refresh');
784+
785+
this._resumeTask.resumeConnection();
786+
787+
return true;
788+
} else {
789+
this._resumeTask.schedule();
790+
}
769791

770792
const r = this._resumeTask.retryCount <= MAX_CONNECTION_RETRIES;
771793

@@ -778,4 +800,34 @@ export default class XmppConnection extends Listenable {
778800

779801
return false;
780802
}
803+
804+
/**
805+
* This method allows renewal of the tokens if they are expiring.
806+
* @param token - The new token.
807+
*/
808+
refreshToken(serviceUrl: string): Promise<void> {
809+
this._stropheConn.service = serviceUrl;
810+
811+
// this will trigger a resume
812+
this._stropheConn._doDisconnect(TOKEN_REFRESH);
813+
814+
return new Promise((resolve, reject) => {
815+
const handler = status => {
816+
if (status === Strophe.Status.CONNECTED && this._stropheConn.restored) {
817+
resolve();
818+
}
819+
};
820+
821+
this.addCancellableListener(XmppConnection.Events.CONN_STATUS_CHANGED, handler);
822+
823+
setTimeout(() => {
824+
this.removeListener(XmppConnection.Events.CONN_STATUS_CHANGED, handler);
825+
reject();
826+
}, 3000);
827+
});
828+
}
829+
830+
cancelResume() {
831+
this._resumeTask.cancelResume();
832+
}
781833
}

modules/xmpp/xmpp.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,12 @@ export default class XMPP extends Listenable {
368368
}
369369
});
370370

371+
this.connection.on(XmppConnection.Events.CONN_STATUS_CHANGED, status => {
372+
if (status === XmppConnection.Status.RESUMING) {
373+
this.eventEmitter.emit(JitsiConnectionEvents.CONNECTION_RESUMING);
374+
}
375+
});
376+
371377
this._initStrophePlugins();
372378

373379
this.caps = new Caps(this.connection, /* clientNode */ 'https://jitsi.org/jitsi-meet');
@@ -1334,4 +1340,20 @@ export default class XMPP extends Listenable {
13341340

13351341
return false;
13361342
}
1343+
1344+
/**
1345+
* This method allows renewal of the tokens if they are expiring.
1346+
* @param token - The new token.
1347+
*/
1348+
refreshToken(token: string): Promise<void> {
1349+
let serviceUrl = this.options.serviceUrl;
1350+
1351+
serviceUrl += `${serviceUrl.indexOf('?') === -1 ? '?' : '&'}token=${token}`;
1352+
1353+
return this.connection.refreshToken(serviceUrl);
1354+
}
1355+
1356+
cancelResume() {
1357+
this.connection.cancelResume();
1358+
}
13371359
}

0 commit comments

Comments
 (0)