{"id":15762413,"url":"https://github.com/williamvenner/gmsv_reqwest","last_synced_at":"2025-04-23T13:39:58.482Z","repository":{"id":46001657,"uuid":"382440488","full_name":"WilliamVenner/gmsv_reqwest","owner":"WilliamVenner","description":"🌐 Drop-in HTTP replacement module for Garry's Mod","archived":false,"fork":false,"pushed_at":"2024-08-02T12:15:21.000Z","size":92,"stargazers_count":63,"open_issues_count":2,"forks_count":6,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-10-11T11:34:12.570Z","etag":null,"topics":["discord","garrys-mod","garrysmod","glua","gmod","gmod-module","gmod-modules","gmsv","http","https","lua","rust","ssl","tls"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/WilliamVenner.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-02T19:11:17.000Z","updated_at":"2024-10-02T07:45:11.000Z","dependencies_parsed_at":"2024-10-25T10:18:15.514Z","dependency_job_id":"0d6f5e3c-7200-40b5-b37a-f9fb648fdd72","html_url":"https://github.com/WilliamVenner/gmsv_reqwest","commit_stats":{"total_commits":67,"total_committers":2,"mean_commits":33.5,"dds":0.04477611940298509,"last_synced_commit":"fb5d63c86987288f62d228ae63aca2b08a1d3d4f"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WilliamVenner%2Fgmsv_reqwest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WilliamVenner%2Fgmsv_reqwest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WilliamVenner%2Fgmsv_reqwest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WilliamVenner%2Fgmsv_reqwest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WilliamVenner","download_url":"https://codeload.github.com/WilliamVenner/gmsv_reqwest/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250440666,"owners_count":21431037,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["discord","garrys-mod","garrysmod","glua","gmod","gmod-module","gmod-modules","gmsv","http","https","lua","rust","ssl","tls"],"created_at":"2024-10-04T11:09:05.916Z","updated_at":"2025-04-23T13:39:58.439Z","avatar_url":"https://github.com/WilliamVenner.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🌐 gmsv_reqwest\r\n\r\nThis module is a drop-in replacement for Garry's Mod's [`HTTP`](https://wiki.facepunch.com/gmod/Global.HTTP) function, inspired by [`gmsv_chttp`](https://github.com/timschumi/gmod-chttp) created by [timschumi](https://github.com/timschumi).\r\n\r\nThe module uses the [`reqwest`](https://docs.rs/reqwest/*/reqwest/) crate for dispatching HTTP requests, [`tokio`](https://tokio.rs/) crate for async/thread scheduling runtime and the [`rustls`](https://github.com/ctz/rustls) crate for SSL/TLS.\r\n\r\nThis module was written in Rust and serves as a decent example on how to write a Garry's Mod binary module in Rust, using the [`gmod`](https://github.com/WilliamVenner/gmod-rs) crate.\r\n\r\n# Installation\r\n\r\nDownload the relevant module for your server's operating system and platform/Gmod branch from the [releases section](https://github.com/WilliamVenner/gmsv_reqwest/releases).\r\n\r\nDrop the module into `garrysmod/lua/bin/` in your server's files. If the `bin` folder doesn't exist, create it.\r\n\r\nIf you're not sure on what operating system/platform your server is running, run this in your server's console:\r\n\r\n```lua\r\nlua_run print((system.IsWindows()and\"Windows\"or system.IsLinux()and\"Linux\"or\"Unsupported\")..\" \"..(jit.arch==\"x64\"and\"x86-64\"or\"x86\"))\r\n```\r\n\r\n## Custom root certificates (for SSL/TLS)\r\n\r\nTo add custom root certificates, place them in the `garrysmod/tls_certificates/client` directory.\r\n\r\nThe certificates must be X509 and encoded in either `pem` or `der`. They must also end in the `.pem` or `.der` file extensions respective to their econding. If there is a problem loading the certificate, it'll be skipped over and a message will be displayed in the console.\r\n\r\n# Overriding Garry's Mod HTTP\r\n\r\nTo override Garry's Mod's `HTTP` function with `reqwest`, you can add this code snippet to `lua/autorun/server/reqwest.lua`:\r\n\r\n```lua\r\nif pcall(require, \"reqwest\") and reqwest ~= nil then\r\n    my_http = reqwest\r\nelse\r\n    my_http = HTTP\r\nend\r\n```\r\n\r\n# Developer Usage\r\n\r\nOnce loaded, gmsv_reqwest will create a global function called `reqwest` which behaves exactly the same as [`HTTP`](https://wiki.facepunch.com/gmod/Global.HTTP) and uses the same configuration struct ([`HTTPRequest`](https://wiki.facepunch.com/gmod/Structures/HTTPRequest)).\r\n\r\n**There is one difference:** on HTTP request failure, reqwest will provide an extended error message (known as `errExt`) _as well as_ Garry's Mod's useless error message.\r\n\r\n## Discord Webhook Example\r\n\r\n```lua\r\nrequire(\"reqwest\")\r\n\r\nreqwest({\r\n    method = \"POST\",\r\n    url = \"https://discord.com/api/webhooks/988854737435070417/pHbHIjR15oa4ZmJ1PMCwEPaK4hdlCC21AIme94Iw9Xh7M9Mhg6GLLV2u6Q1rppH_7esX\",\r\n    timeout = 30,\r\n    \r\n    body = util.TableToJSON({ content = \"Hello, world!\" }), -- https://discord.com/developers/docs/resources/webhook#execute-webhook\r\n    type = \"application/json\",\r\n\r\n    headers = {\r\n        [\"User-Agent\"] = \"My User Agent\", -- This is REQUIRED to dispatch a Discord webhook\r\n    },\r\n\r\n    success = function(status, body, headers)\r\n        print(\"HTTP \" .. status)\r\n        PrintTable(headers)\r\n        print(body)\r\n    end,\r\n\r\n    failed = function(err, errExt)\r\n        print(\"Error: \" .. err .. \" (\" .. errExt .. \")\")\r\n    end\r\n})\r\n```\r\n\r\n_By the way, that webhook URL is fake :D_\r\n\r\n## Support both gmsv_reqwest and [`gmsv_chttp`](https://github.com/timschumi/gmod-chttp)\r\n\r\nThis example loads either reqwest or CHTTP\r\n\r\n```lua\r\nif not reqwest and not CHTTP then\r\n    local suffix = ({\"osx64\", \"osx\", \"linux64\", \"linux\", \"win64\", \"win32\"})[(system.IsWindows() and 4 or 0) + (system.IsLinux() and 2 or 0) + (jit.arch == \"x86\" and 1 or 0) + 1]\r\n    local fmt = \"lua/bin/gm\" .. (CLIENT and \"cl\" or \"sv\") .. \"_%s_%s.dll\"\r\n    local function installed(name)\r\n        if file.Exists(string.format(fmt, name, suffix), \"GAME\") then return true end\r\n        if jit.versionnum ~= 20004 and jit.arch == \"x86\" and system.IsLinux() then return file.Exists(string.format(fmt, name, \"linux32\"), \"GAME\") end\r\n        return false\r\n    end\r\n\r\n    if installed(\"reqwest\") then\r\n        require(\"reqwest\")\r\n    end\r\n    if not reqwest and installed(\"chttp\") then\r\n        require(\"chttp\")\r\n    end\r\n    if not CHTTP then\r\n        error(\"reqwest or CHTTP is required to use this!\")\r\n    end\r\nend\r\n\r\nlocal HTTP = reqwest or CHTTP\r\n\r\n-- Your code\r\n```\r\n\r\n# Thread-blocking requests\r\n\r\nYou can make requests that block the main thread using gmsv_reqwest, i.e., they are not asynchronous.\r\n\r\n* Only do this if you know what you are doing.\r\n* Make sure that you choose an appropriate timeout to avoid timing out players if any are online and the request hangs.\r\n* If you provide a `success` and `failed` callback, they will still be called\r\n* On success, `true`, `status`, `body` and `headers` will be returned\r\n* On failure, `false`, `err`, `errExt` will be returned\r\n\r\nTo do this, simply add `blocking = true` to the [`HTTPRequest`](https://wiki.facepunch.com/gmod/Structures/HTTPRequest) table when creating your HTTP request.\r\n\r\n## Example\r\n\r\n```lua\r\nrequire(\"reqwest\")\r\n\r\nlocal success, status, body, headers = reqwest({\r\n    blocking = true, -- note this!\r\n\r\n    url = \"https://google.com\",\r\n\r\n    -- callbacks will still be called for blocking requests\r\n    success = function(status, body, headers) PrintTable({status, body, headers}) end,\r\n    failed = function(err, errExt) PrintTable({err, errExt}) end\r\n})\r\nif success then\r\n    print(\"HTTP \" .. status)\r\n    PrintTable(headers)\r\n    print(body)\r\nelse\r\n    local err, errExt = status, body\r\n    -- In this case, `status` will be the \"error message\" that Garry's Mod provides (typically always \"unsuccessful\")\r\n    --  and `body` will be a custom error message from reqwest which actually describes what the error was.\r\n    print(\"Error: \" .. err .. \" (\" .. errExt .. \")\")\r\nend\r\n```\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwilliamvenner%2Fgmsv_reqwest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwilliamvenner%2Fgmsv_reqwest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwilliamvenner%2Fgmsv_reqwest/lists"}