harmony/harmony/src/modules/http.rs
Jean-Gabriel Gill-Couture da5a869771
All checks were successful
Run Check Script / check (pull_request) Successful in 59s
feat(opnsense-config): dnsmasq dhcp static mappings (#130)
Co-authored-by: Jean-Gabriel Gill-Couture <jeangabriel.gc@gmail.com>
Co-authored-by: Ian Letourneau <ian@noma.to>
Reviewed-on: https://git.nationtech.io/NationTech/harmony/pulls/130
Reviewed-by: Ian Letourneau <ian@noma.to>
Co-authored-by: Jean-Gabriel Gill-Couture <jg@nationtech.io>
Co-committed-by: Jean-Gabriel Gill-Couture <jg@nationtech.io>
2025-09-08 19:06:17 +00:00

130 lines
3.6 KiB
Rust

use async_trait::async_trait;
use derive_new::new;
use serde::Serialize;
use crate::{
data::{FileContent, FilePath, Version},
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
inventory::Inventory,
score::Score,
topology::{HttpServer, Topology},
};
use harmony_types::net::Url;
use harmony_types::{id::Id, net::MacAddress};
/// Configure an HTTP server that is provided by the Topology
///
/// This Score will let you easily specify a file path to be served by the HTTP server
///
/// For example, if you have a folder of assets at `/var/www/assets` simply do :
///
/// ```rust,ignore
/// StaticFilesHttpScore {
/// files_to_serve: url!("file:///var/www/assets"),
/// }
/// ```
#[derive(Debug, new, Clone, Serialize)]
pub struct StaticFilesHttpScore {
// TODO this should be split in two scores, one for folder and
// other for files
pub folder_to_serve: Option<Url>,
pub files: Vec<FileContent>,
pub remote_path: Option<String>,
}
impl<T: Topology + HttpServer> Score<T> for StaticFilesHttpScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
Box::new(StaticFilesHttpInterpret::new(self.clone()))
}
fn name(&self) -> String {
"HttpScore".to_string()
}
}
#[derive(Debug, new, Clone)]
pub struct StaticFilesHttpInterpret {
score: StaticFilesHttpScore,
}
#[async_trait]
impl<T: Topology + HttpServer> Interpret<T> for StaticFilesHttpInterpret {
async fn execute(
&self,
_inventory: &Inventory,
http_server: &T,
) -> Result<Outcome, InterpretError> {
http_server.ensure_initialized().await?;
// http_server.set_ip(topology.router.get_gateway()).await?;
if let Some(folder) = self.score.folder_to_serve.as_ref() {
http_server
.serve_files(folder, &self.score.remote_path)
.await?;
}
for f in self.score.files.iter() {
http_server.serve_file_content(&f).await?
}
http_server.commit_config().await?;
http_server.reload_restart().await?;
Ok(Outcome::success(format!(
"Http Server running and serving files from folder {:?} and content for {}",
self.score.folder_to_serve,
self.score
.files
.iter()
.map(|f| f.path.to_string())
.collect::<Vec<String>>()
.join(",")
)))
}
fn get_name(&self) -> InterpretName {
InterpretName::Http
}
fn get_version(&self) -> Version {
todo!()
}
fn get_status(&self) -> InterpretStatus {
todo!()
}
fn get_children(&self) -> Vec<Id> {
todo!()
}
}
#[derive(Debug, new, Clone, Serialize)]
pub struct IPxeMacBootFileScore {
pub content: String,
pub mac_address: Vec<MacAddress>,
}
impl<T: Topology + HttpServer> Score<T> for IPxeMacBootFileScore {
fn name(&self) -> String {
"IPxeMacBootFileScore".to_string()
}
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
StaticFilesHttpScore {
remote_path: None,
folder_to_serve: None,
files: self
.mac_address
.iter()
.map(|mac| FileContent {
path: FilePath::Relative(format!(
"byMAC/01-{}.ipxe",
mac.to_string().replace(":", "-")
)),
content: self.content.clone(),
})
.collect(),
}
.create_interpret()
}
}