1pub mod binding_defaults;
7pub mod client_registry;
8pub mod connect_context;
9pub mod default_port;
10pub mod dependencies;
11pub mod docs;
12pub mod dual;
13pub mod easy_registry;
14pub mod event_logger;
15pub mod event_type;
16pub mod log_template;
17pub mod metadata;
18pub mod server_registry;
19pub mod spawn_context;
20
21pub use binding_defaults::BindingDefaults;
22pub use client_registry::CLIENT_REGISTRY;
23pub use connect_context::ConnectContext;
24pub use dependencies::ProtocolDependency;
25pub use docs::render_all_protocol_docs;
26pub use dual::{client_protocol_for_server, compiled_client_protocol_for_server};
27pub use easy_registry::EASY_REGISTRY;
28pub use event_logger::{log_action_result, EventLogContext};
29pub use event_type::{Event, EventType};
30pub use log_template::{LogLevel, LogTemplate};
31pub use metadata::{DevelopmentState, ProtocolMetadata, ProtocolMetadataV2};
32pub use server_registry::registry;
33pub use spawn_context::{SpawnContext, StartupParamError, StartupParamResult, StartupParams};
34
35pub fn stability_report(min_stability: Option<DevelopmentState>) -> Vec<String> {
44 fn one_line_note(notes: Option<&'static str>) -> Option<String> {
45 let raw = notes?;
46 let first = raw.lines().next().unwrap_or(raw).trim();
47 if first.is_empty() {
48 return None;
49 }
50 Some(crate::utils::truncate::truncate_with_suffix(
51 first, 120, "…",
52 ))
53 }
54
55 let mut server_rows: Vec<(DevelopmentState, String, Option<String>)> = registry()
57 .all_protocols()
58 .into_iter()
59 .map(|(name, p)| {
60 let m = p.metadata();
61 (m.state, name, one_line_note(m.notes))
62 })
63 .collect();
64 let mut client_rows: Vec<(DevelopmentState, String, Option<String>)> = CLIENT_REGISTRY
65 .get_all()
66 .into_iter()
67 .map(|p| {
68 let m = p.metadata();
69 (
70 m.state,
71 p.protocol_name().to_string(),
72 one_line_note(m.notes),
73 )
74 })
75 .collect();
76
77 server_rows.sort_by_key(|r| r.1.to_lowercase());
79 client_rows.sort_by_key(|r| r.1.to_lowercase());
80
81 let mut lines = Vec::new();
82 match min_stability {
83 Some(min) => lines.push(format!(
84 "Minimum stability to start (--min-stability): {} — protocols below this are refused",
85 min.as_str()
86 )),
87 None => lines.push(
88 "Minimum stability to start (--min-stability): not set (only Incomplete is hidden from the model)"
89 .to_string(),
90 ),
91 }
92
93 for (label, rows) in [("Servers", &server_rows), ("Clients", &client_rows)] {
94 lines.push(String::new());
95 lines.push(format!("=== {} ({}) ===", label, rows.len()));
96 for state in DevelopmentState::ALL.iter().rev().copied() {
98 let group: Vec<_> = rows.iter().filter(|r| r.0 == state).collect();
99 if group.is_empty() {
100 continue;
101 }
102 lines.push(format!("-- {} ({}) --", state.as_str(), group.len()));
103 for (st, name, note) in group {
104 let blocked = min_stability.map(|min| *st < min).unwrap_or(false);
105 let marker = if blocked {
106 " [blocked by --min-stability]"
107 } else {
108 ""
109 };
110 match note {
111 Some(n) => {
112 lines.push(format!(" {} [{}]{} — {}", name, st.as_str(), marker, n))
113 }
114 None => lines.push(format!(" {} [{}]{}", name, st.as_str(), marker)),
115 }
116 }
117 }
118 }
119
120 lines
121}