1mod auth_context;
5#[cfg(test)]
6mod auth_tests;
7mod auth_token;
8mod capabilities;
9mod message_auth;
10mod message_delta;
11mod message_hosted;
12mod message_objects;
13mod message_pushpull;
14mod message_refs;
15mod message_status;
16mod native_pack;
17mod object_availability;
18mod object_graph;
19mod object_transfer;
20
21pub use auth_context::AuthContext;
22pub use auth_token::{AuthToken, TokenScope};
23pub use capabilities::{
24 CAPABILITY_CHUNKED_TRANSFER, CAPABILITY_PACK_TRANSFER, CAPABILITY_PARTIAL_FETCH,
25 CAPABILITY_RESUMABLE_TRANSFER, Capabilities, CapabilitySet,
26};
27pub use message_auth::{AuthMethod, Permission};
28pub use message_delta::{DeltaData, RequestDelta};
29pub use message_hosted::{
30 CreateHostedGrant, CreateHostedRepository, CreateNamespace, DeleteHostedGrant,
31 DeleteHostedRepository, DeleteNamespace, HarnessIdentity, HostedGrantCreated,
32 HostedGrantDeleted, HostedGrantInfo, HostedGrantUpdated, HostedGrantsList, HostedNamespaceInfo,
33 HostedRepositoryInfo, ListHostedGrants, ListHostedNamespaces, ListHostedRepositories,
34 NamespaceCreated, NamespaceDeleted, NamespaceUpdated, NamespacesList, ProgressCheckpoint,
35 RepositoriesList, RepositoryCreated, RepositoryDeleted, RepositoryUpdated, SessionDiffSummary,
36 SessionReportEnvelope, TranscriptAttachmentRef, UpdateHostedGrant, UpdateHostedRepository,
37 UpdateNamespace, UsageTotals, WorktreeChangeBaseline,
38};
39pub use message_objects::{HaveObjects, ObjectData, ObjectRequest, SendObjects, WantObjects};
40pub use message_pushpull::{
41 PARTIAL_FETCH_DISABLED, PARTIAL_FETCH_ENABLED, PARTIAL_FETCH_REQUIRED, PullComplete, PullReady,
42 PullRequest, PushComplete, PushReady, PushRequest, TRANSPORT_MODE_NATIVE_PACK,
43};
44pub use message_refs::{HeadInfo, ListRefs, RefEntry, RefFilter, RefUpdated, RefsList, UpdateRef};
45pub use message_status::{Error, ErrorCode, Status, StatusCode};
46pub use native_pack::{
47 NativePackBundle, PackChunkState, build_native_pack, install_received_pack, next_pack_chunk,
48 receive_pack_chunk,
49};
50pub use object_availability::{ObjectAvailabilityPlan, has_object, plan_object_availability};
51pub use object_graph::{
52 ObjectId, ObjectInfo, ObjectType, PlannedObject, StateClosureOptions, enumerate_state_closure,
53 enumerate_state_closure_plan, enumerate_state_closure_plan_with_options,
54 enumerate_state_closure_with_options, is_ancestor,
55};
56pub use object_transfer::{
57 chunk_bounds, chunk_count, chunk_offset, load_object_data, load_requested_object,
58 store_received_object,
59};
60
61pub const DEFAULT_PORT: u16 = 8421;
63
64pub const PROTOCOL_VERSION: u32 = 1;
66
67pub const MAX_MESSAGE_SIZE: usize = 64 * 1024 * 1024;
69
70#[derive(Debug, thiserror::Error)]
72pub enum ProtocolError {
73 #[error("io error: {0}")]
74 Io(#[from] std::io::Error),
75
76 #[error("serialization error: {0}")]
77 Serialization(String),
78
79 #[error("message too large: {size} bytes (max {max})")]
80 MessageTooLarge { size: usize, max: usize },
81
82 #[error("invalid message type: {0}")]
83 InvalidMessageType(u8),
84
85 #[error("protocol version mismatch: server={server}, client={client}")]
86 VersionMismatch { server: u32, client: u32 },
87
88 #[error("capability not supported: {0}")]
89 CapabilityNotSupported(String),
90
91 #[error("authentication failed: {0}")]
92 AuthenticationFailed(String),
93
94 #[error("authorization failed: {0}")]
95 AuthorizationFailed(String),
96
97 #[error("object not found: {0}")]
98 ObjectNotFound(String),
99
100 #[error("invalid state: {0}")]
101 InvalidState(String),
102
103 #[error("remote error: {0}")]
104 Remote(String),
105
106 #[error("remote failure ({code:?}): {message}")]
107 RemoteFailure {
108 code: ErrorCode,
109 message: String,
110 details: Option<String>,
111 },
112
113 #[error("lock error: {0}")]
114 LockError(String),
115}
116
117impl From<rmp_serde::encode::Error> for ProtocolError {
118 fn from(e: rmp_serde::encode::Error) -> Self {
119 ProtocolError::Serialization(e.to_string())
120 }
121}
122
123impl From<rmp_serde::decode::Error> for ProtocolError {
124 fn from(e: rmp_serde::decode::Error) -> Self {
125 ProtocolError::Serialization(e.to_string())
126 }
127}
128
129impl From<objects::error::HeddleError> for ProtocolError {
130 fn from(e: objects::error::HeddleError) -> Self {
131 ProtocolError::Remote(e.to_string())
132 }
133}
134
135impl ProtocolError {
136 pub fn client_message(&self) -> String {
137 match self {
138 ProtocolError::Io(_) => "network error".to_string(),
139 ProtocolError::Serialization(_) => "protocol error".to_string(),
140 ProtocolError::MessageTooLarge { .. } => "message too large".to_string(),
141 ProtocolError::InvalidMessageType(_) => "protocol error".to_string(),
142 ProtocolError::VersionMismatch { .. } => "protocol version mismatch".to_string(),
143 ProtocolError::CapabilityNotSupported(_) => "capability not supported".to_string(),
144 ProtocolError::AuthenticationFailed(_) => "permission denied".to_string(),
145 ProtocolError::AuthorizationFailed(_) => "permission denied".to_string(),
146 ProtocolError::ObjectNotFound(_) => "object not found".to_string(),
147 ProtocolError::InvalidState(_) => "invalid request state".to_string(),
148 ProtocolError::Remote(_) => "internal server error".to_string(),
149 ProtocolError::RemoteFailure { message, .. } => message.clone(),
150 ProtocolError::LockError(_) => "internal server error".to_string(),
151 }
152 }
153
154 pub fn error_code(&self) -> ErrorCode {
155 match self {
156 ProtocolError::Io(_) => ErrorCode::Network,
157 ProtocolError::Serialization(_) => ErrorCode::Protocol,
158 ProtocolError::MessageTooLarge { .. } => ErrorCode::Protocol,
159 ProtocolError::InvalidMessageType(_) => ErrorCode::Protocol,
160 ProtocolError::VersionMismatch { .. } => ErrorCode::Protocol,
161 ProtocolError::CapabilityNotSupported(_) => ErrorCode::Protocol,
162 ProtocolError::AuthenticationFailed(_) => ErrorCode::PermissionDenied,
163 ProtocolError::AuthorizationFailed(_) => ErrorCode::PermissionDenied,
164 ProtocolError::ObjectNotFound(_) => ErrorCode::NotFound,
165 ProtocolError::InvalidState(_) => ErrorCode::InvalidArgument,
166 ProtocolError::Remote(_) => ErrorCode::Server,
167 ProtocolError::RemoteFailure { code, .. } => *code,
168 ProtocolError::LockError(_) => ErrorCode::Server,
169 }
170 }
171
172 pub fn to_wire_error(&self, details: Option<String>) -> Error {
173 Error {
174 code: self.error_code(),
175 message: self.client_message(),
176 details,
177 }
178 }
179}
180
181pub type Result<T> = std::result::Result<T, ProtocolError>;