diff --git a/browser/src/core/rpc.ts b/browser/src/core/rpc.ts index 1b31ed2..896405f 100644 --- a/browser/src/core/rpc.ts +++ b/browser/src/core/rpc.ts @@ -1,7 +1,6 @@ import { Rpc } from '@entityseven/rage-fw-rpc' export const rpc = new Rpc({ - forceBrowserDevMode: - process.env.RageFW_forceBrowserDevMode === 'true' ?? false, + forceBrowserDevMode: process.env.RageFW_forceBrowserDevMode === 'true', debugLogs: false, }) diff --git a/client/src/core/client.ts b/client/src/core/client.ts index 27e0f64..8cc45a7 100644 --- a/client/src/core/client.ts +++ b/client/src/core/client.ts @@ -1,16 +1,24 @@ import { rpc } from './rpc' +import { Middleware } from './middleware' import type * as T from '../types' export class Client { public register( eventName: EventName, callback: T.RageFW_ClientCallback, + options?: { + middlewares?: T.RageFW_MiddlewareOptions + }, ): Client { rpc.register< Parameters, - ReturnType, + ReturnType | Promise, EventName - >(eventName, async (...data) => await callback(...data)) + >(eventName, async (...data) => { + if (!options?.middlewares) return await callback(...data) + + await Middleware.process(options.middlewares, callback, data) + }) return this } diff --git a/client/src/core/index.ts b/client/src/core/index.ts index 375ef93..bbd7d8f 100644 --- a/client/src/core/index.ts +++ b/client/src/core/index.ts @@ -1,4 +1,5 @@ export * from './client' export * from './logger' +export * from './middleware' export * from './player' export * from './rpc' diff --git a/client/src/core/middleware.ts b/client/src/core/middleware.ts new file mode 100644 index 0000000..9c08fbf --- /dev/null +++ b/client/src/core/middleware.ts @@ -0,0 +1,54 @@ +import type * as T from '../types' + +export class Middleware { + constructor() {} + + private static async execute( + middlewares: T.RageFW_MiddlewareFunction[], + args: T.RageFW_ClientArgs, + ): Promise { + for (let i = 0; i < middlewares.length; i++) { + const result = await middlewares[i](...args) + + if (typeof result === 'boolean' && !result) + return { success: result, id: i } + if (typeof result !== 'boolean' && !result.success) + return { ...result, id: i } + } + + return { + success: true, + } + } + + public static async process( + middlewareOptions: T.RageFW_MiddlewareOptions, + callback: T.RageFW_ClientCallback, + args: T.RageFW_ClientArgs, + ) { + if (Array.isArray(middlewareOptions)) { + const middlewaresResponse = await Middleware.execute( + middlewareOptions, + args, + ) + + if (middlewaresResponse.success) return await callback(...args) + } else { + const middlewaresResponse = await Middleware.execute( + middlewareOptions.executables, + args, + ) + + if (middlewaresResponse.success) { + return await callback(...args) + } else { + middlewareOptions.onError( + middlewaresResponse.message ?? + 'Middleware with id ' + + middlewaresResponse.id + + ' failed', + ) + } + } + } +} diff --git a/client/src/index.ts b/client/src/index.ts index f653742..553e7a2 100644 --- a/client/src/index.ts +++ b/client/src/index.ts @@ -1,5 +1,7 @@ import { Client, Logger, Player, rpc } from './core' +export type { RageFW_MiddlewareFunction } from './types' + export const fw = { event: new Client(), player: new Player(), diff --git a/client/src/types/index.ts b/client/src/types/index.ts index 86863ca..915a170 100644 --- a/client/src/types/index.ts +++ b/client/src/types/index.ts @@ -1,3 +1,4 @@ -export * from './client' -export * from './server' export * from './browser' +export * from './client' +export * from './middleware' +export * from './server' diff --git a/client/src/types/middleware.ts b/client/src/types/middleware.ts new file mode 100644 index 0000000..102cabd --- /dev/null +++ b/client/src/types/middleware.ts @@ -0,0 +1,26 @@ +import type * as T from './client' + +export type RageFW_MiddlewareResponse = + | { + success: boolean + message?: string + } + | boolean + +export type RageFW_MiddlewareResponseInternal = { + success: boolean + message?: string + id?: number +} + +export type RageFW_MiddlewareFunction = + ( + ...args: T.RageFW_ClientArgs + ) => Promise + +export type RageFW_MiddlewareOptions = + | RageFW_MiddlewareFunction[] + | { + executables: RageFW_MiddlewareFunction[] + onError: (error: string) => unknown + } diff --git a/server/src/core/index.ts b/server/src/core/index.ts index b6900db..ebed456 100644 --- a/server/src/core/index.ts +++ b/server/src/core/index.ts @@ -1,4 +1,5 @@ export * from './logger' +export * from './middleware' export * from './player' export * from './rpc' export * from './server' diff --git a/server/src/core/middleware.ts b/server/src/core/middleware.ts new file mode 100644 index 0000000..c319a03 --- /dev/null +++ b/server/src/core/middleware.ts @@ -0,0 +1,54 @@ +import type * as T from '../types' + +export class Middleware { + constructor() {} + + private static async execute( + middlewares: T.RageFW_MiddlewareFunction[], + args: T.RageFW_ServerArgs, + ): Promise { + for (let i = 0; i < middlewares.length; i++) { + const result = await middlewares[i](...args) + + if (typeof result === 'boolean' && !result) + return { success: result, id: i } + if (typeof result !== 'boolean' && !result.success) + return { ...result, id: i } + } + + return { + success: true, + } + } + + public static async process( + middlewareOptions: T.RageFW_MiddlewareOptions, + callback: T.RageFW_ServerCallback, + args: T.RageFW_ServerArgs, + ) { + if (Array.isArray(middlewareOptions)) { + const middlewaresResponse = await Middleware.execute( + middlewareOptions, + args, + ) + + if (middlewaresResponse.success) return await callback(...args) + } else { + const middlewaresResponse = await Middleware.execute( + middlewareOptions.executables, + args, + ) + + if (middlewaresResponse.success) { + return await callback(...args) + } else { + middlewareOptions.onError( + middlewaresResponse.message ?? + 'Middleware with id ' + + middlewaresResponse.id + + ' failed', + ) + } + } + } +} diff --git a/server/src/core/server.ts b/server/src/core/server.ts index c3cea7e..8d2582c 100644 --- a/server/src/core/server.ts +++ b/server/src/core/server.ts @@ -1,16 +1,24 @@ import { rpc } from './rpc' +import { Middleware } from './middleware' import type * as T from '../types' export class Server { public register( eventName: EventName, callback: T.RageFW_ServerCallback, + options?: { + middlewares?: T.RageFW_MiddlewareOptions + }, ): Server { rpc.register< Parameters, - ReturnType, + ReturnType | Promise, EventName - >(eventName, async (...data) => await callback(...data)) + >(eventName, async (...data) => { + if (!options?.middlewares) return await callback(...data) + + await Middleware.process(options.middlewares, callback, data) + }) return this } diff --git a/server/src/index.ts b/server/src/index.ts index 555ca74..54a7c0c 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -1,5 +1,7 @@ import { Logger, Player, Server, rpc } from './core' +export type { RageFW_MiddlewareFunction } from './types' + export const fw = { event: new Server(), player: new Player(), diff --git a/server/src/types/index.ts b/server/src/types/index.ts index 86863ca..915a170 100644 --- a/server/src/types/index.ts +++ b/server/src/types/index.ts @@ -1,3 +1,4 @@ -export * from './client' -export * from './server' export * from './browser' +export * from './client' +export * from './middleware' +export * from './server' diff --git a/server/src/types/middleware.ts b/server/src/types/middleware.ts new file mode 100644 index 0000000..06ee8f1 --- /dev/null +++ b/server/src/types/middleware.ts @@ -0,0 +1,26 @@ +import type * as T from './server' + +export type RageFW_MiddlewareResponse = + | { + success: boolean + message?: string + } + | boolean + +export type RageFW_MiddlewareResponseInternal = { + success: boolean + message?: string + id?: number +} + +export type RageFW_MiddlewareFunction = + ( + ...args: T.RageFW_ServerArgs + ) => Promise + +export type RageFW_MiddlewareOptions = + | RageFW_MiddlewareFunction[] + | { + executables: RageFW_MiddlewareFunction[] + onError: (error: string) => unknown + }