trueno/brick/connection/
mod.rs1use std::time::{Duration, Instant};
8
9#[derive(Debug)]
15pub struct ManagedConnection<T> {
16 inner: T,
18 created_at: Instant,
20 last_used: Instant,
22 max_lifetime: Duration,
24 max_idle: Duration,
26 health_failures: usize,
28}
29
30impl<T> ManagedConnection<T> {
31 pub fn new(inner: T, max_lifetime: Duration, max_idle: Duration) -> Self {
33 let now = Instant::now();
34 Self { inner, created_at: now, last_used: now, max_lifetime, max_idle, health_failures: 0 }
35 }
36
37 #[must_use]
39 pub fn is_valid(&self) -> bool {
40 let now = Instant::now();
41 let not_expired = now.duration_since(self.created_at) < self.max_lifetime;
42 let not_idle = now.duration_since(self.last_used) < self.max_idle;
43 let healthy = self.health_failures < 3;
44 not_expired && not_idle && healthy
45 }
46
47 #[must_use]
49 pub fn is_expired(&self) -> bool {
50 self.created_at.elapsed() >= self.max_lifetime
51 }
52
53 #[must_use]
55 pub fn is_idle(&self) -> bool {
56 self.last_used.elapsed() >= self.max_idle
57 }
58
59 pub fn touch(&mut self) {
61 self.last_used = Instant::now();
62 }
63
64 pub fn record_health_failure(&mut self) {
66 self.health_failures += 1;
67 }
68
69 pub fn reset_health(&mut self) {
71 self.health_failures = 0;
72 }
73
74 pub fn inner(&self) -> &T {
76 &self.inner
77 }
78
79 pub fn inner_mut(&mut self) -> &mut T {
81 &mut self.inner
82 }
83
84 pub fn into_inner(self) -> T {
86 self.inner
87 }
88
89 #[must_use]
91 pub fn age(&self) -> Duration {
92 self.created_at.elapsed()
93 }
94
95 #[must_use]
97 pub fn idle_time(&self) -> Duration {
98 self.last_used.elapsed()
99 }
100
101 #[must_use]
103 pub fn health_failures(&self) -> usize {
104 self.health_failures
105 }
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
116pub struct KeepAliveConfig {
117 pub enabled: bool,
119 pub timeout_secs: u32,
121 pub max_requests: u32,
123}
124
125impl KeepAliveConfig {
126 pub fn new() -> Self {
128 Self { enabled: true, timeout_secs: 60, max_requests: 100 }
129 }
130
131 pub fn disabled() -> Self {
133 Self { enabled: false, timeout_secs: 0, max_requests: 0 }
134 }
135
136 pub fn from_header(header: &str) -> Self {
138 let mut config = Self::new();
139
140 for part in header.split(',') {
141 let part = part.trim();
142 if let Some((key, val)) = part.split_once('=') {
143 let key = key.trim().to_lowercase();
144 let val = val.trim();
145
146 match key.as_str() {
147 "timeout" => {
148 if let Ok(t) = val.parse() {
149 config.timeout_secs = t;
150 }
151 }
152 "max" => {
153 if let Ok(m) = val.parse() {
154 config.max_requests = m;
155 }
156 }
157 _ => {} }
159 }
160 }
161
162 config
163 }
164
165 #[must_use]
167 pub fn should_keep_alive(&self, request_count: u32) -> bool {
168 self.enabled && request_count < self.max_requests
169 }
170}
171
172impl Default for KeepAliveConfig {
173 fn default() -> Self {
174 Self::new()
175 }
176}
177
178#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
186pub struct ConnectionState(u8);
187
188impl ConnectionState {
189 pub const OPEN: u8 = 0b0000_0001;
191 pub const READABLE: u8 = 0b0000_0010;
193 pub const WRITABLE: u8 = 0b0000_0100;
195 pub const HAS_PENDING: u8 = 0b0000_1000;
197 pub const KEEP_ALIVE: u8 = 0b0001_0000;
199 pub const UPGRADE: u8 = 0b0010_0000;
201 pub const CLOSING: u8 = 0b0100_0000;
203 pub const ERROR: u8 = 0b1000_0000;
205
206 #[must_use]
208 pub fn new() -> Self {
209 Self(0)
210 }
211
212 #[must_use]
214 pub fn open_connection() -> Self {
215 Self(Self::OPEN | Self::WRITABLE)
216 }
217
218 pub fn set(&mut self, flag: u8) {
220 self.0 |= flag;
221 }
222
223 pub fn clear(&mut self, flag: u8) {
225 self.0 &= !flag;
226 }
227
228 #[must_use]
230 pub fn is_set(&self, flag: u8) -> bool {
231 self.0 & flag != 0
232 }
233
234 #[must_use]
236 pub fn is_healthy(&self) -> bool {
237 self.is_set(Self::OPEN) && !self.is_set(Self::ERROR) && !self.is_set(Self::CLOSING)
238 }
239
240 #[must_use]
242 pub fn can_read(&self) -> bool {
243 self.is_set(Self::OPEN) && self.is_set(Self::READABLE)
244 }
245
246 #[must_use]
248 pub fn can_write(&self) -> bool {
249 self.is_set(Self::OPEN) && self.is_set(Self::WRITABLE) && !self.is_set(Self::CLOSING)
250 }
251
252 #[must_use]
254 pub fn bits(&self) -> u8 {
255 self.0
256 }
257}
258
259#[cfg(test)]
260mod tests;