1use std::net::{IpAddr, Ipv4Addr, SocketAddr};
6use std::sync::Arc;
7use std::time::Duration;
8
9use regex::Regex;
10use tracing::{error, info};
11
12use crate::beacon::{BeaconConfig, run_beacon};
13use tokio::net::TcpListener;
14
15use crate::handler::{PvListMode, ServerState, rand_guid, run_tcp_server, run_udp_search};
16use crate::monitor::MonitorRegistry;
17use crate::pvstore::SourceRegistry;
18
19pub struct PvaServerConfig {
21 pub listen_ip: IpAddr,
23 pub tcp_port: u16,
25 pub udp_port: u16,
27 pub advertise_ip: Option<IpAddr>,
29 pub beacon_target: SocketAddr,
31 pub beacon_period_secs: u64,
33 pub conn_timeout: Duration,
35 pub compute_alarms: bool,
37 pub pvlist_mode: PvListMode,
39 pub pvlist_max: usize,
41 pub pvlist_allow_pattern: Option<Regex>,
43}
44
45impl Default for PvaServerConfig {
46 fn default() -> Self {
47 Self {
48 listen_ip: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
49 tcp_port: 5075,
50 udp_port: 5076,
51 advertise_ip: None,
52 beacon_target: "224.0.0.128:5076".parse().unwrap(),
53 beacon_period_secs: 15,
54 conn_timeout: Duration::from_secs(64000),
55 compute_alarms: false,
56 pvlist_mode: PvListMode::List,
57 pvlist_max: 1024,
58 pvlist_allow_pattern: None,
59 }
60 }
61}
62
63pub struct PvaServerState {
68 pub inner: Arc<ServerState>,
69 pub registry: Arc<MonitorRegistry>,
70}
71
72impl PvaServerState {
73 pub fn new(sources: Arc<SourceRegistry>, config: &PvaServerConfig) -> Self {
74 Self::with_registry(sources, config, Arc::new(MonitorRegistry::new()))
75 }
76
77 pub fn with_registry(
78 sources: Arc<SourceRegistry>,
79 config: &PvaServerConfig,
80 registry: Arc<MonitorRegistry>,
81 ) -> Self {
82 let guid = rand_guid();
83 let inner = Arc::new(ServerState::new(
84 sources,
85 registry.clone(),
86 config.compute_alarms,
87 config.pvlist_mode,
88 config.pvlist_max,
89 config.pvlist_allow_pattern.clone(),
90 guid,
91 config.tcp_port,
92 config.advertise_ip,
93 config.listen_ip,
94 ));
95 Self { inner, registry }
96 }
97}
98
99pub async fn run_pva_server(
104 sources: Arc<SourceRegistry>,
105 config: PvaServerConfig,
106) -> Result<(), Box<dyn std::error::Error>> {
107 let registry = Arc::new(MonitorRegistry::new());
108 run_pva_server_with_registry(sources, config, registry).await
109}
110
111pub async fn run_pva_server_with_registry(
113 sources: Arc<SourceRegistry>,
114 config: PvaServerConfig,
115 registry: Arc<MonitorRegistry>,
116) -> Result<(), Box<dyn std::error::Error>> {
117 let server_state = PvaServerState::with_registry(sources, &config, registry);
118 let state = server_state.inner;
119
120 let guid = state.guid;
121 let tcp_addr = SocketAddr::new(config.listen_ip, config.tcp_port);
122 let udp_addr = SocketAddr::new(config.listen_ip, config.udp_port);
123
124 info!(
125 "Starting PVA server: udp={} tcp={} pvlist_mode={:?} pvlist_max={} filter={}",
126 udp_addr,
127 tcp_addr,
128 config.pvlist_mode,
129 config.pvlist_max,
130 config
131 .pvlist_allow_pattern
132 .as_ref()
133 .map(|r| r.as_str())
134 .unwrap_or("<none>")
135 );
136
137 let tcp_listener = TcpListener::bind(tcp_addr).await?;
141 info!("TCP listener bound on {}", tcp_addr);
142
143 let beacon_config = BeaconConfig {
144 target: config.beacon_target,
145 guid,
146 tcp_port: config.tcp_port,
147 advertise_ip: config.advertise_ip,
148 listen_ip: config.listen_ip,
149 period_secs: config.beacon_period_secs,
150 };
151
152 let udp_state = state.clone();
153 let udp_task = tokio::spawn(async move {
154 if let Err(e) = run_udp_search(
155 udp_state,
156 udp_addr,
157 config.tcp_port,
158 guid,
159 config.advertise_ip,
160 )
161 .await
162 {
163 error!("UDP search server error: {}", e);
164 }
165 });
166
167 let tcp_state = state.clone();
168 let tcp_task = tokio::spawn(async move {
169 if let Err(e) = run_tcp_server(tcp_state, tcp_listener, config.conn_timeout).await {
170 error!("TCP server error: {}", e);
171 }
172 });
173
174 let beacon_change = state.beacon_change.clone();
175 let beacon_task = tokio::spawn(async move {
176 if let Err(e) = run_beacon(beacon_config, beacon_change).await {
177 error!("Beacon task error: {}", e);
178 }
179 });
180
181 let _ = tokio::join!(udp_task, tcp_task, beacon_task);
182 Ok(())
183}