diff --git a/plugin/src/Http.lua b/plugin/src/Http.lua index 932f7e87..98997b9f 100644 --- a/plugin/src/Http.lua +++ b/plugin/src/Http.lua @@ -1,9 +1,17 @@ local HttpService = game:GetService("HttpService") +local HTTP_DEBUG = false + local Promise = require(script.Parent.Promise) local HttpError = require(script.Parent.HttpError) local HttpResponse = require(script.Parent.HttpResponse) +local function dprint(...) + if HTTP_DEBUG then + print(...) + end +end + local Http = {} Http.__index = Http @@ -20,6 +28,7 @@ function Http.new(baseUrl) end function Http:get(endpoint) + dprint("\nGET", endpoint) return Promise.new(function(resolve, reject) spawn(function() local ok, result = pcall(function() @@ -27,6 +36,7 @@ function Http:get(endpoint) end) if ok then + dprint("\t", result, "\n") resolve(HttpResponse.new(result)) else reject(HttpError.fromErrorString(result)) @@ -36,6 +46,8 @@ function Http:get(endpoint) end function Http:post(endpoint, body) + dprint("\nPOST", endpoint) + dprint(body) return Promise.new(function(resolve, reject) spawn(function() local ok, result = pcall(function() @@ -43,6 +55,7 @@ function Http:post(endpoint, body) end) if ok then + dprint("\t", result, "\n") resolve(HttpResponse.new(result)) else reject(HttpError.fromErrorString(result)) diff --git a/plugin/src/Main.server.lua b/plugin/src/Main.server.lua index fbf3d48a..24f75fce 100644 --- a/plugin/src/Main.server.lua +++ b/plugin/src/Main.server.lua @@ -12,17 +12,26 @@ local function main() toolbar:CreateButton("Test Connection", "Connect to Rojo Server", "") .Click:Connect(function() pluginInstance:connect() + :catch(function(err) + warn(err) + end) end) toolbar:CreateButton("Sync In", "Sync into Roblox Studio", "") .Click:Connect(function() pluginInstance:syncIn() + :catch(function(err) + warn(err) + end) end) toolbar:CreateButton("Toggle Polling", "Poll server for changes", "") .Click:Connect(function() spawn(function() pluginInstance:togglePolling() + :catch(function(err) + warn(err) + end) end) end) end diff --git a/plugin/src/Plugin.lua b/plugin/src/Plugin.lua index 65b7ea0b..4bb1185f 100644 --- a/plugin/src/Plugin.lua +++ b/plugin/src/Plugin.lua @@ -149,7 +149,7 @@ end function Plugin:connect() print("Testing connection...") - self:server() + return self:server() :andThen(function(server) return server:getInfo() end) @@ -163,8 +163,10 @@ end function Plugin:togglePolling() if self._polling then self:stopPolling() + + return Promise.resolve(nil) else - self:startPolling() + return self:startPolling() end end @@ -173,12 +175,30 @@ function Plugin:stopPolling() return end - print("Stopping polling...") + print("Stopped polling.") self._polling = false self._label.Enabled = false end +function Plugin:_pull(server, project, routes) + local items = server:read(routes):await() + + for index = 1, #routes do + local route = routes[index] + local partitionName = route[1] + local partition = project.partitions[partitionName] + local data = items[index] + + local fullRoute = collectMatch(partition.target, "[^.]+") + for i = 2, #route do + table.insert(fullRoute, routes[index][i]) + end + + write(game, fullRoute, data) + end +end + function Plugin:startPolling() if self._polling then return @@ -204,17 +224,7 @@ function Plugin:startPolling() table.insert(routes, change.route) end - local items = server:read(routes):await() - - for index = 1, #routes do - local partitionName = routes[index][1] - local partition = project.partitions[partitionName] - local data = items[index] - - local fullRoute = collectMatch(partition.target, "[^.]+") - - write(game, fullRoute, data) - end + self:_pull(server, project, routes) wait(Config.pollingRate) end @@ -231,23 +241,13 @@ function Plugin:syncIn() :andThen(function(server) local project = server:getInfo():await().project - local readRoutes = {} + local routes = {} for name in pairs(project.partitions) do - table.insert(readRoutes, {name}) + table.insert(routes, {name}) end - local items = server:read(readRoutes):await() - - for index = 1, #readRoutes do - local partitionName = readRoutes[index][1] - local partition = project.partitions[partitionName] - local data = items[index] - - local fullRoute = collectMatch(partition.target, "[^.]+") - - write(game, fullRoute, data) - end + self:_pull(server, project, routes) print("Sync successful!") end) diff --git a/plugin/src/Promise.lua b/plugin/src/Promise.lua index a1e8800a..12c82344 100644 --- a/plugin/src/Promise.lua +++ b/plugin/src/Promise.lua @@ -2,7 +2,7 @@ An implementation of Promises similar to Promise/A+. ]] -local PROMISE_DEBUG = true +local PROMISE_DEBUG = false -- If promise debugging is on, use a version of pcall that warns on failure. -- This is useful for finding errors that happen within Promise itself. @@ -89,6 +89,9 @@ function Promise.new(callback) -- Only valid if _status is set to something besides Started _value = nil, + -- If an error occurs with no observers, this will be set. + _unhandledRejection = false, + -- Queues representing functions we should invoke when we update! _queuedResolve = {}, _queuedReject = {}, @@ -157,6 +160,8 @@ end The given callbacks are invoked depending on that result. ]] function Promise:andThen(successHandler, failureHandler) + self._unhandledRejection = false + -- Create a new promise to follow this part of the chain return Promise.new(function(resolve, reject) -- Our default callbacks just pass values onto the next promise. @@ -199,6 +204,8 @@ end This matches the execution model of normal Roblox functions. ]] function Promise:await() + self._unhandledRejection = false + if self._status == Promise.Status.Started then local result local bindable = Instance.new("BindableEvent") @@ -279,11 +286,22 @@ function Promise:_reject(...) -- synchronously. We'll wait one tick, and if there are still no -- observers, then we should put a message in the console. - local message = ("Unhandled promise rejection:\n\n%s\n\n%s"):format( - tostring((...)), - self._source - ) - warn(message) + self._unhandledRejection = true + local err = tostring((...)) + + spawn(function() + -- Someone observed the error, hooray! + if not self._unhandledRejection then + return + end + + -- Build a reasonable message + local message = ("Unhandled promise rejection:\n\n%s\n\n%s"):format( + err, + self._source + ) + warn(message) + end) end end