mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-20 17:41:37 +00:00
136 lines
No EOL
3.2 KiB
Lua
136 lines
No EOL
3.2 KiB
Lua
local t = require(script.Parent.Parent.t)
|
|
|
|
local strict = require(script.Parent.strict)
|
|
|
|
local Status = strict("Session.Status", {
|
|
NotStarted = "NotStarted",
|
|
Connecting = "Connecting",
|
|
Connected = "Connected",
|
|
Disconnected = "Disconnected",
|
|
})
|
|
|
|
local function DEBUG_printPatch(patch)
|
|
local HttpService = game:GetService("HttpService")
|
|
|
|
for removed in ipairs(patch.removed) do
|
|
print("Remove:", removed)
|
|
end
|
|
|
|
for id, added in pairs(patch.added) do
|
|
print("Add:", id, HttpService:JSONEncode(added))
|
|
end
|
|
|
|
for updated in ipairs(patch.updated) do
|
|
print("Update:", HttpService:JSONEncode(updated))
|
|
end
|
|
end
|
|
|
|
local ServeSession = {}
|
|
ServeSession.__index = ServeSession
|
|
|
|
ServeSession.Status = Status
|
|
|
|
local validateServeOptions = t.strictInterface({
|
|
apiContext = t.table,
|
|
reconciler = t.table,
|
|
})
|
|
|
|
function ServeSession.new(options)
|
|
assert(validateServeOptions(options))
|
|
|
|
local self = {
|
|
__status = Status.NotStarted,
|
|
__apiContext = options.apiContext,
|
|
__reconciler = options.reconciler,
|
|
__statusChangedCallback = nil,
|
|
}
|
|
|
|
setmetatable(self, ServeSession)
|
|
|
|
return self
|
|
end
|
|
|
|
function ServeSession:onStatusChanged(callback)
|
|
self.__statusChangedCallback = callback
|
|
end
|
|
|
|
function ServeSession:start()
|
|
self:__setStatus(Status.Connecting)
|
|
|
|
self.__apiContext:connect()
|
|
:andThen(function(serverInfo)
|
|
self:__setStatus(Status.Connected)
|
|
|
|
local rootInstanceId = serverInfo.rootInstanceId
|
|
|
|
return self:__initialSync(rootInstanceId)
|
|
:andThen(function()
|
|
return self:__mainSyncLoop()
|
|
end)
|
|
end)
|
|
:catch(function(err)
|
|
self:__stopInternal(err)
|
|
end)
|
|
end
|
|
|
|
function ServeSession:stop()
|
|
self:__stopInternal()
|
|
end
|
|
|
|
function ServeSession:__initialSync(rootInstanceId)
|
|
return self.__apiContext:read({ rootInstanceId })
|
|
:andThen(function(readResponseBody)
|
|
-- Tell the API Context that we're up-to-date with the version of
|
|
-- the tree defined in this response.
|
|
self.__apiContext:setMessageCursor(readResponseBody.messageCursor)
|
|
|
|
-- Calculate the initial patch to apply to the DataModel to catch us
|
|
-- up to what Rojo thinks the place should look like.
|
|
local hydratePatch = self.__reconciler:hydrate(
|
|
readResponseBody.instances,
|
|
rootInstanceId,
|
|
game
|
|
)
|
|
|
|
-- TODO: Prompt user to notify them of this patch, since it's
|
|
-- effectively a conflict between the Rojo server and the client.
|
|
|
|
self.__reconciler:applyPatch(hydratePatch)
|
|
end)
|
|
end
|
|
|
|
function ServeSession:__mainSyncLoop()
|
|
return self.__apiContext:retrieveMessages()
|
|
:andThen(function(messages)
|
|
for _, message in ipairs(messages) do
|
|
-- TODO: Update server to return patches in correct format so
|
|
-- that we don't have to transform them for the reconciler.
|
|
local asPatch = {
|
|
removed = message.removedInstances,
|
|
updated = message.updatedInstances,
|
|
added = message.addedInstances,
|
|
}
|
|
|
|
self.__reconciler:applyPatch(asPatch)
|
|
end
|
|
|
|
if self.__status ~= Status.Disconnected then
|
|
return self:__mainSyncLoop()
|
|
end
|
|
end)
|
|
end
|
|
|
|
function ServeSession:__stopInternal(err)
|
|
self:__setStatus(Status.Disconnected, err)
|
|
self.__apiContext:disconnect()
|
|
end
|
|
|
|
function ServeSession:__setStatus(status, detail)
|
|
self.__status = status
|
|
|
|
if self.__statusChangedCallback ~= nil then
|
|
self.__statusChangedCallback(status, detail)
|
|
end
|
|
end
|
|
|
|
return ServeSession |