添加signal

main
落雨楓 5 months ago
parent a966aa9378
commit 5d7f192b45

@ -10,12 +10,7 @@ var router *gin.Engine
func init() {
serverOpts := socket.DefaultServerOptions()
csrOpts := &socket.ConnectionStateRecovery{}
csrOpts.SetMaxDisconnectionDuration(2 * 60 * 1000) // 2 minutes
csrOpts.SetSkipMiddlewares(true)
serverOpts.SetConnectionStateRecovery(csrOpts)
serverOpts.SetConnectionStateRecovery(nil)
server = socket.NewServer(nil, serverOpts)

@ -0,0 +1,52 @@
import { useMemo, useRef, useState } from "react";
export interface SignalWrapper<T> {
value: T;
setValue: (value: T) => void;
update: () => void;
}
export function useSignal<T>(): SignalWrapper<T | undefined>;
export function useSignal<T>(initialValue: T): SignalWrapper<T>;
export function useSignal<T>(initialValue?: T): SignalWrapper<T | undefined> {
const $value = useRef<T | undefined>(initialValue);
const [_, updateState] = useState(0);
return useMemo(() => {
const setValue = (value: T | undefined) => {
$value.current = value;
updateState((prev) => prev + 1);
};
const update = () => {
updateState((prev) => prev + 1);
};
const proxy: SignalWrapper<T | undefined> = new Proxy({} as SignalWrapper<T | undefined>, {
get(_, prop) {
if (prop === 'value') {
return $value.current;
}
if (prop === 'setValue') {
return setValue;
}
if (prop === 'update') {
return update;
}
// 处理其他可能的属性访问
return undefined;
},
set(_, prop, value) {
if (prop === 'value') {
$value.current = value;
// 避免直接调用 update而是直接更新状态
updateState((prev) => prev + 1);
return true;
}
return false;
}
});
return proxy;
}, [updateState]);
}

@ -2,6 +2,7 @@ import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@radix-ui/react-label'
import { Inter } from 'next/font/google'
import Head from 'next/head'
import { useRouter } from 'next/router'
import { useState } from 'react'
@ -25,6 +26,9 @@ export default function Home() {
<main
className={`${inter.className}`}
>
<Head>
<title></title>
</Head>
<div className='flex justify-center items-center h-screen'>
<form className='flex flex-col gap-3' onSubmit={onSubmit}>
<Label className='font-bold text-center'></Label>

@ -8,18 +8,20 @@ import { ClientMessage, RoomStateChangedMessage, ServerMessage, UserJoinLeaveMes
import { $playerState, $userInfo, $userStatus } from '@/store/player'
import { useStore } from '@nanostores/react'
import { useRouter } from 'next/router'
import { useCallback, useEffect, useState } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import "@radix-ui/themes/components/tabs"
import { Label } from '@/components/ui/label'
import { useSignal } from '@/lib/signal'
import Head from 'next/head'
export default function Page() {
const router = useRouter()
const userInfo = useStore($userInfo)
const playerState = useStore($playerState)
const [joinRole, setJoinRole] = useState<string>('user')
const [urlInput, setUrlInput] = useState<string | undefined>()
const [isRoomEmpty, setIsRoomEmpty] = useState(false)
const [isJoined, setIsJoined] = useState(false)
const joinRole = useSignal<string>('user')
const urlInput = useSignal<string | undefined>()
const isRoomEmpty = useSignal(false)
const isJoined = useSignal(false)
const roomName = router.query.room as string
@ -34,12 +36,12 @@ export default function Page() {
function onRoomInfo(d: any) {
const msg = d as RoomStateChangedMessage
if (!msg.userStatus || msg.userStatus.length === 0) {
setIsRoomEmpty(true)
setJoinRole('admin')
isRoomEmpty.value = true
joinRole.value = 'admin'
return
} else {
setIsRoomEmpty(false)
setJoinRole('user')
isRoomEmpty.value = false
joinRole.value = 'user'
}
$userStatus.set([
@ -53,7 +55,7 @@ export default function Page() {
if (!msg.userInfo) {
return
}
setIsJoined(true)
isJoined.value = true
$userInfo.set({
...$userInfo.value,
isAdmin: msg.userInfo.isAdmin,
@ -62,6 +64,10 @@ export default function Page() {
console.log('$userInfo', $userInfo.value)
}
function onSetUrl(d: any) {
}
socket.on('connect', onConnect)
socket.on('roomInfo', onRoomInfo)
socket.on('joined', onJoined)
@ -80,35 +86,38 @@ export default function Page() {
const handleJoinClick = useCallback(() => {
socket.connect()
socket.emit('join', {
username: userInfo?.username,
username: $userInfo.value?.username,
room: roomName,
password: userInfo?.password,
password: $userInfo.value?.password,
} as ClientMessage)
}, [userInfo, roomName])
}, [roomName])
const handleSetUrlClick = useCallback(() => {
$playerState.set({ ...$playerState.value, url: urlInput })
$playerState.set({ ...$playerState.value, url: urlInput.value })
socket.emit('setUrl', {
room: roomName,
username: userInfo?.username,
url: urlInput
username: $userInfo.value?.username,
url: urlInput.value,
} as ClientMessage)
}, [roomName, userInfo, urlInput])
}, [])
const isAllowedLogin = useCallback(() => {
if (isJoined) {
if (isJoined.value) {
return false
}
if (joinRole === 'admin' && !userInfo?.password) {
if (joinRole.value === 'admin' && !$userInfo.value?.password) {
return false
}
return userInfo?.username && userInfo.username.length > 0
}, [joinRole, isJoined, userInfo])
return $userInfo.value?.username && $userInfo.value.username.length > 0
}, [])
return (
<div className='flex flex-col lg:flex-row m-2 justify-center'>
{isJoined && <div className='w-full lg:mr-2'>
<Head>
<title>{roomName} | </title>
</Head>
{isJoined.value && <div className='w-full lg:mr-2'>
<Player roomName={roomName} />
</div>}
<div className='w-full lg:w-[450px] mb-1 border rounded'>
@ -117,12 +126,12 @@ export default function Page() {
<div className='flex flex-row gap-4 items-center'>
<Badge className='!px-2 !py-1 mt-1'></Badge>
<Tabs.Root value={joinRole} onValueChange={setJoinRole}>
<Tabs.Root value={joinRole.value} onValueChange={joinRole.setValue}>
<Tabs.List size="1">
<Tabs.Trigger
value="user"
disabled={isRoomEmpty}
title={isRoomEmpty ? '创建房间必须使用房管身份' : undefined}>
disabled={isRoomEmpty.value}
title={isRoomEmpty.value ? '创建房间必须使用房管身份' : undefined}>
</Tabs.Trigger>
<Tabs.Trigger value="admin"></Tabs.Trigger>
@ -132,51 +141,51 @@ export default function Page() {
</div>
{roomName && <div className='m-2 flex flex-row gap-2'>
<Input
value={userInfo?.username ?? ""}
onChange={(e) => {
$userInfo.set({
...userInfo,
...$userInfo.value,
username: e.target.value
})
}}
value={userInfo?.username ?? ""}
placeholder='你的用户名'
name='username'
disabled={isJoined}
disabled={isJoined.value}
/>
{joinRole == 'admin' && (
{joinRole.value == 'admin' && (
<Input
placeholder='管理密码'
value={userInfo?.password ?? ""}
onChange={(e) => {
$userInfo.set({
...userInfo,
...$userInfo.value,
password: e.target.value,
})
}}
value={userInfo?.password ?? ""}
type='password'
name='password'
disabled={isJoined}
disabled={isJoined.value}
/>
)}
<Button
onClick={handleJoinClick}
disabled={!isAllowedLogin()}
>{isRoomEmpty ? "创建房间" : "加入房间"}</Button>
>{isRoomEmpty.value ? "创建房间" : "加入房间"}</Button>
</div>}
{isJoined && userInfo?.isAdmin && <div className='m-2 flex flex-row gap-2'>
{isJoined.value && userInfo?.isAdmin && <div className='m-2 flex flex-row gap-2'>
<Input
name='videoUrl'
type='url'
value={urlInput}
autoComplete='url'
value={urlInput.value}
onChange={(e) => {
setUrlInput(e.target.value)
urlInput.value = e.target.value
}}
autoComplete='url'
placeholder='视频直链'
/>
<Button onClick={handleSetUrlClick} ></Button>
<Button onClick={handleSetUrlClick}></Button>
</div>}
{roomName && <UserList roomName={roomName} />}
</div>

@ -0,0 +1,3 @@
- [ ] 手机端播放器问题
- [ ] 自动重连后没有join的问题
- [ ] 播放结束后没有停止计时
Loading…
Cancel
Save