Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix locking race condition #557

Closed
wants to merge 1 commit into from
Closed
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
28 changes: 14 additions & 14 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -595,10 +595,10 @@ function logger(type, message) {
const clients = new Set();

// Used to broadcast messages to all connected clients
function broadcastToClients(message){
function broadcastToClients(message) {
const payload = JSON.stringify(message);
clients.forEach((client) => {
if(client.readyState === WebSocket.OPEN){
if (client.readyState === (process.env.SERVER_CURR_ENV !== '#{CURR_ENV}#' ? WebSocket.OPEN : 1)) {
logger('INFO', `Payload sent to the client`);
client.send(payload);
}
Expand All @@ -614,7 +614,7 @@ wss.on('connection', (ws) => {
// { uuid: <uuid>, lock: false }
ws.on('message', function (msg) {
const message = JSON.parse(msg);
const {uuid, lock} = message;
const { uuid, lock } = message;

if (!uuid) {
ws.send(JSON.stringify({ status: 'fail', message: 'UUID not provided.' }));
Expand All @@ -639,10 +639,10 @@ wss.on('connection', (ws) => {
ws.uuid = uuid;
ws.send(JSON.stringify({ status: 'success', secret }));

broadcastToClients({
type:'lock',
uuid,
});
/* broadcastToClients({
type: 'lock',
uuid
}); */
}
} else {
// Attempting to unlock a different storyline, other than the one this connection has locked, so do not allow.
Expand All @@ -662,10 +662,10 @@ wss.on('connection', (ws) => {
delete ws.uuid;
ws.send(JSON.stringify({ status: 'success' }));

broadcastToClients({
type:'unlock',
uuid,
});
/* broadcastToClients({
type: 'unlock',
uuid
}); */
}
}
});
Expand All @@ -678,10 +678,10 @@ wss.on('connection', (ws) => {
if (currentLock) {
logger('INFO', `Releasing lock on storyline ${ws.uuid} after connection closed`);
delete lockedUuids[ws.uuid];
broadcastToClients({
/* broadcastToClients({
type: 'unlock',
uuid: ws.uuid,
});
uuid: ws.uuid
}); */
}
}

Expand Down
17 changes: 8 additions & 9 deletions src/stores/lockStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ export const useLockStore = defineStore('lock', {
result: {} as any,
broadcast: undefined as BroadcastChannel | undefined,
confirmationTimeout: undefined as NodeJS.Timeout | undefined, // the timer to show the session extension confirmation modal
endTimeout: undefined as NodeJS.Timeout | undefined, // the timer to kill the session due to timeout
endTimeout: undefined as NodeJS.Timeout | undefined // the timer to kill the session due to timeout
}),
actions: {
// Opens a connection with the web socket
initConnection() {
return new Promise((resolve) => {
return new Promise<void>((resolve) => {
const socketUrl = `${
import.meta.env.VITE_APP_CURR_ENV ? import.meta.env.VITE_APP_API_URL : 'http://localhost:6040'
}`;
Expand All @@ -37,7 +37,7 @@ export const useLockStore = defineStore('lock', {
};
});
},
// Attempts to lock a storyline for this user.
// Attempts to lock a storyline for this user.
// Returns a promise that resolves if the lock was successfully fetched and rejects if it was not.
async lockStoryline(uuid: string): Promise<void> {
// Stop the previous storyline's timer
Expand All @@ -50,21 +50,19 @@ export const useLockStore = defineStore('lock', {

return new Promise((resolve, reject) => {
this.received = false;
this.socket?.send(JSON.stringify({ uuid, lock: true }));

const handleMessage = (event: MessageEvent) => {
const data = JSON.parse(event.data);

if(data !== undefined){
if(data.status === 'fail'){
if (data !== undefined) {
if (data.status === 'fail') {
this.socket!.removeEventListener('message', handleMessage);
reject(new Error(data.message || 'Failed to lock storyline.'));
}
else if (data.status === 'success') {
} else if (data.status === 'success') {
this.socket!.removeEventListener('message', handleMessage);

this.uuid = uuid;
this.secret = data.secret;
this.secret = data.secret;
this.broadcast = new BroadcastChannel(data.secret);

resolve();
Expand All @@ -73,6 +71,7 @@ export const useLockStore = defineStore('lock', {
};

this.socket!.addEventListener('message', handleMessage);
this.socket?.send(JSON.stringify({ uuid, lock: true }));
});
},
// Unlocks the curent storyline for this user. Only to be called on session end.
Expand Down
Loading