Skip to content

Commit

Permalink
Introduce web preview url generation
Browse files Browse the repository at this point in the history
  • Loading branch information
lucemans committed Feb 6, 2025
1 parent bf64b04 commit 9b588a6
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 15 deletions.
1 change: 1 addition & 0 deletions app/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ serde_json = "1"
figment = { version = "0.10.19", features = ["toml", "json", "env"] }
rumqttc = "0.24.0"
chromiumoxide = "0.7.0"
base64 = "0.22.1"
34 changes: 22 additions & 12 deletions app/src/chrome.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{collections::HashMap, time::Duration};
use std::{collections::HashMap, sync::Arc, time::Duration};

use anyhow::Result;
use async_std::{
Expand All @@ -7,27 +7,27 @@ use async_std::{
task::{self, sleep},
};
use chromiumoxide::{
cdp::{
browser_protocol::page::{
EventScreencastFrame, NavigateParams, ScreencastFrameAckParams, StartScreencastFormat,
StartScreencastParams,
},
CdpEvent,
cdp::browser_protocol::page::{
EventScreencastFrame, NavigateParams, ScreencastFrameAckParams, StartScreencastFormat,
StartScreencastParams,
},
listeners::EventStream,
Browser, BrowserConfig, Page,
};

use crate::config::ChromiumConfig;

pub struct ChromeController {
current_playlist: Mutex<Option<String>>,
pub current_playlist: Arc<Mutex<Option<String>>>,
pub should_screen_capture: Arc<Mutex<bool>>,
pub last_frame: Arc<Mutex<HashMap<String, Vec<u8>>>>,
}

impl Default for ChromeController {
fn default() -> Self {
Self {
current_playlist: Mutex::new(None),
current_playlist: Arc::new(Mutex::new(None)),
should_screen_capture: Arc::new(Mutex::new(true)),
last_frame: Arc::new(Mutex::new(HashMap::new())),
}
}
}
Expand Down Expand Up @@ -74,7 +74,9 @@ impl ChromeController {
// Open all tabs that should be persisted
let mut pages: HashMap<String, Page> = HashMap::new();

if let Some(tabs) = &config.tabs {
let tabs = config.tabs.clone();

if let Some(tabs) = tabs {
for (key, tab) in tabs {
// Open a new tab for user-requested URL.
let page = browser.new_page("about:blank").await?;
Expand All @@ -96,17 +98,25 @@ impl ChromeController {
.await?;

let page_ref = page.clone();
let self_arc = self.last_frame.clone();
let key_clone = key.clone();

task::spawn(async move {
let mut events = page_ref
.event_listener::<EventScreencastFrame>()
.await
.await
.unwrap();
while let Some(frame) = events.next().await {
// println!("Event: {:?}", frame);

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

self_arc
.lock()
.await
.insert(key_clone.clone(), frame_buf.to_vec());

// Acknowledge the frame to continue the stream
page_ref
.execute(
Expand Down
47 changes: 47 additions & 0 deletions app/src/http/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use std::{ops::Deref, str::Bytes, sync::Arc};

use anyhow::Result;
use base64::Engine;
use poem::{
get, handler,
listener::TcpListener,
web::{Data, Path},
Body, EndpointExt as _, IntoResponse, Response, Route, Server,
};

use crate::state::AppState;

pub async fn start_http(state: Arc<AppState>) -> Result<()> {
let app = Route::new()
.at("/", get(root))
.at("/preview/:tab_id", get(preview))
.data(state);

let server = Server::new(TcpListener::bind("0.0.0.0:3000"));
server.run(app).await?;

Ok(())
}

#[handler]
async fn root() -> &'static str {
"v3x-mission-control"
}

#[handler]
async fn preview(state: Data<&Arc<AppState>>, tab_id: Path<String>) -> impl IntoResponse {
format!("preview: {}", tab_id.0);

let last_frames = state.chrome.last_frame.lock().await;
let body = last_frames.get(&tab_id.0).unwrap();

// base64 decode body
let body = base64::engine::general_purpose::STANDARD.decode(body).unwrap();

println!("body: {:?}", body.len());

Response::builder()
.body(Body::from_bytes(body.clone().into()))
.set_content_type("image/jpeg")
.into_response()
}
20 changes: 17 additions & 3 deletions app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ use chrome::ChromeController;
use models::hass::HassDeviceDiscoveryPayload;
use reqwest::Url;
use rumqttc::{Client, Event, LastWill, MqttOptions, Packet, QoS};
use state::AppState;

pub mod chrome;
pub mod config;
pub mod models;
pub mod state;
pub mod http;

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

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

let chromium = ChromeController::new();
let chromium = Arc::new(ChromeController::new());

if let Some(chromium_config) = config.chromium {
let chromium_config_clone = chromium_config.clone();


let chromium_2 = chromium.clone();

task::spawn(async move {
chromium.start(&chromium_config_clone).await.unwrap();
chromium_2.start(&chromium_config_clone).await.unwrap();
});
}

let state = Arc::new(AppState {
chrome: chromium,
});

let mqtt_url = config.homeassistant.mqtt_url.parse::<Url>().unwrap();
let mqtt_port = mqtt_url.port().unwrap_or(1883);

Expand Down Expand Up @@ -146,6 +155,11 @@ async fn main() -> Result<()> {
.unwrap();
});

let http_state = state;
task::spawn(async move {
http::start_http(http_state).await.unwrap();
});

for (i, notification) in connection.iter().enumerate() {
println!("Notification: {:?}", notification);

Expand Down
7 changes: 7 additions & 0 deletions app/src/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use std::sync::Arc;

use crate::chrome::ChromeController;

pub struct AppState {
pub chrome: Arc<ChromeController>,
}

0 comments on commit 9b588a6

Please sign in to comment.