slit server source & client source

This commit is contained in:
SrGooglo 2025-03-26 10:55:51 +00:00
parent 7136402109
commit 0a11a24460
45 changed files with 230 additions and 9 deletions

21
client/package.json Normal file
View File

@ -0,0 +1,21 @@
{
"name": "linebridge-client",
"version": "0.2.0",
"main": "./dist/index.js",
"author": "RageStudio <support@ragestudio.net>",
"license": "MIT",
"files": [
"src/**/**",
"dist/**/**",
"./package.json"
],
"publishConfig": {
"access": "public"
},
"scripts": {
"build": "hermes build --parallel --clean"
},
"devDependencies": {
"@ragestudio/hermes": "^1.0.0"
}
}

1
client/src/index.js Normal file
View File

@ -0,0 +1 @@
export { default as RTEngineClient } from "./rtengine"

View File

@ -0,0 +1,149 @@
import TopicsController from "./topics"
export class RTEngineClient {
constructor(params = {}) {
this.params = {
maxConnectRetries: 3,
...params,
}
}
state = {
id: null,
connected: false,
}
socket = null
handlers = new Set()
topics = new TopicsController(this)
async connect() {
if (this.socket) {
await this.disconnect()
}
let url = `${this.params.url}`
if (this.params.token) {
url += `?token=${this.params.token}`
}
this.socket = new WebSocket(url)
this.socket.onopen = (e) => this.#handleOpen(e)
this.socket.onclose = (e) => this.#handleClose(e)
this.socket.onerror = (e) => this.#handleError(e)
this.socket.onmessage = (e) => this.#handleMessage(e)
return new Promise((resolve, reject) => {
this.once("connected", resolve)
})
}
async disconnect() {
if (!this.socket) {
return false
}
this.topics.unsubscribeAll()
this.socket.close()
this.socket = null
}
on = (event, handler) => {
this.handlers.add({
event,
handler,
})
}
off = (event, handler) => {
this.handlers.delete({
event,
handler,
})
}
once = (event, handler) => {
this.handlers.add({
event,
handler,
once: true,
})
}
emit = async (event, data) => {
if (!this.socket) {
throw new Error("Failed to send, socket not connected")
}
return await this.socket.send(JSON.stringify({ event, data }))
}
#_decode(payload) {
return JSON.parse(payload)
}
//* HANDLERS
#handleMessage(event) {
try {
const payload = this.#_decode(event.data)
if (typeof payload.event !== "string") {
throw new Error("Invalid event or payload")
}
return this.#dispatchToHandlers(payload.event, payload.data)
} catch (error) {
console.error("Error handling message:", error)
}
}
#handleClose() {
this.state.connected = false
this.#dispatchToHandlers("disconnect")
}
#handleOpen() {
this.state.connected = true
this.#dispatchToHandlers("connect")
}
#handleError(error) {
console.error("WebSocket connection error:", error)
this.#dispatchToHandlers("error")
}
baseHandlers = {
connected: (data) => {
this.state.connected = true
if (data.id) {
this.state.id = data.id
}
},
error: (error) => {
console.error(error)
},
}
async #dispatchToHandlers(event, data) {
if (this.baseHandlers[event]) {
await this.baseHandlers[event](data)
}
for (const handler of this.handlers) {
if (handler.event === event) {
handler.handler(data)
if (handler.once === true) {
this.handlers.delete(handler)
}
}
}
}
}
export default RTEngineClient

View File

@ -0,0 +1,31 @@
class TopicsController {
constructor(client) {
this.client = client
}
subscribed = new Set()
subscribe = async (topic) => {
await this.client.emit("topic:subscribe", topic)
this.subscribed.add(topic)
return true
}
unsubscribe = async (topic) => {
await this.client.emit("topic:unsubscribe", topic)
this.subscribed.delete(topic)
return true
}
unsubscribeAll = async () => {
for (const topic of this.subscribed) {
await this.leave(topic)
}
return true
}
}
export default TopicsController

View File

@ -4,7 +4,7 @@ class Client {
this.id = socket.context.id this.id = socket.context.id
this.userId = socket.context.user?._id || null this.userId = socket.context.user?._id || null
this.authed = !!socket.context.session this.autheticated = !!socket.context.session
} }
emit(event, data) { emit(event, data) {
@ -36,10 +36,12 @@ class Client {
} }
subscribe(topic) { subscribe(topic) {
this.emit("topic:subscribed", topic)
return this.socket.subscribe(topic) return this.socket.subscribe(topic)
} }
unsubscribe(topic) { unsubscribe(topic) {
this.emit("topic:unsubscribed", topic)
return this.socket.unsubscribe(topic) return this.socket.unsubscribe(topic)
} }
} }

View File

@ -0,0 +1,20 @@
import { performance } from "node:perf_hooks"
export default {
"server:ping": async (client, data) => {
const pongTime = performance.now()
return {
ping: data.ping ?? 0,
pong: pongTime,
latency: Number(pongTime - data.ping),
latencyMs: Number(pongTime - data.ping).toFixed(2),
}
},
"topic:subscribe": async (client, topic) => {
client.subscribe(topic)
},
"topic:unsubscribe": async (client, topic) => {
client.unsubscribe(topic)
},
}

View File

@ -104,6 +104,11 @@ class RTEngineNG {
const client = new Client(socket) const client = new Client(socket)
await client.emit("connected", {
id: client.id,
autheticated: client.autheticated,
})
this.clients.set(socket.context.id, client) this.clients.set(socket.context.id, client)
} }

BIN
src/.DS_Store vendored

Binary file not shown.

View File

@ -1,8 +0,0 @@
export default {
"topic:join": async (client, topic) => {
client.subscribe(topic)
},
"topic:leave": async (client, topic) => {
client.unsubscribe(topic)
},
}