chore: online user count

This commit is contained in:
molvqingtai 2024-09-18 06:07:20 +08:00
parent 3d45e4609c
commit ad2278f5ba
5 changed files with 106 additions and 9 deletions

View file

@ -1,14 +1,11 @@
import { type ReactNode, type FC } from 'react'
import useResizable from '@/hooks/useResizable'
import useBreakpoint from '@/hooks/useBreakpoint'
export interface AppContainerProps {
children?: ReactNode
}
const AppContainer: FC<AppContainerProps> = ({ children }) => {
const { breakpoint } = useBreakpoint()
console.log(breakpoint)
const { size, ref } = useResizable({
initSize: Math.max(375, window.innerWidth / 5),
maxSize: Math.max(750, window.innerWidth / 3),

View file

@ -4,9 +4,13 @@ import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/Avatar'
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/HoverCard'
import { Button } from '@/components/ui/Button'
import { getSiteInfo } from '@/utils'
import { useRemeshDomain, useRemeshQuery } from 'remesh-react'
import RoomDomain from '@/domain/Room'
const Header: FC = () => {
const siteInfo = getSiteInfo()
const roomDomain = useRemeshDomain(RoomDomain())
const peerList = useRemeshQuery(roomDomain.query.PeerListQuery())
return (
<div className="z-10 grid h-12 grid-flow-col items-center justify-between gap-x-4 rounded-t-xl bg-white px-4 backdrop-blur-lg">
@ -41,7 +45,7 @@ const Header: FC = () => {
</div>
</HoverCardContent>
</HoverCard>
<div className="text-sm text-slate-500">Online 99</div>
<div className="text-sm text-slate-500">Online {peerList.length}</div>
</div>
)
}

View file

@ -41,6 +41,19 @@ const RoomDomain = Remesh.domain({
const peerRoom = domain.getExtern(PeerRoomExtern)
peerRoom.joinRoom(hostRoomId)
const PeersListState = domain.state<string[]>({
name: 'Room.PeersListState',
default: [peerRoom.selfId]
})
const MessageListQuery = messageListDomain.query.ListQuery
const PeerListQuery = domain.query({
name: 'Room.PeerListQuery',
impl: ({ get }) => {
return get(PeersListState())
}
})
const SendTextMessageCommand = domain.command({
name: 'RoomSendTextMessageCommand',
impl: ({ get }, message: string) => {
@ -113,6 +126,21 @@ const RoomDomain = Remesh.domain({
name: 'RoomSendHateMessageEvent'
})
const JoinRoomEvent = domain.event<string>({
name: 'RoomJoinRoomEvent'
})
const LeaveRoomEvent = domain.event<string>({
name: 'RoomLeaveRoomEvent'
})
const SyncPeersListCommand = domain.command({
name: 'RoomSyncPeersListCommand',
impl: (_, list: string[]) => {
return [PeersListState().new(list)]
}
})
domain.effect({
name: 'RoomSendTextMessageEffect',
impl: ({ fromEvent }) => {
@ -200,11 +228,40 @@ const RoomDomain = Remesh.domain({
}
})
domain.effect({
name: 'RoomOnJoinRoomEffect',
impl: ({ get }) => {
const onJoinRoom$ = callbackToObservable<string>(peerRoom.onJoinRoom.bind(peerRoom))
return onJoinRoom$.pipe(
map((peerId) => {
return [SyncPeersListCommand([...get(PeersListState()), peerId]), JoinRoomEvent(peerId)]
})
)
}
})
domain.effect({
name: 'RoomOnLeaveRoomEffect',
impl: ({ get }) => {
const onLeaveRoom$ = callbackToObservable<string>(peerRoom.onLeaveRoom.bind(peerRoom))
return onLeaveRoom$.pipe(
map((peerId) => {
return [SyncPeersListCommand(get(PeersListState()).filter((id) => id !== peerId)), LeaveRoomEvent(peerId)]
})
)
}
})
return {
query: {
PeerListQuery,
MessageListQuery
},
event: {
SendTextMessageEvent,
SendLikeMessageEvent,
SendHateMessageEvent
SendHateMessageEvent,
JoinRoomEvent,
LeaveRoomEvent
},
command: {
SendTextMessageCommand,

View file

@ -4,14 +4,19 @@ import { type Promisable } from 'type-fest'
export type PeerMessage = object | Blob | ArrayBuffer | ArrayBufferView
export interface PeerRoom {
readonly selfId: string
joinRoom: (roomId: string) => Promise<any>
sendMessage: <T extends PeerMessage>(message: T) => Promise<any>
onMessage: <T extends PeerMessage>(callback: (message: T) => void) => Promisable<void>
leaveRoom: () => Promisable<void>
onJoinRoom: (callback: (id: string) => void) => Promisable<void>
onLeaveRoom: (callback: (id: string) => void) => Promisable<void>
getRoomPeers: () => string[]
}
export const PeerRoomExtern = Remesh.extern<PeerRoom>({
default: {
selfId: '',
joinRoom: async () => {
throw new Error('"joinRoom" not implemented.')
},
@ -23,6 +28,15 @@ export const PeerRoomExtern = Remesh.extern<PeerRoom>({
},
leaveRoom: () => {
throw new Error('"leaveRoom" not implemented.')
},
onJoinRoom: () => {
throw new Error('"onJoinRoom" not implemented.')
},
onLeaveRoom: () => {
throw new Error('"onLeaveRoom" not implemented.')
},
getRoomPeers: () => {
throw new Error('"getRoomPeers" not implemented.')
}
}
})

View file

@ -1,4 +1,4 @@
import { type DataPayload, type Room, joinRoom } from 'trystero'
import { type DataPayload, type Room, joinRoom, selfId } from 'trystero'
// import { joinRoom } from 'trystero/firebase'
import { PeerRoomExtern, type PeerMessage } from '@/domain/externs/PeerRoom'
@ -11,17 +11,21 @@ export interface Config {
class PeerRoom {
readonly appId: string
room: Room | null
readonly selfId: string
constructor(config: Config) {
this.appId = config.appId
this.room = null
this.selfId = selfId
}
async joinRoom(roomId: string) {
this.room = joinRoom({ appId: this.appId }, roomId)
this.room?.onPeerJoin((peerId) => console.log(`${peerId} joined`))
this.room?.onPeerJoin((peerId) => {
console.log(`${peerId} joined`)
console.log(this.room?.getPeers())
})
this.room?.onPeerLeave((peerId) => console.log(`${peerId} leaved`))
console.log(this.room.getPeers())
return this.room
}
@ -42,6 +46,27 @@ class PeerRoom {
on((message) => callback(message as T))
}
onJoinRoom(callback: (id: string) => void) {
if (!this.room) {
throw new Error('Room not joined')
}
this.room.onPeerJoin((peerId) => callback(peerId))
}
onLeaveRoom(callback: (id: string) => void) {
if (!this.room) {
throw new Error('Room not joined')
}
this.room.onPeerLeave((peerId) => callback(peerId))
}
getRoomPeers() {
if (!this.room) {
throw new Error('Room not joined')
}
return Object.keys(this.room.getPeers()).map((id) => id)
}
async leaveRoom() {
return await this.room?.leave()
}