Skip to main content

wire/
lib.rs

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