WIP: remoting (#10085)

Release Notes:

- Added private alpha support for remote development. Please reach out to hi@zed.dev if you'd like to be part of shaping this feature.
This commit is contained in:
Conrad Irwin 2024-04-11 15:36:35 -06:00 committed by GitHub
parent ea4419076e
commit f6c85b28d5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
54 changed files with 4117 additions and 759 deletions

View file

@ -1,7 +1,7 @@
use crate::db::{ChannelId, ChannelRole, UserId};
use crate::db::{ChannelId, ChannelRole, DevServerId, PrincipalId, UserId};
use anyhow::{anyhow, Result};
use collections::{BTreeMap, HashMap, HashSet};
use rpc::ConnectionId;
use rpc::{proto, ConnectionId};
use semantic_version::SemanticVersion;
use serde::Serialize;
use std::fmt;
@ -10,12 +10,13 @@ use tracing::instrument;
#[derive(Default, Serialize)]
pub struct ConnectionPool {
connections: BTreeMap<ConnectionId, Connection>,
connected_users: BTreeMap<UserId, ConnectedUser>,
connected_users: BTreeMap<UserId, ConnectedPrincipal>,
connected_dev_servers: BTreeMap<DevServerId, ConnectionId>,
channels: ChannelPool,
}
#[derive(Default, Serialize)]
struct ConnectedUser {
struct ConnectedPrincipal {
connection_ids: HashSet<ConnectionId>,
}
@ -36,7 +37,7 @@ impl ZedVersion {
#[derive(Serialize)]
pub struct Connection {
pub user_id: UserId,
pub principal_id: PrincipalId,
pub admin: bool,
pub zed_version: ZedVersion,
}
@ -59,7 +60,7 @@ impl ConnectionPool {
self.connections.insert(
connection_id,
Connection {
user_id,
principal_id: PrincipalId::UserId(user_id),
admin,
zed_version,
},
@ -68,6 +69,25 @@ impl ConnectionPool {
connected_user.connection_ids.insert(connection_id);
}
pub fn add_dev_server(
&mut self,
connection_id: ConnectionId,
dev_server_id: DevServerId,
zed_version: ZedVersion,
) {
self.connections.insert(
connection_id,
Connection {
principal_id: PrincipalId::DevServerId(dev_server_id),
admin: false,
zed_version,
},
);
self.connected_dev_servers
.insert(dev_server_id, connection_id);
}
#[instrument(skip(self))]
pub fn remove_connection(&mut self, connection_id: ConnectionId) -> Result<()> {
let connection = self
@ -75,12 +95,18 @@ impl ConnectionPool {
.get_mut(&connection_id)
.ok_or_else(|| anyhow!("no such connection"))?;
let user_id = connection.user_id;
let connected_user = self.connected_users.get_mut(&user_id).unwrap();
connected_user.connection_ids.remove(&connection_id);
if connected_user.connection_ids.is_empty() {
self.connected_users.remove(&user_id);
self.channels.remove_user(&user_id);
match connection.principal_id {
PrincipalId::UserId(user_id) => {
let connected_user = self.connected_users.get_mut(&user_id).unwrap();
connected_user.connection_ids.remove(&connection_id);
if connected_user.connection_ids.is_empty() {
self.connected_users.remove(&user_id);
self.channels.remove_user(&user_id);
}
}
PrincipalId::DevServerId(dev_server_id) => {
self.connected_dev_servers.remove(&dev_server_id);
}
}
self.connections.remove(&connection_id).unwrap();
Ok(())
@ -110,6 +136,18 @@ impl ConnectionPool {
.copied()
}
pub fn dev_server_status(&self, dev_server_id: DevServerId) -> proto::DevServerStatus {
if self.dev_server_connection_id(dev_server_id).is_some() {
proto::DevServerStatus::Online
} else {
proto::DevServerStatus::Offline
}
}
pub fn dev_server_connection_id(&self, dev_server_id: DevServerId) -> Option<ConnectionId> {
self.connected_dev_servers.get(&dev_server_id).copied()
}
pub fn channel_user_ids(
&self,
channel_id: ChannelId,
@ -154,22 +192,39 @@ impl ConnectionPool {
#[cfg(test)]
pub fn check_invariants(&self) {
for (connection_id, connection) in &self.connections {
assert!(self
.connected_users
.get(&connection.user_id)
.unwrap()
.connection_ids
.contains(connection_id));
match &connection.principal_id {
PrincipalId::UserId(user_id) => {
assert!(self
.connected_users
.get(user_id)
.unwrap()
.connection_ids
.contains(connection_id));
}
PrincipalId::DevServerId(dev_server_id) => {
assert_eq!(
self.connected_dev_servers.get(&dev_server_id).unwrap(),
connection_id
);
}
}
}
for (user_id, state) in &self.connected_users {
for connection_id in &state.connection_ids {
assert_eq!(
self.connections.get(connection_id).unwrap().user_id,
*user_id
self.connections.get(connection_id).unwrap().principal_id,
PrincipalId::UserId(*user_id)
);
}
}
for (dev_server_id, connection_id) in &self.connected_dev_servers {
assert_eq!(
self.connections.get(connection_id).unwrap().principal_id,
PrincipalId::DevServerId(*dev_server_id)
);
}
}
}