Publish/Receive Loop¶
End-to-end flow when one user publishes a module and another receives it. The receiving side required no new code — CPulseConnection.ProcessPublishQueue already handled SettingsType.CORE_MODULE. This page documents how the round-trip works so future maintainers know where each piece lives.
Round-trip diagram¶
sequenceDiagram
participant A as User A (publisher)
participant DB as Database (PublishQueue column)
participant B as User B (receiver)
participant VFS as Pulse.UserSettings (B's VFS)
participant Module as CCoreModule (B's instance)
A->>A: Right-click module header
A->>A: Click "Publish Module..."
Note over A: btnPublish_ItemClick:<br/>builds CPublishInfo_CSD_1<br/>SettingsType = CORE_MODULE<br/>PublishMap("Module") = ModuleID<br/>SerialData = CCoreModuleData
A->>DB: ShowPublishForm writes to<br/>PublishQueue rows of target users
Note over B: Later — User B clicks Refresh
B->>DB: Read own PublishQueue
B->>B: ProcessPublishQueue() drains the queue
Note over B: For SettingsType.CORE_MODULE:<br/>writes SerialData into<br/>VirtualFile("\<ModuleID>.core")
B->>VFS: Update virtual file
B->>B: Main.LoadFromFiles()
loop For each core module
B->>Module: Settings.LoadFromVirtualFile()
Module->>Module: Settings_DataLoadEnd fires
Module->>Module: Disposes inner MyTabPage instances
Module->>Module: Recreates from CoreModuleData.m_BoxModuleTabs
end
Module->>B: Tab control rebuilt with A's tabs
Publisher side (User A)¶
The new btnPublish_ItemClick handler in FCoreModule_Popup.vb does three things:
curCoreModule.Settings.RaiseOnDataSave() ' (1)
Dim newPF As New SaveAndShare.CPublishInfo_CSD_1(
curCoreModule.Settings.m_SerialData, ' (2)
SaveAndShare.SettingsType.CORE_MODULE)
newPF.PublishPolicy.PublishPolicyCode = SaveAndShare.PolicyCode.Everyone
newPF.PublishMap.Add("Module", curCoreModule.ModuleInfo.ModuleID) ' (3)
newPF.ShowPublishForm(Instance.MainForm)
RaiseOnDataSave()flushes the in-memory tab state intoCoreModuleData.m_BoxModuleTabs. Without this, recently-edited tabs would not be in the published payload.CCoreModule.Settings_DataSaveBegin(around line 374 ofCCoreModule.vb) is the handler that does the flush.m_SerialDatais theCCoreModuleDataitself.CPublishInfo_CSD_1accepts any serializable payload.PublishMap("Module") = ModuleIDis the key the receiver uses to locate the right virtual file. This shape is whatProcessPublishQueueexpects (see below).
ShowPublishForm is the existing UI — picks recipients, writes entries into each recipient's PublishQueue column.
Receiver side (User B)¶
Triggered when User B clicks the global Refresh button (Main.btnRefreshCurrent_MouseDown around line 1457): Main.vb — global Refresh handler (excerpt)
SaveSettingsToVirtualFileAndDatabase()
If Pulse.Connection.ProcessPublishQueue Then
LoadFromFiles()
End If
ProcessPublishQueue reads User B's row from the USER_CONTROL table, deserializes the PublishQueue column into a Queue(Of CPublishInfo_CSD_1), and drains it: CPulseConnection.vb — ProcessPublishQueue (CORE_MODULE branch)
While PublishQueue.Count > 0
Dim curPublishInfo = PublishQueue.Dequeue()
Select Case curPublishInfo.SettingsType
Case SettingsType.CORE_MODULE
Dim szCoreModuleVFBName As String = "\" & curPublishInfo.PublishMap("Module") & ".core"
Pulse.UserSettings.VirtualFile(szCoreModuleVFBName).SerializableObject = curPublishInfo.SerialData
' ... (TAB branch is similar)
End Select
End While
Two things are happening:
- Lookup key. The path \<ModuleID>.core is the canonical virtual file name for a core module's settings. Same key is used everywhere else for LoadFromVirtualFile / SaveToVirtualFile.
- In-memory write. The new CCoreModuleData is now in User B's Pulse.UserSettings virtual file system, but the live CCoreModule instance is still showing the old data.
The "live update" happens inside LoadFromFiles (around line 2106 of Main.vb):
For Each curCoreModule As CCoreModule In m_CoreModules
curCoreModule.Settings.LoadFromVirtualFile()
Next
LoadFromVirtualFile reads from Pulse.UserSettings.VirtualFile(...) (which now contains A's payload), fires DataLoad, and CCoreModule.Settings_DataLoadEnd rebuilds the tab control: CCoreModule.vb — Settings_DataLoadEnd (rebuild loop)
m_TabControl.TabPages.Clear()
For Each curTab As CBoxModuleTabData In CoreModuleData.m_BoxModuleTabs
Dim newTabPage As New MyTabPage(True)
m_TabControl.TabPages.Add(newTabPage)
newTabPage.SerialData = curTab
Next
m_TabControl.PerformLayout()
When User B clicks the refreshed module tab, the new MyTabPage instances run their LoadSettings() / LoadData() flow on focus, populating each Pulse box with live data.
Why no new code on the receive side¶
The shape btnPublish_ItemClick produces — SettingsType.CORE_MODULE, PublishMap("Module") = ModuleID, SerialData = CCoreModuleData — exactly matches what ProcessPublishQueue already expects. The downstream chain (LoadFromFiles → LoadFromVirtualFile → Settings_DataLoadEnd) was also already in place for handling settings reloads from any source (user switch, manual import, etc.), so it picks up the published payload without needing to know it came from a publish.
This means the publish-receive loop for Load Module from File… is also implicit: a file load uses the same Settings.RaiseOnDataLoad() trigger, so the rebuild path is shared.