Skip to content

Commit f5789d3

Browse files
committed
Improve player lock mechanism with expiration
Added a lockedAt timestamp to the Player class and enhanced the lock method to automatically expire locks after 20 seconds. This prevents the player from remaining locked indefinitely due to unexpected errors or missed unlocks.
1 parent a505252 commit f5789d3

File tree

1 file changed

+22
-6
lines changed

1 file changed

+22
-6
lines changed

src/Core/GTATunesPlayer.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import {
1818
randomNumber,
1919
registerDiscordEvent,
2020
requireActivePlayer,
21-
songToOpus
21+
songToOpus,
22+
unix
2223
} from './functions';
2324
import {
2425
ComponentType,
@@ -127,6 +128,7 @@ export class Player extends EventEmitter<PlayerEventMap> {
127128
private _currentSeeked: number = 0;
128129
private destroying: boolean = false;
129130
private locked: boolean = false;
131+
private lockedAt: number | null = null;
130132
private autoplay: boolean = false;
131133

132134
constructor(
@@ -288,7 +290,9 @@ export class Player extends EventEmitter<PlayerEventMap> {
288290
return;
289291
}
290292

291-
await this.playSong('next');
293+
this.lock(async () => {
294+
await this.playSong('next');
295+
}).catch(() => null);
292296
});
293297

294298
this.on('play', () => {
@@ -719,13 +723,24 @@ export class Player extends EventEmitter<PlayerEventMap> {
719723
* @param action The action to execute while the player is locked.
720724
* @param interaction Optional Discord interaction for error handling.
721725
* @throws {LockedPlayerError} if the player is already locked and no interaction is provided.
722-
* @returns The result of the action or null if handled via interaction.
726+
* @returns Whether the player was successfully locked and the action executed.
723727
*/
724728
async lock(
725729
action: () => PossiblyAsync<void>,
726730
interaction?: Interaction
727731
): Promise<boolean> {
728-
if (this.locked) {
732+
let isLocked = this.isLocked;
733+
const lockedAt = this.lockedAt;
734+
this.locked = true;
735+
this.lockedAt = unix();
736+
737+
if (lockedAt !== null && isLocked && (unix() - (lockedAt ?? 0) > 20)) {
738+
gtaTunesLog('PLAYER', `Player lock in guild ${p.magenta(this.guild.name)} (${p.magenta(this.guild.id)}) has expired, forcing unlock.`);
739+
isLocked = false;
740+
this.lockedAt = null;
741+
}
742+
743+
if (isLocked) {
729744
gtaTunesLog(
730745
'PLAYER',
731746
`Player in guild ${p.magenta(this.guild.name)} (${p.magenta(this.guild.id)}) is already locked.`
@@ -743,16 +758,16 @@ export class Player extends EventEmitter<PlayerEventMap> {
743758
'PLAYER',
744759
`Locking player in ${p.magenta(this.guild.name)} (${p.magenta(this.guild.id)}).`
745760
);
746-
this.locked = true;
747761

748762
try {
749763
await action();
750764
} catch (e) {
751765
gtaTunesLog(
752766
'PLAYER',
753-
`Unlocking player in ${p.magenta(this.guild.name)} (${p.magenta(this.guild.id)}).`
767+
`Unlocking player in ${p.magenta(this.guild.name)} (${p.magenta(this.guild.id)}) after failing action.`
754768
);
755769
this.locked = false;
770+
this.lockedAt = null;
756771
throw e;
757772
}
758773

@@ -761,6 +776,7 @@ export class Player extends EventEmitter<PlayerEventMap> {
761776
`Unlocking player in ${p.magenta(this.guild.name)} (${p.magenta(this.guild.id)}).`
762777
);
763778
this.locked = false;
779+
this.lockedAt = null;
764780

765781
return true;
766782
}

0 commit comments

Comments
 (0)