Skip to content

Commit 72ff2e0

Browse files
fix(voice): preserve canonical credential results
1 parent b1268c3 commit 72ff2e0

1 file changed

Lines changed: 49 additions & 6 deletions

File tree

src-tauri/src/commands/openai_voice_credentials.rs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@ fn clear_account(account: &str) -> Result<(), String> {
5959
}
6060
}
6161

62+
#[cfg(any(test, target_os = "macos"))]
63+
fn canonical_mutation_with_legacy_cleanup<T>(
64+
canonical_mutation: impl FnOnce() -> Result<T, String>,
65+
legacy_cleanup: impl FnOnce() -> Result<(), String>,
66+
) -> Result<T, String> {
67+
let value = canonical_mutation()?;
68+
if let Err(error) = legacy_cleanup() {
69+
log::warn!("Could not remove Berd's legacy OpenAI voice credential: {error}");
70+
}
71+
Ok(value)
72+
}
73+
6274
#[cfg(target_os = "macos")]
6375
pub(crate) fn read(credential: OpenAiVoiceCredential) -> Result<Option<String>, String> {
6476
if let Some(api_key) = read_account(credential.account())? {
@@ -79,10 +91,14 @@ pub(crate) fn read(_credential: OpenAiVoiceCredential) -> Result<Option<String>,
7991
#[cfg(target_os = "macos")]
8092
pub(crate) fn store(credential: OpenAiVoiceCredential, api_key: &str) -> Result<(), String> {
8193
let entry = entry(credential.account())?;
82-
entry
83-
.set_password(api_key)
84-
.map_err(|error| format!("Could not save Berd's OpenAI voice credential: {error}"))?;
85-
clear_account(LEGACY_TTS_KEYCHAIN_ACCOUNT)
94+
canonical_mutation_with_legacy_cleanup(
95+
|| {
96+
entry
97+
.set_password(api_key)
98+
.map_err(|error| format!("Could not save Berd's OpenAI voice credential: {error}"))
99+
},
100+
|| clear_account(LEGACY_TTS_KEYCHAIN_ACCOUNT),
101+
)
86102
}
87103

88104
#[cfg(not(target_os = "macos"))]
@@ -92,8 +108,10 @@ pub(crate) fn store(_credential: OpenAiVoiceCredential, _api_key: &str) -> Resul
92108

93109
#[cfg(target_os = "macos")]
94110
pub(crate) fn clear(credential: OpenAiVoiceCredential) -> Result<(), String> {
95-
clear_account(credential.account())?;
96-
clear_account(LEGACY_TTS_KEYCHAIN_ACCOUNT)
111+
canonical_mutation_with_legacy_cleanup(
112+
|| clear_account(credential.account()),
113+
|| clear_account(LEGACY_TTS_KEYCHAIN_ACCOUNT),
114+
)
97115
}
98116

99117
#[cfg(not(target_os = "macos"))]
@@ -109,9 +127,34 @@ pub(crate) fn require(credential: OpenAiVoiceCredential) -> Result<String, Strin
109127
#[cfg(test)]
110128
mod tests {
111129
use super::*;
130+
use std::cell::RefCell;
112131

113132
#[test]
114133
fn text_to_speech_uses_the_shared_voice_keychain_account() {
115134
assert_eq!(OpenAiVoiceCredential::TextToSpeech.account(), "api-key");
116135
}
136+
137+
#[test]
138+
fn legacy_cleanup_failure_does_not_change_canonical_mutation_result() {
139+
let credential = RefCell::new(None);
140+
let save = canonical_mutation_with_legacy_cleanup(
141+
|| {
142+
credential.replace(Some("shared-key"));
143+
Ok(())
144+
},
145+
|| Err("legacy cleanup failed".to_string()),
146+
);
147+
assert_eq!(save, Ok(()));
148+
assert_eq!(*credential.borrow(), Some("shared-key"));
149+
150+
let clear = canonical_mutation_with_legacy_cleanup(
151+
|| {
152+
credential.replace(None);
153+
Ok(())
154+
},
155+
|| Err("legacy cleanup failed".to_string()),
156+
);
157+
assert_eq!(clear, Ok(()));
158+
assert_eq!(*credential.borrow(), None);
159+
}
117160
}

0 commit comments

Comments
 (0)