Skip to main content

haste_health/
main.rs

1use std::{
2    path::PathBuf,
3    sync::{Arc, LazyLock},
4};
5
6use clap::{Parser, Subcommand};
7use haste_config::{ConfigType, get_config};
8use haste_fhir_operation_error::OperationOutcomeError;
9use haste_server::auth_n::oidc::routes::discovery::WellKnownDiscoveryDocument;
10use tokio::sync::Mutex;
11
12use crate::commands::config::{CLIConfiguration, load_config};
13
14mod client;
15mod commands;
16
17#[derive(Parser)]
18#[command(version, about, long_about = None)] // Read from `Cargo.toml`
19struct Cli {
20    #[command(subcommand)]
21    command: CLICommand,
22}
23
24#[derive(Subcommand)]
25enum CLICommand {
26    /// Data gets pulled from stdin.
27    FHIRPath {
28        /// lists test values
29        fhirpath: String,
30    },
31    Generate {
32        /// Input FHIR StructureDefinition file (JSON)
33        #[command(subcommand)]
34        command: commands::codegen::CodeGen,
35    },
36    Server {
37        #[command(subcommand)]
38        command: commands::server::ServerCommands,
39    },
40    Api {
41        #[command(subcommand)]
42        command: commands::api::ApiCommands,
43    },
44    Config {
45        #[command(subcommand)]
46        command: commands::config::ConfigCommands,
47    },
48    Worker {
49        #[command(subcommand)]
50        command: Option<commands::worker::WorkerCommands>,
51    },
52    Testscript {
53        #[command(subcommand)]
54        command: commands::testscript::TestScriptCommands,
55    },
56    Admin {
57        #[command(subcommand)]
58        command: commands::admin::AdminCommands,
59    },
60}
61
62static CONFIG_LOCATION: LazyLock<PathBuf> = LazyLock::new(|| {
63    let config_dir = std::env::home_dir()
64        .unwrap_or_else(|| std::path::PathBuf::from("."))
65        .join(".haste_health");
66
67    std::fs::create_dir_all(&config_dir).expect("Failed to create config directory");
68
69    config_dir.join("config.toml")
70});
71
72pub struct CLIState {
73    config: CLIConfiguration,
74    access_token: Option<String>,
75    well_known_document: Option<WellKnownDiscoveryDocument>,
76}
77
78impl CLIState {
79    pub fn new(config: CLIConfiguration) -> Self {
80        CLIState {
81            config,
82            access_token: None,
83            well_known_document: None,
84        }
85    }
86}
87
88static CLI_STATE: LazyLock<Arc<Mutex<CLIState>>> = LazyLock::new(|| {
89    let config = load_config(&CONFIG_LOCATION);
90
91    Arc::new(Mutex::new(CLIState::new(config)))
92});
93
94enum CLIEnvironmentVariables {
95    SentryDSN,
96}
97
98impl From<CLIEnvironmentVariables> for String {
99    fn from(value: CLIEnvironmentVariables) -> Self {
100        match value {
101            CLIEnvironmentVariables::SentryDSN => "SENTRY_DSN".to_string(),
102        }
103    }
104}
105
106fn main() -> Result<(), OperationOutcomeError> {
107    tracing_subscriber::fmt::init();
108    let cli = Cli::parse();
109    let config = CLI_STATE.clone();
110    let env = get_config(ConfigType::Environment);
111    let sentry_location = env.get(CLIEnvironmentVariables::SentryDSN);
112
113    // let subscriber = tracing_subscriber::FmtSubscriber::new();
114    // tracing::subscriber::set_global_default(subscriber).unwrap();
115
116    let _guard = sentry::init((
117        sentry_location.unwrap_or_default(),
118        sentry::ClientOptions {
119            release: sentry::release_name!(),
120            // Capture user IPs and potentially sensitive headers when using HTTP server integrations
121            // see https://docs.sentry.io/platforms/rust/data-management/data-collected for more info
122            send_default_pii: true,
123            ..Default::default()
124        },
125    ));
126
127    tokio::runtime::Builder::new_multi_thread()
128        .enable_all()
129        .build()
130        .unwrap()
131        .block_on(async {
132            match &cli.command {
133                CLICommand::FHIRPath { fhirpath } => commands::fhirpath::fhirpath(fhirpath).await,
134                CLICommand::Generate { command } => commands::codegen::codegen(command).await,
135                CLICommand::Server { command } => commands::server::server(command).await,
136                CLICommand::Worker { command } => commands::worker::worker(command).await,
137                CLICommand::Config { command } => commands::config::config(&config, command).await,
138                CLICommand::Api { command } => commands::api::api_commands(config, command).await,
139                CLICommand::Testscript { command } => {
140                    commands::testscript::testscript_commands(config, command).await
141                }
142                CLICommand::Admin { command } => commands::admin::admin(command).await,
143            }
144        })
145}