wip - working exampole
This commit is contained in:
parent
b6cc3d4631
commit
0d91994a4c
18
Cargo.lock
generated
18
Cargo.lock
generated
@ -47,6 +47,15 @@ version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "async-mutex"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.3.5"
|
||||
@ -422,6 +431,12 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.0.1"
|
||||
@ -964,6 +979,8 @@ dependencies = [
|
||||
name = "ovlach_pdf"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-mutex",
|
||||
"async-trait",
|
||||
"fern",
|
||||
"headless_chrome",
|
||||
"log",
|
||||
@ -971,6 +988,7 @@ dependencies = [
|
||||
"rocket",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -14,3 +14,6 @@ rocket = { version = "0.5.0", features = ["json"] }
|
||||
headless_chrome = "1.0.8"
|
||||
|
||||
ovlach_data = { git = "ssh://git@gitlab.nanobyte.cz/ondrej/ov-site-api-data.git", branch = "add_missing_fields"}
|
||||
async-trait = "0.1.74"
|
||||
async-mutex = "1.4.0"
|
||||
tokio = { version = "1.34.0", features = ["macros"] }
|
1
src/chromium/mod.rs
Normal file
1
src/chromium/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod rocket;
|
127
src/chromium/rocket.rs
Normal file
127
src/chromium/rocket.rs
Normal file
@ -0,0 +1,127 @@
|
||||
use std::{sync::{Arc}, time::Duration};
|
||||
use async_trait::async_trait;
|
||||
use async_mutex::Mutex;
|
||||
use headless_chrome::{Browser, LaunchOptions};
|
||||
use log::{warn, error};
|
||||
use rocket::{fairing::{Fairing, self}, Rocket, Build, catcher::Result, Request, Response, request::{FromRequest, Outcome}};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Chromium {
|
||||
}
|
||||
|
||||
impl Chromium {
|
||||
pub fn ignite() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn default() -> Self {
|
||||
Self {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Fairing for Chromium {
|
||||
fn info(&self) -> fairing::Info {
|
||||
fairing::Info {
|
||||
name: "Chromium",
|
||||
kind: fairing::Kind::Ignite,
|
||||
}
|
||||
}
|
||||
|
||||
async fn on_ignite(&self, rocket: Rocket<Build>) -> fairing::Result {
|
||||
let new_rocket = rocket.manage(ChromiumCoordinator::new().await);
|
||||
let coordinator = new_rocket.state::<ChromiumCoordinator>().unwrap();
|
||||
error!("{:p}", &coordinator);
|
||||
Ok(new_rocket)
|
||||
}
|
||||
}
|
||||
pub struct ChromiumCoordinator {
|
||||
instances: Arc<Mutex<Vec<BrowserHolder>>>,
|
||||
}
|
||||
|
||||
impl ChromiumCoordinator {
|
||||
const NUMBER_OF_INSTANCES: usize = 1;
|
||||
|
||||
pub async fn new() -> Self {
|
||||
error!("ChromiumCoordinator::new()");
|
||||
let instances: Arc<Mutex<Vec<BrowserHolder>>> = Arc::new(Mutex::new(Vec::with_capacity(Self::NUMBER_OF_INSTANCES)));
|
||||
while instances.lock().await.len() < Self::NUMBER_OF_INSTANCES {
|
||||
instances.lock().await.push(BrowserHolder { browser: Browser::new(LaunchOptions {
|
||||
idle_browser_timeout: Duration::from_secs(1), // Wait inifinity for commands
|
||||
..LaunchOptions::default()
|
||||
}).unwrap() });
|
||||
}
|
||||
|
||||
Self { instances }
|
||||
}
|
||||
|
||||
fn spawn_browser(&self) {
|
||||
let instances = self.instances.clone();
|
||||
tokio::spawn(async move {
|
||||
error!("Spawn new instance of browser");
|
||||
// Create new instance
|
||||
let browser = Browser::new(LaunchOptions::default()).unwrap();
|
||||
instances.lock().await.push( BrowserHolder {browser });
|
||||
});
|
||||
}
|
||||
|
||||
fn try_get_instance(&self) -> Option<BrowserHolder> {
|
||||
let mut instances = self.instances.lock().await;
|
||||
if instances.len() == 0 {
|
||||
return None;
|
||||
}
|
||||
Some(instances.remove(0))
|
||||
}
|
||||
|
||||
pub async fn try_get_browser(&self) -> std::result::Result<BrowserHolder, ()> {
|
||||
let instances = self.instances.clone();
|
||||
|
||||
let mut loop_count = 0;
|
||||
|
||||
while instances.lock().await.len() == 0 {
|
||||
warn!("Waiting for Chromium instances to start...");
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
if loop_count > 100 * 10 * 60 {
|
||||
panic!("Can't start Chromium instances");
|
||||
}
|
||||
loop_count += 1;
|
||||
}
|
||||
|
||||
let browser = self.instances.lock().await.remove(0);
|
||||
self.spawn_browser();
|
||||
// test connection state
|
||||
match browser.browser.get_version() {
|
||||
Ok(_) => Ok(browser),
|
||||
Err(_) => {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_browser(&self) -> std::result::Result<BrowserHolder, ()> {
|
||||
loop {
|
||||
match self.try_get_browser().await {
|
||||
Ok(browser) => return Ok(browser),
|
||||
Err(_) => {} // all instances may be dead ... we must wait for new instance
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BrowserHolder {
|
||||
pub browser: Browser,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<'r> FromRequest<'r> for BrowserHolder {
|
||||
type Error = ();
|
||||
|
||||
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, ()> {
|
||||
let coordinator = request.rocket().state::<ChromiumCoordinator>().unwrap();
|
||||
error!("{:p}", &coordinator);
|
||||
let browser = coordinator.get_browser().await.unwrap();
|
||||
Outcome::Success(browser)
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
use chromium::rocket::Chromium;
|
||||
use rocket::{Rocket, Build, routes};
|
||||
|
||||
pub mod routes;
|
||||
mod chromium;
|
||||
|
||||
pub fn rocket_builder() -> Rocket<Build> {
|
||||
rocket::build().mount("/", routes![
|
||||
rocket::build()
|
||||
.attach(Chromium::ignite())
|
||||
.mount("/", routes![
|
||||
routes::pdf::render_pdf_cv,
|
||||
])
|
||||
}
|
@ -7,8 +7,9 @@ use headless_chrome::{types::PrintToPdfOptions, LaunchOptions};
|
||||
use log::error;
|
||||
use rocket::{get, Response, futures::Stream, tokio::net::UnixStream, fs::NamedFile};
|
||||
|
||||
fn generate_pdf() {
|
||||
let browser = Browser::new(LaunchOptions::default()).unwrap();
|
||||
use crate::chromium::rocket::BrowserHolder;
|
||||
|
||||
fn generate_pdf(browser: Browser) {
|
||||
let tab = browser.new_tab().unwrap();
|
||||
let tab = tab.navigate_to("file:///home/6a6996c0-1609-48b6-8ca6-affbef1b4d1d/Devel/Nanobyte/ovlach/ovlach_pdf/template.html").unwrap().wait_until_navigated().unwrap();
|
||||
let options = PrintToPdfOptions{
|
||||
@ -34,8 +35,8 @@ fn generate_pdf() {
|
||||
}
|
||||
|
||||
#[get("/cv/<username>/pdf")]
|
||||
pub async fn render_pdf_cv(username: &str) -> NamedFile {
|
||||
generate_pdf();
|
||||
pub async fn render_pdf_cv(username: &str, browser: BrowserHolder) -> NamedFile {
|
||||
generate_pdf(browser.browser);
|
||||
"foo!".to_string();
|
||||
NamedFile::open("/tmp/foo.pdf").await.expect("failed to open foo.pdf")
|
||||
}
|
Loading…
Reference in New Issue
Block a user