// // WatchMainViewModel+WCSessionDelegate.swift // Werkout_watch Watch App // // Created by Trey Tartt on 6/19/24. // import Foundation import WatchConnectivity import SwiftUI import HealthKit import os import SharedCore extension WatchMainViewModel: WCSessionDelegate { func session(_ session: WCSession, didReceiveMessageData messageData: Data) { dataToAction(messageData: messageData) } func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { if let error { logger.error("Watch session activation failed: \(error.localizedDescription, privacy: .public)") } else { logger.info("Watch session activation state: \(activationState.rawValue, privacy: .public)") if activationState == .activated { DataSender.flushQueuedPayloadsIfPossible(session: session) } } } } class DataSender { private static let logger = Logger(subsystem: "com.werkout.watch", category: "session") private static let queue = DispatchQueue(label: "com.werkout.watch.sender") private static var queuedPayloads = BoundedFIFOQueue(maxCount: 100) static func send(_ data: Data) { if let validationError = WatchPayloadValidation.validate(data) { logger.error("Dropped invalid watch payload: \(String(describing: validationError), privacy: .public)") return } queue.async { let session = WCSession.default guard session.activationState == .activated else { enqueue(data) session.activate() return } deliver(data, using: session) flushQueuedPayloads(using: session) } } static func flushQueuedPayloadsIfPossible(session: WCSession = .default) { queue.async { flushQueuedPayloads(using: session) } } private static func flushQueuedPayloads(using session: WCSession) { guard session.activationState == .activated else { return } guard queuedPayloads.isEmpty == false else { return } let payloads = queuedPayloads.dequeueAll() payloads.forEach { deliver($0, using: session) } } private static func deliver(_ data: Data, using session: WCSession) { #if os(iOS) guard session.isWatchAppInstalled else { return } #else guard session.isCompanionAppInstalled else { return } #endif if session.isReachable { session.sendMessageData(data, replyHandler: nil) { error in logger.error("Cannot send watch message: \(error.localizedDescription, privacy: .public)") queue.async { enqueue(data) } } } else { session.transferUserInfo(["package": data]) } } private static func enqueue(_ data: Data) { let droppedCount = queuedPayloads.enqueue(data) if droppedCount > 0 { logger.warning("Dropping oldest queued watch payload to enforce queue cap") } } } extension WatchMainViewModel { func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String: Any]) { if let messageData = applicationContext["package"] as? Data { dataToAction(messageData: messageData) } } public func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any] = [:]) { if let messageData = userInfo["package"] as? Data { dataToAction(messageData: messageData) } } }