avina-api 1.2.1

Rust API server for the LRZ-specific features of the Openstack-based LRZ Compute Cloud.
use std::collections::HashMap;

use actix_web::{
    HttpResponse, Scope, http,
    web::{Data, ReqData, get, scope},
};
use avina_wire::user::User;
use reqwest::Client;

use crate::{
    authentication::Token, error::AuthOnlyError, startup::CloudUsageUrl,
};

pub fn usage_scope() -> Scope {
    scope("/usage").route("", get().to(cloud_usage))
}

#[tracing::instrument(name = "cloud_usage")]
async fn cloud_usage(
    user: ReqData<User>,
    token: ReqData<Token>,
    cloud_usage_url: Data<CloudUsageUrl>,
) -> Result<HttpResponse, AuthOnlyError> {
    let Some(url) = cloud_usage_url.as_ref().0.clone() else {
        tracing::error!("Cloud usage URL is not configured.");
        return Ok(HttpResponse::InternalServerError().finish());
    };
    let mut data = HashMap::new();
    data.insert("project_id", user.openstack_id.clone());
    data.insert("token_id", token.0.clone());
    let Ok(response) = Client::new().get(url).json(&data).send().await else {
        tracing::error!("Call to Cloud Usage backend failed.");
        return Ok(HttpResponse::InternalServerError().finish());
    };
    if response.status().as_u16() != http::StatusCode::OK {
        tracing::error!("Cloud Usage backend returned unexpected status code.");
        return Ok(HttpResponse::InternalServerError().finish());
    }
    let Ok(body) = response.text().await else {
        tracing::error!("Unable to get body from Cloud Usage response.");
        return Ok(HttpResponse::InternalServerError().finish());
    };
    Ok(HttpResponse::Ok().body(body))
}