Set up basic RPC for managing channels

Co-authored-by: Mikayla <mikayla@zed.dev>
This commit is contained in:
Max Brunsfeld 2023-07-28 17:05:56 -07:00
parent 758e1f6e57
commit 4b94bfa045
12 changed files with 541 additions and 150 deletions

View file

@ -0,0 +1,189 @@
use crate::{Client, Subscription, User, UserStore};
use anyhow::Result;
use futures::Future;
use gpui::{AsyncAppContext, Entity, ModelContext, ModelHandle, Task};
use rpc::{proto, TypedEnvelope};
use std::sync::Arc;
pub struct ChannelStore {
channels: Vec<Channel>,
channel_invitations: Vec<Channel>,
client: Arc<Client>,
user_store: ModelHandle<UserStore>,
rpc_subscription: Subscription,
}
#[derive(Debug, PartialEq)]
pub struct Channel {
pub id: u64,
pub name: String,
pub parent_id: Option<u64>,
}
impl Entity for ChannelStore {
type Event = ();
}
impl ChannelStore {
pub fn new(
client: Arc<Client>,
user_store: ModelHandle<UserStore>,
cx: &mut ModelContext<Self>,
) -> Self {
let rpc_subscription =
client.add_message_handler(cx.handle(), Self::handle_update_channels);
Self {
channels: vec![],
channel_invitations: vec![],
client,
user_store,
rpc_subscription,
}
}
pub fn channels(&self) -> &[Channel] {
&self.channels
}
pub fn channel_invitations(&self) -> &[Channel] {
&self.channel_invitations
}
pub fn create_channel(
&self,
name: &str,
parent_id: Option<u64>,
) -> impl Future<Output = Result<u64>> {
let client = self.client.clone();
let name = name.to_owned();
async move {
Ok(client
.request(proto::CreateChannel { name, parent_id })
.await?
.channel_id)
}
}
pub fn invite_member(
&self,
channel_id: u64,
user_id: u64,
admin: bool,
) -> impl Future<Output = Result<()>> {
let client = self.client.clone();
async move {
client
.request(proto::InviteChannelMember {
channel_id,
user_id,
admin,
})
.await?;
Ok(())
}
}
pub fn respond_to_channel_invite(
&mut self,
channel_id: u64,
accept: bool,
) -> impl Future<Output = Result<()>> {
let client = self.client.clone();
async move {
client
.request(proto::RespondToChannelInvite { channel_id, accept })
.await?;
Ok(())
}
}
pub fn remove_member(
&self,
channel_id: u64,
user_id: u64,
cx: &mut ModelContext<Self>,
) -> Task<Result<()>> {
todo!()
}
pub fn channel_members(
&self,
channel_id: u64,
cx: &mut ModelContext<Self>,
) -> Task<Result<Vec<Arc<User>>>> {
todo!()
}
pub fn add_guest_channel(&self, channel_id: u64) -> Task<Result<()>> {
todo!()
}
async fn handle_update_channels(
this: ModelHandle<Self>,
message: TypedEnvelope<proto::UpdateChannels>,
_: Arc<Client>,
mut cx: AsyncAppContext,
) -> Result<()> {
let payload = message.payload;
this.update(&mut cx, |this, cx| {
this.channels
.retain(|channel| !payload.remove_channels.contains(&channel.id));
this.channel_invitations
.retain(|channel| !payload.remove_channel_invitations.contains(&channel.id));
for channel in payload.channel_invitations {
if let Some(existing_channel) = this
.channel_invitations
.iter_mut()
.find(|c| c.id == channel.id)
{
existing_channel.name = channel.name;
continue;
}
this.channel_invitations.insert(
0,
Channel {
id: channel.id,
name: channel.name,
parent_id: None,
},
);
}
for channel in payload.channels {
if let Some(existing_channel) =
this.channels.iter_mut().find(|c| c.id == channel.id)
{
existing_channel.name = channel.name;
continue;
}
if let Some(parent_id) = channel.parent_id {
if let Some(ix) = this.channels.iter().position(|c| c.id == parent_id) {
this.channels.insert(
ix + 1,
Channel {
id: channel.id,
name: channel.name,
parent_id: Some(parent_id),
},
);
}
} else {
this.channels.insert(
0,
Channel {
id: channel.id,
name: channel.name,
parent_id: None,
},
);
}
}
cx.notify();
});
Ok(())
}
}

View file

