support on exit

This commit is contained in:
SrGooglo 2025-02-26 20:24:50 +00:00
parent d7fa42e53d
commit 4fe16f1a81
3 changed files with 620 additions and 525 deletions

View File

@ -11,11 +11,23 @@ export default class RTEngineServer {
this.clusterMode = !!cluster.isWorker this.clusterMode = !!cluster.isWorker
this.redisConnParams = { this.redisConnParams = {
host: this.params.redisOptions?.host ?? process.env.REDIS_HOST ?? "localhost", host:
port: this.params.redisOptions?.port ?? process.env.REDIS_PORT ?? 6379, this.params.redisOptions?.host ??
username: this.params.redisOptions?.username ?? (process.env.REDIS_AUTH && process.env.REDIS_AUTH.split(":")[0]), process.env.REDIS_HOST ??
password: this.params.redisOptions?.password ?? (process.env.REDIS_AUTH && process.env.REDIS_AUTH.split(":")[1]), "localhost",
db: this.params.redisOptions?.db ?? process.env.REDIS_DB ?? 0 port:
this.params.redisOptions?.port ??
process.env.REDIS_PORT ??
6379,
username:
this.params.redisOptions?.username ??
(process.env.REDIS_AUTH &&
process.env.REDIS_AUTH.split(":")[0]),
password:
this.params.redisOptions?.password ??
(process.env.REDIS_AUTH &&
process.env.REDIS_AUTH.split(":")[1]),
db: this.params.redisOptions?.db ?? process.env.REDIS_DB ?? 0,
} }
this.redis = params.redis this.redis = params.redis
@ -43,14 +55,18 @@ export default class RTEngineServer {
if (!this.redis) { if (!this.redis) {
this.redis = new redis({ this.redis = new redis({
lazyConnect: true,
host: this.redisConnParams.host, host: this.redisConnParams.host,
port: this.redisConnParams.port, port: this.redisConnParams.port,
username: this.redisConnParams.username, username: this.redisConnParams.username,
password: this.redisConnParams.password, password: this.redisConnParams.password,
db: this.redisConnParams.db, db: this.redisConnParams.db,
maxRetriesPerRequest: null,
}) })
} }
await this.redis.connect()
// create mappers // create mappers
this.connections = new RedisMap(this.redis, { this.connections = new RedisMap(this.redis, {
refKey: "connections", refKey: "connections",
@ -63,7 +79,10 @@ export default class RTEngineServer {
}) })
// register middlewares // register middlewares
if (typeof this.middlewares === "object" && Array.isArray(this.middlewares)) { if (
typeof this.middlewares === "object" &&
Array.isArray(this.middlewares)
) {
for (const middleware of this.middlewares) { for (const middleware of this.middlewares) {
this.io.use(middleware) this.io.use(middleware)
} }
@ -111,6 +130,7 @@ export default class RTEngineServer {
// register events // register events
if (typeof this.events === "object") { if (typeof this.events === "object") {
console.log("registering events", this.events)
for (const [key, handler] of this.events.entries()) { for (const [key, handler] of this.events.entries()) {
socket.on(key, (...args) => { socket.on(key, (...args) => {
this.eventHandler(handler, socket, ...args) this.eventHandler(handler, socket, ...args)
@ -131,19 +151,29 @@ export default class RTEngineServer {
await this.connections.set(socket.id, socket) await this.connections.set(socket.id, socket)
if (this.params.requireAuth) { if (this.params.requireAuth) {
await this.onAuth(socket, null, (this.params.handleAuth ?? this.handleAuth)) await this.onAuth(
socket,
null,
this.params.handleAuth ?? this.handleAuth,
)
} else if (socket.handshake.auth.token ?? socket.handshake.query.auth) { } else if (socket.handshake.auth.token ?? socket.handshake.query.auth) {
await this.onAuth(socket, (socket.handshake.auth.token ?? socket.handshake.query.auth), (this.params.handleAuth ?? this.handleAuth)) await this.onAuth(
socket,
socket.handshake.auth.token ?? socket.handshake.query.auth,
this.params.handleAuth ?? this.handleAuth,
)
} }
} }
onDisconnect = async (socket,) => { onDisconnect = async (socket) => {
console.log(`[RTEngine] disconnect:client | id [${socket.id}]`) console.log(`[RTEngine] disconnect:client | id [${socket.id}]`)
if (socket.eventBus.emit) { if (socket.eventBus.emit) {
socket.eventBus.emit("disconnect") socket.eventBus.emit("disconnect")
} else { } else {
console.warn(`[${socket.id}][@${socket.userData.username}] Cannot emit disconnect event`) console.warn(
`[${socket.id}][@${socket.userData.username}] Cannot emit disconnect event`,
)
} }
const conn = await this.connections.get(socket.id) const conn = await this.connections.get(socket.id)
@ -173,7 +203,10 @@ export default class RTEngineServer {
} }
function err(code, message) { function err(code, message) {
console.log(`[RTEngine] [${socket.id}] Auth error: ${code} >`, message) console.log(
`[RTEngine] [${socket.id}] Auth error: ${code} >`,
message,
)
socket.emit("response:error", { socket.emit("response:error", {
code, code,
@ -207,7 +240,9 @@ export default class RTEngineServer {
socket.emit("response:auth:ok") socket.emit("response:auth:ok")
console.log(`[RTEngine] client:authenticated | socket_id [${socket.id}] | user_id [${authResult.user_id}] | username [@${authResult.username}]`) console.log(
`[RTEngine] client:authenticated | socket_id [${socket.id}] | user_id [${authResult.user_id}] | username [@${authResult.username}]`,
)
} }
} }
@ -236,9 +271,7 @@ export default class RTEngineServer {
return users return users
}, },
userBySocket: (socket_id) => { userBySocket: (socket_id) => {},
},
userById: async (user_id) => { userById: async (user_id) => {
const user = await this.users.get(user_id) const user = await this.users.get(user_id)
@ -254,6 +287,6 @@ export default class RTEngineServer {
const socket = await this.connections.get(user.socket_id) const socket = await this.connections.get(user.socket_id)
return socket return socket
} },
} }
} }

View File

@ -2,8 +2,9 @@ import he from "hyper-express"
import rtengine from "../../classes/rtengine" import rtengine from "../../classes/rtengine"
export default class Engine { export default class Engine {
constructor(params) { constructor(params, ctx) {
this.params = params this.params = params
this.ctx = ctx
} }
app = null app = null
@ -32,7 +33,7 @@ export default class Engine {
await this.router.any("*", (req, res) => { await this.router.any("*", (req, res) => {
return res.status(404).json({ return res.status(404).json({
code: 404, code: 404,
message: "Not found" message: "Not found",
}) })
}) })
@ -50,7 +51,11 @@ export default class Engine {
// register body parser // register body parser
if (req.headers["content-type"]) { if (req.headers["content-type"]) {
if (!req.headers["content-type"].startsWith("multipart/form-data")) { if (
!req.headers["content-type"].startsWith(
"multipart/form-data",
)
) {
req.body = await req.urlencoded() req.body = await req.urlencoded()
req.body = await req.json(req.body) req.body = await req.json(req.body)
} }
@ -61,7 +66,7 @@ export default class Engine {
this.ws = global.websocket = new rtengine({ this.ws = global.websocket = new rtengine({
...params, ...params,
handleAuth: params.handleWsAuth, handleAuth: params.handleWsAuth,
root: `/${params.refName}` root: `/${params.refName}`,
}) })
this.ws.initialize() this.ws.initialize()
@ -99,7 +104,7 @@ export default class Engine {
ip: this.params.listen_ip, ip: this.params.listen_ip,
port: this.params.listen_port, port: this.params.listen_port,
}, },
} },
}) })
} }
@ -116,7 +121,7 @@ export default class Engine {
ip: this.params.listen_ip, ip: this.params.listen_ip,
port: this.params.listen_port, port: this.params.listen_port,
}, },
} },
}) })
} }
} }
@ -137,5 +142,9 @@ export default class Engine {
if (typeof this.app?.close === "function") { if (typeof this.app?.close === "function") {
this.app.close() this.app.close()
} }
if (typeof this.ctx.onClose === "function") {
this.ctx.onClose()
}
} }
} }

