Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T05:36:02.874Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

native.rs

92 lines · 3.2 KB · rust
1use std::time::Duration;
2
3use anyhow::{Context as _, Result, anyhow};
4use cloud_api_types::websocket_protocol::{PROTOCOL_VERSION, PROTOCOL_VERSION_HEADER_NAME};
5use futures::channel::mpsc::unbounded;
6use futures::stream::{SplitSink, SplitStream};
7use futures::{FutureExt as _, SinkExt as _, StreamExt as _, TryStreamExt as _};
8use gpui::{App, Task};
9use http_client::http::request;
10use yawc::frame::Frame;
11use yawc::{TcpWebSocket, WebSocket};
12
13use super::{MessageStream, forward_frame};
14use crate::CloudApiClient;
15
16const KEEPALIVE_INTERVAL: Duration = Duration::from_secs(1);
17
18pub struct Connection {
19    tx: SplitSink<TcpWebSocket, Frame>,
20    rx: SplitStream<TcpWebSocket>,
21}
22
23impl Connection {
24    fn new(websocket: TcpWebSocket) -> Self {
25        let (tx, rx) = websocket.split();
26        Self { tx, rx }
27    }
28
29    pub fn spawn(self, cx: &App) -> (MessageStream, Task<()>) {
30        let mut tx = self.tx;
31        let rx = self.rx.fuse();
32        let (message_tx, message_rx) = unbounded();
33        let executor = cx.background_executor().clone();
34        let task = cx.spawn(async move |_cx| {
35            let keepalive_timer = executor.timer(KEEPALIVE_INTERVAL).fuse();
36            futures::pin_mut!(keepalive_timer, rx);
37
38            loop {
39                futures::select_biased! {
40                    _ = keepalive_timer => {
41                        if tx.send(Frame::ping(Vec::new())).await.is_err() {
42                            break;
43                        }
44                        keepalive_timer.set(executor.timer(KEEPALIVE_INTERVAL).fuse());
45                    }
46                    frame = rx.next() => {
47                        let Some(frame) = frame else {
48                            break;
49                        };
50                        if !forward_frame(frame, &message_tx) {
51                            break;
52                        }
53                    }
54                }
55            }
56        });
57
58        (message_rx.into_stream().boxed(), task)
59    }
60}
61
62impl CloudApiClient {
63    pub fn connect(self: &std::sync::Arc<Self>, cx: &App) -> Result<Task<Result<Connection>>> {
64        let mut connect_url = self
65            .http_client
66            .build_zed_cloud_url("/client/users/connect")?;
67        connect_url
68            .set_scheme(match connect_url.scheme() {
69                "https" => "wss",
70                "http" => "ws",
71                scheme => Err(anyhow!("invalid URL scheme: {scheme}"))?,
72            })
73            .map_err(|_| anyhow!("failed to set URL scheme"))?;
74
75        let credentials = self.credentials.read();
76        let credentials = credentials.as_ref().context("no credentials provided")?;
77        let authorization_header = format!("{} {}", credentials.user_id, credentials.access_token);
78
79        Ok(gpui_tokio::Tokio::spawn_result(cx, async move {
80            let websocket = WebSocket::connect(connect_url)
81                .with_request(
82                    request::Builder::new()
83                        .header("Authorization", authorization_header)
84                        .header(PROTOCOL_VERSION_HEADER_NAME, PROTOCOL_VERSION.to_string()),
85                )
86                .await?;
87
88            Ok(Connection::new(websocket))
89        }))
90    }
91}
92
Served at tenant.openagents/omega Member data and write actions are omitted.