Files
zyrarbot/frontend/src/composables/useBotStatus.ts
T

107 lines
2.7 KiB
TypeScript

import { onUnmounted, ref } from 'vue'
import type { BotStatus } from '@/types/status'
import { getGuildId, setGuildId } from '@/api/client'
const RECONNECT_DELAY_MS = 3000
const status = ref<BotStatus | null>(null)
const connected = ref(false)
/** Wstrzymuje przyjmowanie aktualizacji, gdy użytkownik przeciąga utwory. */
const paused = ref(false)
const pendingTracks = ref<{ id: string; guildId: string; title: string }[]>([])
let socket: WebSocket | null = null
let reconnectTimer: number | null = null
let subscribers = 0
/** Jedno połączenie WebSocket na aplikację, niezależnie od liczby komponentów. */
export function useBotStatus() {
function open() {
const scheme = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
const guild = getGuildId()
const currentSocket = new WebSocket(
`${scheme}//${window.location.host}/ws${guild ? `?guild_id=${guild}` : ''}`,
)
socket = currentSocket
currentSocket.onopen = () => {
connected.value = true
}
currentSocket.onmessage = (event) => {
if (socket !== currentSocket) return
if (paused.value) return
try {
status.value = JSON.parse(event.data) as BotStatus
} catch (error) {
console.error('Błąd parsowania danych z WS:', error)
}
}
currentSocket.onclose = () => {
if (socket !== currentSocket) return
connected.value = false
socket = null
if (subscribers > 0) {
reconnectTimer = window.setTimeout(open, RECONNECT_DELAY_MS)
}
}
currentSocket.onerror = () => currentSocket.close()
}
function connect() {
subscribers += 1
if (!socket) open()
}
function disconnect() {
subscribers = Math.max(0, subscribers - 1)
if (subscribers > 0) return
if (reconnectTimer !== null) {
window.clearTimeout(reconnectTimer)
reconnectTimer = null
}
socket?.close()
socket = null
}
function selectGuild(guildId: string) {
setGuildId(guildId)
if (reconnectTimer !== null) {
window.clearTimeout(reconnectTimer)
reconnectTimer = null
}
if (socket) {
const previousSocket = socket
socket = null
previousSocket.close()
open()
}
}
function addPendingTrack(guildId: string, title: string) {
const id = `pending-${Date.now()}-${Math.random().toString(36).slice(2)}`
pendingTracks.value.push({ id, guildId, title })
return id
}
function removePendingTrack(id: string) {
pendingTracks.value = pendingTracks.value.filter((track) => track.id !== id)
}
onUnmounted(disconnect)
return {
status,
connected,
paused,
pendingTracks,
connect,
disconnect,
selectGuild,
addPendingTrack,
removePendingTrack,
}
}