Use fairing to read the My Autarco config (closes: #3)

* Read My Autarco credentials from `Rocket.toml`
* Remove custom config loading function and `autarco.toml.example`
* Update `Rocket.toml.example` but comment out the variables so that the
  user won't forget to set them
* Update `.gitignore`
* Update documentation
This commit is contained in:
Paul van Tilburg 2023-01-03 17:08:25 +01:00
parent 31e8ca65af
commit 3c35c4fe72
Signed by: paul
GPG Key ID: C6DE073EDA9EEC4D
5 changed files with 14 additions and 34 deletions

2
.gitignore vendored
View File

@ -2,4 +2,4 @@
/target
# Config
autarco.toml
Rocket.toml

View File

@ -1,3 +1,8 @@
[default]
address = "0.0.0.0"
port = 2356
# Put your My Autarco credentials below and uncomment them
# username = "foo@domain.tld"
# password = "secret"
# site_id = "abc123de"

View File

@ -1,3 +0,0 @@
# Put your My Autarco credentials below
username = "foo@domain.tld"
password = "secret"

View File

@ -7,15 +7,11 @@
)]
#![deny(missing_docs)]
use std::path::Path;
use std::sync::Mutex;
use color_eyre::Result;
use once_cell::sync::Lazy;
use rocket::fairing::AdHoc;
use rocket::serde::json::Json;
use rocket::tokio::fs::File;
use rocket::tokio::io::AsyncReadExt;
use rocket::{get, routes};
use serde::{Deserialize, Serialize};
@ -31,7 +27,7 @@ const BASE_URL: &str = "https://my.autarco.com";
/// This depends on with which interval Autaurco processes new information from the invertor.
const POLL_INTERVAL: u64 = 300;
/// The configuration for the My Autarco site
/// The extra configuration necessary to access the My Autarco site.
#[derive(Debug, Deserialize)]
struct Config {
/// The username of the account to login with
@ -45,25 +41,6 @@ struct Config {
/// The global, concurrently accessible current status.
static STATUS: Lazy<Mutex<Option<Status>>> = Lazy::new(|| Mutex::new(None));
/// Loads the configuration.
///
/// The configuration file `autarco.toml` should be located in the project path.
///
/// # Errors
///
/// Returns an error if the file could not be found, opened or read and if the contents are
/// not valid TOML or does not contain all the necessary keys (see [`Config`]).
async fn load_config() -> Result<Config> {
let config_file_name = Path::new(env!("CARGO_MANIFEST_DIR")).join("autarco.toml");
let mut file = File::open(config_file_name).await?;
let mut contents = String::new();
file.read_to_string(&mut contents).await?;
let config = toml::from_str(&contents)?;
Ok(config)
}
/// The current photovoltaic invertor status.
#[derive(Clone, Copy, Debug, Serialize)]
struct Status {
@ -82,15 +59,17 @@ async fn status() -> Option<Json<Status>> {
status_guard.map(Json)
}
/// Creates a Rocket and attaches the update loop as fairing.
/// Creates a Rocket and attaches the config parsing and update loop as fairings.
#[rocket::launch]
fn rocket() -> _ {
rocket::build()
.mount("/", routes![status])
.attach(AdHoc::on_liftoff("Updater", |_| {
.attach(AdHoc::config::<Config>())
.attach(AdHoc::on_liftoff("Updater", |rocket| {
Box::pin(async move {
// We don't care about the join handle nor error results?
let _ = rocket::tokio::spawn(update_loop());
let config = rocket.figment().extract().expect("Invalid configuration");
let _ = rocket::tokio::spawn(update_loop(config));
})
}))
}

View File

@ -7,7 +7,7 @@ use rocket::tokio::time::sleep;
use serde::Deserialize;
use url::{ParseError, Url};
use super::{load_config, Config, Status, BASE_URL, POLL_INTERVAL, STATUS};
use super::{Config, Status, BASE_URL, POLL_INTERVAL, STATUS};
/// Returns the login URL for the My Autarco site.
fn login_url() -> Result<Url, ParseError> {
@ -88,8 +88,7 @@ async fn update(config: &Config, client: &Client, last_updated: u64) -> Result<S
///
/// It updates the mutex-guarded current update [`Status`] struct which can be retrieved via
/// Rocket.
pub(super) async fn update_loop() -> color_eyre::Result<()> {
let config = load_config().await?;
pub(super) async fn update_loop(config: Config) -> color_eyre::Result<()> {
let client = ClientBuilder::new().cookie_store(true).build()?;
// Go to the My Autarco site and login.