View File

@ -36,35 +36,70 @@ class Server {
this.params = { this.params = {
...defaults.params, ...defaults.params,
...params.default ?? params, ...(params.default ?? params),
} }
this.controllers = { this.controllers = {
...controllers.default ?? controllers, ...(controllers.default ?? controllers),
} }
this.middlewares = { this.middlewares = {
...middlewares.default ?? middlewares, ...(middlewares.default ?? middlewares),
} }
this.headers = { this.headers = {
...defaults.headers, ...defaults.headers,
...headers.default ?? headers, ...(headers.default ?? headers),
} }
// fix and fulfill params // fix and fulfill params
this.params.useMiddlewares = this.params.useMiddlewares ?? [] this.params.useMiddlewares = this.params.useMiddlewares ?? []
this.params.name = this.constructor.refName ?? this.params.refName
this.params.useEngine = this.constructor.useEngine ?? this.params.useEngine ?? "hyper-express"
this.params.listen_ip = this.constructor.listenIp ?? this.constructor.listen_ip ?? this.params.listen_ip ?? "0.0.0.0"
this.params.listen_port = this.constructor.listenPort ?? this.constructor.listen_port ?? this.params.listen_port ?? 3000
this.params.http_protocol = this.params.http_protocol ?? "http"
this.params.http_address = `${this.params.http_protocol}://${defaults.localhost_address}:${this.params.listen_port}`
this.params.enableWebsockets = this.constructor.enableWebsockets ?? this.params.enableWebsockets ?? false
this.params.ignoreCors = this.constructor.ignoreCors ?? this.params.ignoreCors ?? true
this.params.routesPath = this.constructor.routesPath ?? this.params.routesPath ?? path.resolve(process.cwd(), "routes") this.params.name = this.constructor.refName ?? this.params.refName
this.params.wsRoutesPath = this.constructor.wsRoutesPath ?? this.params.wsRoutesPath ?? path.resolve(process.cwd(), "routes_ws")
this.params.useEngine =
this.constructor.useEngine ??
this.params.useEngine ??
"hyper-express"
this.params.listen_ip =
this.constructor.listenIp ??
this.constructor.listen_ip ??
this.params.listen_ip ??
"0.0.0.0"
this.params.listen_port =
this.constructor.listenPort ??
this.constructor.listen_port ??
this.params.listen_port ??
3000
this.params.http_protocol = this.params.http_protocol ?? "http"
this.params.http_address = `${this.params.http_protocol}://${defaults.localhost_address}:${this.params.listen_port}`
this.params.enableWebsockets =
this.constructor.enableWebsockets ??
this.params.enableWebsockets ??
false
this.params.ignoreCors =
this.constructor.ignoreCors ?? this.params.ignoreCors ?? true
this.params.disableBaseEndpoints =
this.constructor.disableBaseEndpoints ??
this.params.disableBaseEndpoints ??
false
this.params.routesPath =
this.constructor.routesPath ??
this.params.routesPath ??
path.resolve(process.cwd(), "routes")
this.params.wsRoutesPath =
this.constructor.wsRoutesPath ??
this.params.wsRoutesPath ??
path.resolve(process.cwd(), "routes_ws")
globalThis._linebridge = { globalThis._linebridge = {
name: this.params.name, name: this.params.name,
@ -101,7 +136,9 @@ class Server {
this.events = this.events.default this.events = this.events.default
} }
for (const [eventName, eventHandler] of Object.entries(this.events)) { for (const [eventName, eventHandler] of Object.entries(
this.events,
)) {
this.eventBus.on(eventName, eventHandler) this.eventBus.on(eventName, eventHandler)
} }
} }
@ -118,7 +155,7 @@ class Server {
// initialize engine // initialize engine
this.engine = await loadEngine(this.params.useEngine) this.engine = await loadEngine(this.params.useEngine)
this.engine = new this.engine(engineParams) this.engine = new this.engine(engineParams, this)
if (typeof this.engine.initialize === "function") { if (typeof this.engine.initialize === "function") {
await this.engine.initialize(engineParams) await this.engine.initialize(engineParams)
@ -127,9 +164,13 @@ class Server {
// check if ws events are defined // check if ws events are defined
if (typeof this.wsEvents !== "undefined") { if (typeof this.wsEvents !== "undefined") {
if (!this.engine.ws) { if (!this.engine.ws) {
console.warn("`wsEvents` detected, but Websockets are not enabled! Ignoring...") console.warn(
"`wsEvents` detected, but Websockets are not enabled! Ignoring...",
)
} else { } else {
for (const [eventName, eventHandler] of Object.entries(this.wsEvents)) { for (const [eventName, eventHandler] of Object.entries(
this.wsEvents,
)) {
this.engine.ws.events.set(eventName, eventHandler) this.engine.ws.events.set(eventName, eventHandler)
} }
} }
@ -139,8 +180,7 @@ class Server {
if (typeof this.onInitialize === "function") { if (typeof this.onInitialize === "function") {
try { try {
await this.onInitialize() await this.onInitialize()
} } catch (err) {
catch (err) {
console.error(err) console.error(err)
process.exit(1) process.exit(1)
} }
@ -152,25 +192,29 @@ class Server {
if (this.routes) { if (this.routes) {
for (const [route, endpoint] of Object.entries(this.routes)) { for (const [route, endpoint] of Object.entries(this.routes)) {
this.engine.router.map[route] = new Endpoint( this.engine.router.map[route] = new Endpoint(this, {
this,
{
...endpoint, ...endpoint,
route: route, route: route,
handlers: { handlers: {
[endpoint.method]: endpoint.fn, [endpoint.method]: endpoint.fn,
}, },
} })
)
} }
} }
// register http & ws routes // register http & ws routes
this.engine = await registerHttpRoutes(this.params.routesPath, this.engine, this) this.engine = await registerHttpRoutes(
this.engine = await registerWebsocketsEvents(this.params.wsRoutesPath, this.engine) this.params.routesPath,
this.engine,
this,
)
this.engine = await registerWebsocketsEvents(
this.params.wsRoutesPath,
this.engine,
)
// register base endpoints if enabled // register base endpoints if enabled
if (!this.params.disableBaseEndpoint) { if (!this.params.disableBaseEndpoints) {
await registerBaseEndpoints(this) await registerBaseEndpoints(this)
} }
@ -194,7 +238,9 @@ class Server {
const elapsedHrTime = process.hrtime(startHrTime) const elapsedHrTime = process.hrtime(startHrTime)
const elapsedTimeInMs = elapsedHrTime[0] * 1e3 + elapsedHrTime[1] / 1e6 const elapsedTimeInMs = elapsedHrTime[0] * 1e3 + elapsedHrTime[1] / 1e6
console.info(`🛰 Server ready!\n\t - ${this.params.http_protocol}://${this.params.listen_ip}:${this.params.listen_port} \n\t - Tooks ${elapsedTimeInMs.toFixed(2)}ms`) console.info(
`🛰 Server ready!\n\t - ${this.params.http_protocol}://${this.params.listen_ip}:${this.params.listen_port} \n\t - Tooks ${elapsedTimeInMs.toFixed(2)}ms`,
)
} }
initializeIpc = async () => { initializeIpc = async () => {
@ -216,7 +262,7 @@ class Server {
useDefaultMiddlewares = async () => { useDefaultMiddlewares = async () => {
const middlewares = await this.resolveMiddlewares([ const middlewares = await this.resolveMiddlewares([
...this.params.useMiddlewares, ...this.params.useMiddlewares,
...this.useMiddlewares ?? [], ...(this.useMiddlewares ?? []),
...defaults.useMiddlewares, ...defaults.useMiddlewares,
]) ])
@ -247,7 +293,10 @@ class Server {
endpoint.middlewares = [endpoint.middlewares] endpoint.middlewares = [endpoint.middlewares]
} }
middlewares = [...middlewares, ...this.resolveMiddlewares(endpoint.middlewares)] middlewares = [
...middlewares,
...this.resolveMiddlewares(endpoint.middlewares),
]
} }
this.engine.router.map[endpoint.route] = { this.engine.router.map[endpoint.route] = {
@ -256,7 +305,11 @@ class Server {
} }
// register endpoint to http interface router // register endpoint to http interface router
this.engine.router[endpoint.method](endpoint.route, ...middlewares, endpoint.fn) this.engine.router[endpoint.method](
endpoint.route,
...middlewares,
endpoint.fn,
)
}, },
} }