1use std::sync::Arc;
2
3use dk_engine::conflict::{ClaimTracker, LocalClaimTracker};
4use dk_engine::repo::Engine;
5use tonic::{Request, Response, Status};
6
7use crate::auth::AuthConfig;
8use crate::events::EventBus;
9use crate::session::{AgentSession, SessionManager};
10
11pub struct ProtocolServer {
17 pub(crate) engine: Arc<Engine>,
18 pub(crate) session_mgr: Arc<SessionManager>,
19 pub(crate) auth_config: AuthConfig,
20 pub(crate) event_bus: Arc<EventBus>,
21 pub(crate) claim_tracker: Arc<dyn ClaimTracker>,
22}
23
24impl ProtocolServer {
25 pub fn new(engine: Arc<Engine>, auth_config: AuthConfig) -> Self {
30 Self {
31 engine,
32 session_mgr: Arc::new(SessionManager::new(std::time::Duration::from_secs(
33 30 * 60,
34 ))),
35 auth_config,
36 event_bus: Arc::new(EventBus::new()),
37 claim_tracker: Arc::new(LocalClaimTracker::new()),
38 }
39 }
40
41 pub fn engine(&self) -> &Engine {
43 &self.engine
44 }
45
46 pub fn session_mgr(&self) -> &SessionManager {
48 &self.session_mgr
49 }
50
51 pub fn event_bus(&self) -> &EventBus {
53 &self.event_bus
54 }
55
56 pub fn event_bus_arc(&self) -> Arc<EventBus> {
62 Arc::clone(&self.event_bus)
63 }
64
65 pub fn claim_tracker(&self) -> &dyn ClaimTracker {
67 &*self.claim_tracker
68 }
69
70 pub fn with_claim_tracker(
72 engine: Arc<Engine>,
73 auth_config: AuthConfig,
74 claim_tracker: Arc<dyn ClaimTracker>,
75 ) -> Self {
76 Self {
77 engine,
78 session_mgr: Arc::new(SessionManager::new(std::time::Duration::from_secs(
79 30 * 60,
80 ))),
81 auth_config,
82 event_bus: Arc::new(EventBus::new()),
83 claim_tracker,
84 }
85 }
86
87 pub(crate) fn validate_auth(&self, token: &str) -> Result<String, Status> {
89 self.auth_config.validate(token)
90 }
91
92 pub(crate) fn has_admin_scope(&self, metadata: &tonic::metadata::MetadataMap) -> bool {
103 let Some(val) = metadata.get("authorization") else {
104 return false;
105 };
106 let Ok(header) = val.to_str() else {
107 return false;
108 };
109 let token = header.strip_prefix("Bearer ").unwrap_or(header);
110 self.auth_config
113 .validate_claims(token)
114 .as_ref()
115 .map(crate::auth::claims_have_admin_scope)
116 .unwrap_or(false)
117 }
118
119 pub(crate) fn validate_session(&self, session_id_str: &str) -> Result<AgentSession, Status> {
122 let sid = session_id_str
123 .parse::<uuid::Uuid>()
124 .map_err(|_| Status::invalid_argument("Invalid session ID format"))?;
125 self.session_mgr
126 .get_session(&sid)
127 .ok_or_else(|| Status::not_found("Session not found or expired"))
128 }
129}
130
131#[tonic::async_trait]
134impl crate::agent_service_server::AgentService for ProtocolServer {
135 async fn connect(
136 &self,
137 request: Request<crate::ConnectRequest>,
138 ) -> Result<Response<crate::ConnectResponse>, Status> {
139 crate::connect::handle_connect(self, request.into_inner()).await
140 }
141
142 async fn context(
143 &self,
144 request: Request<crate::ContextRequest>,
145 ) -> Result<Response<crate::ContextResponse>, Status> {
146 crate::context::handle_context(self, request.into_inner()).await
147 }
148
149 async fn submit(
150 &self,
151 request: Request<crate::SubmitRequest>,
152 ) -> Result<Response<crate::SubmitResponse>, Status> {
153 crate::submit::handle_submit(self, request.into_inner()).await
154 }
155
156 type VerifyStream = tokio_stream::wrappers::ReceiverStream<Result<crate::VerifyStepResult, Status>>;
157
158 async fn verify(
159 &self,
160 request: Request<crate::VerifyRequest>,
161 ) -> Result<Response<Self::VerifyStream>, Status> {
162 let req = request.into_inner();
163 let (tx, rx) = tokio::sync::mpsc::channel(32);
164
165 let server_clone = ProtocolServer {
166 engine: self.engine.clone(),
167 session_mgr: self.session_mgr.clone(),
168 auth_config: self.auth_config.clone(),
169 event_bus: self.event_bus.clone(),
170 claim_tracker: self.claim_tracker.clone(),
171 };
172
173 tokio::spawn(async move {
174 crate::verify::handle_verify(&server_clone, req, tx).await;
175 });
176
177 Ok(Response::new(tokio_stream::wrappers::ReceiverStream::new(rx)))
178 }
179
180 async fn merge(
181 &self,
182 request: Request<crate::MergeRequest>,
183 ) -> Result<Response<crate::MergeResponse>, Status> {
184 let resp = crate::merge::handle_merge(self, request.into_inner()).await?;
185 Ok(Response::new(resp))
186 }
187
188 type WatchStream = tokio_stream::wrappers::ReceiverStream<Result<crate::WatchEvent, Status>>;
189
190 async fn watch(
191 &self,
192 request: Request<crate::WatchRequest>,
193 ) -> Result<Response<Self::WatchStream>, Status> {
194 let req = request.into_inner();
195 let (tx, rx) = tokio::sync::mpsc::channel(64);
196 let server_clone = ProtocolServer {
197 engine: self.engine.clone(),
198 session_mgr: self.session_mgr.clone(),
199 auth_config: self.auth_config.clone(),
200 event_bus: self.event_bus.clone(),
201 claim_tracker: self.claim_tracker.clone(),
202 };
203 tokio::spawn(async move {
204 crate::watch::handle_watch(&server_clone, req, tx).await;
205 });
206 Ok(Response::new(tokio_stream::wrappers::ReceiverStream::new(rx)))
207 }
208
209 async fn file_read(
210 &self,
211 request: Request<crate::FileReadRequest>,
212 ) -> Result<Response<crate::FileReadResponse>, Status> {
213 crate::file_read::handle_file_read(self, request.into_inner()).await
214 }
215
216 async fn file_write(
217 &self,
218 request: Request<crate::FileWriteRequest>,
219 ) -> Result<Response<crate::FileWriteResponse>, Status> {
220 crate::file_write::handle_file_write(self, request.into_inner()).await
221 }
222
223 async fn file_list(
224 &self,
225 request: Request<crate::FileListRequest>,
226 ) -> Result<Response<crate::FileListResponse>, Status> {
227 crate::file_list::handle_file_list(self, request.into_inner()).await
228 }
229
230 async fn pre_submit_check(
231 &self,
232 request: Request<crate::PreSubmitCheckRequest>,
233 ) -> Result<Response<crate::PreSubmitCheckResponse>, Status> {
234 crate::pre_submit::handle_pre_submit_check(self, request.into_inner()).await
235 }
236
237 async fn get_session_status(
238 &self,
239 request: Request<crate::SessionStatusRequest>,
240 ) -> Result<Response<crate::SessionStatusResponse>, Status> {
241 crate::session_status::handle_get_session_status(self, request.into_inner()).await
242 }
243
244 async fn push(
245 &self,
246 request: Request<crate::PushRequest>,
247 ) -> Result<Response<crate::PushResponse>, Status> {
248 let resp = crate::push::handle_push(self, request.into_inner()).await?;
249 Ok(Response::new(resp))
250 }
251
252 async fn approve(
253 &self,
254 _request: Request<crate::ApproveRequest>,
255 ) -> Result<Response<crate::ApproveResponse>, Status> {
256 Err(Status::unimplemented(
257 "approve is a platform-level operation; use the managed server",
258 ))
259 }
260
261 async fn resolve(
262 &self,
263 _request: Request<crate::ResolveRequest>,
264 ) -> Result<Response<crate::ResolveResponse>, Status> {
265 Err(Status::unimplemented(
266 "resolve is a platform-level operation; use the managed server",
267 ))
268 }
269
270 async fn close(
271 &self,
272 _request: Request<crate::CloseRequest>,
273 ) -> Result<Response<crate::CloseResponse>, Status> {
274 Err(Status::unimplemented(
275 "close is a platform-level operation; use the managed server",
276 ))
277 }
278
279 async fn abandon(
280 &self,
281 request: Request<crate::AbandonRequest>,
282 ) -> Result<Response<crate::AbandonResponse>, Status> {
283 crate::abandon::handle_abandon(self, request).await
284 }
285
286 async fn review(
287 &self,
288 _request: Request<crate::ReviewRequest>,
289 ) -> Result<Response<crate::ReviewResponse>, Status> {
290 Err(Status::unimplemented(
291 "review is a platform-level operation; use the managed server",
292 ))
293 }
294
295 async fn record_review(
296 &self,
297 _request: Request<crate::RecordReviewRequest>,
298 ) -> Result<Response<crate::RecordReviewResponse>, Status> {
299 Err(Status::unimplemented(
300 "record_review is a platform-level operation; use the managed server",
301 ))
302 }
303}