aoc_leaderbot_aws_lambda_impl 3.0.0

Implementation of an Advent of Code leaderboard-watching bot running in AWS Lambda
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(rustdoc::private_intra_doc_links)]
#![cfg_attr(coverage_nightly, feature(coverage_attribute))]

use aoc_leaderbot_aws_lib::leaderbot::storage::aws::dynamodb::DynamoDbStorage;
use aoc_leaderbot_aws_lib::leaderbot::storage::aws::dynamodb::config::table::{
    BillingModeConfig, TableConfig,
};
use aws_config::BehaviorVersion;
use clap::Parser;
use dotenvy::dotenv;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let _ = dotenv();

    let cli = Cli::parse();

    let storage = get_storage(&cli).await;
    let table_config = get_table_config(&cli);
    storage.create_table(Some(table_config)).await?;

    Ok(())
}

async fn get_storage(cli: &Cli) -> DynamoDbStorage {
    if cli.test_endpoint_url.is_empty() {
        DynamoDbStorage::new(&cli.table_name).await
    } else {
        let config = aws_config::defaults(BehaviorVersion::latest())
            .region("ca-central-1")
            .test_credentials()
            .endpoint_url(&cli.test_endpoint_url)
            .load()
            .await;
        DynamoDbStorage::with_config(&config, &cli.table_name).await
    }
}

fn get_table_config(cli: &Cli) -> TableConfig {
    let billing_mode = match cli.billing_mode {
        cli::BillingMode::PayPerRequest => BillingModeConfig::pay_per_request(
            cli.max_read_request_units,
            cli.max_write_request_units,
        ),
        cli::BillingMode::Provisioned => {
            BillingModeConfig::provisioned(cli.read_capacity_units, cli.write_capacity_units)
        },
    };

    TableConfig { billing_mode: Some(billing_mode) }
}

use cli::Cli;

// It seems some code generated by `clap` is flagged as not covered by tests,
// but I don't know how to cover them, so I'll move the struct to a "no coverage" module.
#[cfg_attr(coverage_nightly, coverage(off))]
mod cli {
    use aoc_leaderbot_aws_lambda_impl::leaderbot::DEFAULT_DYNAMODB_TABLE_NAME;
    use aoc_leaderbot_aws_lib::leaderbot::storage::aws::dynamodb::config::table::{
        DEFAULT_READ_CAPACITY_UNITS, DEFAULT_WRITE_CAPACITY_UNITS,
    };
    use clap::ValueEnum;
    use gratte::Display;

    use super::*;

    #[derive(Debug, Copy, Clone, Display, ValueEnum)]
    pub enum BillingMode {
        PayPerRequest,
        Provisioned,
    }

    #[derive(Debug, Parser)]
    #[command(version, about = "Prepare DynamoDB table for aoc_leaderbot", long_about = None)]
    pub struct Cli {
        /// Name of DynamoDB table to use for leaderboard data
        #[arg(short, long, default_value_t = DEFAULT_DYNAMODB_TABLE_NAME.into())]
        pub table_name: String,

        /// DynamoDB billing mode
        #[arg(short, long, value_enum, default_value_t = BillingMode::Provisioned)]
        pub billing_mode: BillingMode,

        /// Max read request units in pay-per-request mode
        #[arg(long)]
        pub max_read_request_units: Option<i64>,

        /// Max write request units in pay-per-request mode
        #[arg(long)]
        pub max_write_request_units: Option<i64>,

        /// Read capacity units in provisioned mode
        #[arg(long, default_value_t = DEFAULT_READ_CAPACITY_UNITS)]
        pub read_capacity_units: i64,

        /// Write capacity units in provisioned mode
        #[arg(long, default_value_t = DEFAULT_WRITE_CAPACITY_UNITS)]
        pub write_capacity_units: i64,

        /// Test endpoint URL. Used by tests only, not shown in help
        #[arg(long, hide = true, default_value_t)]
        pub test_endpoint_url: String,
    }
}