mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 10:34:17 +00:00
185 lines
5.6 KiB
JavaScript
185 lines
5.6 KiB
JavaScript
import buildFunctionHandler from "@utils/buildFunctionHandler"
|
|
import { Snowflake } from "nodejs-snowflake"
|
|
|
|
import { ChatMessage } from "@db_models"
|
|
|
|
export default class Room {
|
|
constructor(io, roomID, options) {
|
|
if (!io) {
|
|
throw new OperationError(500, "io is required")
|
|
}
|
|
|
|
this.io = io
|
|
|
|
if (!roomID) {
|
|
throw new OperationError(500, "roomID is required")
|
|
}
|
|
|
|
this.roomID = `room:${roomID}`
|
|
this.roomSocket = this.io.to(`room:${this.roomID}`)
|
|
this.options = {
|
|
owner_user_id: null,
|
|
...options,
|
|
}
|
|
}
|
|
|
|
connections = new Set()
|
|
|
|
limitations = {
|
|
maxMessageLength: 540,
|
|
}
|
|
|
|
roomEvents = {
|
|
"room:change:owner": async (client, payload) => {
|
|
throw new OperationError(500, "Not implemented")
|
|
},
|
|
"room:send:message": async (client, payload) => {
|
|
console.log(`[${this.roomID}] [@${client.userData.username}] sent message >`, payload)
|
|
|
|
let { message } = payload
|
|
|
|
if (!message || typeof message !== "string") {
|
|
throw new Error("Invalid message")
|
|
}
|
|
|
|
if (message.length > this.limitations.maxMessageLength) {
|
|
message = message.substring(0, this.limitations.maxMessageLength)
|
|
}
|
|
|
|
const created_at = new Date().getTime()
|
|
|
|
const id = `msg:${client.userData._id}:${created_at}`
|
|
|
|
this.handlers.broadcastToMembers("room:message", {
|
|
_id: id,
|
|
timestamp: payload.timestamp ?? Date.now(),
|
|
content: String(message),
|
|
user: {
|
|
user_id: client.userData._id,
|
|
username: client.userData.username,
|
|
fullName: client.userData.fullName,
|
|
avatar: client.userData.avatar,
|
|
},
|
|
})
|
|
|
|
if (payload.route) {
|
|
const routeValues = payload.route.split(":")
|
|
|
|
console.log(routeValues)
|
|
|
|
if (routeValues.length > 0) {
|
|
const [type, to_id] = routeValues
|
|
|
|
switch (type) {
|
|
case "user": {
|
|
const doc = await ChatMessage.create({
|
|
type: type,
|
|
from_user_id: client.userData._id,
|
|
to_user_id: to_id,
|
|
content: message,
|
|
created_at: created_at,
|
|
})
|
|
|
|
console.log(doc)
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
handlers = {
|
|
join: (client) => {
|
|
if (client.connectedRoomID) {
|
|
console.warn(`[${client.id}][@${client.userData.username}] already connected to room ${client.connectedRoomID}`)
|
|
|
|
client.leave(client.connectedRoomID)
|
|
}
|
|
|
|
console.log(`[${client.id}][@${client.userData.username}] joined room ${this.roomID}`)
|
|
|
|
client.connectedRoomID = this.roomID
|
|
|
|
this.connections.add(client)
|
|
|
|
for (let [event, handler] of Object.entries(this.roomEvents)) {
|
|
handler = buildFunctionHandler(handler, client)
|
|
|
|
if (!Array.isArray(client.handlers)) {
|
|
client.handlers = []
|
|
}
|
|
|
|
client.handlers.push([event, handler])
|
|
|
|
client.on(event, handler)
|
|
}
|
|
|
|
// emit to self
|
|
client.emit("room:joined", {
|
|
roomID: this.roomID,
|
|
limitations: this.limitations,
|
|
connectedUsers: this.getConnectedUsers(),
|
|
})
|
|
|
|
// emit to others
|
|
this.roomSocket.emit("room:user:joined", {
|
|
user: {
|
|
user_id: client.userData._id,
|
|
username: client.userData.username,
|
|
fullName: client.userData.fullName,
|
|
avatar: client.userData.avatar,
|
|
}
|
|
})
|
|
},
|
|
leave: (client) => {
|
|
if (!client.connectedRoomID) {
|
|
console.warn(`[${client.id}][@${client.userData.username}] not connected to any room`)
|
|
return
|
|
}
|
|
|
|
if (client.connectedRoomID !== this.roomID) {
|
|
console.warn(`[${client.id}][@${client.userData.username}] not connected to room ${this.roomID}, cannot leave`)
|
|
return false
|
|
}
|
|
|
|
this.connections.delete(client)
|
|
|
|
client.emit("room:left", {
|
|
room: this.roomID,
|
|
})
|
|
|
|
this.roomSocket.emit("room:user:left", {
|
|
user: {
|
|
user_id: client.userData._id,
|
|
username: client.userData.username,
|
|
fullName: client.userData.fullName,
|
|
avatar: client.userData.avatar,
|
|
}
|
|
})
|
|
|
|
for (const [event, handler] of client.handlers) {
|
|
client.off(event, handler)
|
|
}
|
|
|
|
console.log(`[${client.id}][@${client.userData.username}] left room ${this.roomID}`)
|
|
},
|
|
broadcastToMembers: (event, payload) => {
|
|
for (const client of this.connections) {
|
|
client.emit(event, payload)
|
|
}
|
|
}
|
|
}
|
|
|
|
getConnectedUsers = () => {
|
|
let users = {}
|
|
|
|
for (const client of this.connections) {
|
|
users[client.userData._id] = client.userData
|
|
}
|
|
|
|
return users
|
|
}
|
|
} |