Can get domains screenshots

This commit is contained in:
2023-10-13 15:27:01 +02:00
parent 4c29184a3b
commit 0a00e43216
6 changed files with 329 additions and 35 deletions

View File

@ -2,8 +2,11 @@ use crate::app_config::AppConfig;
use crate::libvirt_lib_structures::{DomainState, DomainXML, DomainXMLUuid};
use crate::libvirt_rest_structures::*;
use actix::{Actor, Context, Handler, Message};
use image::ImageOutputFormat;
use std::io::Cursor;
use virt::connect::Connect;
use virt::domain::Domain;
use virt::stream::Stream;
use virt::sys;
use virt::sys::VIR_DOMAIN_XML_SECURE;
@ -225,3 +228,36 @@ impl Handler<ResumeDomainReq> for LibVirtActor {
Ok(())
}
}
#[derive(Message)]
#[rtype(result = "anyhow::Result<Vec<u8>>")]
pub struct ScreenshotDomainReq(pub DomainXMLUuid);
impl Handler<ScreenshotDomainReq> for LibVirtActor {
type Result = anyhow::Result<Vec<u8>>;
fn handle(&mut self, msg: ScreenshotDomainReq, _ctx: &mut Self::Context) -> Self::Result {
log::debug!("Take screenshot of domain:\n{}", msg.0.as_string());
let domain = Domain::lookup_by_uuid_string(&self.m, &msg.0.as_string())?;
let stream = Stream::new(&self.m, 0)?;
domain.screenshot(&stream, 0, 0)?;
let mut screen_out = Vec::with_capacity(1000000);
let mut buff = [0u8; 1000];
loop {
let size = stream.recv(&mut buff)?;
if size == 0 {
break;
}
screen_out.extend_from_slice(&buff[0..size]);
}
let image = image::load_from_memory(&screen_out)?;
let mut png_out = Cursor::new(Vec::new());
image.write_to(&mut png_out, ImageOutputFormat::Png)?;
Ok(png_out.into_inner())
}
}

View File

@ -130,3 +130,17 @@ pub async fn resume(client: LibVirtReq, id: web::Path<SingleVMUUidReq>) -> HttpR
}
})
}
/// Take a screenshot of a VM
pub async fn screenshot(client: LibVirtReq, id: web::Path<SingleVMUUidReq>) -> HttpResult {
Ok(match client.screenshot_domain(id.uid).await {
Ok(b) => HttpResponse::Ok().content_type("image/png").body(b),
Err(e) => {
log::error!(
"Failed to take the screenshot of a domain {:?} ! {e}",
id.uid
);
HttpResponse::InternalServerError().json("Failed to take the screenshot of the domain!")
}
})
}

View File

@ -67,4 +67,9 @@ impl LibVirtClient {
pub async fn resume_domain(&self, id: DomainXMLUuid) -> anyhow::Result<()> {
self.0.send(libvirt_actor::ResumeDomainReq(id)).await?
}
/// Take a screenshot of the domain
pub async fn screenshot_domain(&self, id: DomainXMLUuid) -> anyhow::Result<Vec<u8>> {
self.0.send(libvirt_actor::ScreenshotDomainReq(id)).await?
}
}

View File

@ -150,6 +150,10 @@ async fn main() -> std::io::Result<()> {
web::get().to(vm_controller::suspend),
)
.route("/api/vm/{uid}/resume", web::get().to(vm_controller::resume))
.route(
"/api/vm/{uid}/screenshot",
web::get().to(vm_controller::screenshot),
)
})
.bind(&AppConfig::get().listen_address)?
.run()