mirror of
https://github.com/littensy/charm.git
synced 2026-10-20 17:51:37 +00:00
fix: send init payload even if atom did not update
This commit is contained in:
parent
079abaacc1
commit
0dbc0587a0
2 changed files with 29 additions and 12 deletions
|
|
@ -6,7 +6,6 @@ type SyncPayload = types.SyncPayload
|
||||||
|
|
||||||
local atomRegister: { [string]: Charm.Atom } = {}
|
local atomRegister: { [string]: Charm.Atom } = {}
|
||||||
|
|
||||||
--- @client
|
|
||||||
local function registerAtoms(atoms: { [string]: Charm.Atom })
|
local function registerAtoms(atoms: { [string]: Charm.Atom })
|
||||||
for key, atom in atoms do
|
for key, atom in atoms do
|
||||||
if atomRegister[key] and atomRegister[key] ~= atom then
|
if atomRegister[key] and atomRegister[key] ~= atom then
|
||||||
|
|
@ -18,12 +17,10 @@ local function registerAtoms(atoms: { [string]: Charm.Atom })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @client
|
|
||||||
local function clearAtoms()
|
local function clearAtoms()
|
||||||
table.clear(atomRegister)
|
table.clear(atomRegister)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @client
|
|
||||||
local function unregisterAtoms(...: string)
|
local function unregisterAtoms(...: string)
|
||||||
for index = 1, select("#", ...) do
|
for index = 1, select("#", ...) do
|
||||||
local key = select(index, ...)
|
local key = select(index, ...)
|
||||||
|
|
@ -54,7 +51,6 @@ local function applyPatchPayload(data: { [string | number]: any })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @client
|
|
||||||
local function applyPayloads(payloads: { SyncPayload })
|
local function applyPayloads(payloads: { SyncPayload })
|
||||||
for _, payload in payloads do
|
for _, payload in payloads do
|
||||||
if payload.type == "init" then
|
if payload.type == "init" then
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ local function registerAtom<T>(key: string, atom: () -> T)
|
||||||
registeredAtom.stop = Charm.effect(function()
|
registeredAtom.stop = Charm.effect(function()
|
||||||
local value = atom()
|
local value = atom()
|
||||||
|
|
||||||
|
-- When preserving history, we need to keep track of previous values
|
||||||
|
-- so we can create granular patches for each change.
|
||||||
if config.preserveHistory and registeredAtom.value ~= value then
|
if config.preserveHistory and registeredAtom.value ~= value then
|
||||||
table.insert(globalUpdates, {
|
table.insert(globalUpdates, {
|
||||||
key = key,
|
key = key,
|
||||||
|
|
@ -81,7 +83,7 @@ end
|
||||||
|
|
||||||
local function createHistoricalPatches(): { any }
|
local function createHistoricalPatches(): { any }
|
||||||
local patchCount = #globalUpdates
|
local patchCount = #globalUpdates
|
||||||
local patches: { any } = table.create(patchCount)
|
local patches = table.create(patchCount)
|
||||||
|
|
||||||
for index, update in globalUpdates do
|
for index, update in globalUpdates do
|
||||||
patches[index] = patch.diff(update.previousValue, update.value)
|
patches[index] = patch.diff(update.previousValue, update.value)
|
||||||
|
|
@ -99,6 +101,8 @@ local function createHistoricalPayloadsForClient(client: any, patches: { any }):
|
||||||
|
|
||||||
local payloads: { SyncPayload } = {}
|
local payloads: { SyncPayload } = {}
|
||||||
|
|
||||||
|
-- Iterate over all global updates and see if the client is interested in
|
||||||
|
-- any of them. If so, we create a patch payload for the update.
|
||||||
for index, update in globalUpdates do
|
for index, update in globalUpdates do
|
||||||
local patchData = patches[index]
|
local patchData = patches[index]
|
||||||
|
|
||||||
|
|
@ -124,6 +128,23 @@ local function createHistoricalPayloadsForClient(client: any, patches: { any }):
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- If a pending atom was never updated, we still need to send its initial
|
||||||
|
-- state. This can happen if the atom was registered after its last change.
|
||||||
|
local initPayload: { [string]: any } = {}
|
||||||
|
|
||||||
|
for key, status in syncedAtoms do
|
||||||
|
local registeredAtom = atomRegister[key]
|
||||||
|
|
||||||
|
if status == PENDING_INITIAL_STATE and registeredAtom then
|
||||||
|
initPayload[key] = registeredAtom.value
|
||||||
|
syncedAtoms[key] = LISTENING_FOR_CHANGES
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if next(initPayload) ~= nil then
|
||||||
|
table.insert(payloads, 1, { type = "init" :: "init", data = initPayload })
|
||||||
|
end
|
||||||
|
|
||||||
return payloads
|
return payloads
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -148,10 +169,11 @@ local function createPayloadsForClient(client: any, patchData: any): { SyncPaylo
|
||||||
return payloads
|
return payloads
|
||||||
end
|
end
|
||||||
|
|
||||||
local shouldSendInitialState = false
|
|
||||||
local initPayload: { [string]: any } = {}
|
local initPayload: { [string]: any } = {}
|
||||||
local patchPayload: { [string]: any } = {}
|
local patchPayload: { [string]: any } = {}
|
||||||
|
|
||||||
|
-- Create patches for initialized atoms that changed, and add atoms that
|
||||||
|
-- are still pending initial state to the init payload.
|
||||||
for key, status in syncedAtoms do
|
for key, status in syncedAtoms do
|
||||||
local registeredAtom = atomRegister[key]
|
local registeredAtom = atomRegister[key]
|
||||||
|
|
||||||
|
|
@ -160,11 +182,10 @@ local function createPayloadsForClient(client: any, patchData: any): { SyncPaylo
|
||||||
elseif status == PENDING_INITIAL_STATE then
|
elseif status == PENDING_INITIAL_STATE then
|
||||||
initPayload[key] = registeredAtom.value
|
initPayload[key] = registeredAtom.value
|
||||||
syncedAtoms[key] = LISTENING_FOR_CHANGES
|
syncedAtoms[key] = LISTENING_FOR_CHANGES
|
||||||
shouldSendInitialState = true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if shouldSendInitialState then
|
if next(initPayload) ~= nil then
|
||||||
table.insert(payloads, { type = "init", data = initPayload })
|
table.insert(payloads, { type = "init", data = initPayload })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -175,7 +196,6 @@ local function createPayloadsForClient(client: any, patchData: any): { SyncPaylo
|
||||||
return payloads
|
return payloads
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @server
|
|
||||||
local function syncAtomsToClient(client: any, atoms: { [string]: () -> any })
|
local function syncAtomsToClient(client: any, atoms: { [string]: () -> any })
|
||||||
if not clientRegister[client] then
|
if not clientRegister[client] then
|
||||||
clientRegister[client] = {}
|
clientRegister[client] = {}
|
||||||
|
|
@ -187,17 +207,17 @@ local function syncAtomsToClient(client: any, atoms: { [string]: () -> any })
|
||||||
registerAtom(key, atom)
|
registerAtom(key, atom)
|
||||||
|
|
||||||
if not syncedAtoms[key] then
|
if not syncedAtoms[key] then
|
||||||
|
-- Mark the atom as pending initial state so we send its full value
|
||||||
|
-- the next time we sync.
|
||||||
syncedAtoms[key] = PENDING_INITIAL_STATE
|
syncedAtoms[key] = PENDING_INITIAL_STATE
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @server
|
|
||||||
local function unsyncClient(client: any)
|
local function unsyncClient(client: any)
|
||||||
clientRegister[client] = nil
|
clientRegister[client] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @server
|
|
||||||
local function unsyncAtomsFromClient(client: any, ...: string)
|
local function unsyncAtomsFromClient(client: any, ...: string)
|
||||||
local syncedAtoms = clientRegister[client]
|
local syncedAtoms = clientRegister[client]
|
||||||
|
|
||||||
|
|
@ -215,7 +235,6 @@ local function unsyncAtomsFromClient(client: any, ...: string)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @server
|
|
||||||
local function startSync(onSync: (client: any, payloads: { SyncPayload }) -> ())
|
local function startSync(onSync: (client: any, payloads: { SyncPayload }) -> ())
|
||||||
if connection then
|
if connection then
|
||||||
connection:Disconnect()
|
connection:Disconnect()
|
||||||
|
|
@ -226,6 +245,8 @@ local function startSync(onSync: (client: any, payloads: { SyncPayload }) -> ())
|
||||||
local function sync()
|
local function sync()
|
||||||
local patches = if config.preserveHistory then createHistoricalPatches() else createPatch()
|
local patches = if config.preserveHistory then createHistoricalPatches() else createPatch()
|
||||||
|
|
||||||
|
-- While payload objects are technically mutable as they are unique to
|
||||||
|
-- each client, the data inside them is not safe to mutate.
|
||||||
if Charm.flags.frozen then
|
if Charm.flags.frozen then
|
||||||
Charm.deepFreeze(patches)
|
Charm.deepFreeze(patches)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue