From d60e7d0916da774a90309328938381be19807260 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 15 Jan 2026 11:15:35 -0600 Subject: [PATCH] Signed-off-by: Matt Bruce --- Sources/LocalData/Helpers/SyncHelper.swift | 30 ++++++------------- .../LocalData/Services/StorageRouter.swift | 19 ++++++++++-- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/Sources/LocalData/Helpers/SyncHelper.swift b/Sources/LocalData/Helpers/SyncHelper.swift index 4b57545..b9deb19 100644 --- a/Sources/LocalData/Helpers/SyncHelper.swift +++ b/Sources/LocalData/Helpers/SyncHelper.swift @@ -1,7 +1,5 @@ import Foundation -#if os(iOS) || os(watchOS) import WatchConnectivity -#endif /// Actor that handles WatchConnectivity sync operations. /// Manages data synchronization between iPhone and Apple Watch. @@ -35,7 +33,6 @@ actor SyncHelper { availability: PlatformAvailability, syncPolicy: SyncPolicy ) throws { - #if os(iOS) || os(watchOS) // Only sync for appropriate availability settings guard availability == .all || availability == .phoneWithWatchSync else { return @@ -54,7 +51,6 @@ actor SyncHelper { case .manual: try performSync(data: data, keyName: keyName) } - #endif } /// Manually triggers a sync for the given data. @@ -63,15 +59,12 @@ actor SyncHelper { /// - keyName: The key name for the application context. /// - Throws: Various errors if sync fails. public func manualSync(data: Data, keyName: String) throws { - #if os(iOS) || os(watchOS) try performSync(data: data, keyName: keyName) - #endif } /// Checks if sync is available. /// - Returns: True if WatchConnectivity is supported and active. public func isSyncAvailable() -> Bool { - #if os(iOS) || os(watchOS) guard WCSession.isSupported() else { return false } let session = WCSession.default @@ -82,25 +75,17 @@ actor SyncHelper { #else return true #endif - #else - return false - #endif } /// Gets the current application context. /// - Returns: The current application context dictionary. public func currentContext() -> [String: Any] { - #if os(iOS) || os(watchOS) guard WCSession.isSupported() else { return [:] } return WCSession.default.applicationContext - #else - return [:] - #endif } // MARK: - Private Helpers - #if os(iOS) || os(watchOS) private func performSync(data: Data, keyName: String) throws { guard WCSession.isSupported() else { return } @@ -129,16 +114,20 @@ actor SyncHelper { fileprivate func handleReceivedContext(_ context: [String: Any]) async { Logger.info(">>> [SYNC] Received application context with \(context.count) keys") for (key, value) in context { - guard let data = value as? Data else { continue } + guard let data = value as? Data else { + continue + } Logger.debug(">>> [SYNC] Processing received data for key: \(key)") - // Future implementation: Route this back to StorageRouter to update local storage - // For now, we just log it as a skeleton implementation + + do { + try await StorageRouter.shared.updateFromSync(keyName: key, data: data) + } catch { + Logger.error("Failed to update storage from sync for key: \(key)", error: error) + } } } - #endif } -#if os(iOS) || os(watchOS) /// A private proxy class to handle WCSessionDelegate callbacks and route them to the SyncHelper actor. private final class SessionDelegateProxy: NSObject, WCSessionDelegate { static let shared = SessionDelegateProxy() @@ -164,4 +153,3 @@ private final class SessionDelegateProxy: NSObject, WCSessionDelegate { } #endif } -#endif diff --git a/Sources/LocalData/Services/StorageRouter.swift b/Sources/LocalData/Services/StorageRouter.swift index 71d09f2..bdbca02 100644 --- a/Sources/LocalData/Services/StorageRouter.swift +++ b/Sources/LocalData/Services/StorageRouter.swift @@ -1,8 +1,6 @@ import Foundation -#if os(iOS) || os(watchOS) import WatchConnectivity -#endif /// The main storage router that coordinates all storage operations. /// Uses specialized helper actors for each storage domain. @@ -427,6 +425,23 @@ public actor StorageRouter: StorageProviding { ) } + // MARK: - Internal Sync Handling + + /// Internal method to update storage from received sync data. + /// This is called by SyncHelper when the paired device sends new context. + func updateFromSync(keyName: String, data: Data) async throws { + // Find the registered entry for this key + guard let entry = registeredEntries.first(where: { $0.descriptor.name == keyName }) else { + Logger.debug("Received sync data for unregistered or uncatalogued key: \(keyName)") + return + } + + // The data received is already 'secured' (encrypted if necessary) by the sender. + // We can store it directly in our local domain. + try await store(data, for: entry) + Logger.info("Successfully updated local storage from sync for key: \(keyName)") + } + // MARK: - Resolution Helpers private func resolveService(_ service: String?) throws -> String {