From 064075fbd989c6cb7a96cc94c7cb80cdacbcdaea Mon Sep 17 00:00:00 2001 From: EternityDev Date: Wed, 29 May 2024 16:58:20 +0700 Subject: [PATCH] v1.0.12 --- Warp.rbxm | Bin 15336 -> 16079 bytes docs/.vitepress/config.mts | 1 + docs/api/1.0/middleware.md | 64 +++++++++++++++++++++++++++++++++ docs/guide/example.md | 3 +- docs/guide/installation.md | 2 +- src/Index/Client/Index.luau | 37 ++++++++++++++----- src/Index/Server/Index.luau | 34 ++++++++++++++---- src/Index/Type.luau | 14 +++++--- src/Index/Util/Middleware.luau | 46 ++++++++++++++++++++++++ src/init.luau | 2 +- wally.toml | 2 +- 11 files changed, 183 insertions(+), 22 deletions(-) create mode 100644 docs/api/1.0/middleware.md create mode 100644 src/Index/Util/Middleware.luau diff --git a/Warp.rbxm b/Warp.rbxm index 5ef629c2a842bcfb09a56a41557e619913071dcc..02be9e1925ee7ca3e49482da3ee551707eb7cd71 100644 GIT binary patch delta 8376 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 BBb@*M 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"