Skip to content

Commit c495aa0

Browse files
committed
reuse session in webdriver
Signed-off-by: Andrei Gherghescu <[email protected]>
1 parent 5753948 commit c495aa0

File tree

2 files changed

+47
-11
lines changed

2 files changed

+47
-11
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,6 @@ jobs:
129129
130130
cargo test --verbose --workspace --features plotly_ndarray,plotly_image,chromedriver --exclude plotly_kaleido
131131
132-
# Windows-specific cleanup
133-
- if: matrix.os == 'windows-latest'
134-
run: gci -recurse -filter "*example*"
135-
136132
code-coverage:
137133
name: Code Coverage
138134
runs-on: ubuntu-latest

plotly_static/src/lib.rs

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ use std::{println as error, println as warn, println as debug};
266266

267267
use anyhow::{anyhow, Context, Result};
268268
use base64::{engine::general_purpose, Engine as _};
269-
use fantoccini::{wd::Capabilities, ClientBuilder};
269+
use fantoccini::{wd::Capabilities, ClientBuilder, Client};
270270
#[cfg(not(test))]
271271
use log::{debug, error, warn};
272272
use serde::Serialize;
@@ -469,10 +469,15 @@ struct PlotData<'a> {
469469
/// - Browser capabilities: Default Chrome/Firefox headless options
470470
/// - Automatic WebDriver detection and connection reuse
471471
pub struct StaticExporterBuilder {
472+
/// WebDriver server port (default: 4444)
472473
webdriver_port: u32,
474+
/// WebDriver server base URL (default: "http://localhost")
473475
webdriver_url: String,
476+
/// Auto-spawn WebDriver if not running (default: true)
474477
spawn_webdriver: bool,
478+
/// Use bundled JS libraries instead of CDN (default: false)
475479
offline_mode: bool,
480+
/// Browser command-line flags (e.g., "--headless", "--no-sandbox")
476481
webdriver_browser_caps: Vec<String>,
477482
}
478483

@@ -675,6 +680,7 @@ impl StaticExporterBuilder {
675680
offline_mode: self.offline_mode,
676681
webdriver_browser_caps: self.webdriver_browser_caps.clone(),
677682
runtime,
683+
webdriver_client: None,
678684
})
679685
}
680686

@@ -737,12 +743,26 @@ impl StaticExporterBuilder {
737743
/// - Offline mode support
738744
/// - Automatic WebDriver management
739745
pub struct StaticExporter {
746+
/// WebDriver server port (default: 4444)
740747
webdriver_port: u32,
748+
749+
/// WebDriver server base URL (default: "http://localhost")
741750
webdriver_url: String,
751+
752+
/// WebDriver process manager for spawning and cleanup
742753
webdriver: WebDriver,
754+
755+
/// Use bundled JS libraries instead of CDN
743756
offline_mode: bool,
757+
758+
/// Browser command-line flags (e.g., "--headless", "--no-sandbox")
744759
webdriver_browser_caps: Vec<String>,
760+
761+
/// Tokio runtime for async operations
745762
runtime: std::sync::Arc<tokio::runtime::Runtime>,
763+
764+
/// Cached WebDriver client for session reuse
765+
webdriver_client: Option<Client>,
746766
}
747767

748768
impl Drop for StaticExporter {
@@ -757,6 +777,16 @@ impl Drop for StaticExporter {
757777
/// - Leaves externally managed WebDriver sessions running
758778
/// - Logs errors but doesn't panic if cleanup fails
759779
fn drop(&mut self) {
780+
// Close the WebDriver client if it exists
781+
if let Some(client) = self.webdriver_client.take() {
782+
let runtime = self.runtime.clone();
783+
runtime.block_on(async {
784+
if let Err(e) = client.close().await {
785+
error!("Failed to close WebDriver client: {}", e);
786+
}
787+
});
788+
}
789+
760790
// Stop the WebDriver process
761791
if let Err(e) = self.webdriver.stop() {
762792
error!("Failed to stop WebDriver: {e}");
@@ -941,11 +971,20 @@ impl StaticExporter {
941971
debug!("Use WebDriver and headless browser to export static plot");
942972
let webdriver_url = format!("{}:{}", self.webdriver_url, self.webdriver_port,);
943973

944-
let client = ClientBuilder::native()
945-
.capabilities(caps)
946-
.connect(&webdriver_url)
947-
.await
948-
.with_context(|| "WebDriver session errror")?;
974+
// Reuse existing client or create new one
975+
let client = if let Some(ref client) = self.webdriver_client {
976+
debug!("Reusing existing WebDriver session");
977+
client.clone()
978+
} else {
979+
debug!("Creating new WebDriver session");
980+
let new_client = ClientBuilder::native()
981+
.capabilities(caps)
982+
.connect(&webdriver_url)
983+
.await
984+
.with_context(|| "WebDriver session error")?;
985+
self.webdriver_client = Some(new_client.clone());
986+
new_client
987+
};
949988

950989
// URL-encode the HTML
951990
let data_uri = format!("data:text/html,{}", encode(data_uri));
@@ -978,7 +1017,8 @@ impl StaticExporter {
9781017

9791018
let data = client.execute_async(js_script, args).await?;
9801019

981-
client.close().await?;
1020+
// Don't close the client - keep it for reuse
1021+
// client.close().await?;
9821022

9831023
let src = data.as_str().ok_or(anyhow!(
9841024
"Failed to execute Plotly.toImage in browser session"

0 commit comments

Comments
 (0)