From d117c964a3059fec284e0ea063a3f72189261ee1 Mon Sep 17 00:00:00 2001 From: Hammoud Mohammed Date: Wed, 20 May 2026 21:44:52 +0200 Subject: [PATCH] feat(github): add in-memory token cache for keychain reads and writes --- src-tauri/src/core/github/auth/keychain.rs | 37 ++++++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src-tauri/src/core/github/auth/keychain.rs b/src-tauri/src/core/github/auth/keychain.rs index 9ee22d0..ce3cc08 100644 --- a/src-tauri/src/core/github/auth/keychain.rs +++ b/src-tauri/src/core/github/auth/keychain.rs @@ -1,3 +1,5 @@ +use std::sync::{Mutex, OnceLock}; + use crate::core::errors::{AppError, AppResult}; use crate::core::github::constants::{KEYCHAIN_SERVICE, KEYCHAIN_USER}; @@ -5,6 +7,27 @@ use crate::core::github::types::GithubErrorCode; use super::session::cancel_github_login; +static TOKEN_CACHE: OnceLock>> = OnceLock::new(); + +fn token_cache() -> &'static Mutex> { + TOKEN_CACHE.get_or_init(|| Mutex::new(None)) +} + +fn cache_token(token: Option) -> AppResult<()> { + let mut cache = token_cache() + .lock() + .map_err(|_error| AppError::unknown("GitHub token cache lock failed"))?; + *cache = token; + Ok(()) +} + +fn cached_token() -> AppResult> { + token_cache() + .lock() + .map(|cache| cache.clone()) + .map_err(|_error| AppError::unknown("GitHub token cache lock failed")) +} + fn token_entry() -> AppResult { keyring::Entry::new(KEYCHAIN_SERVICE, KEYCHAIN_USER) .map_err(|_error| AppError::new(GithubErrorCode::KeychainFailed, "Keychain access failed")) @@ -13,12 +36,20 @@ fn token_entry() -> AppResult { pub fn save_token(token: &str) -> AppResult<()> { token_entry()? .set_password(token) - .map_err(|_error| AppError::new(GithubErrorCode::KeychainFailed, "Keychain access failed")) + .map_err(|_error| AppError::new(GithubErrorCode::KeychainFailed, "Keychain access failed"))?; + cache_token(Some(token.to_string())) } pub fn read_token() -> AppResult> { + if let Some(token) = cached_token()? { + return Ok(Some(token)); + } + match token_entry()?.get_password() { - Ok(token) => Ok(Some(token)), + Ok(token) => { + cache_token(Some(token.clone()))?; + Ok(Some(token)) + } Err(keyring::Error::NoEntry) => Ok(None), Err(_error) => Err(AppError::new( GithubErrorCode::KeychainFailed, @@ -30,7 +61,7 @@ pub fn read_token() -> AppResult> { pub fn delete_token() -> AppResult<()> { cancel_github_login(); match token_entry()?.delete_credential() { - Ok(()) | Err(keyring::Error::NoEntry) => Ok(()), + Ok(()) | Err(keyring::Error::NoEntry) => cache_token(None), Err(_error) => Err(AppError::new( GithubErrorCode::KeychainFailed, "Keychain access failed",