-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathplayer-cache.ts
92 lines (77 loc) · 3.07 KB
/
player-cache.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import { AudioPlayer, AudioPlayerStatus, createAudioPlayer, PlayerSubscription, VoiceConnection } from "@discordjs/voice";
import { Snowflake } from "discord.js";
import log from "loglevel"
type ConnectionInfo = {subscription: PlayerSubscription, disconnectTimer?: NodeJS.Timeout}
export class PlayerCache {
private readonly availablePlayers: Array<AudioPlayer> = [];
private totalPlayers = 0
private readonly activeConnections: Map<Snowflake | null, ConnectionInfo> = new Map();
constructor(
public readonly maxPlayers: number,
public readonly disconnectTimeoutMs: number) {
}
acquire(connection: VoiceConnection): AudioPlayer | null {
log.info(`PlayerCache stats: created ${this.totalPlayers} available: ${this.availablePlayers.length}, channels: ${this.activeConnections.size}`)
const channelId = connection.joinConfig.channelId
if (!channelId) {
throw new Error("Connection is missing channelId");
}
const existingSubscription = this.activeConnections.get(channelId);
const player = existingSubscription?.subscription?.player || this.getPlayer();
if (!player) {
return null;
}
if (existingSubscription?.disconnectTimer) {
clearTimeout(existingSubscription.disconnectTimer);
delete existingSubscription.disconnectTimer;
}
const subscription = connection.subscribe(player)
if (!subscription) {
this.availablePlayers.push(player);
throw new Error("Failed to create player subscription. ChannelID:" + connection.joinConfig.channelId);
}
if (!existingSubscription) {
this.activeConnections.set(channelId, {subscription})
}
return player
}
private release(subscription: PlayerSubscription) {
this.availablePlayers.push(subscription.player);
this.activeConnections.delete(subscription.connection.joinConfig.channelId);
}
private getPlayer(): AudioPlayer | undefined {
if (this.availablePlayers.length > 0) {
return this.availablePlayers.shift()
}
if (this.totalPlayers < this.maxPlayers) {
this.totalPlayers++;
return this.createPlayer();
}
return undefined;
}
private createPlayer() {
const player = createAudioPlayer();
player.on("error", log.warn);
player.on("unsubscribe", (e) => this.release(e));
player.on("stateChange", (oldState, newState) => {
if (newState.status === AudioPlayerStatus.Idle) {
(player["subscribers"] as PlayerSubscription[]).forEach(subscription => {
const connectionInfo = this.activeConnections.get(subscription.connection.joinConfig.channelId);
if (connectionInfo) {
this.resetDisconnectionTimer(connectionInfo)
}
});
}
});
return player;
}
private resetDisconnectionTimer(connectionInfo: ConnectionInfo) {
if (connectionInfo.disconnectTimer) {
clearTimeout(connectionInfo.disconnectTimer);
}
connectionInfo.disconnectTimer = setTimeout(() => {
connectionInfo.subscription.unsubscribe();
connectionInfo.subscription.connection.disconnect();
}, this.disconnectTimeoutMs);
}
}