Create energy actor

This commit is contained in:
2024-06-29 11:45:39 +02:00
parent 49a3e3a669
commit d4a81f5fdf
10 changed files with 163 additions and 7 deletions

View File

@ -0,0 +1,7 @@
use std::time::Duration;
/// Energy refresh operations interval
pub const ENERGY_REFRESH_INTERVAL: Duration = Duration::from_secs(30);
/// Fallback value to use if production cannot be fetched
pub const FALLBACK_PRODUCTION_VALUE: i32 = 5000;

View File

@ -0,0 +1,64 @@
use crate::constants;
use crate::energy::consumption;
use crate::energy::consumption::EnergyConsumption;
use actix::prelude::*;
pub struct EnergyActor {
curr_consumption: EnergyConsumption,
}
impl EnergyActor {
pub async fn new() -> anyhow::Result<Self> {
Ok(Self {
curr_consumption: consumption::get_curr_consumption().await?,
})
}
async fn refresh(&mut self) -> anyhow::Result<()> {
// Refresh energy
self.curr_consumption = consumption::get_curr_consumption()
.await
.unwrap_or_else(|e| {
log::error!(
"Failed to fetch latest consumption value, will use fallback value! {e}"
);
constants::FALLBACK_PRODUCTION_VALUE
});
Ok(())
}
}
impl Actor for EnergyActor {
type Context = Context<Self>;
fn started(&mut self, ctx: &mut Self::Context) {
log::info!("Energy actor successfully started!");
ctx.run_interval(constants::ENERGY_REFRESH_INTERVAL, |act, _ctx| {
log::info!("Performing energy refresh operation");
if let Err(e) = futures::executor::block_on(act.refresh()) {
log::error!("Energy refresh failed! {e}")
}
});
}
fn stopped(&mut self, _ctx: &mut Self::Context) {
log::info!("Energy actor successfully stopped!");
}
}
pub type EnergyActorAddr = Addr<EnergyActor>;
/// Get current consumption
#[derive(Message)]
#[rtype(result = "EnergyConsumption")]
pub struct GetCurrConsumption;
impl Handler<GetCurrConsumption> for EnergyActor {
type Result = EnergyConsumption;
fn handle(&mut self, _msg: GetCurrConsumption, _ctx: &mut Context<Self>) -> Self::Result {
self.curr_consumption
}
}

View File

@ -1 +1,2 @@
pub mod consumption;
pub mod energy_actor;

View File

@ -1,4 +1,5 @@
pub mod app_config;
pub mod constants;
pub mod crypto;
pub mod energy;
pub mod server;

View File

@ -1,5 +1,7 @@
use actix::Actor;
use central_backend::app_config::AppConfig;
use central_backend::crypto::pki;
use central_backend::energy::energy_actor::EnergyActor;
use central_backend::server::{secure_server, unsecure_server};
use central_backend::utils::files_utils::create_directory_if_missing;
use futures::future;
@ -22,7 +24,13 @@ async fn main() -> std::io::Result<()> {
pki::refresh_crls().expect("Failed to initialize Root CA!");
let s1 = secure_server();
// Initialize energy actor
let actor = EnergyActor::new()
.await
.expect("Failed to initialize energy actor!")
.start();
let s1 = secure_server(actor);
let s2 = unsecure_server();
future::try_join(s1, s2)
.await

View File

@ -85,6 +85,12 @@ impl From<actix_web::Error> for HttpErr {
}
}
impl From<actix::MailboxError> for HttpErr {
fn from(value: actix::MailboxError) -> Self {
HttpErr::Err(std::io::Error::new(ErrorKind::Other, value.to_string()).into())
}
}
impl From<HttpResponse> for HttpErr {
fn from(value: HttpResponse) -> Self {
HttpErr::HTTPResponse(value)

View File

@ -1,9 +1,10 @@
use crate::energy::consumption;
use crate::energy::{consumption, energy_actor};
use crate::server::custom_error::HttpResult;
use crate::server::WebEnergyActor;
use actix_web::HttpResponse;
#[derive(serde::Serialize)]
struct CurrConsumption {
struct Consumption {
consumption: i32,
}
@ -11,5 +12,12 @@ struct CurrConsumption {
pub async fn curr_consumption() -> HttpResult {
let consumption = consumption::get_curr_consumption().await?;
Ok(HttpResponse::Ok().json(CurrConsumption { consumption }))
Ok(HttpResponse::Ok().json(Consumption { consumption }))
}
/// Get cached energy consumption
pub async fn cached_consumption(energy_actor: WebEnergyActor) -> HttpResult {
let consumption = energy_actor.send(energy_actor::GetCurrConsumption).await?;
Ok(HttpResponse::Ok().json(Consumption { consumption }))
}

View File

@ -4,12 +4,15 @@ use openssl::ssl::{SslAcceptor, SslMethod};
use crate::app_config::AppConfig;
use crate::crypto::pki;
use crate::energy::energy_actor::EnergyActorAddr;
pub mod custom_error;
pub mod energy_controller;
pub mod pki_controller;
pub mod server_controller;
pub type WebEnergyActor = web::Data<EnergyActorAddr>;
/// Start unsecure (HTTP) server
pub async fn unsecure_server() -> anyhow::Result<()> {
log::info!(
@ -31,7 +34,7 @@ pub async fn unsecure_server() -> anyhow::Result<()> {
}
/// Start secure (HTTPS) server
pub async fn secure_server() -> anyhow::Result<()> {
pub async fn secure_server(energy_actor: EnergyActorAddr) -> anyhow::Result<()> {
let web_ca = pki::CertData::load_web_ca()?;
let server_cert = pki::CertData::load_server()?;
@ -45,14 +48,19 @@ pub async fn secure_server() -> anyhow::Result<()> {
AppConfig::get().listen_address,
AppConfig::get().secure_origin()
);
HttpServer::new(|| {
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(energy_actor.clone()))
.wrap(Logger::default())
.route("/", web::get().to(server_controller::secure_home))
.route(
"/api/energy/curr_consumption",
web::get().to(energy_controller::curr_consumption),
)
.route(
"/api/energy/cached_consumption",
web::get().to(energy_controller::cached_consumption),
)
})
.bind_openssl(&AppConfig::get().listen_address, builder)?
.run()