From 0ddd5eabbdd038882b70956f17516daaaf4af4ef Mon Sep 17 00:00:00 2001 From: Maloron Date: Wed, 3 Jun 2026 11:52:25 +0300 Subject: [PATCH] Optimize FFI bridge serialization and move blocking Swift FFI calls to background --- GooseSwift/HealthDataStore+Snapshots.swift | 129 +++++++++++++++------ GooseSwift/HealthDataStore.swift | 69 ++++++----- Rust/core/src/bridge.rs | 21 +++- 3 files changed, 146 insertions(+), 73 deletions(-) diff --git a/GooseSwift/HealthDataStore+Snapshots.swift b/GooseSwift/HealthDataStore+Snapshots.swift index 7614974d5..2941077f1 100644 --- a/GooseSwift/HealthDataStore+Snapshots.swift +++ b/GooseSwift/HealthDataStore+Snapshots.swift @@ -5,49 +5,102 @@ import UIKit extension HealthDataStore { func runPacketScores() { + packetScoreStatus = "Extracting bridge packet-derived scores..." let baseArgs = bridgeBaseArgs(requireTrustedEvidence: false) - do { - packetScoreReports["sleep"] = try sleepScoreReport(baseArgs: baseArgs) - refreshPrimarySleepFromScoreReport() - packetScoreReports["strain"] = try bridge.request( - method: "metrics.strain_score_from_features", - args: baseArgs.merging([ - "resting_start": "0000", - "resting_end": "9999", - "resting_baseline_min_days": 3, - ]) { _, new in new } - ) - packetScoreReports["recovery"] = try bridge.request( - method: "metrics.recovery_score_from_features", - args: baseArgs.merging(recoveryScoreBridgeArgs()) { _, new in new } - ) - packetScoreReports["stress"] = try bridge.request( - method: "metrics.stress_score_from_features", - args: baseArgs.merging([ - "resting_start": "0000", - "resting_end": "9999", - "hrv_start": "0000", - "hrv_end": "9999", - "hrv_baseline_start": "0000", - "hrv_baseline_end": "9999", - "resting_baseline_min_days": 3, - "hrv_min_rr_intervals_to_compute": 2, - "hrv_baseline_min_days": 3, - ]) { _, new in new } - ) - packetScoreStatus = "Bridge packet-derived scores recomputed" - } catch { - packetScoreStatus = "Bridge score run blocked: \(Self.shortError(error))" + let recoveryArgs = baseArgs.merging(recoveryScoreBridgeArgs()) { _, new in new } + let strainArgs = baseArgs.merging([ + "resting_start": "0000", + "resting_end": "9999", + "resting_baseline_min_days": 3, + ]) { _, new in new } + let stressArgs = baseArgs.merging([ + "resting_start": "0000", + "resting_end": "9999", + "hrv_start": "0000", + "hrv_end": "9999", + "hrv_baseline_start": "0000", + "hrv_baseline_end": "9999", + "resting_baseline_min_days": 3, + "hrv_min_rr_intervals_to_compute": 2, + "hrv_baseline_min_days": 3, + ]) { _, new in new } + + let bridge = self.bridge + packetInputQueue.async { [weak self] in + do { + let sleepReport = try bridge.request( + method: "metrics.sleep_score_from_features", + args: baseArgs.merging([ + "sleep_need_minutes": 480.0, + "low_motion_threshold_0_to_1": 0.05, + "disturbance_motion_threshold_0_to_1": 0.20, + "target_midpoint_minutes_since_midnight": 180.0, + "history_import_in_progress": false, + "algorithm_id": "goose.sleep.v1", + ]) { _, new in new } + ) + let strainReport = try bridge.request( + method: "metrics.strain_score_from_features", + args: strainArgs + ) + let recoveryReport = try bridge.request( + method: "metrics.recovery_score_from_features", + args: recoveryArgs + ) + let stressReport = try bridge.request( + method: "metrics.stress_score_from_features", + args: stressArgs + ) + + DispatchQueue.main.async { [weak self] in + guard let self else { return } + self.packetScoreReports["sleep"] = sleepReport + self.refreshPrimarySleepFromScoreReport() + self.packetScoreReports["strain"] = strainReport + self.packetScoreReports["recovery"] = recoveryReport + self.packetScoreReports["stress"] = stressReport + self.packetScoreStatus = "Bridge packet-derived scores recomputed" + } + } catch { + let shortErr = Self.shortError(error) + DispatchQueue.main.async { [weak self] in + guard let self else { return } + self.packetScoreStatus = "Bridge score run blocked: \(shortErr)" + } + } } } func runSleepScore() { - do { - packetScoreReports["sleep"] = try sleepScoreReport(baseArgs: bridgeBaseArgs(requireTrustedEvidence: false)) - refreshPrimarySleepFromScoreReport() - packetScoreStatus = "Bridge sleep score recomputed" - } catch { - packetScoreStatus = "Bridge sleep score blocked: \(Self.shortError(error))" + packetScoreStatus = "Extracting bridge sleep score..." + let baseArgs = bridgeBaseArgs(requireTrustedEvidence: false) + let bridge = self.bridge + packetInputQueue.async { [weak self] in + do { + let sleepReport = try bridge.request( + method: "metrics.sleep_score_from_features", + args: baseArgs.merging([ + "sleep_need_minutes": 480.0, + "low_motion_threshold_0_to_1": 0.05, + "disturbance_motion_threshold_0_to_1": 0.20, + "target_midpoint_minutes_since_midnight": 180.0, + "history_import_in_progress": false, + "algorithm_id": "goose.sleep.v1", + ]) { _, new in new } + ) + DispatchQueue.main.async { [weak self] in + guard let self else { return } + self.packetScoreReports["sleep"] = sleepReport + self.refreshPrimarySleepFromScoreReport() + self.packetScoreStatus = "Bridge sleep score recomputed" + } + } catch { + let shortErr = Self.shortError(error) + DispatchQueue.main.async { [weak self] in + guard let self else { return } + self.packetScoreStatus = "Bridge sleep score blocked: \(shortErr)" + } + } } } diff --git a/GooseSwift/HealthDataStore.swift b/GooseSwift/HealthDataStore.swift index 2ad47dc82..d509a121c 100644 --- a/GooseSwift/HealthDataStore.swift +++ b/GooseSwift/HealthDataStore.swift @@ -162,38 +162,49 @@ final class HealthDataStore: ObservableObject { } func refreshBridgeCatalogs() { - do { - let algorithmsValue = try bridge.requestValue(method: "metrics.built_in_definitions") - let referencesValue = try bridge.requestValue(method: "metrics.reference_definitions") - let preferencesValue = try bridge.requestValue(method: "metrics.default_preferences") + catalogStatus = "Loading bridge catalog..." + let bridge = self.bridge + packetInputQueue.async { [weak self] in + do { + let algorithmsValue = try bridge.requestValue(method: "metrics.built_in_definitions") + let referencesValue = try bridge.requestValue(method: "metrics.reference_definitions") + let preferencesValue = try bridge.requestValue(method: "metrics.default_preferences") - let parsedAlgorithms = Self.algorithmRows(from: algorithmsValue) - .map { HealthAlgorithmDefinition(row: $0, source: .bridge("metrics.built_in_definitions")) } - let parsedReferences = Self.algorithmRows(from: referencesValue) - .map { HealthAlgorithmDefinition(row: $0, source: .bridge("metrics.reference_definitions")) } - let parsedPreferences = Self.preferenceRows(from: preferencesValue) + let parsedAlgorithms = Self.algorithmRows(from: algorithmsValue) + .map { HealthAlgorithmDefinition(row: $0, source: .bridge("metrics.built_in_definitions")) } + let parsedReferences = Self.algorithmRows(from: referencesValue) + .map { HealthAlgorithmDefinition(row: $0, source: .bridge("metrics.reference_definitions")) } + let parsedPreferences = Self.preferenceRows(from: preferencesValue) - if !parsedAlgorithms.isEmpty { - algorithmDefinitions = parsedAlgorithms - } - if !parsedReferences.isEmpty { - referenceDefinitions = parsedReferences - } - if !parsedPreferences.isEmpty { - selectedAlgorithmByFamily = parsedPreferences - } else { - selectedAlgorithmByFamily = Dictionary( - uniqueKeysWithValues: algorithmDefinitions.map { ($0.family, $0.id) } - ) + DispatchQueue.main.async { [weak self] in + guard let self else { return } + if !parsedAlgorithms.isEmpty { + self.algorithmDefinitions = parsedAlgorithms + } + if !parsedReferences.isEmpty { + self.referenceDefinitions = parsedReferences + } + if !parsedPreferences.isEmpty { + self.selectedAlgorithmByFamily = parsedPreferences + } else { + self.selectedAlgorithmByFamily = Dictionary( + uniqueKeysWithValues: self.algorithmDefinitions.map { ($0.family, $0.id) } + ) + } + self.catalogSource = .bridge("Rust metric registry") + self.catalogStatus = "Bridge catalog loaded" + } + } catch { + let shortErr = Self.shortError(error) + DispatchQueue.main.async { [weak self] in + guard let self else { return } + self.algorithmDefinitions = [] + self.referenceDefinitions = [] + self.selectedAlgorithmByFamily = [:] + self.catalogSource = .unavailable("Rust catalog unavailable") + self.catalogStatus = "Metric catalog unavailable: \(shortErr)" + } } - catalogSource = .bridge("Rust metric registry") - catalogStatus = "Bridge catalog loaded" - } catch { - algorithmDefinitions = [] - referenceDefinitions = [] - selectedAlgorithmByFamily = [:] - catalogSource = .unavailable("Rust catalog unavailable") - catalogStatus = "Metric catalog unavailable: \(Self.shortError(error))" } } diff --git a/Rust/core/src/bridge.rs b/Rust/core/src/bridge.rs index 754b2719b..1bc5645a5 100644 --- a/Rust/core/src/bridge.rs +++ b/Rust/core/src/bridge.rs @@ -210,6 +210,8 @@ struct ParseFrameBatchArgs { frames: Vec, #[serde(default = "default_device_type")] device_type: String, + #[serde(default = "default_true")] + include_result: bool, } #[derive(Debug, Clone, Deserialize)] @@ -2546,12 +2548,19 @@ fn parse_frame_hex_batch_bridge(args: ParseFrameBatchArgs) -> GooseResult results.push(json!({ - "index": index, - "ok": true, - "compact": compact_parsed_frame_summary(&parsed), - "result": parsed, - })), + Ok(parsed) => { + let mut item = json!({ + "index": index, + "ok": true, + "compact": compact_parsed_frame_summary(&parsed), + }); + if args.include_result { + if let Some(obj) = item.as_object_mut() { + obj.insert("result".to_string(), json!(parsed)); + } + } + results.push(item); + } Err(error) => results.push(json!({ "index": index, "ok": false,