Skip to main content

Mountain/Vine/Client/
Shared.rs

1#![allow(non_snake_case)]
2
3//! Module-private state for the Vine client: connection pool, per-
4//! connection metadata, the broadcast fan-out, the shutdown flag, plus
5//! the constants and message-size validator that every entry-point shares.
6
7use std::{
8	collections::HashMap,
9	sync::{
10		Arc,
11		atomic::{AtomicBool, Ordering},
12	},
13	time::Instant,
14};
15
16use lazy_static::lazy_static;
17use parking_lot::Mutex;
18
19use crate::Vine::{Client::NotificationFrame, Error::VineError, Generated::cocoon_service_client::CocoonServiceClient};
20
21/// Cocoon gRPC client over a tonic transport channel.
22pub type CocoonClient = CocoonServiceClient<tonic::transport::Channel>;
23
24/// Default timeout for RPC calls.
25pub const DEFAULT_TIMEOUT_MS:u64 = 5000;
26
27/// Maximum number of retry attempts for failed connections.
28pub const MAX_RETRY_ATTEMPTS:usize = 3;
29
30/// Base delay between retry attempts.
31pub const RETRY_BASE_DELAY_MS:u64 = 100;
32
33/// Maximum message size for validation (4 MB to match the tonic default).
34pub const MAX_MESSAGE_SIZE_BYTES:usize = 4 * 1024 * 1024;
35
36/// Health-check interval.
37pub const HEALTH_CHECK_INTERVAL_MS:u64 = 30000;
38
39/// Connection timeout (currently unused - kept for the streaming variant).
40#[allow(dead_code)]
41pub const CONNECTION_TIMEOUT_MS:u64 = 10000;
42
43/// Notification broadcast capacity (drop-oldest when full). 4096 covers
44/// the worst-case storms (sky://diagnostics/changed at 50-200/s during
45/// rust-analyzer cargo-check) with margin.
46pub const NOTIFICATION_BROADCAST_CAPACITY:usize = 4096;
47
48/// Connection metadata tracking health and last activity.
49pub struct ConnectionMetadata {
50	pub LastActivity:Instant,
51
52	pub FailureCount:usize,
53
54	pub IsHealthy:bool,
55}
56
57lazy_static! {
58	pub static ref SIDECAR_CLIENTS: Arc<Mutex<HashMap<String, CocoonClient>>> = Arc::new(Mutex::new(HashMap::new()));
59	pub static ref CONNECTION_METADATA: Arc<Mutex<HashMap<String, ConnectionMetadata>>> =
60		Arc::new(Mutex::new(HashMap::new()));
61	pub static ref NOTIFICATION_BROADCAST: tokio::sync::broadcast::Sender<NotificationFrame::Struct> = {
62		let (Sender, _) = tokio::sync::broadcast::channel(NOTIFICATION_BROADCAST_CAPACITY);
63
64		Sender
65	};
66}
67
68/// Process-wide shutdown flag. Set to `true` once Mountain has issued
69/// `$shutdown` (or SIGKILL'd) Cocoon. After that point all
70/// `SendNotification` / `SendRequest` calls short-circuit.
71pub static SHUTDOWN_FLAG:AtomicBool = AtomicBool::new(false);
72
73pub fn ShutdownFlagStore(Value:bool) { SHUTDOWN_FLAG.store(Value, Ordering::Relaxed); }
74
75pub fn ShutdownFlagLoad() -> bool { SHUTDOWN_FLAG.load(Ordering::Relaxed) }
76
77/// Increment the failure counter and mark the connection unhealthy.
78pub fn RecordSideCarFailure(SideCarIdentifier:&str) {
79	let mut Metadata = CONNECTION_METADATA.lock();
80
81	if let Some(Connection) = Metadata.get_mut(SideCarIdentifier) {
82		Connection.FailureCount += 1;
83
84		Connection.IsHealthy = false;
85	}
86}
87
88/// Refresh the last-activity timestamp and reset the failure counter.
89pub fn UpdateSideCarActivity(SideCarIdentifier:&str) {
90	let mut Metadata = CONNECTION_METADATA.lock();
91
92	if let Some(Connection) = Metadata.get_mut(SideCarIdentifier) {
93		Connection.LastActivity = Instant::now();
94
95		Connection.FailureCount = 0;
96
97		Connection.IsHealthy = true;
98	}
99}
100
101/// Reject messages above `MAX_MESSAGE_SIZE_BYTES` to bound the worst-case
102/// gRPC frame. Mirrors tonic's own check so we don't pay the codec round-
103/// trip for an oversize payload.
104pub fn ValidateMessageSize(Data:&[u8]) -> Result<(), VineError> {
105	if Data.len() > MAX_MESSAGE_SIZE_BYTES {
106		Err(VineError::MessageTooLarge { ActualSize:Data.len(), MaxSize:MAX_MESSAGE_SIZE_BYTES })
107	} else {
108		Ok(())
109	}
110}