@ -1,6 +1,7 @@
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
pub mod test; pub mod test;
pub mod channel_store;
pub mod telemetry; pub mod telemetry;
pub mod user; pub mod user;
@ -44,6 +45,7 @@ use util::channel::ReleaseChannel;
use util::http::HttpClient; use util::http::HttpClient;
use util::{ResultExt, TryFutureExt}; use util::{ResultExt, TryFutureExt};
pub use channel_store::*;
pub use rpc::*; pub use rpc::*;
pub use telemetry::ClickhouseEvent; pub use telemetry::ClickhouseEvent;
pub use user::*; pub use user::*;

View file

@ -203,6 +203,7 @@ CREATE TABLE "channel_members" (
"channel_id" INTEGER NOT NULL REFERENCES channels (id) ON DELETE CASCADE, "channel_id" INTEGER NOT NULL REFERENCES channels (id) ON DELETE CASCADE,
"user_id" INTEGER NOT NULL REFERENCES users (id) ON DELETE CASCADE, "user_id" INTEGER NOT NULL REFERENCES users (id) ON DELETE CASCADE,
"admin" BOOLEAN NOT NULL DEFAULT false, "admin" BOOLEAN NOT NULL DEFAULT false,
"accepted" BOOLEAN NOT NULL DEFAULT false,
"updated_at" TIMESTAMP NOT NULL DEFAULT now "updated_at" TIMESTAMP NOT NULL DEFAULT now
); );

View file

@ -22,6 +22,7 @@ CREATE TABLE "channel_members" (
"channel_id" INTEGER NOT NULL REFERENCES channels (id) ON DELETE CASCADE, "channel_id" INTEGER NOT NULL REFERENCES channels (id) ON DELETE CASCADE,
"user_id" INTEGER NOT NULL REFERENCES users (id) ON DELETE CASCADE, "user_id" INTEGER NOT NULL REFERENCES users (id) ON DELETE CASCADE,
"admin" BOOLEAN NOT NULL DEFAULT false, "admin" BOOLEAN NOT NULL DEFAULT false,
"accepted" BOOLEAN NOT NULL DEFAULT false,
"updated_at" TIMESTAMP NOT NULL DEFAULT now() "updated_at" TIMESTAMP NOT NULL DEFAULT now()
); );

View file

