From 7bda135da5b70f9ebf65b65f076497c2fdd8b20f Mon Sep 17 00:00:00 2001 From: Lucien Greathouse Date: Mon, 13 Aug 2018 15:26:17 -0700 Subject: [PATCH 1/3] Stub out GetAsync --- lib/http.lua | 15 +++++++++++++++ lib/instances/HttpService.lua | 31 ++++++++++++++++++------------- 2 files changed, 33 insertions(+), 13 deletions(-) create mode 100644 lib/http.lua diff --git a/lib/http.lua b/lib/http.lua new file mode 100644 index 0000000..5d12070 --- /dev/null +++ b/lib/http.lua @@ -0,0 +1,15 @@ +local exists, http = require("socket.http") + +local httpShim = {} + +function httpShim.get(url) + error("Please install `luasocket` to use HTTP features.", 2) +end + +if exists then + function httpShim.get(url) + return (http.request(url)) + end +end + +return httpShim \ No newline at end of file diff --git a/lib/instances/HttpService.lua b/lib/instances/HttpService.lua index 3601a79..e34fa19 100644 --- a/lib/instances/HttpService.lua +++ b/lib/instances/HttpService.lua @@ -1,14 +1,19 @@ -local BaseInstance = import("./BaseInstance") -local json = import("../json") - -local HttpService = BaseInstance:extend("HttpService") - -function HttpService.prototype:JSONEncode(input) - return json.encode(input) -end - -function HttpService.prototype:JSONDecode(input) - return json.decode(input) -end - +local BaseInstance = import("./BaseInstance") +local json = import("../json") +local http = import("../http") + +local HttpService = BaseInstance:extend("HttpService") + +function HttpService.prototype:JSONEncode(input) + return json.encode(input) +end + +function HttpService.prototype:JSONDecode(input) + return json.decode(input) +end + +function HttpService.prototype:GetAsync(url) + return http.get(url) +end + return HttpService \ No newline at end of file From 9b95bdeb964ea4fb14243c87555a51c75d44112d Mon Sep 17 00:00:00 2001 From: Lucien Greathouse Date: Mon, 13 Aug 2018 15:28:01 -0700 Subject: [PATCH 2/3] Fix require --- lib/http.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http.lua b/lib/http.lua index 5d12070..464bc6d 100644 --- a/lib/http.lua +++ b/lib/http.lua @@ -1,4 +1,4 @@ -local exists, http = require("socket.http") +local exists, http = pcall(require, "socket.http") local httpShim = {} From 96d4166a2d9e146e6955eeacccc0c79a86a177f5 Mon Sep 17 00:00:00 2001 From: Lucien Greathouse Date: Sun, 19 Aug 2018 01:21:39 -0700 Subject: [PATCH 3/3] Improve HTTP implementation, add mocking support --- lib/http.lua | 16 +++---- lib/instances/Game.lua | 3 +- lib/instances/HttpService.lua | 70 ++++++++++++++++++++++++++++-- lib/instances/HttpService_spec.lua | 19 ++++++++ 4 files changed, 96 insertions(+), 12 deletions(-) diff --git a/lib/http.lua b/lib/http.lua index 464bc6d..cf48735 100644 --- a/lib/http.lua +++ b/lib/http.lua @@ -1,15 +1,15 @@ -local exists, http = pcall(require, "socket.http") +local httpExists, socketHttp = pcall(require, "socket.http") +local ltn12Exists, ltn12 = pcall(require, "ltn12") -local httpShim = {} +local http = {} -function httpShim.get(url) +function http.request() error("Please install `luasocket` to use HTTP features.", 2) end -if exists then - function httpShim.get(url) - return (http.request(url)) - end +if httpExists and ltn12Exists then + http.request = socketHttp.request + http.tableSink = ltn12.sink.table end -return httpShim \ No newline at end of file +return http \ No newline at end of file diff --git a/lib/instances/Game.lua b/lib/instances/Game.lua index 3ebc945..9ef6820 100644 --- a/lib/instances/Game.lua +++ b/lib/instances/Game.lua @@ -1,3 +1,4 @@ +local http = import("../http") local BaseInstance = import("./BaseInstance") local AnalyticsService = import("./AnalyticsService") @@ -27,7 +28,7 @@ function Game:init(instance) CoreGui:new().Parent = instance CorePackages:new().Parent = instance GuiService:new().Parent = instance - HttpService:new().Parent = instance + HttpService:new(http).Parent = instance LocalizationService:new().Parent = instance NotificationService:new().Parent = instance Players:new().Parent = instance diff --git a/lib/instances/HttpService.lua b/lib/instances/HttpService.lua index e34fa19..0c33da2 100644 --- a/lib/instances/HttpService.lua +++ b/lib/instances/HttpService.lua @@ -1,9 +1,13 @@ local BaseInstance = import("./BaseInstance") local json = import("../json") -local http = import("../http") local HttpService = BaseInstance:extend("HttpService") +function HttpService:init(instance, httpImpl) + local internalInstance = getmetatable(instance).instance + internalInstance.httpImpl = httpImpl +end + function HttpService.prototype:JSONEncode(input) return json.encode(input) end @@ -12,8 +16,68 @@ function HttpService.prototype:JSONDecode(input) return json.decode(input) end -function HttpService.prototype:GetAsync(url) - return http.get(url) +function HttpService.prototype:RequestAsync(options) + local internalInstance = getmetatable(self).instance + local httpImpl = internalInstance.httpImpl + + if type(options) ~= "table" then + error(("Bad argument #1 to RequestAsync: expected table, found %s"):format(type(options)), 2) + end + + local url = options.Url + local method = options.Method + local headers = options.Headers + local body = options.body + + if type(url) ~= "string" then + error(("Option `Url` must be a string, but it was a %s"):format(type(url)), 2) + end + + if method ~= nil and type(method) ~= "string" then + error(("Option `Method` must be a string or nil, but it was a %s"):format(type(url)), 2) + end + + if headers ~= nil and type(headers) ~= "table" then + error(("Option `Headers` must be a table or nil, but it was a %s"):format(type(url)), 2) + end + + if body ~= nil and type(body) ~= "string" then + error(("Option `Body` must be a string or nil, but it was a %s"):format(type(url)), 2) + end + + if headers == nil then + headers = {} + end + + if body ~= nil then + headers["Content-Length"] = #body + end + + local responseBody = {} + + local _, statusCode, responseHeaders = httpImpl.request({ + url = url, + sink = httpImpl.tableSink(responseBody), + method = method, + headers = headers, + source = body, + }) + + return { + Success = statusCode >= 200 and statusCode <= 399, + StatusCode = statusCode, + StatusMessage = "uhhh", + Headers = responseHeaders, + Body = table.concat(responseBody), + } +end + +function HttpService.prototype:GetAsync() + error("GetAsync is not implemented by Lemur -- use RequestAsync instead.", 2) +end + +function HttpService.prototype:PostAsync() + error("PostAsync is not implemented by Lemur -- use RequestAsync instead.", 2) end return HttpService \ No newline at end of file diff --git a/lib/instances/HttpService_spec.lua b/lib/instances/HttpService_spec.lua index 52ce55a..508c56a 100644 --- a/lib/instances/HttpService_spec.lua +++ b/lib/instances/HttpService_spec.lua @@ -18,4 +18,23 @@ describe("instances.HttpService", function() assert.are.same(instance:JSONDecode("[1,true]"), { 1, true }) end) + + it("should send HTTP requests", function() + local httpImpl = { + request = function() + return 1, 200, {} + end, + tableSink = function() + return {} + end, + } + + local instance = HttpService:new(httpImpl) + + local response = instance:RequestAsync({ + Url = "https://google.com/", + }) + + print(response.Body) + end) end) \ No newline at end of file