diff --git a/Warp.rbxm b/Warp.rbxm index 5ef629c..02be9e1 100644 Binary files a/Warp.rbxm and b/Warp.rbxm differ diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 96aaa7f..3d49b9b 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -33,6 +33,7 @@ function side() { text: 'Feature', items: [ { text: 'Rate Limit', link: '/api/1.0/ratelimit' }, + { text: 'Middleware', link: '/api/1.0/middleware' }, ] }, { diff --git a/docs/api/1.0/middleware.md b/docs/api/1.0/middleware.md new file mode 100644 index 0000000..b0b79d0 --- /dev/null +++ b/docs/api/1.0/middleware.md @@ -0,0 +1,64 @@ +# Middleware + +::: code-group +```lua [Server] +local Event1 = Warp.Server("Remote1") + +local storeC = Event1:Connect(function(player: Player, arg1: string, arg2: number, arg3: boolean) + print(player, arg1, arg2, arg3) +end):middleware(function(player: Player, arg1: string, arg2: number, arg3: boolean) + assert(type(player) == "userdata" and player:IsA("Player"), "player must be a Player.") + assert(typeof(arg1) == "string", "arg1 must be a string.") + assert(typeof(arg2) == "number", "arg2 must be a number.") + assert(typeof(arg3) == "boolean", "arg3 must be a boolean.") +end) + +print(storeC:key()) + +task.delay(15, function() + Event1:Disconnect(storeC:key()) +end) + +for _=1,5 do + print("send incorrect values") + Event1:Fires(true, 1e9, "hello world!") + task.wait(0.5) +end + +for _=1,5 do + print("send correct values") + Event1:Fires(true, "hello world!", 1e9) + task.wait(0.5) +end +``` + +```lua [Client] +local Event1 = Warp.Client("Remote1") + +local storeC = Event1:Connect(function(arg1: boolean, arg2: string, arg3: number) + print(arg1, arg2, arg3) +end):middleware(function(arg1: boolean, arg2: string, arg3: number) + assert(typeof(arg1) == "boolean", "arg1 must be a boolean.") + assert(typeof(arg2) == "string", "arg2 must be a string.") + assert(typeof(arg3) == "number", "arg3 must be a number.") +end) + +print(storeC:key()) + +task.delay(15, function() + Event1:Disconnect(storeC:key()) +end) + +for _=1,5 do + print("send incorrect values") + Event1:Fires("hello world!", false, 1e9) + task.wait(0.5) +end + +for _=1,5 do + print("send correct values") + Event1:Fires("hello world!", 1e9, false) + task.wait(0.5) +end +``` +::: \ No newline at end of file diff --git a/docs/guide/example.md b/docs/guide/example.md index 06cc6d9..1f49fc3 100644 --- a/docs/guide/example.md +++ b/docs/guide/example.md @@ -67,4 +67,5 @@ Pong:Disconnect(connection1) Pong:Destroy() -- Yay Done! -``` \ No newline at end of file +``` +::: \ No newline at end of file diff --git a/docs/guide/installation.md b/docs/guide/installation.md index 925582f..4ac6dc5 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -8,7 +8,7 @@ ::: code-group ```toml [wally.toml] [dependencies] -warp = "imezx/warp@1.0.11" +warp = "imezx/warp@1.0.12" ``` 3. Run `wally install` in command. diff --git a/src/Index/Client/Index.luau b/src/Index/Client/Index.luau index 5b0fd33..eecfc0b 100644 --- a/src/Index/Client/Index.luau +++ b/src/Index/Client/Index.luau @@ -13,6 +13,7 @@ local Assert = require(Util.Assert) local Key = require(Util.Key) local Serdes = require(Util.Serdes) local Buffer = require(Util.Buffer) +local Middleware = require(Util.Middleware) function Client.new(Identifier: string, conf: Type.ClientConf?) local self = setmetatable({}, Client) @@ -21,6 +22,7 @@ function Client.new(Identifier: string, conf: Type.ClientConf?) self._buffer:wu8(Serdes(Identifier, conf and conf.yieldWait)) self.id = Buffer.convert(self._buffer:build()) self.fn = {} + self.middleware = {} self._conf = table.freeze(conf or {}) self.IsConnected = false @@ -43,23 +45,39 @@ function Client:Invoke(timeout: number, ...: any): any return ClientProcess.insertRequest(self.id, timeout, ...) end -function Client:Connect(callback: (args: any) -> ()): string +function Client:Connect(callback: (args: any) -> ()) local key = tostring(Key()) + local _middleware = Middleware(key) + table.insert(self.fn, key) + self.middleware[key] = _middleware + self.IsConnected = #self.fn > 0 - ClientProcess.addCallback(self.id, key, callback) - return key + ClientProcess.addCallback(self.id, key, function(...) + if _middleware.bridge(...) then + return callback(...) + end + return nil + end) + return _middleware end -function Client:Once(callback: (args: any) -> ()): string +function Client:Once(callback: (args: any) -> ()) local key = tostring(Key()) + local _middleware = Middleware(key) + table.insert(self.fn, key) + self.middleware[key] = _middleware + self.IsConnected = #self.fn > 0 ClientProcess.addCallback(self.id, key, function(...) self:Disconnect(key) - task.spawn(callback, ...) + if _middleware.bridge(...) then + return callback(...) + end + return nil end) - return key + return _middleware end function Client:Wait() @@ -76,12 +94,15 @@ function Client:DisconnectAll() end end -function Client:Disconnect(key: string): boolean +function Client:Disconnect(key: string) Assert(typeof(key) == "string", "Key must be a string type.") ClientProcess.removeCallback(self.id, key) table.remove(self.fn, table.find(self.fn, key)) self.IsConnected = #self.fn > 0 - return table.find(self.fn, key) == nil + if self.middleware[key] then + self.middleware[key]:destroy() + self.middleware[key] = nil + end end function Client:Destroy() diff --git a/src/Index/Server/Index.luau b/src/Index/Server/Index.luau index 8a9d5ee..f41f668 100644 --- a/src/Index/Server/Index.luau +++ b/src/Index/Server/Index.luau @@ -13,6 +13,7 @@ local Assert = require(Util.Assert) local Key = require(Util.Key) local Serdes = require(Util.Serdes) local Buffer = require(Util.Buffer) +local Middleware = require(Util.Middleware) function Server.new(Identifier: string, conf: Type.ServerConf?) local self = setmetatable({}, Server) @@ -21,6 +22,7 @@ function Server.new(Identifier: string, conf: Type.ServerConf?) self._buffer:wu8(Serdes(Identifier)) self.id = Buffer.convert(self._buffer:build()) self.fn = {} + self.middleware = {} self._conf = table.freeze(conf or {}) self.IsConnected = false @@ -63,23 +65,39 @@ function Server:Invoke(timeout: number, player: Player, ...: any): any return ServerProcess.insertRequest(self.id, timeout, player, ...) end -function Server:Connect(callback: (plyer: Player, args: any) -> ()): string +function Server:Connect(callback: (plyer: Player, args: any) -> ()) local key = tostring(Key()) + local _middleware = Middleware(key) + table.insert(self.fn, key) - ServerProcess.addCallback(self.id, key, callback) + self.middleware[key] = _middleware + self.IsConnected = #self.fn > 0 - return key + ServerProcess.addCallback(self.id, key, function(...) + if _middleware.bridge(...) then + return callback(...) + end + return nil + end) + return _middleware end -function Server:Once(callback: (plyer: Player, args: any) -> ()): string +function Server:Once(callback: (plyer: Player, args: any) -> ()) local key = tostring(Key()) + local _middleware = Middleware(key) + table.insert(self.fn, key) + self.middleware[key] = _middleware + self.IsConnected = #self.fn > 0 ServerProcess.addCallback(self.id, key, function(...) self:Disconnect(key) - task.spawn(callback, ...) + if _middleware.bridge(...) then + return callback(...) + end + return nil end) - return key + return _middleware end function Server:Wait() @@ -101,6 +119,10 @@ function Server:Disconnect(key: string): boolean ServerProcess.removeCallback(self.id, key) table.remove(self.fn, table.find(self.fn, key)) self.IsConnected = #self.fn > 0 + if self.middleware[key] then + self.middleware[key]:destroy() + self.middleware[key] = nil + end return table.find(self.fn, key) == nil end diff --git a/src/Index/Type.luau b/src/Index/Type.luau index 57569be..be97f3f 100644 --- a/src/Index/Type.luau +++ b/src/Index/Type.luau @@ -19,11 +19,17 @@ export type ClientConf = { logging: logging?, } +export type Middleware = { + middleware: (self: Middleware, middleware: (...any) -> (...any)) -> (), + key: (self: Middleware) -> string, + destroy: (self: Middleware) -> (), +} + export type Client = { Fire: (self: Client, reliable: boolean, ...any) -> (), Invoke: (self: Client, timeout: number, ...any) -> any, - Connect: (self: Client, callback: (...any) -> ()) -> string, - Once: (self: Client, callback: (player: Player, ...any) -> ()) -> string, + Connect: (self: Client, callback: (...any) -> ()) -> Middleware, + Once: (self: Client, callback: (player: Player, ...any) -> ()) -> Middleware, Disconnect: (self: Client, key: string) -> (), DisconnectAll: (self: Client) -> (), Wait: (self: Client) -> number, @@ -35,8 +41,8 @@ export type Server = { Fire: (self: Server, reliable: boolean, player: Player, ...any) -> (), Fires: (self: Server, reliable: boolean, ...any) -> (), Invoke: (self: Server, timeout: number, player: Player, ...any) -> any, - Connect: (self: Server, callback: (player: Player, ...any) -> ()) -> string, - Once: (self: Server, callback: (player: Player, ...any) -> ()) -> string, + Connect: (self: Server, callback: (player: Player, ...any) -> ()) -> Middleware, + Once: (self: Server, callback: (player: Player, ...any) -> ()) -> Middleware, Disconnect: (self: Server, key: string) -> (), DisconnectAll: (self: Server) -> (), Wait: (self: Server) -> number, diff --git a/src/Index/Util/Middleware.luau b/src/Index/Util/Middleware.luau new file mode 100644 index 0000000..27dd713 --- /dev/null +++ b/src/Index/Util/Middleware.luau @@ -0,0 +1,46 @@ +--!strict +--!native +--!optimize 2 +local Middleware = {} +Middleware.__index = Middleware + +local function wrap(middleware: (...any) -> (...any)): (...any) -> boolean + return function(...): boolean + local obj: any = { ... } + local s, r = pcall(function() + return middleware(table.unpack(obj)) + end) + if not s and r then + warn(r) + r = nil + table.clear(obj) + obj = nil + end + return s + end +end + +function Middleware.new(key: string) + return setmetatable({ + root = key, + bridge = function(...: any?): any? + return true + end, + }, Middleware) +end + +function Middleware:middleware(middleware: (...any) -> (...any)) + self.bridge = wrap(middleware) + return self +end + +function Middleware:key(): string + return self.root +end + +function Middleware:destroy() + table.clear(self) + setmetatable(self, nil) +end + +return Middleware.new :: typeof(Middleware.new) \ No newline at end of file diff --git a/src/init.luau b/src/init.luau index ccc8644..15eae29 100644 --- a/src/init.luau +++ b/src/init.luau @@ -1,5 +1,5 @@ -- Warp Library (@Eternity_Devs) --- version 1.0.11 +-- version 1.0.12 --!strict --!native --!optimize 2 diff --git a/wally.toml b/wally.toml index 71d26fb..f78eaa7 100644 --- a/wally.toml +++ b/wally.toml @@ -1,6 +1,6 @@ [package] name = "imezx/warp" -version = "1.0.11" +version = "1.0.12" registry = "https://github.com/UpliftGames/wally-index" realm = "shared" license = "MIT"