cat_gateway/cli.rs
1//! CLI interpreter for the service
2use std::{io::Write, path::PathBuf, time::Duration};
3
4use clap::Parser;
5use tracing::{error, info};
6
7use crate::{
8 cardano::start_followers,
9 db::{self, index::session::CassandraSession},
10 service::{
11 self,
12 utilities::health::{
13 condition_for_started, is_live, live_counter_reset, service_has_started, set_to_started,
14 },
15 },
16 settings::{ServiceSettings, Settings},
17};
18
19#[derive(Parser)]
20#[clap(rename_all = "kebab-case")]
21/// Simple service CLI options
22pub(crate) enum Cli {
23 /// Run the service
24 Run(ServiceSettings),
25 /// Build API docs of the service in the JSON format
26 Docs {
27 /// The output path to the generated docs file, if omitted prints to stdout.
28 output: Option<PathBuf>,
29 },
30}
31
32impl Cli {
33 /// Execute the specified operation.
34 ///
35 /// This method is asynchronous and returns a `Result` indicating whether the
36 /// operation was successful or if an error occurred.
37 ///
38 /// # Errors
39 ///
40 /// This method can return an error if:
41 ///
42 /// - Failed to initialize the logger with the specified log level.
43 /// - Failed to create a new `State` with the provided database URL.
44 /// - Failed to run the service on the specified address.
45 pub(crate) async fn exec(self) -> anyhow::Result<()> {
46 match self {
47 Self::Run(settings) => {
48 // Returns optional guard for telemetry providers.
49 // We must hold this guard while the main process runs.
50 // No need to do anything else.
51 let _guard = Settings::init(settings)?;
52
53 let mut tasks = Vec::new();
54
55 info!("Catalyst Gateway - Starting");
56
57 // Start the DB's.
58 CassandraSession::init();
59
60 // Initialize Event DB connection pool
61 db::event::establish_connection_pool();
62
63 // Start the chain indexing follower.
64 start_followers().await?;
65
66 // Start the API service.
67 let handle = tokio::spawn(async move {
68 match service::run().await {
69 Ok(()) => info!("Endpoints started ok"),
70 Err(err) => {
71 error!("Error starting endpoints {err}");
72 },
73 }
74 });
75 tasks.push(handle);
76
77 // Start task to reset the service 'live counter' at a regular interval.
78 let handle = tokio::spawn(async move {
79 while is_live() {
80 tokio::time::sleep(Settings::service_live_timeout_interval()).await;
81 live_counter_reset();
82 }
83 });
84 tasks.push(handle);
85
86 // Start task to wait for the service 'started' flag to be `true`.
87 let handle = tokio::spawn(async move {
88 while !service_has_started() {
89 tokio::time::sleep(Duration::from_secs(1)).await;
90 if condition_for_started() {
91 set_to_started();
92 }
93 }
94 });
95 tasks.push(handle);
96
97 // Run all asynchronous tasks to completion.
98 for task in tasks {
99 task.await?;
100 }
101
102 info!("Catalyst Gateway - Shut Down");
103 },
104 Self::Docs { output } => {
105 let docs = service::get_app_docs();
106 match output {
107 Some(path) => {
108 let mut docs_file = std::fs::File::create(path)?;
109 docs_file.write_all(docs.as_bytes())?;
110 },
111 None => println!("{docs}"),
112 }
113 },
114 }
115
116 Ok(())
117 }
118}