mirror of
https://github.com/bitwarden/browser
synced 2025-12-14 15:23:33 +00:00
PM-19424: React to IPC disconnect (#14123)
* React to IPC disconnects * Minor cleanup * Update apps/desktop/package.json Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com> * Relaxed ordering --------- Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
This commit is contained in:
@@ -49,6 +49,12 @@ trait Callback: Send + Sync {
|
|||||||
fn error(&self, error: BitwardenError);
|
fn error(&self, error: BitwardenError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(uniffi::Enum, Debug)]
|
||||||
|
pub enum ConnectionStatus {
|
||||||
|
Connected,
|
||||||
|
Disconnected,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(uniffi::Object)]
|
#[derive(uniffi::Object)]
|
||||||
pub struct MacOSProviderClient {
|
pub struct MacOSProviderClient {
|
||||||
to_server_send: tokio::sync::mpsc::Sender<String>,
|
to_server_send: tokio::sync::mpsc::Sender<String>,
|
||||||
@@ -57,6 +63,9 @@ pub struct MacOSProviderClient {
|
|||||||
response_callbacks_counter: AtomicU32,
|
response_callbacks_counter: AtomicU32,
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
response_callbacks_queue: Arc<Mutex<HashMap<u32, (Box<dyn Callback>, Instant)>>>,
|
response_callbacks_queue: Arc<Mutex<HashMap<u32, (Box<dyn Callback>, Instant)>>>,
|
||||||
|
|
||||||
|
// Flag to track connection status - atomic for thread safety without locks
|
||||||
|
connection_status: Arc<std::sync::atomic::AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[uniffi::export]
|
#[uniffi::export]
|
||||||
@@ -74,11 +83,13 @@ impl MacOSProviderClient {
|
|||||||
to_server_send,
|
to_server_send,
|
||||||
response_callbacks_counter: AtomicU32::new(0),
|
response_callbacks_counter: AtomicU32::new(0),
|
||||||
response_callbacks_queue: Arc::new(Mutex::new(HashMap::new())),
|
response_callbacks_queue: Arc::new(Mutex::new(HashMap::new())),
|
||||||
|
connection_status: Arc::new(std::sync::atomic::AtomicBool::new(false)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let path = desktop_core::ipc::path("autofill");
|
let path = desktop_core::ipc::path("autofill");
|
||||||
|
|
||||||
let queue = client.response_callbacks_queue.clone();
|
let queue = client.response_callbacks_queue.clone();
|
||||||
|
let connection_status = client.connection_status.clone();
|
||||||
|
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let rt = tokio::runtime::Builder::new_current_thread()
|
let rt = tokio::runtime::Builder::new_current_thread()
|
||||||
@@ -96,9 +107,11 @@ impl MacOSProviderClient {
|
|||||||
match serde_json::from_str::<SerializedMessage>(&message) {
|
match serde_json::from_str::<SerializedMessage>(&message) {
|
||||||
Ok(SerializedMessage::Command(CommandMessage::Connected)) => {
|
Ok(SerializedMessage::Command(CommandMessage::Connected)) => {
|
||||||
info!("Connected to server");
|
info!("Connected to server");
|
||||||
|
connection_status.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
Ok(SerializedMessage::Command(CommandMessage::Disconnected)) => {
|
Ok(SerializedMessage::Command(CommandMessage::Disconnected)) => {
|
||||||
info!("Disconnected from server");
|
info!("Disconnected from server");
|
||||||
|
connection_status.store(false, std::sync::atomic::Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
Ok(SerializedMessage::Message {
|
Ok(SerializedMessage::Message {
|
||||||
sequence_number,
|
sequence_number,
|
||||||
@@ -159,6 +172,17 @@ impl MacOSProviderClient {
|
|||||||
) {
|
) {
|
||||||
self.send_message(request, Box::new(callback));
|
self.send_message(request, Box::new(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_connection_status(&self) -> ConnectionStatus {
|
||||||
|
let is_connected = self
|
||||||
|
.connection_status
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed);
|
||||||
|
if is_connected {
|
||||||
|
ConnectionStatus::Connected
|
||||||
|
} else {
|
||||||
|
ConnectionStatus::Disconnected
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
|||||||
@@ -62,12 +62,56 @@ class CredentialProviderViewController: ASCredentialProviderViewController {
|
|||||||
return MacOsProviderClient.connect()
|
return MacOsProviderClient.connect()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Timer for checking connection status
|
||||||
|
private var connectionMonitorTimer: Timer?
|
||||||
|
private var lastConnectionStatus: ConnectionStatus = .disconnected
|
||||||
|
|
||||||
|
// Setup the connection monitoring timer
|
||||||
|
private func setupConnectionMonitoring() {
|
||||||
|
// Check connection status every 1 second
|
||||||
|
connectionMonitorTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
|
||||||
|
self?.checkConnectionStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure timer runs even when UI is busy
|
||||||
|
RunLoop.current.add(connectionMonitorTimer!, forMode: .common)
|
||||||
|
|
||||||
|
// Initial check
|
||||||
|
checkConnectionStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the connection status by calling into Rust
|
||||||
|
private func checkConnectionStatus() {
|
||||||
|
// Get the current connection status from Rust
|
||||||
|
let currentStatus = client.getConnectionStatus()
|
||||||
|
|
||||||
|
// Only post notification if state changed
|
||||||
|
if currentStatus != lastConnectionStatus {
|
||||||
|
if(currentStatus == .connected) {
|
||||||
|
logger.log("[autofill-extension] Connection status changed: Connected")
|
||||||
|
} else {
|
||||||
|
logger.log("[autofill-extension] Connection status changed: Disconnected")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the new status
|
||||||
|
lastConnectionStatus = currentStatus
|
||||||
|
|
||||||
|
// If we just disconnected, try to cancel the request
|
||||||
|
if currentStatus == .disconnected {
|
||||||
|
self.extensionContext.cancelRequest(withError: BitwardenError.Internal("Bitwarden desktop app disconnected"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
logger = Logger(subsystem: "com.bitwarden.desktop.autofill-extension", category: "credential-provider")
|
logger = Logger(subsystem: "com.bitwarden.desktop.autofill-extension", category: "credential-provider")
|
||||||
|
|
||||||
logger.log("[autofill-extension] initializing extension")
|
logger.log("[autofill-extension] initializing extension")
|
||||||
|
|
||||||
super.init(nibName: nil, bundle: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
|
||||||
|
// Setup connection monitoring now that self is available
|
||||||
|
setupConnectionMonitoring()
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
@@ -76,6 +120,10 @@ class CredentialProviderViewController: ASCredentialProviderViewController {
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
logger.log("[autofill-extension] deinitializing extension")
|
logger.log("[autofill-extension] deinitializing extension")
|
||||||
|
|
||||||
|
// Stop the connection monitor timer
|
||||||
|
connectionMonitorTimer?.invalidate()
|
||||||
|
connectionMonitorTimer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"postinstall": "electron-rebuild",
|
"postinstall": "electron-rebuild",
|
||||||
"start": "cross-env ELECTRON_IS_DEV=0 ELECTRON_NO_UPDATER=1 electron ./build",
|
"start": "cross-env ELECTRON_IS_DEV=0 ELECTRON_NO_UPDATER=1 electron ./build",
|
||||||
|
"build-native-macos": "cd desktop_native && ./macos_provider/build.sh && node build.js cross-platform",
|
||||||
"build-native": "cd desktop_native && node build.js",
|
"build-native": "cd desktop_native && node build.js",
|
||||||
"build": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" concurrently -n Main,Rend,Prel -c yellow,cyan \"npm run build:main\" \"npm run build:renderer\" \"npm run build:preload\"",
|
"build": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" concurrently -n Main,Rend,Prel -c yellow,cyan \"npm run build:main\" \"npm run build:renderer\" \"npm run build:preload\"",
|
||||||
"build:dev": "concurrently -n Main,Rend -c yellow,cyan \"npm run build:main:dev\" \"npm run build:renderer:dev\"",
|
"build:dev": "concurrently -n Main,Rend -c yellow,cyan \"npm run build:main:dev\" \"npm run build:renderer:dev\"",
|
||||||
|
|||||||
Reference in New Issue
Block a user