saluki_env/helpers/remote_agent/
session.rs1use std::{
2 fmt,
3 sync::{Arc, Mutex},
4};
5
6use saluki_error::{ErrorContext as _, GenericError};
7use tokio::sync::Notify;
8use tonic::metadata::{Ascii, MetadataValue};
9
10#[derive(Debug)]
17pub struct SessionId(MetadataValue<Ascii>);
18
19impl SessionId {
20 pub fn new(session_id: &str) -> Result<Self, GenericError> {
26 MetadataValue::try_from(session_id)
27 .map(Self)
28 .error_context("Session ID is not valid ASCII")
29 }
30
31 pub fn as_str(&self) -> &str {
33 self.0
34 .to_str()
35 .expect("session ID is ensured to be valid ASCII on creation")
36 }
37
38 pub fn to_grpc_header_value(&self) -> MetadataValue<Ascii> {
40 self.0.clone()
41 }
42}
43
44impl fmt::Display for SessionId {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 write!(f, "{}", self.as_str())
47 }
48}
49
50#[derive(Debug, Default)]
51struct SessionIdHandleInner {
52 session_id: Mutex<Option<SessionId>>,
53 change_notify: Notify,
54}
55
56#[derive(Clone, Debug)]
61pub struct SessionIdHandle {
62 inner: Arc<SessionIdHandleInner>,
63}
64
65impl SessionIdHandle {
66 pub fn empty() -> Self {
68 Self {
69 inner: Arc::new(SessionIdHandleInner::default()),
70 }
71 }
72
73 pub fn update(&self, new_session_id: Option<SessionId>) {
75 if let Ok(mut session_id) = self.inner.session_id.lock() {
76 *session_id = new_session_id;
77 self.inner.change_notify.notify_waiters();
78 }
79 }
80
81 pub fn get(&self) -> Option<SessionId> {
83 self.inner
84 .session_id
85 .lock()
86 .ok()
87 .and_then(|s| (*s).as_ref().map(|session_id| SessionId(session_id.0.clone())))
88 }
89
90 pub async fn wait_for_update(&self) -> SessionId {
92 loop {
93 let updated = self.inner.change_notify.notified();
94 if let Some(session_id) = self.get() {
95 return session_id;
96 }
97
98 updated.await;
99 }
100 }
101}