| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- 'use client';
- import { useEffect, useRef, useState, useCallback } from 'react';
- import * as signalR from '@microsoft/signalr';
- import { DonationAlertData, DonationRemoteState } from '@/types/donation';
- type AlertQueueItem = DonationAlertData & { status: 'queued'|'playing'|'done' };
- export function useDonationAlert(widgetToken: string, hubUrl: string) {
- const connectionRef = useRef<signalR.HubConnection|null>(null);
- const [connected, setConnected] = useState(false);
- const [queue, setQueue] = useState<AlertQueueItem[]>([]);
- const [current, setCurrent] = useState<AlertQueueItem|null>(null);
- const [remoteState, setRemoteState] = useState<DonationRemoteState>({
- isPaused: false,
- isAccepting: true,
- isAudioOnly: false,
- isVideoOnly: false
- });
- const [skipSignal, setSkipSignal] = useState(0);
- // SignalR 연결
- useEffect(() => {
- const conn = new signalR.HubConnectionBuilder()
- .withUrl(hubUrl)
- .withAutomaticReconnect()
- .build();
- conn.on('ReceiveAlert', (data: DonationAlertData) => {
- setQueue(prev => [...prev, { ...data, status: 'queued' }]);
- });
- conn.on('ReceiveSkip', () => {
- setSkipSignal(prev => prev + 1);
- });
- conn.on('ReceivePause', (isPaused: boolean) => {
- setRemoteState(prev => ({ ...prev, isPaused }));
- });
- conn.on('ReceiveState', (state: DonationRemoteState) => {
- setRemoteState(state);
- });
- conn.start().then(() => {
- conn.invoke('JoinChannel', widgetToken);
- setConnected(true);
- }).catch(err => {
- console.error('[DonationHub] Connect failed:', err);
- });
- conn.onreconnected(() => {
- conn.invoke('JoinChannel', widgetToken);
- setConnected(true);
- });
- conn.onclose(() => setConnected(false));
- connectionRef.current = conn;
- return () => {
- conn.stop();
- };
- }, [widgetToken, hubUrl]);
- // 큐 처리 — 일시정지가 아닐 때 다음 알림 꺼내기
- useEffect(() => {
- if (current || remoteState.isPaused || queue.length === 0) {
- return;
- }
- const next = queue[0];
- setQueue(prev => prev.slice(1));
- setCurrent({ ...next, status: 'playing' });
- // 알림 재생 시작 보고
- connectionRef.current?.invoke('AlertDelivered', next.alertID).catch(() => {});
- }, [queue, current, remoteState.isPaused]);
- // 스킵 시그널 처리
- useEffect(() => {
- if (skipSignal > 0 && current) {
- setCurrent(null);
- }
- }, [skipSignal]);
- // 알림 완료 콜백
- const onAlertComplete = useCallback(() => {
- setCurrent(null);
- }, []);
- return {
- connected,
- current,
- queue,
- remoteState,
- skipSignal,
- onAlertComplete
- };
- }
|