1 use anyhow::{anyhow, Result};
2 use app_fun::handler::process_fun_app;
3 use app_oten::handler::process_oten_app;
4 use app_pkt::handler::process_pkt_app;
5 use app_rdb::handler::process_rdb_app;
6 use clap::Parser;
7 use console::style;
8 use dotenv::dotenv;
9 use smbpndk_cli::{
10 account::process_account,
11 cli::{Cli, Commands},
12 project::process_project,
13 };
14 use smbpndk_model::CommandResult;
15 use std::{
16 fs::{create_dir_all, OpenOptions},
17 path::PathBuf,
18 str::FromStr,
19 };
20 use tracing::subscriber::set_global_default;
21 use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer};
22 use tracing_subscriber::{filter::LevelFilter, prelude::*, EnvFilter};
23
24 fn setup_logging(level: Option<EnvFilter>) -> Result<()> {
25 // Log in the current directory
26 let log_path = match home::home_dir() {
27 Some(path) => {
28 create_dir_all(path.join(".smb"))?;
29 let log_path = [path.to_str().unwrap(), "/.smb/smbpndk-cli.log"].join("");
30 // Create the file if it doesn't exist
31 let _file = OpenOptions::new()
32 .create(true)
33 .write(true)
34 .open(&log_path)?;
35
36 PathBuf::from(log_path)
37 }
38 None => {
39 return Err(anyhow!("Could not find home directory."));
40 }
41 };
42
43 let file = OpenOptions::new()
44 .create(true)
45 .write(true)
46 .open(log_path)
47 .unwrap();
48
49 let env_filter = if let Some(filter) = level {
50 filter
51 } else {
52 EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("trace"))
53 };
54
55 let formatting_layer = BunyanFormattingLayer::new("smb".into(), file);
56 let level_filter = LevelFilter::from_str(&env_filter.to_string())?;
57
58 let subscriber = tracing_subscriber::registry()
59 .with(formatting_layer.with_filter(level_filter))
60 .with(JsonStorageLayer);
61
62 set_global_default(subscriber).expect("Failed to set global default subscriber");
63
64 Ok(())
65 }
66
67 #[tokio::main]
68 async fn main() {
69 dotenv().ok();
70 match run().await {
71 Ok(result) => {
72 let mut spinner = result.spinner;
73 spinner.stop_and_persist(&result.symbol, result.msg);
74 std::process::exit(1);
75 }
76 Err(e) => {
77 println!(
78 "\n{} {}",
79 style("✘".to_string()).for_stderr().red(),
80 style(e).red()
81 );
82 std::process::exit(1);
83 }
84 }
85 }
86
87 async fn run() -> Result<CommandResult> {
88 let cli = Cli::parse();
89
90 let log_level_error: Result<CommandResult> = Err(anyhow!(
91 "Invalid log level: {:?}.\n Valid levels are: trace, debug, info, warn, and error.",
92 cli.log_level
93 ));
94
95 if let Some(user_filter) = cli.log_level {
96 let filter = match EnvFilter::from_str(&user_filter) {
97 Ok(filter) => filter,
98 Err(_) => return log_level_error,
99 };
100 setup_logging(Some(filter))?;
101 } else {
102 setup_logging(None)?;
103 }
104
105 match cli.command {
106 Commands::Account { command } => process_account(command).await,
107 Commands::Project { command } => process_project(command).await,
108 Commands::Oten { command } => process_oten_app(command).await,
109 Commands::Fun { command } => process_fun_app(command).await,
110 Commands::Pkt { command } => process_pkt_app(command).await,
111 Commands::Rdb { command } => process_rdb_app(command).await,
112 }
113 }