Break apart plugin reconciler (#332)

* Start splitting apart reconciler, with tests

* Reify children in reify

* Baseline hydrate implementation

* Remove debug print

* Scaffold out diff implementation, just supporting name changes

* invariant -> error in decodeValue

* Flesh out diff and add getProperty

* Clear out top-level reconciler interface, start updating code that touches it

* Address review feedback

* Add (experimental) Selene configuration

* Add emptiness checks to PatchSet, remove unimplement invert method

* Improve descendant destruction behavior in InstanceMap

* Track instanceId on all reify errors

* Base implementation of applyPatch, returning partial patches on failure

* Change reify to accept InstanceMap and insert instances into it

* Start testing applyPatch for removals

* Add test for applyPatch adding instances successfully and not

* Add , which is just error with formatting

* Correctly use new diff and applyPatch APIs

* Improve applyPatch logging and fix field name typo

* Better debug output when reify fails

* Print out unapplied patch in debug mode

* Don't write properties if their values are not different.

This was exposed trying to sync the Rojo plugin, which
has a gigantic ModuleScript in it with the reflection
database. This workaround was present in some form in
many versions of Rojo, and I guess we still need it.

This time, I actually documented why it's here so that
I don't forget for the umpteenth time...

* Add placeholder test that needs to happen still

* Introduce easier plugin testing, write applyPatch properties test

* Delete legacy get/setCanonicalProperty files

* Fix trying to remove numbers instead of instances

* Change applyPatch to return partial patches instead of binary success

* Work towards being able to decode and apply refs

* Add helpers for PatchSet assertions

* Apply refs in reify, test all cases

* Improve diagnostics when patches fail to apply

* Stop logging when destroying untracked instances, it's ok

* Remove read before setting property in applyPatch

* Fix diff thinking all properties are changed
This commit is contained in:
Lucien Greathouse
2020-11-11 16:30:23 -08:00
committed by GitHub
parent 50f0a2bd2e
commit f66860bdfe
26 changed files with 1818 additions and 466 deletions

View File

@@ -5,6 +5,7 @@ local Fmt = require(script.Parent.Parent.Fmt)
local t = require(script.Parent.Parent.t)
local InstanceMap = require(script.Parent.InstanceMap)
local PatchSet = require(script.Parent.PatchSet)
local Reconciler = require(script.Parent.Reconciler)
local strict = require(script.Parent.strict)
@@ -214,22 +215,36 @@ function ServeSession:__initialSync(rootInstanceId)
-- the tree defined in this response.
self.__apiContext:setMessageCursor(readResponseBody.messageCursor)
Log.trace("Computing changes that plugin needs to make to catch up to server...")
-- For any instances that line up with the Rojo server's view, start
-- tracking them in the reconciler.
Log.trace("Matching existing Roblox instances to Rojo IDs")
self.__reconciler:hydrate(readResponseBody.instances, rootInstanceId, game)
-- 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(
Log.trace("Computing changes that plugin needs to make to catch up to server...")
local success, catchUpPatch = self.__reconciler:diff(
readResponseBody.instances,
rootInstanceId,
game
)
Log.trace("Computed hydration patch: {:#?}", debugPatch(hydratePatch))
if not success then
Log.error("Could not compute a diff to catch up to the Rojo server: {:#?}", catchUpPatch)
end
Log.trace("Computed hydration patch: {:#?}", debugPatch(catchUpPatch))
-- TODO: Prompt user to notify them of this patch, since it's
-- effectively a conflict between the Rojo server and the client.
-- effectively a conflict between the Rojo server and the client. In
-- the future, we'll ask which changes the user wants to keep.
self.__reconciler:applyPatch(hydratePatch)
local unappliedPatch = self.__reconciler:applyPatch(catchUpPatch)
if not PatchSet.isEmpty(unappliedPatch) then
Log.warn("Could not apply all changes requested by the Rojo server:\n{}",
PatchSet.humanSummary(self.__instanceMap, unappliedPatch))
end
end)
end
@@ -237,7 +252,12 @@ function ServeSession:__mainSyncLoop()
return self.__apiContext:retrieveMessages()
:andThen(function(messages)
for _, message in ipairs(messages) do
self.__reconciler:applyPatch(message)
local unappliedPatch = self.__reconciler:applyPatch(message)
if not PatchSet.isEmpty(unappliedPatch) then
Log.warn("Could not apply all changes requested by the Rojo server:\n{}",
PatchSet.humanSummary(self.__instanceMap, unappliedPatch))
end
end
if self.__status ~= Status.Disconnected then