Skip to content

Instantly share code, notes, and snippets.

@lewisakura
Created October 19, 2021 15:14
Show Gist options
  • Save lewisakura/5308748d2d65a195ff580d4b9a54845f to your computer and use it in GitHub Desktop.
Save lewisakura/5308748d2d65a195ff580d4b9a54845f to your computer and use it in GitHub Desktop.
WebhookProxy
local HttpService = game:GetService("HttpService")
local Proxy = {}
Proxy.__index = Proxy
local function safeReq(url: string, data: any)
local info = HttpService:RequestAsync({
Url = url,
Method = "POST",
Body = HttpService:JSONEncode(data),
Headers = {
["Content-Type"] = "application/json"
}
})
if info.StatusCode == 204 then return true, 204, nil end
local body = HttpService:JSONDecode(info.Body)
if not info.Success then
if info.StatusCode == 500 then
warn("[WebhookProxy] Proxy instance encountered an internal error. Silently failing.")
return true, 204, nil
else
return false, info.StatusCode, body.error
end
end
return true, info.StatusCode, body
end
local function processStatus(statusCode: number, body: any)
if statusCode == 403 then
if body.message == "This IP address has been banned." then
error("This Roblox server IP has been temporarily banned due to abuse.")
end
if body.message == "This webhook has been blocked. Please contact @Lewis_Schumer on the DevForum." then
error("This webhook has been blocked: " .. body.reason)
end
end
if statusCode == 429 then
warn(
"[WebhookProxy] Hit ratelimit. If you are seeing this warning often, consider using Proxy:Queue() instead. Otherwise, please enforce ratelimits yourself."
)
return nil
end
if statusCode == 404 then
error("Attempted to request to a non-existent webhook.")
end
if statusCode == 400 and not body.proxy then
error("Bad request: " .. body.message)
end
end
--[[
Create a new proxy instance.
@param id The webhook ID. This is the first part of your webhook.
@param token The webhook token. This is the second part of your webhook.
@param instance The proxy to use. If not provided, uses the default WebhookProxy server.
@returns An instance of the proxy.
]]
function Proxy.new(id: string, token: string, instance: string?)
return setmetatable({
_id = id,
_token = token,
_instance = instance or "https://webhook.lewistehminerz.dev"
}, Proxy)
end
--[[
Queue a message.
@param data The message data.
@param threadId The thread to send the message to.
]]
function Proxy:Queue(data: any, threadId: string?)
if typeof(data) ~= "table" or (data.content == nil and data.embeds == nil and data.file == nil) then
error("Invalid data object. Expecting a table containing `content`, `embeds`, or `file`.")
end
local url = self._instance .. "/api/webhooks/" .. self._id .. "/" .. self._token .. "/queue"
if threadId then
url = url .. "?thread_id=" .. threadId
end
local success, statusCode, response = safeReq(url, data)
if success then return nil end
if statusCode == 403 and response.proxy and response.error == "Queues have been disabled." then
error("Queues are disabled on this instance of WebhookProxy.")
end
processStatus(statusCode, response)
return nil
end
--[[
Send a message immediately.
@param data The message data.
@param waitForReply Whether or not to wait for a response.
@param threadId The thread to send the message to.
@returns If `waitForReply` is true, the message object.
]]
function Proxy:Send(data: any, waitForSend: boolean, threadId: string?)
if typeof(data) ~= "table" or (data.content == nil and data.embeds == nil and data.file == nil) then
error("Invalid data object. Expecting a table containing `content`, `embeds`, or `file`.")
end
local url = self._instance .. "/api/webhooks/" .. self._id .. "/" .. self._token
url = url .. "?wait=" .. tostring(waitForSend)
if threadId then
url = url .. "&thread_id=" .. threadId
end
local success, statusCode, response = safeReq(url, data)
if success then return response end
processStatus(statusCode, response)
end
return Proxy
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment