mj_controller/session_manager/
client_backend.rs1use super::*;
2
3#[derive(Clone)]
4pub(super) struct ClientSessionHandle(pub(super) ManagedSessionHandle);
5
6impl mj_client::session::SessionHandleBackend for ClientSessionHandle {
7 fn search_prompts(
8 &self,
9 bundle_id: String,
10 scope: mj_core::storage::HistoryScope,
11 query: String,
12 ) -> mj_client::session::BoxFuture<'_, Result<Vec<mj_core::storage::PromptHistoryEntry>>> {
13 let session_id = self.0.session_id().to_owned();
14 Box::pin(async move {
15 tokio::task::spawn_blocking(move || {
16 crate::database::search_prompts(&session_id, &bundle_id, scope, &query)
17 })
18 .await
19 .context("history search task")?
20 })
21 }
22 fn review_state(
23 &self,
24 ) -> mj_client::session::BoxFuture<'_, Result<mj_client::session::ReviewState>> {
25 let session_id = self.0.session_id().to_owned();
26 Box::pin(async move {
27 tokio::task::spawn_blocking(move || {
28 Ok(mj_client::session::ReviewState {
29 review: crate::database::active_review(&session_id)?,
30 defaults: crate::database::reviewer_defaults()?,
31 })
32 })
33 .await
34 .context("review restoration task")?
35 })
36 }
37
38 fn config_result(
39 &self,
40 command_id: String,
41 ) -> mj_client::session::BoxFuture<'_, Result<Option<Option<String>>>> {
42 let session_id = self.session_id().to_owned();
43 Box::pin(async move {
44 tokio::task::spawn_blocking(move || {
45 crate::database::load_config_result(&session_id, &command_id)
46 })
47 .await
48 .context("read configuration completion task")?
49 })
50 }
51
52 fn clone_box(&self) -> Box<dyn mj_client::session::SessionHandleBackend> {
53 Box::new(self.clone())
54 }
55
56 fn session_id(&self) -> &str {
57 self.0.session_id()
58 }
59
60 fn view(&self) -> ManagedSessionView {
61 self.0.view()
62 }
63
64 fn is_stopped(&self) -> bool {
65 self.0.is_stopped()
66 }
67
68 fn has_changed(&self) -> Result<bool> {
69 self.0.has_changed()
70 }
71
72 fn changed(&mut self) -> mj_client::session::BoxFuture<'_, Result<ManagedSessionView>> {
73 Box::pin(self.0.changed())
74 }
75
76 fn enqueue_submit(
77 &self,
78 command_id: String,
79 command: RelayCommand,
80 ) -> mj_client::session::BoxFuture<'_, Result<mj_client::session::PendingRelaySubmit>> {
81 Box::pin(async move {
82 let pending = self.0.enqueue_submit(command_id, command).await?;
83 Ok(mj_client::session::PendingRelaySubmit::new(Box::pin(
84 pending.wait(),
85 )))
86 })
87 }
88
89 fn enqueue_sync(
90 &self,
91 ) -> mj_client::session::BoxFuture<'_, Result<mj_client::session::PendingRelaySync>> {
92 Box::pin(async move {
93 let pending = self.0.enqueue_sync().await?;
94 Ok(mj_client::session::PendingRelaySync::new(Box::pin(
95 pending.wait(),
96 )))
97 })
98 }
99
100 fn respond_elicitation(
101 &self,
102 elicitation_id: String,
103 response: ElicitationResponse,
104 ) -> mj_client::session::BoxFuture<'_, Result<()>> {
105 Box::pin(self.0.respond_elicitation(elicitation_id, response))
106 }
107
108 fn stop_background_task(
109 &self,
110 background_task_id: String,
111 ) -> mj_client::session::BoxFuture<'_, Result<()>> {
112 Box::pin(self.0.stop_background_task(background_task_id))
113 }
114
115 fn reviewer(
116 &self,
117 role: Option<String>,
118 action: ReviewerAction,
119 ) -> mj_client::session::BoxFuture<'_, Result<ReviewerOutcome>> {
120 Box::pin(self.0.reviewer_as(role, action))
121 }
122}
123
124#[derive(Clone)]
125pub(super) struct ClientSessionControl(pub(super) SessionManagerControl);
126
127impl mj_client::session::SessionControlBackend for ClientSessionControl {
128 fn session(
129 &self,
130 session_id: String,
131 ) -> mj_client::session::BoxFuture<'_, Result<mj_client::session::SessionHandle>> {
132 Box::pin(async move { Ok(self.0.session(session_id).await?.client()) })
133 }
134}
135
136impl SessionManagerControl {
137 pub fn client(&self) -> mj_client::session::SessionControl {
139 mj_client::session::SessionControl::new(ClientSessionControl(self.clone()))
140 }
141
142 pub async fn session(&self, session_id: impl Into<String>) -> Result<ManagedSessionHandle> {
143 let session_id = session_id.into();
144 let (reply, response) = oneshot::channel();
145 self.commands
146 .send(ManagerCommand::Session {
147 session_id: session_id.clone(),
148 reply,
149 })
150 .await
151 .context("session manager stopped")?;
152 response
153 .await
154 .context("session manager stopped")?
155 .with_context(|| format!("session {session_id} is not managed"))
156 }
157
158 pub async fn wait_for_session(
159 &self,
160 session_id: &str,
161 timeout: Duration,
162 ) -> Result<ManagedSessionHandle> {
163 tokio::time::timeout(timeout, async {
164 loop {
165 match self.session(session_id.to_owned()).await {
166 Ok(handle) => return Ok(handle),
167 Err(error) => {
168 tracing::trace!(session_id, "waiting for session actor: {error:#}");
169 tokio::time::sleep(Duration::from_millis(25)).await;
170 }
171 }
172 }
173 })
174 .await
175 .with_context(|| {
176 format!(
177 "session {session_id} did not become available within {} seconds",
178 timeout.as_secs()
179 )
180 })?
181 }
182}