import MWSEEventTarget from './EventTarget.js'; import { RoomInfo } from './RoomInfo.js'; export default class Room extends MWSEEventTarget { constructor(mwse) { super(); this.mwse = mwse; this.peers = new Map(); this.info = new RoomInfo(this); this.options = undefined; this.config = undefined; this.roomId = undefined; this.accessType = undefined; this.joinType = undefined; this.name = undefined; this.owner = undefined; } setRoomOptions(options) { if (typeof options === 'string') { this.roomId = options; } else { const defaults = { joinType: 'free', ifexistsJoin: true, accessType: 'private', notifyActionInvite: true, notifyActionJoined: true, notifyActionEjected: true, autoFetchInfo: true }; this.config = Object.assign(defaults, options); } } setRoomId(uuid) { this.roomId = uuid; } async createRoom(roomOptions) { const config = this.config || roomOptions; const result = await this.mwse.EventPooling.request({ type: 'create-room', ...config }); if (result.status === 'fail') { if (result.message === 'ALREADY-EXISTS' && this.config?.ifexistsJoin) { return this.join(); } throw new Error(result.message || result.messages); } this.options = { ...this.config, ...result.room }; this.roomId = result.room.id; this.mwse.rooms.set(this.roomId, this); } async join() { const result = await this.mwse.EventPooling.request({ type: 'joinroom', name: this.config.name, credential: this.config.credential, autoFetchInfo: this.config.autoFetchInfo || false }); if (result.status === 'fail') throw new Error(result.message); this.options = { ...this.config, ...result.room }; if (result.info) this.info.info = result.info; this.roomId = result.room.id; this.mwse.rooms.set(this.roomId, this); } async eject() { const { type } = await this.mwse.EventPooling.request({ type: 'ejectroom', roomId: this.roomId }); this.peers.clear(); if (type === 'success') this.mwse.rooms.delete(this.roomId); } async send(pack, wom = false, handshake = false) { if (!this.mwse.writable) { console.warn('MWSE: socket is not writable'); return; } if (handshake) { const { type } = await this.mwse.EventPooling.request({ type: 'pack/room', pack, to: this.roomId, wom, handshake }); if (type === 'fail') throw new Error('Cannot send message to room'); } else { // WOM broadcast — fire-and-forget, no waiter (#33). this.mwse.EventPooling.only({ type: 'pack/room', pack, to: this.roomId, wom, handshake }); } } async fetchPeers(filter, onlyNumber = false) { if (onlyNumber) { const { count } = await this.mwse.EventPooling.request({ type: 'room/peer-count', roomId: this.roomId, filter: filter || {} }); return count; } const { status, peers } = await this.mwse.EventPooling.request({ type: 'room-peers', roomId: this.roomId, filter: filter || {} }); if (status === 'fail') throw new Error('Cannot fetch peers from room'); const result = []; for (const peerId of peers) { const peer = this.mwse.peer(peerId, true); result.push(peer); this.peers.set(peerId, peer); } return result; } }