120 lines
3.7 KiB
Swift
120 lines
3.7 KiB
Swift
//
|
|
// 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<Data>(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)
|
|
}
|
|
}
|
|
}
|