1
2pub async fn run() -> Result<()> {
3 env_logger::init();
4 let cli = Cli::parse();
5
6 match cli.command {
7 Commands::Start { config} => {
8 println!("Starting Holger {:?}",config);
9
10 let mut holger = holger_ron::read_ron_config(config)?;
11 let backend=holger.instantiate_backends();
12
13 let r=wire_holger(&mut holger);
14 print_wiring_summary(&holger);
15 let cfg = PrettyConfig::new()
16 .depth_limit(4)
17 .separate_tuple_members(true)
18 .enumerate_arrays(true);
19
20 println!("{}", to_string_pretty(&holger, cfg)?);
21
22
23 holger.start()?;
24
25 println!("Holger is running. Press Ctrl+C to stop.");
26
27 let (tx, rx) = std::sync::mpsc::channel();
29 ctrlc::set_handler(move || {
30 let _ = tx.send(());
31 })?;
32
33 rx.recv().expect("Failed to receive signal");
35
36 println!("Holger stopped.");
38 }
40 }
41
42 Ok(())
43}
44
45
46use ron::ser::{to_string_pretty, PrettyConfig};
48
49use clap::{Parser, Subcommand};
50use std::path::PathBuf;
51use anyhow::Result;
52use holger_ron::{wire_holger, Holger};
53#[derive(Parser)]
57#[command(name = "holger")]
58#[command(about = "Holger: Guards your artifacts at rest.", long_about = None)]
59struct Cli {
60 #[command(subcommand)]
61 command: Commands,
62}
63
64#[derive(Subcommand)]
65enum Commands {
66 Start {
68 #[arg(short, long)]
69 config: PathBuf,
70
71 },
72
73}
74
75
76
77pub fn print_wiring_summary(holger: &Holger) {
78 println!("--- Wiring Summary ---");
79
80 for (i, repo) in holger.repositories.iter().enumerate() {
81 let upstreams = repo.ron_upstreams.len();
82 let in_exists = repo.ron_in.is_some();
83 let out_exists = repo.ron_out.is_some();
84
85 println!(
86 "[Repo #{i}] {} | upstreams:{} in:{} out:{}",
87 repo.ron_name, upstreams, in_exists, out_exists
88 );
89 }
90
91 println!("--- Wiring Check ---");
92 let mut ok = true;
93 for repo in &holger.repositories {
94 if repo.ron_out.is_some() && holger.exposed_endpoints.is_empty() {
95 println!("!! Repo {} has `ron_out` but no exposed endpoints wired", repo.ron_name);
96 ok = false;
97 }
98 if repo.ron_out.is_some() && holger.storage_endpoints.is_empty() {
99 println!("!! Repo {} has `ron_out` but no storage endpoints wired", repo.ron_name);
100 ok = false;
101 }
102 }
103
104 if ok {
105 println!("Wiring looks OK.");
106 } else {
107 println!("Wiring has issues.");
108 }
109
110
111 println!("--- Reverse Wiring ---");
112
113 for (i, ep) in holger.exposed_endpoints.iter().enumerate() {
114 println!(
115 "[Exposed #{i}] {} | in:{} out:{}",
116 ep.ron_name,
117 ep.wired_in_repositories.len(),
118 ep.wired_out_repositories.len()
119 );
120 }
121
122 for (i, st) in holger.storage_endpoints.iter().enumerate() {
123 println!(
124 "[Storage #{i}] {} | in:{} out:{}",
125 st.ron_name,
126 st.wired_in_repositories.len(),
127 st.wired_out_repositories.len()
128 );
129 }
130 println!("--- Aggregated Routes Debug ---");
131
132 for (i, ep) in holger.exposed_endpoints.iter().enumerate() {
133 println!(
134 "[Exposed #{i}] {} | aggregated_routes: {}",
135 ep.ron_name,
136 if ep.aggregated_routes.is_some() { "yes" } else { "no" }
137 );
138
139 if !ep.wired_out_repositories.is_empty() {
140 for &repo_ptr in &ep.wired_out_repositories {
141 if repo_ptr.is_null() {
142 println!(" -> null pointer (skipped)");
143 continue;
144 }
145 let repo = unsafe { &*repo_ptr };
146 println!(
147 " -> wired repo: {} | backend: {}",
148 repo.ron_name,
149 if repo.backend_repository.is_some() { "ready" } else { "none" }
150 );
151 }
152 } else {
153 println!(" -> no wired out repositories");
154 }
155 }
156
157 println!("--- Aggregated Routes Deep Check ---");
158
159 for (i, ep) in holger.exposed_endpoints.iter().enumerate() {
160 let mut possible_routes = 0;
161 let mut ready_routes = 0;
162
163 println!(
164 "[Exposed #{i}] {} | aggregated_routes: {}",
165 ep.ron_name,
166 if ep.aggregated_routes.is_some() { "yes" } else { "no" }
167 );
168
169 if ep.wired_out_repositories.is_empty() {
170 println!(" -> no wired out repositories");
171 } else {
172 for &repo_ptr in &ep.wired_out_repositories {
173 if repo_ptr.is_null() {
174 println!(" -> null pointer (skipped)");
175 continue;
176 }
177 let repo = unsafe { &*repo_ptr };
178 possible_routes += 1;
179
180 let expected = &ep.ron_name;
181 let actual = if let Some(io) = &repo.ron_out {
182 &io.ron_exposed_endpoint
183 } else {
184 "<none>"
185 };
186
187 let backend_ready = repo.backend_repository.is_some();
188 if backend_ready {
189 ready_routes += 1;
190 }
191
192 println!(
193 " -> wired repo: {} | backend:{} | expected:{} vs actual:{}",
194 repo.ron_name,
195 if backend_ready { "ready" } else { "none" },
196 expected,
197 actual
198 );
199 }
200 }
201
202 println!(
203 " -> route candidates: {} | ready for FastRoutes: {}",
204 possible_routes, ready_routes
205 );
206 }
207}