feat: Enhance LoginComponent and SocketManager for improved session management and reauthentication
This commit is contained in:
@@ -9,9 +9,82 @@ class SocketManager {
|
||||
this.on = this.on.bind(this);
|
||||
this.off = this.off.bind(this);
|
||||
this.connectPromise = null;
|
||||
this.reauthPromise = null;
|
||||
this.pendingListeners = new Map();
|
||||
}
|
||||
|
||||
_getStoredUser() {
|
||||
const storedUser = sessionStorage.getItem('user');
|
||||
if (!storedUser) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(storedUser);
|
||||
} catch (error) {
|
||||
console.error('Failed to parse stored user for socket reauth:', error);
|
||||
sessionStorage.removeItem('user');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
_buildSocketAuth() {
|
||||
const token = sessionStorage.getItem('authToken');
|
||||
const user = this._getStoredUser();
|
||||
if (!token && !user) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Provide both nested and flat shapes for backend compatibility.
|
||||
return {
|
||||
token,
|
||||
user,
|
||||
userId: user ? user.id : undefined,
|
||||
email: user ? user.email : undefined
|
||||
};
|
||||
}
|
||||
|
||||
_reauthenticate() {
|
||||
if (!this._socket || !this._socket.connected) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const token = sessionStorage.getItem('authToken');
|
||||
if (!token) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (this.reauthPromise) {
|
||||
return this.reauthPromise;
|
||||
}
|
||||
|
||||
this.reauthPromise = new Promise((resolve) => {
|
||||
let settled = false;
|
||||
const done = () => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
this.reauthPromise = null;
|
||||
resolve();
|
||||
};
|
||||
|
||||
// Don't block emits indefinitely if backend ignores this event.
|
||||
const timeoutId = setTimeout(done, 800);
|
||||
|
||||
this._socket.emit('verifyToken', { token }, (response) => {
|
||||
clearTimeout(timeoutId);
|
||||
if (response && response.success && response.user) {
|
||||
sessionStorage.setItem('user', JSON.stringify(response.user));
|
||||
}
|
||||
if (response && response.success && response.token) {
|
||||
sessionStorage.setItem('authToken', response.token);
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
return this.reauthPromise;
|
||||
}
|
||||
|
||||
// Lazily import socket.io-client and create the socket on first use.
|
||||
// Subsequent calls return the same promise.
|
||||
_ensureSocket() {
|
||||
@@ -22,6 +95,20 @@ class SocketManager {
|
||||
this._socket = io('', {
|
||||
transports: ['websocket', 'polling'],
|
||||
autoConnect: false,
|
||||
withCredentials: true,
|
||||
auth: this._buildSocketAuth()
|
||||
});
|
||||
|
||||
// Always refresh auth data before reconnect attempts.
|
||||
if (this._socket.io && this._socket.io.on) {
|
||||
this._socket.io.on('reconnect_attempt', () => {
|
||||
this._socket.auth = this._buildSocketAuth();
|
||||
});
|
||||
}
|
||||
|
||||
// Re-authenticate every time a new socket connection is established.
|
||||
this._socket.on('connect', () => {
|
||||
this.reauthPromise = this._reauthenticate();
|
||||
});
|
||||
|
||||
// Register any listeners that arrived before the socket was ready
|
||||
@@ -81,9 +168,12 @@ class SocketManager {
|
||||
this.connectPromise = this._ensureSocket().then(
|
||||
(socket) =>
|
||||
new Promise((resolve, reject) => {
|
||||
socket.auth = this._buildSocketAuth();
|
||||
socket.connect();
|
||||
socket.once('connect', () => {
|
||||
resolve();
|
||||
this._reauthenticate()
|
||||
.then(() => resolve())
|
||||
.catch(() => resolve());
|
||||
});
|
||||
socket.once('connect_error', (error) => {
|
||||
this.connectPromise = null;
|
||||
@@ -112,8 +202,16 @@ class SocketManager {
|
||||
reject(error);
|
||||
});
|
||||
} else {
|
||||
socket.emit(event, ...args);
|
||||
resolve();
|
||||
const emitNow = () => {
|
||||
socket.emit(event, ...args);
|
||||
resolve();
|
||||
};
|
||||
|
||||
if (this.reauthPromise) {
|
||||
this.reauthPromise.then(emitNow).catch(emitNow);
|
||||
} else {
|
||||
emitNow();
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(reject);
|
||||
|
||||
Reference in New Issue
Block a user