allwright/
client_launch.rs1use std::sync::Arc;
2
3use crate::proto::surface_session_command::Command as SurfaceCommand;
4use crate::proto::surface_session_event::Event as SurfaceEvent;
5use crate::proto::{
6 BrowserKind as ProtoBrowserKind, BrowserLaunchedEvent, LaunchBrowserCommand,
7 SurfaceSessionCommand,
8};
9use tokio::sync::{Mutex as AsyncMutex, mpsc};
10use tokio_stream::wrappers::ReceiverStream;
11
12use super::command::command_retry_options;
13use super::runtime::get_runtime;
14use super::types::{
15 Browser, BrowserInner, BrowserKind, BrowserState, BrowserType, Error, LaunchOptions, Result,
16 Tab, TabInner, TabState,
17};
18
19pub async fn launch_chrome(options: LaunchOptions) -> Result<Browser> {
20 launch_browser(BrowserKind::Chromium, options).await
21}
22
23pub async fn launch_firefox(options: LaunchOptions) -> Result<Browser> {
24 launch_browser(BrowserKind::Firefox, options).await
25}
26
27pub async fn launch_browser(browser_kind: BrowserKind, options: LaunchOptions) -> Result<Browser> {
28 let runtime = get_runtime().await?;
29 let mut engine = runtime.engine.clone();
30 let (command_tx, command_rx) = mpsc::channel(16);
31 let response = engine
32 .surface_session(tonic::Request::new(ReceiverStream::new(command_rx)))
33 .await?;
34 let mut events = response.into_inner();
35
36 command_tx
37 .send(SurfaceSessionCommand {
38 command: Some(SurfaceCommand::LaunchBrowser(LaunchBrowserCommand {
39 browser_kind: match browser_kind {
40 BrowserKind::Chromium => ProtoBrowserKind::Chromium as i32,
41 BrowserKind::Firefox => ProtoBrowserKind::Firefox as i32,
42 },
43 browser_binary: options.browser_binary,
44 retry_options: command_retry_options(options.timeout_ms),
45 })),
46 })
47 .await
48 .map_err(|_| Error::new("failed to send LaunchBrowserCommand to browser session"))?;
49
50 loop {
51 let event = events
52 .message()
53 .await?
54 .ok_or_else(|| Error::new("browser session closed before launch response"))?;
55
56 match event.event {
57 Some(SurfaceEvent::BrowserLaunched(BrowserLaunchedEvent {
58 browser,
59 note,
60 user_data_dir,
61 initial_page_session_id,
62 ..
63 })) => {
64 return Ok(build_browser(
65 runtime,
66 command_tx,
67 events,
68 event.session_id,
69 browser,
70 note,
71 String::new(),
72 user_data_dir,
73 initial_page_session_id,
74 ));
75 }
76 Some(SurfaceEvent::ChromeLaunched(launched)) => {
77 return Ok(build_browser(
78 runtime,
79 command_tx,
80 events,
81 event.session_id,
82 launched.browser,
83 launched.note,
84 launched.cdp_websocket_url,
85 launched.user_data_dir,
86 launched.initial_page_session_id,
87 ));
88 }
89 Some(SurfaceEvent::Error(error)) => {
90 return Err(Error::new(format!(
91 "browser session error during launch: {}",
92 error.message
93 )));
94 }
95 _ => {}
96 }
97 }
98}
99
100pub fn chromium() -> BrowserType {
101 BrowserType {
102 browser_kind: BrowserKind::Chromium,
103 }
104}
105
106pub fn firefox() -> BrowserType {
107 BrowserType {
108 browser_kind: BrowserKind::Firefox,
109 }
110}
111
112impl BrowserType {
113 pub async fn launch(&self, options: LaunchOptions) -> Result<Browser> {
114 launch_browser(self.browser_kind, options).await
115 }
116}
117
118fn build_browser(
119 runtime: Arc<super::types::RuntimeClient>,
120 command_tx: mpsc::Sender<SurfaceSessionCommand>,
121 events: tonic::Streaming<crate::proto::SurfaceSessionEvent>,
122 surface_session_id: String,
123 browser: String,
124 note: String,
125 cdp_websocket_url: String,
126 user_data_dir: String,
127 initial_page_session_id: String,
128) -> Browser {
129 let initial_tab = Tab {
130 inner: Arc::new(TabInner {
131 runtime: Arc::clone(&runtime),
132 surface_session_id: surface_session_id.clone(),
133 session_id: initial_page_session_id,
134 state: AsyncMutex::new(TabState::default()),
135 }),
136 };
137 Browser {
138 inner: Arc::new(BrowserInner {
139 runtime,
140 state: AsyncMutex::new(BrowserState {
141 command_tx,
142 events,
143 closed: false,
144 }),
145 session_id: surface_session_id,
146 browser_name: browser,
147 launch_note: note,
148 cdp_websocket_url,
149 user_data_dir,
150 initial_tab,
151 }),
152 }
153}