Extract a proto crate out of rpc (#12852)

Release Notes:

- N/A

---------

Co-authored-by: Nathan <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2024-06-10 20:49:53 +02:00 committed by GitHub
parent 57c40299a5
commit 77e88c1ded
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 856 additions and 727 deletions

View File

@ -74,7 +74,7 @@ jobs:
version: v1.29.0 version: v1.29.0
- uses: bufbuild/buf-breaking-action@v1 - uses: bufbuild/buf-breaking-action@v1
with: with:
input: "crates/rpc/proto/" input: "crates/proto/proto/"
against: "https://github.com/${GITHUB_REPOSITORY}.git#branch=${BUF_BASE_BRANCH},subdir=crates/rpc/proto/" against: "https://github.com/${GITHUB_REPOSITORY}.git#branch=${BUF_BASE_BRANCH},subdir=crates/rpc/proto/"
macos_tests: macos_tests:

14
Cargo.lock generated
View File

@ -7931,6 +7931,17 @@ dependencies = [
"prost", "prost",
] ]
[[package]]
name = "proto"
version = "0.1.0"
dependencies = [
"anyhow",
"collections",
"prost",
"prost-build",
"serde",
]
[[package]] [[package]]
name = "protobuf" name = "protobuf"
version = "2.28.0" version = "2.28.0"
@ -8514,8 +8525,7 @@ dependencies = [
"futures 0.3.28", "futures 0.3.28",
"gpui", "gpui",
"parking_lot", "parking_lot",
"prost", "proto",
"prost-build",
"rand 0.8.5", "rand 0.8.5",
"rsa 0.4.0", "rsa 0.4.0",
"serde", "serde",

View File

@ -68,6 +68,7 @@ members = [
"crates/project", "crates/project",
"crates/project_panel", "crates/project_panel",
"crates/project_symbols", "crates/project_symbols",
"crates/proto",
"crates/quick_action_bar", "crates/quick_action_bar",
"crates/recent_projects", "crates/recent_projects",
"crates/refineable", "crates/refineable",
@ -319,6 +320,7 @@ pretty_assertions = "1.3.0"
prost = "0.9" prost = "0.9"
prost-build = "0.9" prost-build = "0.9"
prost-types = "0.9" prost-types = "0.9"
proto = { path = "./crates/proto" }
pulldown-cmark = { version = "0.10.0", default-features = false } pulldown-cmark = { version = "0.10.0", default-features = false }
rand = "0.8.5" rand = "0.8.5"
refineable = { path = "./crates/refineable" } refineable = { path = "./crates/refineable" }

View File

@ -1729,6 +1729,7 @@ mod tests {
use gpui::{BackgroundExecutor, Context, TestAppContext}; use gpui::{BackgroundExecutor, Context, TestAppContext};
use http::FakeHttpClient; use http::FakeHttpClient;
use parking_lot::Mutex; use parking_lot::Mutex;
use proto::TypedEnvelope;
use settings::SettingsStore; use settings::SettingsStore;
use std::future; use std::future;

29
crates/proto/Cargo.toml Normal file
View File

@ -0,0 +1,29 @@
[package]
description = "Shared protocol for communication between the Zed app and the zed.dev server"
edition = "2021"
name = "proto"
version = "0.1.0"
publish = false
license = "GPL-3.0-or-later"
[features]
test-support = ["collections/test-support"]
[lints]
workspace = true
[lib]
path = "src/proto.rs"
doctest = false
[dependencies]
anyhow.workspace = true
collections.workspace = true
prost.workspace = true
serde.workspace = true
[build-dependencies]
prost-build.workspace = true
[dev-dependencies]
collections = { workspace = true, features = ["test-support"] }

View File

@ -31,8 +31,7 @@
/// } /// }
/// ``` /// ```
/// ///
use crate::proto; pub use crate::ErrorCode;
pub use proto::ErrorCode;
/// ErrorCodeExt provides some helpers for structured error handling. /// ErrorCodeExt provides some helpers for structured error handling.
/// ///
@ -53,7 +52,7 @@ pub trait ErrorCodeExt {
fn with_tag(self, k: &str, v: &str) -> RpcError; fn with_tag(self, k: &str, v: &str) -> RpcError;
} }
impl ErrorCodeExt for proto::ErrorCode { impl ErrorCodeExt for ErrorCode {
fn anyhow(self) -> anyhow::Error { fn anyhow(self) -> anyhow::Error {
self.into() self.into()
} }
@ -75,21 +74,21 @@ impl ErrorCodeExt for proto::ErrorCode {
/// what we use throughout our codebase. Though under the hood this /// what we use throughout our codebase. Though under the hood this
pub trait ErrorExt { pub trait ErrorExt {
/// error_code() returns the ErrorCode (or ErrorCode::Internal if there is none) /// error_code() returns the ErrorCode (or ErrorCode::Internal if there is none)
fn error_code(&self) -> proto::ErrorCode; fn error_code(&self) -> ErrorCode;
/// error_tag() returns the value of the tag with the given key, if any. /// error_tag() returns the value of the tag with the given key, if any.
fn error_tag(&self, k: &str) -> Option<&str>; fn error_tag(&self, k: &str) -> Option<&str>;
/// to_proto() converts the error into a proto::Error /// to_proto() converts the error into a crate::Error
fn to_proto(&self) -> proto::Error; fn to_proto(&self) -> crate::Error;
/// Clones the error and turns into an [anyhow::Error]. /// Clones the error and turns into an [anyhow::Error].
fn cloned(&self) -> anyhow::Error; fn cloned(&self) -> anyhow::Error;
} }
impl ErrorExt for anyhow::Error { impl ErrorExt for anyhow::Error {
fn error_code(&self) -> proto::ErrorCode { fn error_code(&self) -> ErrorCode {
if let Some(rpc_error) = self.downcast_ref::<RpcError>() { if let Some(rpc_error) = self.downcast_ref::<RpcError>() {
rpc_error.code rpc_error.code
} else { } else {
proto::ErrorCode::Internal ErrorCode::Internal
} }
} }
@ -101,7 +100,7 @@ impl ErrorExt for anyhow::Error {
} }
} }
fn to_proto(&self) -> proto::Error { fn to_proto(&self) -> crate::Error {
if let Some(rpc_error) = self.downcast_ref::<RpcError>() { if let Some(rpc_error) = self.downcast_ref::<RpcError>() {
rpc_error.to_proto() rpc_error.to_proto()
} else { } else {
@ -118,8 +117,8 @@ impl ErrorExt for anyhow::Error {
} }
} }
impl From<proto::ErrorCode> for anyhow::Error { impl From<ErrorCode> for anyhow::Error {
fn from(value: proto::ErrorCode) -> Self { fn from(value: ErrorCode) -> Self {
RpcError { RpcError {
request: None, request: None,
code: value, code: value,
@ -134,7 +133,7 @@ impl From<proto::ErrorCode> for anyhow::Error {
pub struct RpcError { pub struct RpcError {
request: Option<String>, request: Option<String>,
msg: String, msg: String,
code: proto::ErrorCode, code: ErrorCode,
tags: Vec<String>, tags: Vec<String>,
} }
@ -146,9 +145,9 @@ pub struct RpcError {
/// in the app; however it is useful for chaining .message() and .with_tag() on /// in the app; however it is useful for chaining .message() and .with_tag() on
/// ErrorCode. /// ErrorCode.
impl RpcError { impl RpcError {
/// from_proto converts a proto::Error into an anyhow::Error containing /// from_proto converts a crate::Error into an anyhow::Error containing
/// an RpcError. /// an RpcError.
pub fn from_proto(error: &proto::Error, request: &str) -> anyhow::Error { pub fn from_proto(error: &crate::Error, request: &str) -> anyhow::Error {
RpcError { RpcError {
request: Some(request.to_string()), request: Some(request.to_string()),
code: error.code(), code: error.code(),
@ -188,12 +187,12 @@ impl ErrorExt for RpcError {
None None
} }
fn error_code(&self) -> proto::ErrorCode { fn error_code(&self) -> ErrorCode {
self.code self.code
} }
fn to_proto(&self) -> proto::Error { fn to_proto(&self) -> crate::Error {
proto::Error { crate::Error {
code: self.code as i32, code: self.code as i32,
message: self.msg.clone(), message: self.msg.clone(),
tags: self.tags.clone(), tags: self.tags.clone(),
@ -225,8 +224,8 @@ impl std::fmt::Display for RpcError {
} }
} }
impl From<proto::ErrorCode> for RpcError { impl From<ErrorCode> for RpcError {
fn from(code: proto::ErrorCode) -> Self { fn from(code: ErrorCode) -> Self {
RpcError { RpcError {
request: None, request: None,
code, code,

View File

@ -0,0 +1,70 @@
#[macro_export]
macro_rules! messages {
($(($name:ident, $priority:ident)),* $(,)?) => {
pub fn build_typed_envelope(sender_id: PeerId, received_at: Instant, envelope: Envelope) -> Option<Box<dyn AnyTypedEnvelope>> {
match envelope.payload {
$(Some(envelope::Payload::$name(payload)) => {
Some(Box::new(TypedEnvelope {
sender_id,
original_sender_id: envelope.original_sender_id,
message_id: envelope.id,
payload,
received_at,
}))
}, )*
_ => None
}
}
$(
impl EnvelopedMessage for $name {
const NAME: &'static str = std::stringify!($name);
const PRIORITY: MessagePriority = MessagePriority::$priority;
fn into_envelope(
self,
id: u32,
responding_to: Option<u32>,
original_sender_id: Option<PeerId>,
) -> Envelope {
Envelope {
id,
responding_to,
original_sender_id,
payload: Some(envelope::Payload::$name(self)),
}
}
fn from_envelope(envelope: Envelope) -> Option<Self> {
if let Some(envelope::Payload::$name(msg)) = envelope.payload {
Some(msg)
} else {
None
}
}
}
)*
};
}
#[macro_export]
macro_rules! request_messages {
($(($request_name:ident, $response_name:ident)),* $(,)?) => {
$(impl RequestMessage for $request_name {
type Response = $response_name;
})*
};
}
#[macro_export]
macro_rules! entity_messages {
({$id_field:ident, $entity_type:ty}, $($name:ident),* $(,)?) => {
$(impl EntityMessage for $name {
type Entity = $entity_type;
fn remote_entity_id(&self) -> u64 {
self.$id_field
}
})*
};
}

652
crates/proto/src/proto.rs Normal file
View File

@ -0,0 +1,652 @@
#![allow(non_snake_case)]
pub mod error;
mod macros;
mod typed_envelope;
pub use error::*;
pub use typed_envelope::*;
use collections::HashMap;
pub use prost::Message;
use serde::Serialize;
use std::any::{Any, TypeId};
use std::time::Instant;
use std::{
cmp,
fmt::Debug,
iter,
time::{Duration, SystemTime, UNIX_EPOCH},
};
use std::{fmt, mem};
include!(concat!(env!("OUT_DIR"), "/zed.messages.rs"));
pub trait EnvelopedMessage: Clone + Debug + Serialize + Sized + Send + Sync + 'static {
const NAME: &'static str;
const PRIORITY: MessagePriority;
fn into_envelope(
self,
id: u32,
responding_to: Option<u32>,
original_sender_id: Option<PeerId>,
) -> Envelope;
fn from_envelope(envelope: Envelope) -> Option<Self>;
}
pub trait EntityMessage: EnvelopedMessage {
type Entity;
fn remote_entity_id(&self) -> u64;
}
pub trait RequestMessage: EnvelopedMessage {
type Response: EnvelopedMessage;
}
pub trait AnyTypedEnvelope: 'static + Send + Sync {
fn payload_type_id(&self) -> TypeId;
fn payload_type_name(&self) -> &'static str;
fn as_any(&self) -> &dyn Any;
fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync>;
fn is_background(&self) -> bool;
fn original_sender_id(&self) -> Option<PeerId>;
fn sender_id(&self) -> PeerId;
fn message_id(&self) -> u32;
}
pub enum MessagePriority {
Foreground,
Background,
}
impl<T: EnvelopedMessage> AnyTypedEnvelope for TypedEnvelope<T> {
fn payload_type_id(&self) -> TypeId {
TypeId::of::<T>()
}
fn payload_type_name(&self) -> &'static str {
T::NAME
}
fn as_any(&self) -> &dyn Any {
self
}
fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync> {
self
}
fn is_background(&self) -> bool {
matches!(T::PRIORITY, MessagePriority::Background)
}
fn original_sender_id(&self) -> Option<PeerId> {
self.original_sender_id
}
fn sender_id(&self) -> PeerId {
self.sender_id
}
fn message_id(&self) -> u32 {
self.message_id
}
}
impl PeerId {
pub fn from_u64(peer_id: u64) -> Self {
let owner_id = (peer_id >> 32) as u32;
let id = peer_id as u32;
Self { owner_id, id }
}
pub fn as_u64(self) -> u64 {
((self.owner_id as u64) << 32) | (self.id as u64)
}
}
impl Copy for PeerId {}
impl Eq for PeerId {}
impl Ord for PeerId {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.owner_id
.cmp(&other.owner_id)
.then_with(|| self.id.cmp(&other.id))
}
}
impl PartialOrd for PeerId {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl std::hash::Hash for PeerId {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.owner_id.hash(state);
self.id.hash(state);
}
}
impl fmt::Display for PeerId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}/{}", self.owner_id, self.id)
}
}
messages!(
(Ack, Foreground),
(AckBufferOperation, Background),
(AckChannelMessage, Background),
(AddNotification, Foreground),
(AddProjectCollaborator, Foreground),
(ApplyCodeAction, Background),
(ApplyCodeActionResponse, Background),
(ApplyCompletionAdditionalEdits, Background),
(ApplyCompletionAdditionalEditsResponse, Background),
(BufferReloaded, Foreground),
(BufferSaved, Foreground),
(Call, Foreground),
(CallCanceled, Foreground),
(CancelCall, Foreground),
(ChannelMessageSent, Foreground),
(ChannelMessageUpdate, Foreground),
(CompleteWithLanguageModel, Background),
(ComputeEmbeddings, Background),
(ComputeEmbeddingsResponse, Background),
(CopyProjectEntry, Foreground),
(CountTokensWithLanguageModel, Background),
(CountTokensResponse, Background),
(CreateBufferForPeer, Foreground),
(CreateChannel, Foreground),
(CreateChannelResponse, Foreground),
(CreateProjectEntry, Foreground),
(CreateRoom, Foreground),
(CreateRoomResponse, Foreground),
(DeclineCall, Foreground),
(DeleteChannel, Foreground),
(DeleteNotification, Foreground),
(UpdateNotification, Foreground),
(DeleteProjectEntry, Foreground),
(EndStream, Foreground),
(Error, Foreground),
(ExpandProjectEntry, Foreground),
(ExpandProjectEntryResponse, Foreground),
(Follow, Foreground),
(FollowResponse, Foreground),
(FormatBuffers, Foreground),
(FormatBuffersResponse, Foreground),
(FuzzySearchUsers, Foreground),
(GetCachedEmbeddings, Background),
(GetCachedEmbeddingsResponse, Background),
(GetChannelMembers, Foreground),
(GetChannelMembersResponse, Foreground),
(GetChannelMessages, Background),
(GetChannelMessagesById, Background),
(GetChannelMessagesResponse, Background),
(GetCodeActions, Background),
(GetCodeActionsResponse, Background),
(GetCompletions, Background),
(GetCompletionsResponse, Background),
(GetDefinition, Background),
(GetDefinitionResponse, Background),
(GetDocumentHighlights, Background),
(GetDocumentHighlightsResponse, Background),
(GetHover, Background),
(GetHoverResponse, Background),
(GetNotifications, Foreground),
(GetNotificationsResponse, Foreground),
(GetPrivateUserInfo, Foreground),
(GetPrivateUserInfoResponse, Foreground),
(GetProjectSymbols, Background),
(GetProjectSymbolsResponse, Background),
(GetReferences, Background),
(GetReferencesResponse, Background),
(GetSupermavenApiKey, Background),
(GetSupermavenApiKeyResponse, Background),
(GetTypeDefinition, Background),
(GetTypeDefinitionResponse, Background),
(GetImplementation, Background),
(GetImplementationResponse, Background),
(GetUsers, Foreground),
(Hello, Foreground),
(IncomingCall, Foreground),
(InlayHints, Background),
(InlayHintsResponse, Background),
(InviteChannelMember, Foreground),
(JoinChannel, Foreground),
(JoinChannelBuffer, Foreground),
(JoinChannelBufferResponse, Foreground),
(JoinChannelChat, Foreground),
(JoinChannelChatResponse, Foreground),
(JoinProject, Foreground),
(JoinHostedProject, Foreground),
(JoinProjectResponse, Foreground),
(JoinRoom, Foreground),
(JoinRoomResponse, Foreground),
(LanguageModelResponse, Background),
(LeaveChannelBuffer, Background),
(LeaveChannelChat, Foreground),
(LeaveProject, Foreground),
(LeaveRoom, Foreground),
(MarkNotificationRead, Foreground),
(MoveChannel, Foreground),
(OnTypeFormatting, Background),
(OnTypeFormattingResponse, Background),
(OpenBufferById, Background),
(OpenBufferByPath, Background),
(OpenBufferForSymbol, Background),
(OpenBufferForSymbolResponse, Background),
(OpenBufferResponse, Background),
(PerformRename, Background),
(PerformRenameResponse, Background),
(Ping, Foreground),
(PrepareRename, Background),
(PrepareRenameResponse, Background),
(ProjectEntryResponse, Foreground),
(RefreshInlayHints, Foreground),
(RejoinChannelBuffers, Foreground),
(RejoinChannelBuffersResponse, Foreground),
(RejoinRoom, Foreground),
(RejoinRoomResponse, Foreground),
(ReloadBuffers, Foreground),
(ReloadBuffersResponse, Foreground),
(RemoveChannelMember, Foreground),
(RemoveChannelMessage, Foreground),
(UpdateChannelMessage, Foreground),
(RemoveContact, Foreground),
(RemoveProjectCollaborator, Foreground),
(RenameChannel, Foreground),
(RenameChannelResponse, Foreground),
(RenameProjectEntry, Foreground),
(RequestContact, Foreground),
(ResolveCompletionDocumentation, Background),
(ResolveCompletionDocumentationResponse, Background),
(ResolveInlayHint, Background),
(ResolveInlayHintResponse, Background),
(RespondToChannelInvite, Foreground),
(RespondToContactRequest, Foreground),
(RoomUpdated, Foreground),
(SaveBuffer, Foreground),
(SetChannelMemberRole, Foreground),
(SetChannelVisibility, Foreground),
(SearchProject, Background),
(SearchProjectResponse, Background),
(SendChannelMessage, Background),
(SendChannelMessageResponse, Background),
(ShareProject, Foreground),
(ShareProjectResponse, Foreground),
(ShowContacts, Foreground),
(StartLanguageServer, Foreground),
(SubscribeToChannels, Foreground),
(SynchronizeBuffers, Foreground),
(SynchronizeBuffersResponse, Foreground),
(TaskContextForLocation, Background),
(TaskContext, Background),
(TaskTemplates, Background),
(TaskTemplatesResponse, Background),
(Test, Foreground),
(Unfollow, Foreground),
(UnshareProject, Foreground),
(UpdateBuffer, Foreground),
(UpdateBufferFile, Foreground),
(UpdateChannelBuffer, Foreground),
(UpdateChannelBufferCollaborators, Foreground),
(UpdateChannels, Foreground),
(UpdateUserChannels, Foreground),
(UpdateContacts, Foreground),
(UpdateDiagnosticSummary, Foreground),
(UpdateDiffBase, Foreground),
(UpdateFollowers, Foreground),
(UpdateInviteInfo, Foreground),
(UpdateLanguageServer, Foreground),
(UpdateParticipantLocation, Foreground),
(UpdateProject, Foreground),
(UpdateProjectCollaborator, Foreground),
(UpdateWorktree, Foreground),
(UpdateWorktreeSettings, Foreground),
(UsersResponse, Foreground),
(LspExtExpandMacro, Background),
(LspExtExpandMacroResponse, Background),
(SetRoomParticipantRole, Foreground),
(BlameBuffer, Foreground),
(BlameBufferResponse, Foreground),
(CreateDevServerProject, Background),
(CreateDevServerProjectResponse, Foreground),
(CreateDevServer, Foreground),
(CreateDevServerResponse, Foreground),
(DevServerInstructions, Foreground),
(ShutdownDevServer, Foreground),
(ReconnectDevServer, Foreground),
(ReconnectDevServerResponse, Foreground),
(ShareDevServerProject, Foreground),
(JoinDevServerProject, Foreground),
(RejoinRemoteProjects, Foreground),
(RejoinRemoteProjectsResponse, Foreground),
(MultiLspQuery, Background),
(MultiLspQueryResponse, Background),
(DevServerProjectsUpdate, Foreground),
(ValidateDevServerProjectRequest, Background),
(DeleteDevServer, Foreground),
(DeleteDevServerProject, Foreground),
(RegenerateDevServerToken, Foreground),
(RegenerateDevServerTokenResponse, Foreground),
(RenameDevServer, Foreground),
(OpenNewBuffer, Foreground),
(RestartLanguageServers, Foreground),
);
request_messages!(
(ApplyCodeAction, ApplyCodeActionResponse),
(
ApplyCompletionAdditionalEdits,
ApplyCompletionAdditionalEditsResponse
),
(Call, Ack),
(CancelCall, Ack),
(CopyProjectEntry, ProjectEntryResponse),
(CompleteWithLanguageModel, LanguageModelResponse),
(ComputeEmbeddings, ComputeEmbeddingsResponse),
(CountTokensWithLanguageModel, CountTokensResponse),
(CreateChannel, CreateChannelResponse),
(CreateProjectEntry, ProjectEntryResponse),
(CreateRoom, CreateRoomResponse),
(DeclineCall, Ack),
(DeleteChannel, Ack),
(DeleteProjectEntry, ProjectEntryResponse),
(ExpandProjectEntry, ExpandProjectEntryResponse),
(Follow, FollowResponse),
(FormatBuffers, FormatBuffersResponse),
(FuzzySearchUsers, UsersResponse),
(GetCachedEmbeddings, GetCachedEmbeddingsResponse),
(GetChannelMembers, GetChannelMembersResponse),
(GetChannelMessages, GetChannelMessagesResponse),
(GetChannelMessagesById, GetChannelMessagesResponse),
(GetCodeActions, GetCodeActionsResponse),
(GetCompletions, GetCompletionsResponse),
(GetDefinition, GetDefinitionResponse),
(GetImplementation, GetImplementationResponse),
(GetDocumentHighlights, GetDocumentHighlightsResponse),
(GetHover, GetHoverResponse),
(GetNotifications, GetNotificationsResponse),
(GetPrivateUserInfo, GetPrivateUserInfoResponse),
(GetProjectSymbols, GetProjectSymbolsResponse),
(GetReferences, GetReferencesResponse),
(GetSupermavenApiKey, GetSupermavenApiKeyResponse),
(GetTypeDefinition, GetTypeDefinitionResponse),
(GetUsers, UsersResponse),
(IncomingCall, Ack),
(InlayHints, InlayHintsResponse),
(InviteChannelMember, Ack),
(JoinChannel, JoinRoomResponse),
(JoinChannelBuffer, JoinChannelBufferResponse),
(JoinChannelChat, JoinChannelChatResponse),
(JoinHostedProject, JoinProjectResponse),
(JoinProject, JoinProjectResponse),
(JoinRoom, JoinRoomResponse),
(LeaveChannelBuffer, Ack),
(LeaveRoom, Ack),
(MarkNotificationRead, Ack),
(MoveChannel, Ack),
(OnTypeFormatting, OnTypeFormattingResponse),
(OpenBufferById, OpenBufferResponse),
(OpenBufferByPath, OpenBufferResponse),
(OpenBufferForSymbol, OpenBufferForSymbolResponse),
(OpenNewBuffer, OpenBufferResponse),
(PerformRename, PerformRenameResponse),
(Ping, Ack),
(PrepareRename, PrepareRenameResponse),
(RefreshInlayHints, Ack),
(RejoinChannelBuffers, RejoinChannelBuffersResponse),
(RejoinRoom, RejoinRoomResponse),
(ReloadBuffers, ReloadBuffersResponse),
(RemoveChannelMember, Ack),
(RemoveChannelMessage, Ack),
(UpdateChannelMessage, Ack),
(RemoveContact, Ack),
(RenameChannel, RenameChannelResponse),
(RenameProjectEntry, ProjectEntryResponse),
(RequestContact, Ack),
(
ResolveCompletionDocumentation,
ResolveCompletionDocumentationResponse
),
(ResolveInlayHint, ResolveInlayHintResponse),
(RespondToChannelInvite, Ack),
(RespondToContactRequest, Ack),
(SaveBuffer, BufferSaved),
(SearchProject, SearchProjectResponse),
(SendChannelMessage, SendChannelMessageResponse),
(SetChannelMemberRole, Ack),
(SetChannelVisibility, Ack),
(ShareProject, ShareProjectResponse),
(SynchronizeBuffers, SynchronizeBuffersResponse),
(TaskContextForLocation, TaskContext),
(TaskTemplates, TaskTemplatesResponse),
(Test, Test),
(UpdateBuffer, Ack),
(UpdateParticipantLocation, Ack),
(UpdateProject, Ack),
(UpdateWorktree, Ack),
(LspExtExpandMacro, LspExtExpandMacroResponse),
(SetRoomParticipantRole, Ack),
(BlameBuffer, BlameBufferResponse),
(CreateDevServerProject, CreateDevServerProjectResponse),
(CreateDevServer, CreateDevServerResponse),
(ShutdownDevServer, Ack),
(ShareDevServerProject, ShareProjectResponse),
(JoinDevServerProject, JoinProjectResponse),
(RejoinRemoteProjects, RejoinRemoteProjectsResponse),
(ReconnectDevServer, ReconnectDevServerResponse),
(ValidateDevServerProjectRequest, Ack),
(MultiLspQuery, MultiLspQueryResponse),
(DeleteDevServer, Ack),
(DeleteDevServerProject, Ack),
(RegenerateDevServerToken, RegenerateDevServerTokenResponse),
(RenameDevServer, Ack),
(RestartLanguageServers, Ack)
);
entity_messages!(
{project_id, ShareProject},
AddProjectCollaborator,
ApplyCodeAction,
ApplyCompletionAdditionalEdits,
BlameBuffer,
BufferReloaded,
BufferSaved,
CopyProjectEntry,
CreateBufferForPeer,
CreateProjectEntry,
DeleteProjectEntry,
ExpandProjectEntry,
FormatBuffers,
GetCodeActions,
GetCompletions,
GetDefinition,
GetImplementation,
GetDocumentHighlights,
GetHover,
GetProjectSymbols,
GetReferences,
GetTypeDefinition,
InlayHints,
JoinProject,
LeaveProject,
MultiLspQuery,
RestartLanguageServers,
OnTypeFormatting,
OpenNewBuffer,
OpenBufferById,
OpenBufferByPath,
OpenBufferForSymbol,
PerformRename,
PrepareRename,
RefreshInlayHints,
ReloadBuffers,
RemoveProjectCollaborator,
RenameProjectEntry,
ResolveCompletionDocumentation,
ResolveInlayHint,
SaveBuffer,
SearchProject,
StartLanguageServer,
SynchronizeBuffers,
TaskContextForLocation,
TaskTemplates,
UnshareProject,
UpdateBuffer,
UpdateBufferFile,
UpdateDiagnosticSummary,
UpdateDiffBase,
UpdateLanguageServer,
UpdateProject,
UpdateProjectCollaborator,
UpdateWorktree,
UpdateWorktreeSettings,
LspExtExpandMacro,
);
entity_messages!(
{channel_id, Channel},
ChannelMessageSent,
ChannelMessageUpdate,
RemoveChannelMessage,
UpdateChannelMessage,
UpdateChannelBuffer,
UpdateChannelBufferCollaborators,
);
impl From<Timestamp> for SystemTime {
fn from(val: Timestamp) -> Self {
UNIX_EPOCH
.checked_add(Duration::new(val.seconds, val.nanos))
.unwrap()
}
}
impl From<SystemTime> for Timestamp {
fn from(time: SystemTime) -> Self {
let duration = time.duration_since(UNIX_EPOCH).unwrap();
Self {
seconds: duration.as_secs(),
nanos: duration.subsec_nanos(),
}
}
}
impl From<u128> for Nonce {
fn from(nonce: u128) -> Self {
let upper_half = (nonce >> 64) as u64;
let lower_half = nonce as u64;
Self {
upper_half,
lower_half,
}
}
}
impl From<Nonce> for u128 {
fn from(nonce: Nonce) -> Self {
let upper_half = (nonce.upper_half as u128) << 64;
let lower_half = nonce.lower_half as u128;
upper_half | lower_half
}
}
pub fn split_worktree_update(
mut message: UpdateWorktree,
max_chunk_size: usize,
) -> impl Iterator<Item = UpdateWorktree> {
let mut done_files = false;
let mut repository_map = message
.updated_repositories
.into_iter()
.map(|repo| (repo.work_directory_id, repo))
.collect::<HashMap<_, _>>();
iter::from_fn(move || {
if done_files {
return None;
}
let updated_entries_chunk_size = cmp::min(message.updated_entries.len(), max_chunk_size);
let updated_entries: Vec<_> = message
.updated_entries
.drain(..updated_entries_chunk_size)
.collect();
let removed_entries_chunk_size = cmp::min(message.removed_entries.len(), max_chunk_size);
let removed_entries = message
.removed_entries
.drain(..removed_entries_chunk_size)
.collect();
done_files = message.updated_entries.is_empty() && message.removed_entries.is_empty();
let mut updated_repositories = Vec::new();
if !repository_map.is_empty() {
for entry in &updated_entries {
if let Some(repo) = repository_map.remove(&entry.id) {
updated_repositories.push(repo)
}
}
}
let removed_repositories = if done_files {
mem::take(&mut message.removed_repositories)
} else {
Default::default()
};
if done_files {
updated_repositories.extend(mem::take(&mut repository_map).into_values());
}
Some(UpdateWorktree {
project_id: message.project_id,
worktree_id: message.worktree_id,
root_name: message.root_name.clone(),
abs_path: message.abs_path.clone(),
updated_entries,
removed_entries,
scan_id: message.scan_id,
is_last_update: done_files && message.is_last_update,
updated_repositories,
removed_repositories,
})
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_converting_peer_id_from_and_to_u64() {
let peer_id = PeerId {
owner_id: 10,
id: 3,
};
assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
let peer_id = PeerId {
owner_id: u32::MAX,
id: 3,
};
assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
let peer_id = PeerId {
owner_id: 10,
id: u32::MAX,
};
assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
let peer_id = PeerId {
owner_id: u32::MAX,
id: u32::MAX,
};
assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
}
}

View File

@ -0,0 +1,43 @@
use crate::{PeerId, RequestMessage};
use anyhow::{anyhow, Result};
use std::{marker::PhantomData, time::Instant};
pub struct Receipt<T> {
pub sender_id: PeerId,
pub message_id: u32,
payload_type: PhantomData<T>,
}
impl<T> Clone for Receipt<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Receipt<T> {}
#[derive(Clone, Debug)]
pub struct TypedEnvelope<T> {
pub sender_id: PeerId,
pub original_sender_id: Option<PeerId>,
pub message_id: u32,
pub payload: T,
pub received_at: Instant,
}
impl<T> TypedEnvelope<T> {
pub fn original_sender_id(&self) -> Result<PeerId> {
self.original_sender_id
.ok_or_else(|| anyhow!("missing original_sender_id"))
}
}
impl<T: RequestMessage> TypedEnvelope<T> {
pub fn receipt(&self) -> Receipt<T> {
Receipt {
sender_id: self.sender_id,
message_id: self.message_id,
payload_type: PhantomData,
}
}
}

View File

@ -14,7 +14,7 @@ path = "src/rpc.rs"
doctest = false doctest = false
[features] [features]
test-support = ["collections/test-support", "gpui/test-support"] test-support = ["collections/test-support", "gpui/test-support", "proto/test-support"]
[dependencies] [dependencies]
anyhow.workspace = true anyhow.workspace = true
@ -25,7 +25,7 @@ collections.workspace = true
futures.workspace = true futures.workspace = true
gpui = { workspace = true, optional = true } gpui = { workspace = true, optional = true }
parking_lot.workspace = true parking_lot.workspace = true
prost.workspace = true proto.workspace = true
rand.workspace = true rand.workspace = true
rsa = "0.4" rsa = "0.4"
serde.workspace = true serde.workspace = true
@ -35,10 +35,8 @@ tracing = { version = "0.1.34", features = ["log"] }
util.workspace = true util.workspace = true
zstd = "0.11" zstd = "0.11"
[build-dependencies]
prost-build.workspace = true
[dev-dependencies] [dev-dependencies]
collections.workspace = true collections = { workspace = true, features = ["test-support"] }
env_logger.workspace = true env_logger.workspace = true
gpui.workspace = true gpui = { workspace = true, features = ["test-support"] }
proto = { workspace = true, features = ["test-support"] }

View File

@ -1,7 +1,8 @@
use crate::{ErrorCode, ErrorCodeExt, ErrorExt, RpcError};
use super::{ use super::{
proto::{self, AnyTypedEnvelope, EnvelopedMessage, MessageStream, PeerId, RequestMessage}, proto::{
self, AnyTypedEnvelope, EnvelopedMessage, MessageStream, PeerId, Receipt, RequestMessage,
TypedEnvelope,
},
Connection, Connection,
}; };
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
@ -12,11 +13,11 @@ use futures::{
FutureExt, SinkExt, Stream, StreamExt, TryFutureExt, FutureExt, SinkExt, Stream, StreamExt, TryFutureExt,
}; };
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use proto::{ErrorCode, ErrorCodeExt, ErrorExt, RpcError};
use serde::{ser::SerializeStruct, Serialize}; use serde::{ser::SerializeStruct, Serialize};
use std::{ use std::{
fmt, future, fmt, future,
future::Future, future::Future,
marker::PhantomData,
sync::atomic::Ordering::SeqCst, sync::atomic::Ordering::SeqCst,
sync::{ sync::{
atomic::{self, AtomicU32}, atomic::{self, AtomicU32},
@ -57,46 +58,6 @@ impl fmt::Display for ConnectionId {
} }
} }
pub struct Receipt<T> {
pub sender_id: ConnectionId,
pub message_id: u32,
payload_type: PhantomData<T>,
}
impl<T> Clone for Receipt<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Receipt<T> {}
#[derive(Clone, Debug)]
pub struct TypedEnvelope<T> {
pub sender_id: ConnectionId,
pub original_sender_id: Option<PeerId>,
pub message_id: u32,
pub payload: T,
pub received_at: Instant,
}
impl<T> TypedEnvelope<T> {
pub fn original_sender_id(&self) -> Result<PeerId> {
self.original_sender_id
.ok_or_else(|| anyhow!("missing original_sender_id"))
}
}
impl<T: RequestMessage> TypedEnvelope<T> {
pub fn receipt(&self) -> Receipt<T> {
Receipt {
sender_id: self.sender_id,
message_id: self.message_id,
payload_type: PhantomData,
}
}
}
pub struct Peer { pub struct Peer {
epoch: AtomicU32, epoch: AtomicU32,
pub connections: RwLock<HashMap<ConnectionId, ConnectionState>>, pub connections: RwLock<HashMap<ConnectionId, ConnectionState>>,
@ -376,9 +337,12 @@ impl Peer {
"incoming stream response: requester resumed" "incoming stream response: requester resumed"
); );
} else { } else {
let message_type = let message_type = proto::build_typed_envelope(
proto::build_typed_envelope(connection_id, received_at, incoming) connection_id.into(),
.map(|p| p.payload_type_name()); received_at,
incoming,
)
.map(|p| p.payload_type_name());
tracing::warn!( tracing::warn!(
%connection_id, %connection_id,
message_id, message_id,
@ -391,16 +355,15 @@ impl Peer {
None None
} else { } else {
tracing::trace!(%connection_id, message_id, "incoming message: received"); tracing::trace!(%connection_id, message_id, "incoming message: received");
proto::build_typed_envelope(connection_id, received_at, incoming).or_else( proto::build_typed_envelope(connection_id.into(), received_at, incoming)
|| { .or_else(|| {
tracing::error!( tracing::error!(
%connection_id, %connection_id,
message_id, message_id,
"unable to construct a typed envelope" "unable to construct a typed envelope"
); );
None None
}, })
)
} }
} }
}); });
@ -475,7 +438,7 @@ impl Peer {
let (response, received_at) = response.await?; let (response, received_at) = response.await?;
Ok(TypedEnvelope { Ok(TypedEnvelope {
message_id: response.id, message_id: response.id,
sender_id: receiver_id, sender_id: receiver_id.into(),
original_sender_id: response.original_sender_id, original_sender_id: response.original_sender_id,
payload: T::Response::from_envelope(response) payload: T::Response::from_envelope(response)
.ok_or_else(|| anyhow!("received response of the wrong type"))?, .ok_or_else(|| anyhow!("received response of the wrong type"))?,
@ -619,7 +582,7 @@ impl Peer {
receipt: Receipt<T>, receipt: Receipt<T>,
response: T::Response, response: T::Response,
) -> Result<()> { ) -> Result<()> {
let connection = self.connection_state(receipt.sender_id)?; let connection = self.connection_state(receipt.sender_id.into())?;
let message_id = connection let message_id = connection
.next_message_id .next_message_id
.fetch_add(1, atomic::Ordering::SeqCst); .fetch_add(1, atomic::Ordering::SeqCst);
@ -634,7 +597,7 @@ impl Peer {
} }
pub fn end_stream<T: RequestMessage>(&self, receipt: Receipt<T>) -> Result<()> { pub fn end_stream<T: RequestMessage>(&self, receipt: Receipt<T>) -> Result<()> {
let connection = self.connection_state(receipt.sender_id)?; let connection = self.connection_state(receipt.sender_id.into())?;
let message_id = connection let message_id = connection
.next_message_id .next_message_id
.fetch_add(1, atomic::Ordering::SeqCst); .fetch_add(1, atomic::Ordering::SeqCst);
@ -656,7 +619,7 @@ impl Peer {
receipt: Receipt<T>, receipt: Receipt<T>,
response: proto::Error, response: proto::Error,
) -> Result<()> { ) -> Result<()> {
let connection = self.connection_state(receipt.sender_id)?; let connection = self.connection_state(receipt.sender_id.into())?;
let message_id = connection let message_id = connection
.next_message_id .next_message_id
.fetch_add(1, atomic::Ordering::SeqCst); .fetch_add(1, atomic::Ordering::SeqCst);
@ -674,7 +637,7 @@ impl Peer {
&self, &self,
envelope: Box<dyn AnyTypedEnvelope>, envelope: Box<dyn AnyTypedEnvelope>,
) -> Result<()> { ) -> Result<()> {
let connection = self.connection_state(envelope.sender_id())?; let connection = self.connection_state(envelope.sender_id().into())?;
let response = ErrorCode::Internal let response = ErrorCode::Internal
.message(format!( .message(format!(
"message {} was not handled", "message {} was not handled",
@ -717,7 +680,6 @@ impl Serialize for Peer {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::TypedEnvelope;
use async_tungstenite::tungstenite::Message as WebSocketMessage; use async_tungstenite::tungstenite::Message as WebSocketMessage;
use gpui::TestAppContext; use gpui::TestAppContext;

View File

@ -1,520 +1,11 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use super::{entity_messages, messages, request_messages, ConnectionId, TypedEnvelope}; use anyhow::anyhow;
use anyhow::{anyhow, Result};
use async_tungstenite::tungstenite::Message as WebSocketMessage; use async_tungstenite::tungstenite::Message as WebSocketMessage;
use collections::HashMap;
use futures::{SinkExt as _, StreamExt as _}; use futures::{SinkExt as _, StreamExt as _};
use prost::Message as _; pub use proto::{Message as _, *};
use serde::Serialize;
use std::any::{Any, TypeId};
use std::time::Instant; use std::time::Instant;
use std::{ use std::{fmt::Debug, io};
cmp,
fmt::Debug,
io, iter,
time::{Duration, SystemTime, UNIX_EPOCH},
};
use std::{fmt, mem};
include!(concat!(env!("OUT_DIR"), "/zed.messages.rs"));
pub trait EnvelopedMessage: Clone + Debug + Serialize + Sized + Send + Sync + 'static {
const NAME: &'static str;
const PRIORITY: MessagePriority;
fn into_envelope(
self,
id: u32,
responding_to: Option<u32>,
original_sender_id: Option<PeerId>,
) -> Envelope;
fn from_envelope(envelope: Envelope) -> Option<Self>;
}
pub trait EntityMessage: EnvelopedMessage {
type Entity;
fn remote_entity_id(&self) -> u64;
}
pub trait RequestMessage: EnvelopedMessage {
type Response: EnvelopedMessage;
}
pub trait AnyTypedEnvelope: 'static + Send + Sync {
fn payload_type_id(&self) -> TypeId;
fn payload_type_name(&self) -> &'static str;
fn as_any(&self) -> &dyn Any;
fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync>;
fn is_background(&self) -> bool;
fn original_sender_id(&self) -> Option<PeerId>;
fn sender_id(&self) -> ConnectionId;
fn message_id(&self) -> u32;
}
pub enum MessagePriority {
Foreground,
Background,
}
impl<T: EnvelopedMessage> AnyTypedEnvelope for TypedEnvelope<T> {
fn payload_type_id(&self) -> TypeId {
TypeId::of::<T>()
}
fn payload_type_name(&self) -> &'static str {
T::NAME
}
fn as_any(&self) -> &dyn Any {
self
}
fn into_any(self: Box<Self>) -> Box<dyn Any + Send + Sync> {
self
}
fn is_background(&self) -> bool {
matches!(T::PRIORITY, MessagePriority::Background)
}
fn original_sender_id(&self) -> Option<PeerId> {
self.original_sender_id
}
fn sender_id(&self) -> ConnectionId {
self.sender_id
}
fn message_id(&self) -> u32 {
self.message_id
}
}
impl PeerId {
pub fn from_u64(peer_id: u64) -> Self {
let owner_id = (peer_id >> 32) as u32;
let id = peer_id as u32;
Self { owner_id, id }
}
pub fn as_u64(self) -> u64 {
((self.owner_id as u64) << 32) | (self.id as u64)
}
}
impl Copy for PeerId {}
impl Eq for PeerId {}
impl Ord for PeerId {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.owner_id
.cmp(&other.owner_id)
.then_with(|| self.id.cmp(&other.id))
}
}
impl PartialOrd for PeerId {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl std::hash::Hash for PeerId {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.owner_id.hash(state);
self.id.hash(state);
}
}
impl fmt::Display for PeerId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}/{}", self.owner_id, self.id)
}
}
messages!(
(Ack, Foreground),
(AckBufferOperation, Background),
(AckChannelMessage, Background),
(AddNotification, Foreground),
(AddProjectCollaborator, Foreground),
(ApplyCodeAction, Background),
(ApplyCodeActionResponse, Background),
(ApplyCompletionAdditionalEdits, Background),
(ApplyCompletionAdditionalEditsResponse, Background),
(BufferReloaded, Foreground),
(BufferSaved, Foreground),
(Call, Foreground),
(CallCanceled, Foreground),
(CancelCall, Foreground),
(ChannelMessageSent, Foreground),
(ChannelMessageUpdate, Foreground),
(CompleteWithLanguageModel, Background),
(ComputeEmbeddings, Background),
(ComputeEmbeddingsResponse, Background),
(CopyProjectEntry, Foreground),
(CountTokensWithLanguageModel, Background),
(CountTokensResponse, Background),
(CreateBufferForPeer, Foreground),
(CreateChannel, Foreground),
(CreateChannelResponse, Foreground),
(CreateProjectEntry, Foreground),
(CreateRoom, Foreground),
(CreateRoomResponse, Foreground),
(DeclineCall, Foreground),
(DeleteChannel, Foreground),
(DeleteNotification, Foreground),
(UpdateNotification, Foreground),
(DeleteProjectEntry, Foreground),
(EndStream, Foreground),
(Error, Foreground),
(ExpandProjectEntry, Foreground),
(ExpandProjectEntryResponse, Foreground),
(Follow, Foreground),
(FollowResponse, Foreground),
(FormatBuffers, Foreground),
(FormatBuffersResponse, Foreground),
(FuzzySearchUsers, Foreground),
(GetCachedEmbeddings, Background),
(GetCachedEmbeddingsResponse, Background),
(GetChannelMembers, Foreground),
(GetChannelMembersResponse, Foreground),
(GetChannelMessages, Background),
(GetChannelMessagesById, Background),
(GetChannelMessagesResponse, Background),
(GetCodeActions, Background),
(GetCodeActionsResponse, Background),
(GetCompletions, Background),
(GetCompletionsResponse, Background),
(GetDefinition, Background),
(GetDefinitionResponse, Background),
(GetDocumentHighlights, Background),
(GetDocumentHighlightsResponse, Background),
(GetHover, Background),
(GetHoverResponse, Background),
(GetNotifications, Foreground),
(GetNotificationsResponse, Foreground),
(GetPrivateUserInfo, Foreground),
(GetPrivateUserInfoResponse, Foreground),
(GetProjectSymbols, Background),
(GetProjectSymbolsResponse, Background),
(GetReferences, Background),
(GetReferencesResponse, Background),
(GetSupermavenApiKey, Background),
(GetSupermavenApiKeyResponse, Background),
(GetTypeDefinition, Background),
(GetTypeDefinitionResponse, Background),
(GetImplementation, Background),
(GetImplementationResponse, Background),
(GetUsers, Foreground),
(Hello, Foreground),
(IncomingCall, Foreground),
(InlayHints, Background),
(InlayHintsResponse, Background),
(InviteChannelMember, Foreground),
(JoinChannel, Foreground),
(JoinChannelBuffer, Foreground),
(JoinChannelBufferResponse, Foreground),
(JoinChannelChat, Foreground),
(JoinChannelChatResponse, Foreground),
(JoinProject, Foreground),
(JoinHostedProject, Foreground),
(JoinProjectResponse, Foreground),
(JoinRoom, Foreground),
(JoinRoomResponse, Foreground),
(LanguageModelResponse, Background),
(LeaveChannelBuffer, Background),
(LeaveChannelChat, Foreground),
(LeaveProject, Foreground),
(LeaveRoom, Foreground),
(MarkNotificationRead, Foreground),
(MoveChannel, Foreground),
(OnTypeFormatting, Background),
(OnTypeFormattingResponse, Background),
(OpenBufferById, Background),
(OpenBufferByPath, Background),
(OpenBufferForSymbol, Background),
(OpenBufferForSymbolResponse, Background),
(OpenBufferResponse, Background),
(PerformRename, Background),
(PerformRenameResponse, Background),
(Ping, Foreground),
(PrepareRename, Background),
(PrepareRenameResponse, Background),
(ProjectEntryResponse, Foreground),
(RefreshInlayHints, Foreground),
(RejoinChannelBuffers, Foreground),
(RejoinChannelBuffersResponse, Foreground),
(RejoinRoom, Foreground),
(RejoinRoomResponse, Foreground),
(ReloadBuffers, Foreground),
(ReloadBuffersResponse, Foreground),
(RemoveChannelMember, Foreground),
(RemoveChannelMessage, Foreground),
(UpdateChannelMessage, Foreground),
(RemoveContact, Foreground),
(RemoveProjectCollaborator, Foreground),
(RenameChannel, Foreground),
(RenameChannelResponse, Foreground),
(RenameProjectEntry, Foreground),
(RequestContact, Foreground),
(ResolveCompletionDocumentation, Background),
(ResolveCompletionDocumentationResponse, Background),
(ResolveInlayHint, Background),
(ResolveInlayHintResponse, Background),
(RespondToChannelInvite, Foreground),
(RespondToContactRequest, Foreground),
(RoomUpdated, Foreground),
(SaveBuffer, Foreground),
(SetChannelMemberRole, Foreground),
(SetChannelVisibility, Foreground),
(SearchProject, Background),
(SearchProjectResponse, Background),
(SendChannelMessage, Background),
(SendChannelMessageResponse, Background),
(ShareProject, Foreground),
(ShareProjectResponse, Foreground),
(ShowContacts, Foreground),
(StartLanguageServer, Foreground),
(SubscribeToChannels, Foreground),
(SynchronizeBuffers, Foreground),
(SynchronizeBuffersResponse, Foreground),
(TaskContextForLocation, Background),
(TaskContext, Background),
(TaskTemplates, Background),
(TaskTemplatesResponse, Background),
(Test, Foreground),
(Unfollow, Foreground),
(UnshareProject, Foreground),
(UpdateBuffer, Foreground),
(UpdateBufferFile, Foreground),
(UpdateChannelBuffer, Foreground),
(UpdateChannelBufferCollaborators, Foreground),
(UpdateChannels, Foreground),
(UpdateUserChannels, Foreground),
(UpdateContacts, Foreground),
(UpdateDiagnosticSummary, Foreground),
(UpdateDiffBase, Foreground),
(UpdateFollowers, Foreground),
(UpdateInviteInfo, Foreground),
(UpdateLanguageServer, Foreground),
(UpdateParticipantLocation, Foreground),
(UpdateProject, Foreground),
(UpdateProjectCollaborator, Foreground),
(UpdateWorktree, Foreground),
(UpdateWorktreeSettings, Foreground),
(UsersResponse, Foreground),
(LspExtExpandMacro, Background),
(LspExtExpandMacroResponse, Background),
(SetRoomParticipantRole, Foreground),
(BlameBuffer, Foreground),
(BlameBufferResponse, Foreground),
(CreateDevServerProject, Background),
(CreateDevServerProjectResponse, Foreground),
(CreateDevServer, Foreground),
(CreateDevServerResponse, Foreground),
(DevServerInstructions, Foreground),
(ShutdownDevServer, Foreground),
(ReconnectDevServer, Foreground),
(ReconnectDevServerResponse, Foreground),
(ShareDevServerProject, Foreground),
(JoinDevServerProject, Foreground),
(RejoinRemoteProjects, Foreground),
(RejoinRemoteProjectsResponse, Foreground),
(MultiLspQuery, Background),
(MultiLspQueryResponse, Background),
(DevServerProjectsUpdate, Foreground),
(ValidateDevServerProjectRequest, Background),
(DeleteDevServer, Foreground),
(DeleteDevServerProject, Foreground),
(RegenerateDevServerToken, Foreground),
(RegenerateDevServerTokenResponse, Foreground),
(RenameDevServer, Foreground),
(OpenNewBuffer, Foreground),
(RestartLanguageServers, Foreground),
);
request_messages!(
(ApplyCodeAction, ApplyCodeActionResponse),
(
ApplyCompletionAdditionalEdits,
ApplyCompletionAdditionalEditsResponse
),
(Call, Ack),
(CancelCall, Ack),
(CopyProjectEntry, ProjectEntryResponse),
(CompleteWithLanguageModel, LanguageModelResponse),
(ComputeEmbeddings, ComputeEmbeddingsResponse),
(CountTokensWithLanguageModel, CountTokensResponse),
(CreateChannel, CreateChannelResponse),
(CreateProjectEntry, ProjectEntryResponse),
(CreateRoom, CreateRoomResponse),
(DeclineCall, Ack),
(DeleteChannel, Ack),
(DeleteProjectEntry, ProjectEntryResponse),
(ExpandProjectEntry, ExpandProjectEntryResponse),
(Follow, FollowResponse),
(FormatBuffers, FormatBuffersResponse),
(FuzzySearchUsers, UsersResponse),
(GetCachedEmbeddings, GetCachedEmbeddingsResponse),
(GetChannelMembers, GetChannelMembersResponse),
(GetChannelMessages, GetChannelMessagesResponse),
(GetChannelMessagesById, GetChannelMessagesResponse),
(GetCodeActions, GetCodeActionsResponse),
(GetCompletions, GetCompletionsResponse),
(GetDefinition, GetDefinitionResponse),
(GetImplementation, GetImplementationResponse),
(GetDocumentHighlights, GetDocumentHighlightsResponse),
(GetHover, GetHoverResponse),
(GetNotifications, GetNotificationsResponse),
(GetPrivateUserInfo, GetPrivateUserInfoResponse),
(GetProjectSymbols, GetProjectSymbolsResponse),
(GetReferences, GetReferencesResponse),
(GetSupermavenApiKey, GetSupermavenApiKeyResponse),
(GetTypeDefinition, GetTypeDefinitionResponse),
(GetUsers, UsersResponse),
(IncomingCall, Ack),
(InlayHints, InlayHintsResponse),
(InviteChannelMember, Ack),
(JoinChannel, JoinRoomResponse),
(JoinChannelBuffer, JoinChannelBufferResponse),
(JoinChannelChat, JoinChannelChatResponse),
(JoinHostedProject, JoinProjectResponse),
(JoinProject, JoinProjectResponse),
(JoinRoom, JoinRoomResponse),
(LeaveChannelBuffer, Ack),
(LeaveRoom, Ack),
(MarkNotificationRead, Ack),
(MoveChannel, Ack),
(OnTypeFormatting, OnTypeFormattingResponse),
(OpenBufferById, OpenBufferResponse),
(OpenBufferByPath, OpenBufferResponse),
(OpenBufferForSymbol, OpenBufferForSymbolResponse),
(OpenNewBuffer, OpenBufferResponse),
(PerformRename, PerformRenameResponse),
(Ping, Ack),
(PrepareRename, PrepareRenameResponse),
(RefreshInlayHints, Ack),
(RejoinChannelBuffers, RejoinChannelBuffersResponse),
(RejoinRoom, RejoinRoomResponse),
(ReloadBuffers, ReloadBuffersResponse),
(RemoveChannelMember, Ack),
(RemoveChannelMessage, Ack),
(UpdateChannelMessage, Ack),
(RemoveContact, Ack),
(RenameChannel, RenameChannelResponse),
(RenameProjectEntry, ProjectEntryResponse),
(RequestContact, Ack),
(
ResolveCompletionDocumentation,
ResolveCompletionDocumentationResponse
),
(ResolveInlayHint, ResolveInlayHintResponse),
(RespondToChannelInvite, Ack),
(RespondToContactRequest, Ack),
(SaveBuffer, BufferSaved),
(SearchProject, SearchProjectResponse),
(SendChannelMessage, SendChannelMessageResponse),
(SetChannelMemberRole, Ack),
(SetChannelVisibility, Ack),
(ShareProject, ShareProjectResponse),
(SynchronizeBuffers, SynchronizeBuffersResponse),
(TaskContextForLocation, TaskContext),
(TaskTemplates, TaskTemplatesResponse),
(Test, Test),
(UpdateBuffer, Ack),
(UpdateParticipantLocation, Ack),
(UpdateProject, Ack),
(UpdateWorktree, Ack),
(LspExtExpandMacro, LspExtExpandMacroResponse),
(SetRoomParticipantRole, Ack),
(BlameBuffer, BlameBufferResponse),
(CreateDevServerProject, CreateDevServerProjectResponse),
(CreateDevServer, CreateDevServerResponse),
(ShutdownDevServer, Ack),
(ShareDevServerProject, ShareProjectResponse),
(JoinDevServerProject, JoinProjectResponse),
(RejoinRemoteProjects, RejoinRemoteProjectsResponse),
(ReconnectDevServer, ReconnectDevServerResponse),
(ValidateDevServerProjectRequest, Ack),
(MultiLspQuery, MultiLspQueryResponse),
(DeleteDevServer, Ack),
(DeleteDevServerProject, Ack),
(RegenerateDevServerToken, RegenerateDevServerTokenResponse),
(RenameDevServer, Ack),
(RestartLanguageServers, Ack)
);
entity_messages!(
{project_id, ShareProject},
AddProjectCollaborator,
ApplyCodeAction,
ApplyCompletionAdditionalEdits,
BlameBuffer,
BufferReloaded,
BufferSaved,
CopyProjectEntry,
CreateBufferForPeer,
CreateProjectEntry,
DeleteProjectEntry,
ExpandProjectEntry,
FormatBuffers,
GetCodeActions,
GetCompletions,
GetDefinition,
GetImplementation,
GetDocumentHighlights,
GetHover,
GetProjectSymbols,
GetReferences,
GetTypeDefinition,
InlayHints,
JoinProject,
LeaveProject,
MultiLspQuery,
RestartLanguageServers,
OnTypeFormatting,
OpenNewBuffer,
OpenBufferById,
OpenBufferByPath,
OpenBufferForSymbol,
PerformRename,
PrepareRename,
RefreshInlayHints,
ReloadBuffers,
RemoveProjectCollaborator,
RenameProjectEntry,
ResolveCompletionDocumentation,
ResolveInlayHint,
SaveBuffer,
SearchProject,
StartLanguageServer,
SynchronizeBuffers,
TaskContextForLocation,
TaskTemplates,
UnshareProject,
UpdateBuffer,
UpdateBufferFile,
UpdateDiagnosticSummary,
UpdateDiffBase,
UpdateLanguageServer,
UpdateProject,
UpdateProjectCollaborator,
UpdateWorktree,
UpdateWorktreeSettings,
LspExtExpandMacro,
);
entity_messages!(
{channel_id, Channel},
ChannelMessageSent,
ChannelMessageUpdate,
RemoveChannelMessage,
UpdateChannelMessage,
UpdateChannelBuffer,
UpdateChannelBufferCollaborators,
);
const KIB: usize = 1024; const KIB: usize = 1024;
const MIB: usize = KIB * 1024; const MIB: usize = KIB * 1024;
@ -615,109 +106,6 @@ where
} }
} }
impl From<Timestamp> for SystemTime {
fn from(val: Timestamp) -> Self {
UNIX_EPOCH
.checked_add(Duration::new(val.seconds, val.nanos))
.unwrap()
}
}
impl From<SystemTime> for Timestamp {
fn from(time: SystemTime) -> Self {
let duration = time.duration_since(UNIX_EPOCH).unwrap();
Self {
seconds: duration.as_secs(),
nanos: duration.subsec_nanos(),
}
}
}
impl From<u128> for Nonce {
fn from(nonce: u128) -> Self {
let upper_half = (nonce >> 64) as u64;
let lower_half = nonce as u64;
Self {
upper_half,
lower_half,
}
}
}
impl From<Nonce> for u128 {
fn from(nonce: Nonce) -> Self {
let upper_half = (nonce.upper_half as u128) << 64;
let lower_half = nonce.lower_half as u128;
upper_half | lower_half
}
}
pub fn split_worktree_update(
mut message: UpdateWorktree,
max_chunk_size: usize,
) -> impl Iterator<Item = UpdateWorktree> {
let mut done_files = false;
let mut repository_map = message
.updated_repositories
.into_iter()
.map(|repo| (repo.work_directory_id, repo))
.collect::<HashMap<_, _>>();
iter::from_fn(move || {
if done_files {
return None;
}
let updated_entries_chunk_size = cmp::min(message.updated_entries.len(), max_chunk_size);
let updated_entries: Vec<_> = message
.updated_entries
.drain(..updated_entries_chunk_size)
.collect();
let removed_entries_chunk_size = cmp::min(message.removed_entries.len(), max_chunk_size);
let removed_entries = message
.removed_entries
.drain(..removed_entries_chunk_size)
.collect();
done_files = message.updated_entries.is_empty() && message.removed_entries.is_empty();
let mut updated_repositories = Vec::new();
if !repository_map.is_empty() {
for entry in &updated_entries {
if let Some(repo) = repository_map.remove(&entry.id) {
updated_repositories.push(repo)
}
}
}
let removed_repositories = if done_files {
mem::take(&mut message.removed_repositories)
} else {
Default::default()
};
if done_files {
updated_repositories.extend(mem::take(&mut repository_map).into_values());
}
Some(UpdateWorktree {
project_id: message.project_id,
worktree_id: message.worktree_id,
root_name: message.root_name.clone(),
abs_path: message.abs_path.clone(),
updated_entries,
removed_entries,
scan_id: message.scan_id,
is_last_update: done_files && message.is_last_update,
updated_repositories,
removed_repositories,
})
})
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -753,28 +141,4 @@ mod tests {
stream.read().await.unwrap(); stream.read().await.unwrap();
assert!(stream.encoding_buffer.capacity() <= MAX_BUFFER_LEN); assert!(stream.encoding_buffer.capacity() <= MAX_BUFFER_LEN);
} }
#[gpui::test]
fn test_converting_peer_id_from_and_to_u64() {
let peer_id = PeerId {
owner_id: 10,
id: 3,
};
assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
let peer_id = PeerId {
owner_id: u32::MAX,
id: 3,
};
assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
let peer_id = PeerId {
owner_id: 10,
id: u32::MAX,
};
assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
let peer_id = PeerId {
owner_id: u32::MAX,
id: u32::MAX,
};
assert_eq!(PeerId::from_u64(peer_id.as_u64()), peer_id);
}
} }

View File

@ -1,16 +1,15 @@
pub mod auth; pub mod auth;
mod conn; mod conn;
mod error;
mod extension; mod extension;
mod notification; mod notification;
mod peer; mod peer;
pub mod proto; pub mod proto;
pub use conn::Connection; pub use conn::Connection;
pub use error::*;
pub use extension::*; pub use extension::*;
pub use notification::*; pub use notification::*;
pub use peer::*; pub use peer::*;
pub use proto::{error::*, Receipt, TypedEnvelope};
mod macros; mod macros;
pub const PROTOCOL_VERSION: u32 = 68; pub const PROTOCOL_VERSION: u32 = 68;