From 193a2603b5de1fffa417d9abc1fb69cf307aed52 Mon Sep 17 00:00:00 2001 From: kalrnlo Date: Sat, 27 Jul 2024 13:44:25 -0600 Subject: [PATCH] Update ratelimit * Added ratelimit docs * Added tests --- docs/ratelimit.md | 89 +++++++++++++++++++++++++++++- libs/Ratelimit/ratelimit.luau | 12 +++- libs/Ratelimit/ratelimit.test.luau | 29 ++++++++++ 3 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 libs/Ratelimit/ratelimit.test.luau diff --git a/docs/ratelimit.md b/docs/ratelimit.md index f278f5e..4c86127 100644 --- a/docs/ratelimit.md +++ b/docs/ratelimit.md @@ -1,4 +1,89 @@ # Ratelimit -> [!NOTE] -> The docs for this library are incomplete +Object for handling ratelimits intuitively, can be used without a Ratelimits many keys in a very intuitive interface. Ratelimits can also be used without any keys + +```luau +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local ratelmit = require("ratelimit") + +local check_limit = ratelimit(10, 60) +local event = Instance.new("RemoteEvent") +event.Parent = ReplicatedStorage + +event.OnClientEvent:Connect(function(player, ...) + if check_limit(player) then + -- do stuff + end +end) +``` + +## Type + +```luau +type Ratelimit = { + @metatable { + __call: (self: Ratelimit, key: K?) -> boolean + } + + count_map: { [K]: number }, + interval: number, + limit: number, + count: number, +} +``` + +## Constructor + +Creates a new ratelimit object, with [`limit`](#limit) being the amount of times a key can be called every [`interval`](#interval) seconds. + +> [!TIP] +> The limit is inclusive, use the maximum amount of calls you want to allow as the [`limit`](#limit). + +```luau +local check_limit = ratelimit(10, 60) +``` + +## Methods + +### `__call` + +Checks if a given key's count or [`count`](#count) has exceeded the [`limit`](#limit) within the current [`interval`](#interval) + +```luau +local check_limit = ratelimit(10, 60) +check_limit("meow") +``` + +## Properties + +### `count` + +The count for when the ratelimit object has its [`__call`](#__call) metamethod invoked without the key argument + +```luau +type count = number +``` + +### `count_map` + +A map with keys, with their values being the count for the specified key + +```luau +type count_map = { [K]: number } +``` + +### `limit` + +The limit for the ratelimit object + +```luau +type limit = number +``` + +### `interval` + +The interval for the ratelimit object + +```luau +type interval = number +``` \ No newline at end of file diff --git a/libs/Ratelimit/ratelimit.luau b/libs/Ratelimit/ratelimit.luau index 768afcd..ab4d45a 100644 --- a/libs/Ratelimit/ratelimit.luau +++ b/libs/Ratelimit/ratelimit.luau @@ -17,7 +17,17 @@ export type Ratelimit = typeof(setmetatable({} :: { }, {} :: RatelimitPrototype)) local ratelimit_mt = ({} :: any) :: RatelimitPrototype -local delay = task.delay +local delay = (function() + if task then + return task.delay + elseif string.find(_VERSION, "lune") then + return (require)("@lune/task").delay + else + return function() + + end :: any + end +end)() function ratelimit_mt.__call(ratelimit, key) if key then diff --git a/libs/Ratelimit/ratelimit.test.luau b/libs/Ratelimit/ratelimit.test.luau new file mode 100644 index 0000000..a463a31 --- /dev/null +++ b/libs/Ratelimit/ratelimit.test.luau @@ -0,0 +1,29 @@ +local ratelimit = require("ratelimit") +local testkit = require("../testkit") + +local TEST, CASE, CHECK, FINISH = testkit.test() + +TEST("ratelimit", function() + do CASE "create ratelimit" + local check_limit = ratelimit(10, 60) + + check_limit("meow") + CHECK(testkit.deq(check_limit :: any, { + count_map = { meow = 1 }, + interval = 60, + limit = 10, + count = 0, + })) + end + + do CASE "will get throttled" + local check_limit = ratelimit(10, 60) + + for index = 1, 10 do + check_limit("meow") + end + CHECK(check_limit("meow") == false) + end +end) + +if not FINISH() then error(nil, 0) end