Skip to content

Commit 9b588a6

Browse files
committed
Introduce web preview url generation
1 parent bf64b04 commit 9b588a6

File tree

6 files changed

+95
-15
lines changed

6 files changed

+95
-15
lines changed

app/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ serde_json = "1"
2626
figment = { version = "0.10.19", features = ["toml", "json", "env"] }
2727
rumqttc = "0.24.0"
2828
chromiumoxide = "0.7.0"
29+
base64 = "0.22.1"

app/src/chrome.rs

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{collections::HashMap, time::Duration};
1+
use std::{collections::HashMap, sync::Arc, time::Duration};
22

33
use anyhow::Result;
44
use async_std::{
@@ -7,27 +7,27 @@ use async_std::{
77
task::{self, sleep},
88
};
99
use chromiumoxide::{
10-
cdp::{
11-
browser_protocol::page::{
12-
EventScreencastFrame, NavigateParams, ScreencastFrameAckParams, StartScreencastFormat,
13-
StartScreencastParams,
14-
},
15-
CdpEvent,
10+
cdp::browser_protocol::page::{
11+
EventScreencastFrame, NavigateParams, ScreencastFrameAckParams, StartScreencastFormat,
12+
StartScreencastParams,
1613
},
17-
listeners::EventStream,
1814
Browser, BrowserConfig, Page,
1915
};
2016

2117
use crate::config::ChromiumConfig;
2218

2319
pub struct ChromeController {
24-
current_playlist: Mutex<Option<String>>,
20+
pub current_playlist: Arc<Mutex<Option<String>>>,
21+
pub should_screen_capture: Arc<Mutex<bool>>,
22+
pub last_frame: Arc<Mutex<HashMap<String, Vec<u8>>>>,
2523
}
2624

2725
impl Default for ChromeController {
2826
fn default() -> Self {
2927
Self {
30-
current_playlist: Mutex::new(None),
28+
current_playlist: Arc::new(Mutex::new(None)),
29+
should_screen_capture: Arc::new(Mutex::new(true)),
30+
last_frame: Arc::new(Mutex::new(HashMap::new())),
3131
}
3232
}
3333
}
@@ -74,7 +74,9 @@ impl ChromeController {
7474
// Open all tabs that should be persisted
7575
let mut pages: HashMap<String, Page> = HashMap::new();
7676

77-
if let Some(tabs) = &config.tabs {
77+
let tabs = config.tabs.clone();
78+
79+
if let Some(tabs) = tabs {
7880
for (key, tab) in tabs {
7981
// Open a new tab for user-requested URL.
8082
let page = browser.new_page("about:blank").await?;
@@ -96,17 +98,25 @@ impl ChromeController {
9698
.await?;
9799

98100
let page_ref = page.clone();
101+
let self_arc = self.last_frame.clone();
102+
let key_clone = key.clone();
103+
99104
task::spawn(async move {
100105
let mut events = page_ref
101106
.event_listener::<EventScreencastFrame>()
102-
.await
107+
.await
103108
.unwrap();
104109
while let Some(frame) = events.next().await {
105110
// println!("Event: {:?}", frame);
106111

107112
let frame_buf: &[u8] = frame.data.as_ref();
108113
println!("Received frame: {}", frame_buf.len());
109114

115+
self_arc
116+
.lock()
117+
.await
118+
.insert(key_clone.clone(), frame_buf.to_vec());
119+
110120
// Acknowledge the frame to continue the stream
111121
page_ref
112122
.execute(

app/src/http/mod.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use std::{ops::Deref, str::Bytes, sync::Arc};
2+
3+
use anyhow::Result;
4+
use base64::Engine;
5+
use poem::{
6+
get, handler,
7+
listener::TcpListener,
8+
web::{Data, Path},
9+
Body, EndpointExt as _, IntoResponse, Response, Route, Server,
10+
};
11+
12+
use crate::state::AppState;
13+
14+
pub async fn start_http(state: Arc<AppState>) -> Result<()> {
15+
let app = Route::new()
16+
.at("/", get(root))
17+
.at("/preview/:tab_id", get(preview))
18+
.data(state);
19+
20+
let server = Server::new(TcpListener::bind("0.0.0.0:3000"));
21+
server.run(app).await?;
22+
23+
Ok(())
24+
}
25+
26+
#[handler]
27+
async fn root() -> &'static str {
28+
"v3x-mission-control"
29+
}
30+
31+
#[handler]
32+
async fn preview(state: Data<&Arc<AppState>>, tab_id: Path<String>) -> impl IntoResponse {
33+
format!("preview: {}", tab_id.0);
34+
35+
let last_frames = state.chrome.last_frame.lock().await;
36+
let body = last_frames.get(&tab_id.0).unwrap();
37+
38+
// base64 decode body
39+
let body = base64::engine::general_purpose::STANDARD.decode(body).unwrap();
40+
41+
println!("body: {:?}", body.len());
42+
43+
Response::builder()
44+
.body(Body::from_bytes(body.clone().into()))
45+
.set_content_type("image/jpeg")
46+
.into_response()
47+
}

app/src/main.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ use chrome::ChromeController;
66
use models::hass::HassDeviceDiscoveryPayload;
77
use reqwest::Url;
88
use rumqttc::{Client, Event, LastWill, MqttOptions, Packet, QoS};
9+
use state::AppState;
910

1011
pub mod chrome;
1112
pub mod config;
1213
pub mod models;
14+
pub mod state;
15+
pub mod http;
1316

1417
#[async_std::main]
1518
async fn main() -> Result<()> {
@@ -19,16 +22,22 @@ async fn main() -> Result<()> {
1922

2023
println!("Config: {:?}", config);
2124

22-
let chromium = ChromeController::new();
25+
let chromium = Arc::new(ChromeController::new());
2326

2427
if let Some(chromium_config) = config.chromium {
2528
let chromium_config_clone = chromium_config.clone();
26-
29+
30+
let chromium_2 = chromium.clone();
31+
2732
task::spawn(async move {
28-
chromium.start(&chromium_config_clone).await.unwrap();
33+
chromium_2.start(&chromium_config_clone).await.unwrap();
2934
});
3035
}
3136

37+
let state = Arc::new(AppState {
38+
chrome: chromium,
39+
});
40+
3241
let mqtt_url = config.homeassistant.mqtt_url.parse::<Url>().unwrap();
3342
let mqtt_port = mqtt_url.port().unwrap_or(1883);
3443

@@ -146,6 +155,11 @@ async fn main() -> Result<()> {
146155
.unwrap();
147156
});
148157

158+
let http_state = state;
159+
task::spawn(async move {
160+
http::start_http(http_state).await.unwrap();
161+
});
162+
149163
for (i, notification) in connection.iter().enumerate() {
150164
println!("Notification: {:?}", notification);
151165

app/src/state.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use std::sync::Arc;
2+
3+
use crate::chrome::ChromeController;
4+
5+
pub struct AppState {
6+
pub chrome: Arc<ChromeController>,
7+
}

0 commit comments

Comments
 (0)