@ -3032,11 +3032,16 @@ impl Database {
// channels // channels
pub async fn create_root_channel(&self, name: &str) -> Result<ChannelId> { pub async fn create_root_channel(&self, name: &str, creator_id: UserId) -> Result<ChannelId> {
self.create_channel(name, None).await self.create_channel(name, None, creator_id).await
} }
pub async fn create_channel(&self, name: &str, parent: Option<ChannelId>) -> Result<ChannelId> { pub async fn create_channel(
&self,
name: &str,
parent: Option<ChannelId>,
creator_id: UserId,
) -> Result<ChannelId> {
self.transaction(move |tx| async move { self.transaction(move |tx| async move {
let tx = tx; let tx = tx;
@ -3056,19 +3061,50 @@ impl Database {
.await?; .await?;
} }
channel_member::ActiveModel {
channel_id: ActiveValue::Set(channel.id),
user_id: ActiveValue::Set(creator_id),
accepted: ActiveValue::Set(true),
admin: ActiveValue::Set(true),
..Default::default()
}
.insert(&*tx)
.await?;
Ok(channel.id) Ok(channel.id)
}) })
.await .await
} }
// Property: Members are only pub async fn invite_channel_member(
pub async fn add_channel_member(&self, channel_id: ChannelId, user_id: UserId) -> Result<()> { &self,
channel_id: ChannelId,
invitee_id: UserId,
inviter_id: UserId,
is_admin: bool,
) -> Result<()> {
self.transaction(move |tx| async move { self.transaction(move |tx| async move {
let tx = tx; let tx = tx;
// Check if inviter is a member
channel_member::Entity::find()
.filter(
channel_member::Column::ChannelId
.eq(channel_id)
.and(channel_member::Column::UserId.eq(inviter_id))
.and(channel_member::Column::Admin.eq(true)),
)
.one(&*tx)
.await?
.ok_or_else(|| {
anyhow!("Inviter does not have permissions to invite the invitee")
})?;
let channel_membership = channel_member::ActiveModel { let channel_membership = channel_member::ActiveModel {
channel_id: ActiveValue::Set(channel_id), channel_id: ActiveValue::Set(channel_id),
user_id: ActiveValue::Set(user_id), user_id: ActiveValue::Set(invitee_id),
accepted: ActiveValue::Set(false),
admin: ActiveValue::Set(is_admin),
..Default::default() ..Default::default()
}; };
@ -3079,6 +3115,50 @@ impl Database {
.await .await
} }
pub async fn respond_to_channel_invite(
&self,
channel_id: ChannelId,
user_id: UserId,
accept: bool,
) -> Result<()> {
self.transaction(move |tx| async move {
let tx = tx;
let rows_affected = if accept {
channel_member::Entity::update_many()
.set(channel_member::ActiveModel {
accepted: ActiveValue::Set(accept),
..Default::default()
})
.filter(
channel_member::Column::ChannelId
.eq(channel_id)
.and(channel_member::Column::UserId.eq(user_id))
.and(channel_member::Column::Accepted.eq(false)),
)
.exec(&*tx)
.await?
.rows_affected
} else {
channel_member::ActiveModel {
channel_id: ActiveValue::Unchanged(channel_id),
user_id: ActiveValue::Unchanged(user_id),
..Default::default()
}
.delete(&*tx)
.await?
.rows_affected
};
if rows_affected == 0 {
Err(anyhow!("no such invitation"))?;
}
Ok(())
})
.await
}
pub async fn get_channels(&self, user_id: UserId) -> Result<Vec<Channel>> { pub async fn get_channels(&self, user_id: UserId) -> Result<Vec<Channel>> {
self.transaction(|tx| async move { self.transaction(|tx| async move {
let tx = tx; let tx = tx;
@ -3087,7 +3167,7 @@ impl Database {
WITH RECURSIVE channel_tree(child_id, parent_id, depth) AS ( WITH RECURSIVE channel_tree(child_id, parent_id, depth) AS (
SELECT channel_id as child_id, CAST(NULL as INTEGER) as parent_id, 0 SELECT channel_id as child_id, CAST(NULL as INTEGER) as parent_id, 0
FROM channel_members FROM channel_members
WHERE user_id = $1 WHERE user_id = $1 AND accepted
UNION UNION
SELECT channel_parents.child_id, channel_parents.parent_id, channel_tree.depth + 1 SELECT channel_parents.child_id, channel_parents.parent_id, channel_tree.depth + 1
FROM channel_parents, channel_tree FROM channel_parents, channel_tree
@ -3114,6 +3194,22 @@ impl Database {
.await .await
} }
pub async fn get_channel(&self, channel_id: ChannelId) -> Result<Channel> {
self.transaction(|tx| async move {
let tx = tx;
let channel = channel::Entity::find_by_id(channel_id)
.one(&*tx)
.await?
.ok_or_else(|| anyhow!("no such channel"))?;
Ok(Channel {
id: channel.id,
name: channel.name,
parent_id: None,
})
})
.await
}
async fn transaction<F, Fut, T>(&self, f: F) -> Result<T> async fn transaction<F, Fut, T>(&self, f: F) -> Result<T>
where where
F: Send + Fn(TransactionHandle) -> Fut, F: Send + Fn(TransactionHandle) -> Fut,

View file

@ -10,6 +10,8 @@ pub struct Model {
pub id: ChannelMemberId, pub id: ChannelMemberId,
pub channel_id: ChannelId, pub channel_id: ChannelId,
pub user_id: UserId, pub user_id: UserId,
pub accepted: bool,
pub admin: bool,
} }
impl ActiveModelBehavior for ActiveModel {} impl ActiveModelBehavior for ActiveModel {}

View file

@ -894,18 +894,21 @@ test_both_dbs!(test_channels_postgres, test_channels_sqlite, db, {
.unwrap() .unwrap()
.user_id; .user_id;
let zed_id = db.create_root_channel("zed").await.unwrap(); let zed_id = db.create_root_channel("zed", a_id).await.unwrap();
let crdb_id = db.create_channel("crdb", Some(zed_id)).await.unwrap(); let crdb_id = db.create_channel("crdb", Some(zed_id), a_id).await.unwrap();
let livestreaming_id = db let livestreaming_id = db
.create_channel("livestreaming", Some(zed_id)) .create_channel("livestreaming", Some(zed_id), a_id)
.await
.unwrap();
let replace_id = db
.create_channel("replace", Some(zed_id), a_id)
.await
.unwrap();
let rust_id = db.create_root_channel("rust", a_id).await.unwrap();
let cargo_id = db
.create_channel("cargo", Some(rust_id), a_id)
.await .await
.unwrap(); .unwrap();
let replace_id = db.create_channel("replace", Some(zed_id)).await.unwrap();
let rust_id = db.create_root_channel("rust").await.unwrap();
let cargo_id = db.create_channel("cargo", Some(rust_id)).await.unwrap();
db.add_channel_member(zed_id, a_id).await.unwrap();
db.add_channel_member(rust_id, a_id).await.unwrap();
let channels = db.get_channels(a_id).await.unwrap(); let channels = db.get_channels(a_id).await.unwrap();

View file

@ -2,7 +2,7 @@ mod connection_pool;
use crate::{ use crate::{
auth, auth,
db::{self, Database, ProjectId, RoomId, ServerId, User, UserId}, db::{self, ChannelId, Database, ProjectId, RoomId, ServerId, User, UserId},
executor::Executor, executor::Executor,
AppState, Result, AppState, Result,
}; };
@ -239,6 +239,10 @@ impl Server {
.add_request_handler(request_contact) .add_request_handler(request_contact)
.add_request_handler(remove_contact) .add_request_handler(remove_contact)
.add_request_handler(respond_to_contact_request) .add_request_handler(respond_to_contact_request)
.add_request_handler(create_channel)
.add_request_handler(invite_channel_member)
.add_request_handler(remove_channel_member)
.add_request_handler(respond_to_channel_invite)
.add_request_handler(follow) .add_request_handler(follow)
.add_message_handler(unfollow) .add_message_handler(unfollow)
.add_message_handler(update_followers) .add_message_handler(update_followers)
@ -2084,6 +2088,100 @@ async fn remove_contact(
Ok(()) Ok(())
} }
async fn create_channel(
request: proto::CreateChannel,
response: Response<proto::CreateChannel>,
session: Session,
) -> Result<()> {
let db = session.db().await;
let id = db
.create_channel(
&request.name,
request.parent_id.map(|id| ChannelId::from_proto(id)),
session.user_id,
)
.await?;
let mut update = proto::UpdateChannels::default();
update.channels.push(proto::Channel {
id: id.to_proto(),
name: request.name,
parent_id: request.parent_id,
});
session.peer.send(session.connection_id, update)?;
response.send(proto::CreateChannelResponse {
channel_id: id.to_proto(),
})?;
Ok(())
}
async fn invite_channel_member(
request: proto::InviteChannelMember,
response: Response<proto::InviteChannelMember>,
session: Session,
) -> Result<()> {
let db = session.db().await;
let channel_id = ChannelId::from_proto(request.channel_id);
let channel = db.get_channel(channel_id).await?;
let invitee_id = UserId::from_proto(request.user_id);
db.invite_channel_member(channel_id, invitee_id, session.user_id, false)
.await?;
let mut update = proto::UpdateChannels::default();
update.channel_invitations.push(proto::Channel {
id: channel.id.to_proto(),
name: channel.name,
parent_id: None,
});
for connection_id in session
.connection_pool()
.await
.user_connection_ids(invitee_id)
{
session.peer.send(connection_id, update.clone())?;
}
response.send(proto::Ack {})?;
Ok(())
}
async fn remove_channel_member(
request: proto::RemoveChannelMember,
response: Response<proto::RemoveChannelMember>,
session: Session,
) -> Result<()> {
Ok(())
}
async fn respond_to_channel_invite(
request: proto::RespondToChannelInvite,
response: Response<proto::RespondToChannelInvite>,
session: Session,
) -> Result<()> {
let db = session.db().await;
let channel_id = ChannelId::from_proto(request.channel_id);
let channel = db.get_channel(channel_id).await?;
db.respond_to_channel_invite(channel_id, session.user_id, request.accept)
.await?;
let mut update = proto::UpdateChannels::default();
update
.remove_channel_invitations
.push(channel_id.to_proto());
if request.accept {
update.channels.push(proto::Channel {
id: channel.id.to_proto(),
name: channel.name,
parent_id: None,
});
}
session.peer.send(session.connection_id, update)?;
response.send(proto::Ack {})?;
Ok(())
}
async fn update_diff_base(request: proto::UpdateDiffBase, session: Session) -> Result<()> { async fn update_diff_base(request: proto::UpdateDiffBase, session: Session) -> Result<()> {
let project_id = ProjectId::from_proto(request.project_id); let project_id = ProjectId::from_proto(request.project_id);
let project_connection_ids = session let project_connection_ids = session

View file

@ -7,7 +7,8 @@ use crate::{
use anyhow::anyhow; use anyhow::anyhow;
use call::ActiveCall; use call::ActiveCall;
use client::{ use client::{
self, proto::PeerId, Client, Connection, Credentials, EstablishConnectionError, UserStore, self, proto::PeerId, ChannelStore, Client, Connection, Credentials, EstablishConnectionError,
UserStore,
}; };
use collections::{HashMap, HashSet}; use collections::{HashMap, HashSet};
use fs::FakeFs; use fs::FakeFs;
@ -33,9 +34,9 @@ use std::{
use util::http::FakeHttpClient; use util::http::FakeHttpClient;
use workspace::Workspace; use workspace::Workspace;
mod channel_tests;
mod integration_tests; mod integration_tests;
mod randomized_integration_tests; mod randomized_integration_tests;
mod channel_tests;
struct TestServer { struct TestServer {
app_state: Arc<AppState>, app_state: Arc<AppState>,
@ -187,6 +188,8 @@ impl TestServer {
let fs = FakeFs::new(cx.background()); let fs = FakeFs::new(cx.background());
let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http, cx)); let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http, cx));
let channel_store =
cx.add_model(|cx| ChannelStore::new(client.clone(), user_store.clone(), cx));
let app_state = Arc::new(workspace::AppState { let app_state = Arc::new(workspace::AppState {
client: client.clone(), client: client.clone(),
user_store: user_store.clone(), user_store: user_store.clone(),
@ -218,6 +221,7 @@ impl TestServer {
username: name.to_string(), username: name.to_string(),
state: Default::default(), state: Default::default(),
user_store, user_store,
channel_store,
fs, fs,
language_registry: Arc::new(LanguageRegistry::test()), language_registry: Arc::new(LanguageRegistry::test()),
}; };
@ -320,6 +324,7 @@ struct TestClient {
username: String, username: String,
state: RefCell<TestClientState>, state: RefCell<TestClientState>,
pub user_store: ModelHandle<UserStore>, pub user_store: ModelHandle<UserStore>,
pub channel_store: ModelHandle<ChannelStore>,
language_registry: Arc<LanguageRegistry>, language_registry: Arc<LanguageRegistry>,
fs: Arc<FakeFs>, fs: Arc<FakeFs>,
} }

View file

@ -1,85 +1,108 @@
use client::Channel;
use gpui::{executor::Deterministic, TestAppContext}; use gpui::{executor::Deterministic, TestAppContext};
use std::sync::Arc; use std::sync::Arc;
use crate::db::Channel;
use super::TestServer; use super::TestServer;
#[gpui::test] #[gpui::test]
async fn test_basic_channels(deterministic: Arc<Deterministic>, cx: &mut TestAppContext) { async fn test_basic_channels(
deterministic: Arc<Deterministic>,
cx_a: &mut TestAppContext,
cx_b: &mut TestAppContext,
) {
deterministic.forbid_parking(); deterministic.forbid_parking();
let mut server = TestServer::start(&deterministic).await; let mut server = TestServer::start(&deterministic).await;
let client_a = server.create_client(cx, "user_a").await; let client_a = server.create_client(cx_a, "user_a").await;
let a_id = crate::db::UserId(client_a.user_id().unwrap() as i32); let client_b = server.create_client(cx_b, "user_b").await;
let db = server._test_db.db();
let zed_id = db.create_root_channel("zed").await.unwrap(); let channel_a_id = client_a
let crdb_id = db.create_channel("crdb", Some(zed_id)).await.unwrap(); .channel_store
let livestreaming_id = db .update(cx_a, |channel_store, _| {
.create_channel("livestreaming", Some(zed_id)) channel_store.create_channel("channel-a", None)
})
.await .await
.unwrap(); .unwrap();
let replace_id = db.create_channel("replace", Some(zed_id)).await.unwrap();
let rust_id = db.create_root_channel("rust").await.unwrap();
let cargo_id = db.create_channel("cargo", Some(rust_id)).await.unwrap();
db.add_channel_member(zed_id, a_id).await.unwrap(); client_a.channel_store.read_with(cx_a, |channels, _| {
db.add_channel_member(rust_id, a_id).await.unwrap(); assert_eq!(
channels.channels(),
let channels = db.get_channels(a_id).await.unwrap(); &[Channel {
assert_eq!( id: channel_a_id,
channels, name: "channel-a".to_string(),
vec![
Channel {
id: zed_id,
name: "zed".to_string(),
parent_id: None, parent_id: None,
}, }]
Channel { )
id: rust_id, });
name: "rust".to_string(),
parent_id: None,
},
Channel {
id: crdb_id,
name: "crdb".to_string(),
parent_id: Some(zed_id),
},
Channel {
id: livestreaming_id,
name: "livestreaming".to_string(),
parent_id: Some(zed_id),
},
Channel {
id: replace_id,
name: "replace".to_string(),
parent_id: Some(zed_id),
},
Channel {
id: cargo_id,
name: "cargo".to_string(),
parent_id: Some(rust_id),
}
]
);
}
#[gpui::test] client_b
async fn test_block_cycle_creation(deterministic: Arc<Deterministic>, cx: &mut TestAppContext) { .channel_store
deterministic.forbid_parking(); .read_with(cx_b, |channels, _| assert_eq!(channels.channels(), &[]));
let mut server = TestServer::start(&deterministic).await;
let client_a = server.create_client(cx, "user_a").await;
let a_id = crate::db::UserId(client_a.user_id().unwrap() as i32);
let db = server._test_db.db();
let zed_id = db.create_root_channel("zed").await.unwrap(); // Invite client B to channel A as client A.
let first_id = db.create_channel("first", Some(zed_id)).await.unwrap(); client_a
let second_id = db .channel_store
.create_channel("second_id", Some(first_id)) .update(cx_a, |channel_store, _| {
channel_store.invite_member(channel_a_id, client_b.user_id().unwrap(), false)
})
.await .await
.unwrap(); .unwrap();
// Wait for client b to see the invitation
deterministic.run_until_parked();
client_b.channel_store.read_with(cx_b, |channels, _| {
assert_eq!(
channels.channel_invitations(),
&[Channel {
id: channel_a_id,
name: "channel-a".to_string(),
parent_id: None,
}]
)
});
// Client B now sees that they are in channel A.
client_b
.channel_store
.update(cx_b, |channels, _| {
channels.respond_to_channel_invite(channel_a_id, true)
})
.await
.unwrap();
client_b.channel_store.read_with(cx_b, |channels, _| {
assert_eq!(channels.channel_invitations(), &[]);
assert_eq!(
channels.channels(),
&[Channel {
id: channel_a_id,
name: "channel-a".to_string(),
parent_id: None,
}]
)
});
} }
// TODO:
// Invariants to test:
// 1. Dag structure is maintained for all operations (can't make a cycle)
// 2. Can't be a member of a super channel, and accept a membership of a sub channel (by definition, a noop)
// #[gpui::test]
// async fn test_block_cycle_creation(deterministic: Arc<Deterministic>, cx: &mut TestAppContext) {
// // deterministic.forbid_parking();
// // let mut server = TestServer::start(&deterministic).await;
// // let client_a = server.create_client(cx, "user_a").await;
// // let a_id = crate::db::UserId(client_a.user_id().unwrap() as i32);
// // let db = server._test_db.db();
// // let zed_id = db.create_root_channel("zed", a_id).await.unwrap();
// // let first_id = db.create_channel("first", Some(zed_id)).await.unwrap();
// // let second_id = db
// // .create_channel("second_id", Some(first_id))
// // .await
// // .unwrap();
// }
/* /*
Linear things: Linear things:
- A way of expressing progress to the team - A way of expressing progress to the team

View file

@ -102,17 +102,6 @@ message Envelope {
SearchProject search_project = 80; SearchProject search_project = 80;
SearchProjectResponse search_project_response = 81; SearchProjectResponse search_project_response = 81;
GetChannels get_channels = 82;
GetChannelsResponse get_channels_response = 83;
JoinChannel join_channel = 84;
JoinChannelResponse join_channel_response = 85;
LeaveChannel leave_channel = 86;
SendChannelMessage send_channel_message = 87;
SendChannelMessageResponse send_channel_message_response = 88;
ChannelMessageSent channel_message_sent = 89;
GetChannelMessages get_channel_messages = 90;
GetChannelMessagesResponse get_channel_messages_response = 91;
UpdateContacts update_contacts = 92; UpdateContacts update_contacts = 92;
UpdateInviteInfo update_invite_info = 93; UpdateInviteInfo update_invite_info = 93;
ShowContacts show_contacts = 94; ShowContacts show_contacts = 94;
@ -140,6 +129,13 @@ message Envelope {
InlayHints inlay_hints = 116; InlayHints inlay_hints = 116;
InlayHintsResponse inlay_hints_response = 117; InlayHintsResponse inlay_hints_response = 117;
RefreshInlayHints refresh_inlay_hints = 118; RefreshInlayHints refresh_inlay_hints = 118;
CreateChannel create_channel = 119;
CreateChannelResponse create_channel_response = 120;
InviteChannelMember invite_channel_member = 121;
RemoveChannelMember remove_channel_member = 122;
RespondToChannelInvite respond_to_channel_invite = 123;
UpdateChannels update_channels = 124;
} }
} }
@ -867,23 +863,36 @@ message LspDiskBasedDiagnosticsUpdating {}
message LspDiskBasedDiagnosticsUpdated {} message LspDiskBasedDiagnosticsUpdated {}
message GetChannels {} message UpdateChannels {
message GetChannelsResponse {
repeated Channel channels = 1; repeated Channel channels = 1;
repeated uint64 remove_channels = 2;
repeated Channel channel_invitations = 3;
repeated uint64 remove_channel_invitations = 4;
} }
message JoinChannel { message CreateChannel {
string name = 1;
optional uint64 parent_id = 2;
}
message CreateChannelResponse {
uint64 channel_id = 1; uint64 channel_id = 1;
} }
message JoinChannelResponse { message InviteChannelMember {
repeated ChannelMessage messages = 1; uint64 channel_id = 1;
bool done = 2; uint64 user_id = 2;
bool admin = 3;
} }
message LeaveChannel { message RemoveChannelMember {
uint64 channel_id = 1; uint64 channel_id = 1;
uint64 user_id = 2;
}
message RespondToChannelInvite {
uint64 channel_id = 1;
bool accept = 2;
} }
message GetUsers { message GetUsers {
@ -918,31 +927,6 @@ enum ContactRequestResponse {
Dismiss = 3; Dismiss = 3;
} }
message SendChannelMessage {
uint64 channel_id = 1;
string body = 2;
Nonce nonce = 3;
}
message SendChannelMessageResponse {
ChannelMessage message = 1;
}
message ChannelMessageSent {
uint64 channel_id = 1;
ChannelMessage message = 2;
}
message GetChannelMessages {
uint64 channel_id = 1;
uint64 before_message_id = 2;
}
message GetChannelMessagesResponse {
repeated ChannelMessage messages = 1;
bool done = 2;
}
message UpdateContacts { message UpdateContacts {
repeated Contact contacts = 1; repeated Contact contacts = 1;
repeated uint64 remove_contacts = 2; repeated uint64 remove_contacts = 2;
@ -1274,14 +1258,7 @@ message Nonce {
message Channel { message Channel {
uint64 id = 1; uint64 id = 1;
string name = 2; string name = 2;
} optional uint64 parent_id = 3;
message ChannelMessage {
uint64 id = 1;
string body = 2;
uint64 timestamp = 3;
uint64 sender_id = 4;
Nonce nonce = 5;
} }
message Contact { message Contact {

View file

@ -143,9 +143,10 @@ messages!(
(Call, Foreground), (Call, Foreground),
(CallCanceled, Foreground), (CallCanceled, Foreground),
(CancelCall, Foreground), (CancelCall, Foreground),
(ChannelMessageSent, Foreground),
(CopyProjectEntry, Foreground), (CopyProjectEntry, Foreground),
(CreateBufferForPeer, Foreground), (CreateBufferForPeer, Foreground),
(CreateChannel, Foreground),
(CreateChannelResponse, Foreground),
(CreateProjectEntry, Foreground), (CreateProjectEntry, Foreground),
(CreateRoom, Foreground), (CreateRoom, Foreground),
(CreateRoomResponse, Foreground), (CreateRoomResponse, Foreground),
@ -158,10 +159,6 @@ messages!(
(FormatBuffers, Foreground), (FormatBuffers, Foreground),
(FormatBuffersResponse, Foreground), (FormatBuffersResponse, Foreground),
(FuzzySearchUsers, Foreground), (FuzzySearchUsers, Foreground),
(GetChannelMessages, Foreground),
(GetChannelMessagesResponse, Foreground),
(GetChannels, Foreground),
(GetChannelsResponse, Foreground),
(GetCodeActions, Background), (GetCodeActions, Background),
(GetCodeActionsResponse, Background), (GetCodeActionsResponse, Background),
(GetHover, Background), (GetHover, Background),
@ -181,14 +178,12 @@ messages!(
(GetUsers, Foreground), (GetUsers, Foreground),
(Hello, Foreground), (Hello, Foreground),
(IncomingCall, Foreground), (IncomingCall, Foreground),
(InviteChannelMember, Foreground),
(UsersResponse, Foreground), (UsersResponse, Foreground),
(JoinChannel, Foreground),
(JoinChannelResponse, Foreground),
(JoinProject, Foreground), (JoinProject, Foreground),
(JoinProjectResponse, Foreground), (JoinProjectResponse, Foreground),
(JoinRoom, Foreground), (JoinRoom, Foreground),
(JoinRoomResponse, Foreground), (JoinRoomResponse, Foreground),
(LeaveChannel, Foreground),
(LeaveProject, Foreground), (LeaveProject, Foreground),
(LeaveRoom, Foreground), (LeaveRoom, Foreground),
(OpenBufferById, Background), (OpenBufferById, Background),
@ -211,18 +206,18 @@ messages!(
(RejoinRoom, Foreground), (RejoinRoom, Foreground),
(RejoinRoomResponse, Foreground), (RejoinRoomResponse, Foreground),
(RemoveContact, Foreground), (RemoveContact, Foreground),
(RemoveChannelMember, Foreground),
(ReloadBuffers, Foreground), (ReloadBuffers, Foreground),
(ReloadBuffersResponse, Foreground), (ReloadBuffersResponse, Foreground),
(RemoveProjectCollaborator, Foreground), (RemoveProjectCollaborator, Foreground),
(RenameProjectEntry, Foreground), (RenameProjectEntry, Foreground),
(RequestContact, Foreground), (RequestContact, Foreground),
(RespondToContactRequest, Foreground), (RespondToContactRequest, Foreground),
(RespondToChannelInvite, Foreground),
(RoomUpdated, Foreground), (RoomUpdated, Foreground),
(SaveBuffer, Foreground), (SaveBuffer, Foreground),
(SearchProject, Background), (SearchProject, Background),
(SearchProjectResponse, Background), (SearchProjectResponse, Background),
(SendChannelMessage, Foreground),
(SendChannelMessageResponse, Foreground),
(ShareProject, Foreground), (ShareProject, Foreground),
(ShareProjectResponse, Foreground), (ShareProjectResponse, Foreground),
(ShowContacts, Foreground), (ShowContacts, Foreground),
@ -235,6 +230,7 @@ messages!(
(UpdateBuffer, Foreground), (UpdateBuffer, Foreground),
(UpdateBufferFile, Foreground), (UpdateBufferFile, Foreground),
(UpdateContacts, Foreground), (UpdateContacts, Foreground),
(UpdateChannels, Foreground),
(UpdateDiagnosticSummary, Foreground), (UpdateDiagnosticSummary, Foreground),
(UpdateFollowers, Foreground), (UpdateFollowers, Foreground),
(UpdateInviteInfo, Foreground), (UpdateInviteInfo, Foreground),
@ -260,13 +256,12 @@ request_messages!(
(CopyProjectEntry, ProjectEntryResponse), (CopyProjectEntry, ProjectEntryResponse),
(CreateProjectEntry, ProjectEntryResponse), (CreateProjectEntry, ProjectEntryResponse),
(CreateRoom, CreateRoomResponse), (CreateRoom, CreateRoomResponse),
(CreateChannel, CreateChannelResponse),
(DeclineCall, Ack), (DeclineCall, Ack),
(DeleteProjectEntry, ProjectEntryResponse), (DeleteProjectEntry, ProjectEntryResponse),
(ExpandProjectEntry, ExpandProjectEntryResponse), (ExpandProjectEntry, ExpandProjectEntryResponse),
(Follow, FollowResponse), (Follow, FollowResponse),
(FormatBuffers, FormatBuffersResponse), (FormatBuffers, FormatBuffersResponse),
(GetChannelMessages, GetChannelMessagesResponse),
(GetChannels, GetChannelsResponse),
(GetCodeActions, GetCodeActionsResponse), (GetCodeActions, GetCodeActionsResponse),
(GetHover, GetHoverResponse), (GetHover, GetHoverResponse),
(GetCompletions, GetCompletionsResponse), (GetCompletions, GetCompletionsResponse),
@ -278,7 +273,7 @@ request_messages!(
(GetProjectSymbols, GetProjectSymbolsResponse), (GetProjectSymbols, GetProjectSymbolsResponse),
(FuzzySearchUsers, UsersResponse), (FuzzySearchUsers, UsersResponse),
(GetUsers, UsersResponse), (GetUsers, UsersResponse),
(JoinChannel, JoinChannelResponse), (InviteChannelMember, Ack),
(JoinProject, JoinProjectResponse), (JoinProject, JoinProjectResponse),
(JoinRoom, JoinRoomResponse), (JoinRoom, JoinRoomResponse),
(LeaveRoom, Ack), (LeaveRoom, Ack),
@ -295,12 +290,13 @@ request_messages!(
(RefreshInlayHints, Ack), (RefreshInlayHints, Ack),
(ReloadBuffers, ReloadBuffersResponse), (ReloadBuffers, ReloadBuffersResponse),
(RequestContact, Ack), (RequestContact, Ack),
(RemoveChannelMember, Ack),
(RemoveContact, Ack), (RemoveContact, Ack),
(RespondToContactRequest, Ack), (RespondToContactRequest, Ack),
(RespondToChannelInvite, Ack),
(RenameProjectEntry, ProjectEntryResponse), (RenameProjectEntry, ProjectEntryResponse),
(SaveBuffer, BufferSaved), (SaveBuffer, BufferSaved),
(SearchProject, SearchProjectResponse), (SearchProject, SearchProjectResponse),
(SendChannelMessage, SendChannelMessageResponse),
(ShareProject, ShareProjectResponse), (ShareProject, ShareProjectResponse),
(SynchronizeBuffers, SynchronizeBuffersResponse), (SynchronizeBuffers, SynchronizeBuffersResponse),
(Test, Test), (Test, Test),
@ -363,8 +359,6 @@ entity_messages!(
UpdateDiffBase UpdateDiffBase
); );
entity_messages!(channel_id, ChannelMessageSent);
const KIB: usize = 1024; const KIB: usize = 1024;
const MIB: usize = KIB * 1024; const MIB: usize = KIB * 1024;
const MAX_BUFFER_LEN: usize = MIB; const MAX_BUFFER_LEN: usize = MIB;