1use super::{
3 actions, codec,
4 proto::gnmi as pb,
5 semantic::{self, Answer, Mode},
6 value,
7};
8use crate::{
9 protocol::{Event, SpawnContext},
10 server::{
11 accept_bounded::{self, ConnectionActivity},
12 connection::ConnectionId,
13 grpc::streaming::{ConnectionTasks, OwnedExecutor},
14 },
15 state::ServerId,
16};
17use bytes::Bytes;
18use futures::Stream;
19use http_body_util::{BodyExt, Full};
20use hyper::{body::Incoming, Request};
21use serde_json::{json, Value};
22use std::{
23 collections::VecDeque,
24 convert::Infallible,
25 pin::Pin,
26 sync::{
27 atomic::{AtomicU32, Ordering},
28 Arc,
29 },
30 time::Duration,
31};
32use tokio::sync::Semaphore;
33use tonic::{codec::CompressionEncoding, Status};
34use tower::Service;
35pub const FIRST_BYTE_READ_TIMEOUT: Duration = Duration::from_secs(30);
36pub const IDLE_BETWEEN_REQUESTS_TIMEOUT: Duration = Duration::from_secs(120);
37pub const MAX_CONNECTIONS: usize = 256;
38pub const MAX_ACTIVE_RPCS: usize = 64;
39const MAX_MESSAGES: usize = 256;
40const MAX_HANDLERS: usize = 258;
41const REFUSAL:&[u8]=b"HTTP/1.1 503 Service Unavailable\r\nContent-Length: 0\r\nRetry-After: 5\r\nConnection: close\r\n\r\n";
42#[derive(Clone)]
43struct Context {
44 llm: crate::llm::OllamaClient,
45 state: Arc<crate::state::AppState>,
46 server: ServerId,
47 connection: ConnectionId,
48 protocol: Arc<actions::GnmiProtocol>,
49 id: u32,
50 deadline: tokio::time::Instant,
51}
52impl Context {
53 async fn decide(
54 &self,
55 event_type: &'static crate::protocol::EventType,
56 request: Value,
57 ) -> Result<Vec<Answer>, Status> {
58 let event = Event::new(event_type, json!({"rpc_id":self.id,"request":request}));
59 let result = crate::llm::action_helper::call_llm(
60 &self.llm,
61 &self.state,
62 self.server,
63 Some(self.connection),
64 &event,
65 self.protocol.as_ref(),
66 )
67 .await
68 .map_err(|error| {
69 if crate::llm::is_overload_error(&error) {
70 Status::unavailable("netget: backend at capacity")
71 } else {
72 Status::internal("netget: handler unavailable")
73 }
74 })?;
75 if result.has_failures() {
76 return Err(Status::internal("netget: invalid handler response"));
77 }
78 let answers = result
79 .protocol_results
80 .iter()
81 .filter_map(|result| {
82 if let crate::llm::ActionResult::Custom { name, data } = result {
83 if name == "gnmi_answer" {
84 return Some(data);
85 }
86 }
87 None
88 })
89 .collect::<Vec<_>>();
90 if answers.is_empty() || answers.len() > 16 {
91 return Err(Status::internal("netget: no bounded gNMI answer"));
92 }
93 answers.into_iter().map(semantic::answer).collect()
94 }
95 async fn unary(
96 &self,
97 event: &'static crate::protocol::EventType,
98 request: Value,
99 ) -> Result<Answer, Status> {
100 let mut answers = self.decide(event, request).await?;
101 if answers.len() != 1 {
102 return Err(Status::internal("netget: unary RPC requires one answer"));
103 }
104 let answer = answers.remove(0);
105 if let Answer::Error(error) = answer {
106 Err(error)
107 } else {
108 Ok(answer)
109 }
110 }
111}
112#[derive(Clone)]
113struct Receiver(Context);
114#[tonic::async_trait]
115impl pb::g_nmi_server::GNmi for Receiver {
116 async fn capabilities(
117 &self,
118 request: tonic::Request<pb::CapabilityRequest>,
119 ) -> Result<tonic::Response<pb::CapabilityResponse>, Status> {
120 if !request.get_ref().extension.is_empty() {
121 return Err(Status::unimplemented("extensions excluded"));
122 }
123 match self.0.unary(&actions::CAPABILITIES, json!({})).await? {
124 Answer::Capabilities(v) => Ok(tonic::Response::new(v)),
125 _ => Err(Status::internal("netget: wrong Capabilities answer")),
126 }
127 }
128 async fn get(
129 &self,
130 request: tonic::Request<pb::GetRequest>,
131 ) -> Result<tonic::Response<pb::GetResponse>, Status> {
132 let request = request.into_inner();
133 let event = semantic::get_request(&request)?;
134 match self.0.unary(&actions::GET, event).await? {
135 Answer::Get(notification) => {
136 for n in ¬ification {
137 value::notification_encoding(n, request.encoding)?;
138 }
139 Ok(tonic::Response::new(value::checked(pb::GetResponse {
140 notification,
141 error: None,
142 extension: vec![],
143 })?))
144 }
145 _ => Err(Status::internal("netget: wrong Get answer")),
146 }
147 }
148 async fn set(
149 &self,
150 request: tonic::Request<pb::SetRequest>,
151 ) -> Result<tonic::Response<pb::SetResponse>, Status> {
152 let request = request.into_inner();
153 let event = semantic::set_request(&request)?;
154 match self.0.unary(&actions::SET, event).await? {
155 Answer::Set(timestamp) => Ok(tonic::Response::new(semantic::set_response(
156 &request, ×tamp,
157 )?)),
158 _ => Err(Status::internal("netget: wrong Set answer")),
159 }
160 }
161 type SubscribeStream =
162 Pin<Box<dyn Stream<Item = Result<pb::SubscribeResponse, Status>> + Send>>;
163 async fn subscribe(
164 &self,
165 request: tonic::Request<tonic::Streaming<pb::SubscribeRequest>>,
166 ) -> Result<tonic::Response<Self::SubscribeStream>, Status> {
167 let mut input = request.into_inner();
168 let first = input
169 .message()
170 .await?
171 .ok_or_else(|| Status::invalid_argument("missing SubscriptionList"))?;
172 if !first.extension.is_empty() {
173 return Err(Status::unimplemented("extensions excluded"));
174 }
175 let Some(pb::subscribe_request::Request::Subscribe(list)) = first.request else {
176 return Err(Status::invalid_argument(
177 "first request must contain SubscriptionList",
178 ));
179 };
180 let subscription = semantic::subscription(&list)?;
181 let state = Subscription {
182 ctx: self.0.clone(),
183 subscription,
184 input,
185 pending: VecDeque::new(),
186 input_closed: false,
187 cycle: true,
188 initial: true,
189 synced: false,
190 finished: false,
191 wait: None,
192 messages: 0,
193 inputs: 1,
194 handlers: 0,
195 };
196 let stream = futures::stream::try_unfold(state, |mut state| async move {
197 let next = tokio::time::timeout_at(state.ctx.deadline, state.next())
198 .await
199 .map_err(|_| Status::deadline_exceeded("netget: subscription deadline"))??;
200 Ok(next.map(|next| (next, state)))
201 });
202 Ok(tonic::Response::new(Box::pin(stream)))
203 }
204}
205struct Subscription {
206 ctx: Context,
207 subscription: semantic::Subscription,
208 input: tonic::Streaming<pb::SubscribeRequest>,
209 pending: VecDeque<pb::SubscribeResponse>,
210 input_closed: bool,
211 cycle: bool,
212 initial: bool,
213 synced: bool,
214 finished: bool,
215 wait: Option<Duration>,
216 messages: usize,
217 inputs: usize,
218 handlers: usize,
219}
220impl Subscription {
221 fn input(
222 &mut self,
223 request: Option<pb::SubscribeRequest>,
224 allow_poll: bool,
225 ) -> Result<(), Status> {
226 let Some(request) = request else {
227 self.input_closed = true;
228 return Ok(());
229 };
230 self.inputs += 1;
231 if self.inputs > MAX_MESSAGES {
232 return Err(Status::resource_exhausted(
233 "subscription input count exceeds 256",
234 ));
235 }
236 if !request.extension.is_empty() {
237 return Err(Status::unimplemented("extensions excluded"));
238 }
239 if !allow_poll
240 || self.subscription.mode != Mode::Poll
241 || !matches!(
242 request.request,
243 Some(pb::subscribe_request::Request::Poll(_))
244 )
245 {
246 return Err(Status::invalid_argument(
247 "only POLL mode accepts Poll after its completed snapshot",
248 ));
249 }
250 self.cycle = true;
251 self.synced = false;
252 Ok(())
253 }
254 fn push(&mut self, response: pb::SubscribeResponse) -> Result<(), Status> {
255 self.messages += 1;
256 if self.messages > MAX_MESSAGES {
257 return Err(Status::resource_exhausted(
258 "subscription output count exceeds 256",
259 ));
260 }
261 if self.pending.len() >= 16 {
262 return Err(Status::resource_exhausted(
263 "subscription pending count exceeds 16",
264 ));
265 }
266 use prost::Message;
267 let bytes = self.pending.iter().map(Message::encoded_len).sum::<usize>();
268 if bytes.saturating_add(response.encoded_len()) > codec::MAX_MESSAGE_BYTES {
269 return Err(Status::resource_exhausted(
270 "pending subscription output exceeds 1 MiB",
271 ));
272 }
273 self.pending.push_back(value::checked(response)?);
274 Ok(())
275 }
276 fn sync(&mut self) -> Result<(), Status> {
277 if !self.cycle || self.synced {
278 return Err(Status::failed_precondition(
279 "sync belongs once to each initial/POLL snapshot",
280 ));
281 }
282 self.push(pb::SubscribeResponse {
283 response: Some(pb::subscribe_response::Response::SyncResponse(true)),
284 extension: vec![],
285 })?;
286 self.synced = true;
287 self.cycle = false;
288 match self.subscription.mode {
289 Mode::Once => self.finished = true,
290 Mode::Stream => self.wait = Some(Duration::from_millis(1000)),
291 Mode::Poll => {}
292 }
293 Ok(())
294 }
295 async fn decision(&mut self) -> Result<Vec<Answer>, Status> {
296 self.handlers += 1;
297 if self.handlers > MAX_HANDLERS {
298 return Err(Status::resource_exhausted(
299 "subscription handler count exceeds 258",
300 ));
301 }
302 let kind = if self.initial {
303 &*actions::SUBSCRIBE
304 } else if self.cycle {
305 &*actions::POLL
306 } else {
307 &*actions::TICK
308 };
309 let context = self.ctx.clone();
310 let future = context.decide(kind, self.subscription.event.clone());
311 tokio::pin!(future);
312 loop {
313 tokio::select! {
314 answer=&mut future=>return answer,
315 request=self.input.message(),if !self.input_closed=>{self.input(request?,false)?;}
316 }
317 }
318 }
319 fn apply(&mut self, answers: Vec<Answer>) -> Result<(), Status> {
320 let started_cycle = self.cycle;
321 let mut terminal = false;
322 for answer in answers {
323 if terminal {
324 return Err(Status::internal(
325 "netget: action after terminal subscription control",
326 ));
327 }
328 match answer {
329 Answer::Update(notifications) => {
330 if self.synced && started_cycle {
331 return Err(Status::failed_precondition("snapshot update after sync"));
332 }
333 if self.subscription.updates_only && started_cycle {
334 return Err(Status::failed_precondition(
335 "updates_only snapshot cannot contain updates",
336 ));
337 }
338 for notification in notifications {
339 value::notification_encoding(¬ification, self.subscription.encoding)?;
340 self.push(pb::SubscribeResponse {
341 response: Some(pb::subscribe_response::Response::Update(notification)),
342 extension: vec![],
343 })?;
344 }
345 }
346 Answer::Sync => {
347 self.sync()?;
348 if self.subscription.mode != Mode::Stream {
349 terminal = true;
350 }
351 }
352 Answer::Wait(ms) => {
353 if self.subscription.mode != Mode::Stream || !self.synced {
354 return Err(Status::failed_precondition(
355 "wait requires STREAM initial sync",
356 ));
357 }
358 self.wait = Some(Duration::from_millis(ms));
359 terminal = true;
360 }
361 Answer::Finish => {
362 if self.subscription.mode != Mode::Stream || !self.synced {
363 return Err(Status::failed_precondition(
364 "finish requires STREAM initial sync",
365 ));
366 }
367 self.finished = true;
368 terminal = true;
369 }
370 Answer::Error(error) => return Err(error),
371 _ => return Err(Status::internal("netget: wrong subscription answer")),
372 }
373 }
374 if started_cycle && !self.synced {
375 return Err(Status::internal(
376 "netget: snapshot answer requires gnmi_sync",
377 ));
378 }
379 if !started_cycle && !terminal {
380 return Err(Status::internal(
381 "netget: stream answer requires wait or finish",
382 ));
383 }
384 self.initial = false;
385 Ok(())
386 }
387 async fn next(&mut self) -> Result<Option<pb::SubscribeResponse>, Status> {
388 loop {
389 if let Some(next) = self.pending.pop_front() {
390 return Ok(Some(next));
391 }
392 if self.finished {
393 return Ok(None);
394 }
395 if self.cycle {
396 if self.subscription.updates_only {
397 self.sync()?;
398 self.initial = false;
399 continue;
400 }
401 let answer = self.decision().await?;
402 self.apply(answer)?;
403 continue;
404 }
405 if self.subscription.mode == Mode::Poll {
406 if self.input_closed {
407 return Ok(None);
408 }
409 let request = self.input.message().await?;
410 self.input(request, true)?;
411 continue;
412 }
413 let wait = self
414 .wait
415 .take()
416 .ok_or_else(|| Status::internal("netget: missing stream wait"))?;
417 let sleep = tokio::time::sleep(wait);
418 tokio::pin!(sleep);
419 loop {
420 tokio::select! {
421 _=&mut sleep=>break,
422 request=self.input.message(),if !self.input_closed=>{self.input(request?,false)?;}
423 }
424 }
425 let answer = self.decision().await?;
426 self.apply(answer)?;
427 }
428 }
429}
430struct GuardedBody<G> {
431 body: tonic::body::BoxBody,
432 guard: Option<G>,
433}
434impl<G: Send + Unpin + 'static> hyper::body::Body for GuardedBody<G> {
435 type Data = Bytes;
436 type Error = Status;
437 fn poll_frame(
438 mut self: Pin<&mut Self>,
439 cx: &mut std::task::Context<'_>,
440 ) -> std::task::Poll<Option<Result<hyper::body::Frame<Bytes>, Status>>> {
441 let result = Pin::new(&mut self.body).poll_frame(cx);
442 if matches!(result, std::task::Poll::Ready(None | Some(Err(_)))) {
443 self.guard = None;
444 }
445 result
446 }
447 fn is_end_stream(&self) -> bool {
450 self.body.is_end_stream()
451 }
452 fn size_hint(&self) -> hyper::body::SizeHint {
453 self.body.size_hint()
454 }
455}
456fn hold_body<G: Send + Unpin + 'static>(
457 body: tonic::body::BoxBody,
458 guard: G,
459) -> tonic::body::BoxBody {
460 GuardedBody {
461 body,
462 guard: Some(guard),
463 }
464 .boxed_unsync()
465}
466async fn unary(request: Request<Incoming>) -> Result<Request<tonic::body::BoxBody>, Status> {
467 let (parts, mut body) = request.into_parts();
468 let mut bytes = Vec::new();
469 let mut length = None;
470 while let Some(frame) = body.frame().await {
471 let frame = frame.map_err(|_| Status::invalid_argument("unreadable gNMI body"))?;
472 if let Ok(data) = frame.into_data() {
473 if bytes.len().saturating_add(data.len()) > codec::MAX_MESSAGE_BYTES + 5 {
474 return Err(Status::resource_exhausted(
475 "gNMI unary body exceeds message bound",
476 ));
477 }
478 bytes.extend_from_slice(&data);
479 if length.is_none() && bytes.len() >= 5 {
480 let size = u32::from_be_bytes(
481 bytes[1..5]
482 .try_into()
483 .map_err(|_| Status::invalid_argument("frame prefix"))?,
484 ) as usize;
485 if size > codec::MAX_MESSAGE_BYTES {
486 return Err(Status::resource_exhausted("gNMI message exceeds 1 MiB"));
487 }
488 length = Some(size + 5);
489 }
490 if length.is_some_and(|n| bytes.len() > n) {
491 return Err(Status::invalid_argument(
492 "unary gNMI requires exactly one message",
493 ));
494 }
495 }
496 }
497 if length != Some(bytes.len()) {
498 return Err(Status::invalid_argument("incomplete gNMI message"));
499 }
500 Ok(Request::from_parts(
501 parts,
502 Full::new(Bytes::from(bytes))
503 .map_err(|never| match never {})
504 .boxed_unsync(),
505 ))
506}
507fn headers(request: &Request<Incoming>) -> Result<(), Status> {
508 let headers = request.headers();
509 if headers.len() > 64
510 || headers
511 .iter()
512 .map(|(n, v)| n.as_str().len() + v.as_bytes().len() + 4)
513 .sum::<usize>()
514 > 32768
515 {
516 return Err(Status::resource_exhausted("HTTP header bound"));
517 }
518 if request.method() != hyper::Method::POST
519 || request.version() != hyper::Version::HTTP_2
520 || request.uri().query().is_some()
521 {
522 return Err(Status::invalid_argument(
523 "gNMI requires POST over HTTP/2 without a query",
524 ));
525 }
526 let mut content = headers.get_all("content-type").iter();
527 let value = content
528 .next()
529 .and_then(|v| v.to_str().ok())
530 .unwrap_or("")
531 .split(';')
532 .next()
533 .unwrap_or("")
534 .trim();
535 if content.next().is_some() || !matches!(value, "application/grpc" | "application/grpc+proto") {
536 return Err(Status::invalid_argument(
537 "gNMI requires unique application/grpc content type",
538 ));
539 }
540 for name in ["grpc-encoding", "grpc-accept-encoding"] {
541 if headers.get_all(name).iter().count() > 1 {
542 return Err(Status::invalid_argument("duplicate gRPC encoding header"));
543 }
544 }
545 Ok(())
546}
547async fn serve<T: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static>(
548 io: T,
549 ctx: Context,
550 rpcs: Arc<Semaphore>,
551 timeout: Duration,
552 next: Arc<AtomicU32>,
553) {
554 let executor = OwnedExecutor::default();
555 let _children = ConnectionTasks(executor.clone());
556 let activity = Arc::new(ConnectionActivity::new());
557 let service_activity = activity.clone();
558 let service_executor = executor.clone();
559 let service = hyper::service::service_fn(move |request: Request<Incoming>| {
560 let ctx = ctx.clone();
561 let rpcs = rpcs.clone();
562 let activity = service_activity.clone();
563 let executor = service_executor.clone();
564 let next = next.clone();
565 async move {
566 let prepare = (|| -> Result<_, Status> {
567 headers(&request)?;
568 if !matches!(
569 request.uri().path(),
570 "/gnmi.gNMI/Capabilities"
571 | "/gnmi.gNMI/Get"
572 | "/gnmi.gNMI/Set"
573 | "/gnmi.gNMI/Subscribe"
574 ) {
575 return Err(Status::unimplemented("unknown gNMI method"));
576 }
577 let timeout = crate::server::grpc::streaming::timeout(request.headers(), timeout)?;
578 let deadline = tokio::time::Instant::now() + timeout;
579 let permit = rpcs
580 .try_acquire_owned()
581 .map_err(|_| Status::unavailable("netget: receiver at RPC capacity"))?;
582 let timer = executor.deadline(deadline)?;
583 let busy = activity.busy();
584 let id = next
585 .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |id| id.checked_add(1))
586 .map_err(|_| Status::resource_exhausted("gNMI RPC identifiers exhausted"))?;
587 Ok((deadline, (permit, timer, busy), id))
588 })();
589 let (deadline, guard, id) = match prepare {
590 Ok(v) => v,
591 Err(status) => return Ok::<_, Infallible>(status.into_http()),
592 };
593 let mut ctx = ctx;
594 ctx.deadline = deadline;
595 ctx.id = id;
596 let call = async move {
597 let stream = request.uri().path() == "/gnmi.gNMI/Subscribe";
598 let request = if stream {
599 request.map(|body| {
600 body.map_err(|_| Status::invalid_argument("unreadable gNMI body"))
601 .boxed_unsync()
602 })
603 } else {
604 unary(request).await?
605 };
606 let mut receiver = pb::g_nmi_server::GNmiServer::new(Receiver(ctx))
607 .accept_compressed(CompressionEncoding::Gzip)
608 .send_compressed(CompressionEncoding::Gzip)
609 .max_decoding_message_size(codec::MAX_MESSAGE_BYTES)
610 .max_encoding_message_size(codec::MAX_MESSAGE_BYTES);
611 match receiver.call(request).await {
612 Ok(response) => Ok::<_, Status>(response),
613 Err(never) => match never {},
614 }
615 };
616 let response = match tokio::time::timeout_at(deadline, call).await {
617 Ok(Ok(v)) => v,
618 Ok(Err(error)) => error.into_http(),
619 Err(_) => Status::deadline_exceeded("netget: gNMI RPC deadline").into_http(),
620 };
621 Ok(response.map(|body| hold_body(body, guard)))
622 }
623 });
624 let connection = hyper::server::conn::http2::Builder::new(executor)
625 .max_concurrent_streams(16)
626 .initial_stream_window_size(65536)
627 .initial_connection_window_size(1048576)
628 .max_header_list_size(32768)
629 .max_frame_size(16384)
630 .serve_connection(hyper_util::rt::TokioIo::new(io), service);
631 tokio::pin!(connection);
632 tokio::select! {_=&mut connection=>{},_=accept_bounded::watch_idle(activity,IDLE_BETWEEN_REQUESTS_TIMEOUT)=>{}}
633}
634pub async fn spawn(ctx: SpawnContext) -> anyhow::Result<std::net::SocketAddr> {
635 let params = ctx.startup_params.as_ref();
636 let tls = params
637 .map(|p| p.get_optional_bool("use_tls"))
638 .transpose()?
639 .flatten()
640 .unwrap_or(super::DEFAULT_TLS);
641 let cert = params
642 .map(|p| p.get_optional_string("cert_file"))
643 .transpose()?
644 .flatten();
645 let key = params
646 .map(|p| p.get_optional_string("key_file"))
647 .transpose()?
648 .flatten();
649 let timeout = params
650 .map(|p| p.get_optional_u64("rpc_timeout_secs"))
651 .transpose()?
652 .flatten()
653 .unwrap_or(super::DEFAULT_RPC_TIMEOUT_SECS);
654 anyhow::ensure!(
655 (1..=3600).contains(&timeout),
656 "rpc_timeout_secs must be 1..3600"
657 );
658 anyhow::ensure!(
659 tls || (cert.is_none() && key.is_none()),
660 "cert_file/key_file require use_tls"
661 );
662 let acceptor = if tls {
663 Some(tokio_rustls::TlsAcceptor::from(
664 super::tls::server(
665 cert.ok_or_else(|| anyhow::anyhow!("cert_file required"))?,
666 key.ok_or_else(|| anyhow::anyhow!("key_file required"))?,
667 )
668 .await?,
669 ))
670 } else {
671 None
672 };
673 let listen = ctx
674 .socket_addr()
675 .ok_or_else(|| anyhow::anyhow!("gNMI requires a literal IP host and port"))?;
676 let listener = crate::server::socket_helpers::create_reusable_tcp_listener(listen).await?;
677 let address = listener.local_addr()?;
678 let owner = ctx.state.clone();
679 let server = ctx.server_id;
680 let limiter = accept_bounded::ConnectionLimiter::new(MAX_CONNECTIONS);
681 let rpcs = Arc::new(Semaphore::new(MAX_ACTIVE_RPCS));
682 let next = Arc::new(AtomicU32::new(1));
683 let task = tokio::spawn(async move {
684 loop {
685 let Ok((socket, remote, permit)) = accept_bounded::accept_bounded(
686 &listener,
687 &limiter,
688 if tls { b"" } else { REFUSAL },
689 "gNMI",
690 Some(&ctx.status_tx),
691 )
692 .await
693 else {
694 break;
695 };
696 let id = ConnectionId::new(ctx.state.get_next_unified_id().await);
697 let now = crate::utils::clock::Instant::now();
698 ctx.state
699 .add_connection_to_server(
700 server,
701 crate::state::server::ConnectionState {
702 id,
703 remote_addr: remote,
704 local_addr: address,
705 bytes_sent: 0,
706 bytes_received: 0,
707 packets_sent: 0,
708 packets_received: 0,
709 last_activity: now,
710 status: crate::state::server::ConnectionStatus::Active,
711 status_changed_at: now,
712 protocol_info: crate::state::server::ProtocolConnectionInfo::empty(),
713 },
714 )
715 .await;
716 let context = Context {
717 llm: ctx.llm_client.clone(),
718 state: ctx.state.clone(),
719 server,
720 connection: id,
721 protocol: Arc::new(actions::GnmiProtocol),
722 id: 0,
723 deadline: tokio::time::Instant::now(),
724 };
725 let cleanup = ctx.state.clone();
726 let acceptor = acceptor.clone();
727 let rpcs = rpcs.clone();
728 let next = next.clone();
729 ctx.state.spawn_server_task(server,async move{
730 let _permit=permit;
731 if matches!(tokio::time::timeout(FIRST_BYTE_READ_TIMEOUT,socket.peek(&mut[0u8;1])).await,Ok(Ok(n)) if n>0){
732 if let Some(acceptor)=acceptor{
733 if let Ok(Ok(socket))=tokio::time::timeout(Duration::from_secs(10),acceptor.accept(socket)).await{
734 if socket.get_ref().1.alpn_protocol()==Some(b"h2"){serve(socket,context,rpcs,Duration::from_secs(timeout),next).await;}
735 }
736 }else{serve(socket,context,rpcs,Duration::from_secs(timeout),next).await;}
737 }
738 cleanup.remove_connection_from_server(server,id).await;
739 }).await;
740 }
741 });
742 owner.register_server_task(server, task).await;
743 Ok(address)
744}