1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// wire-rs: encrypted protocol between Ark and host
// Copyright 2026 Dark Bio AG. All rights reserved.
//! Errors returned by protocol methods and promises.
use super::schema;
use crate::transport;
use std::convert::Infallible;
use std::sync::Arc;
/// Failure of a protocol operation. A remote application's error is carried by
/// [`Error::Remote`]; it does not by itself end the session.
#[derive(Clone, Debug, thiserror::Error)]
pub enum Error {
/// The session or server was closed locally, including by dropping its owner.
#[error("wire protocol closed")]
Closed,
/// The operation's absolute deadline expired. Remote work may still run.
#[error("wire operation timed out")]
Timeout,
/// The underlying transport failed or the peer reset the session.
#[error("wire transport failed: {0}")]
Transport(#[from] Arc<transport::Error>),
/// The peer returned an application error for this request.
#[error("wire peer failed the request, code {}: {}", .0.code, .0.msg)]
Remote(schema::Error),
/// The response's `Message` variant does not match the type requested by
/// `Promise::wait()`. This does not end the session.
#[error("wire response type mismatch: expected {expected}, received {received}")]
UnexpectedResponse {
/// Expected protobuf message type.
expected: &'static str,
/// Received protobuf message type.
received: &'static str,
},
/// The submitted message cannot be sent from this session's side. Reported
/// through the request or reply promise; this error does not end the session.
#[error("wire message cannot be sent in this direction: {0}")]
WrongDirection(&'static str),
/// The encoded message exceeds the transport's sending limit.
#[error("wire message too large: {0} bytes")]
TooLarge(usize),
/// The peer sent an invalid envelope or payload. The session closes when this
/// is detected. Nested payloads are checked only when `recv()` or `wait()`
/// reads them.
#[error("wire peer sent a malformed message")]
Malformed,
/// A peer request would exceed the session's request limit. Also returned if
/// the limit is lowered below usage. Carries the configured request limit.
/// This closes the session.
#[error("wire inbound request limit exceeded: {0}")]
InboundRequestLimitExceeded(usize),
/// Buffering an incoming envelope would exceed the session's byte limit.
/// Also returned if the limit is lowered below usage. Carries the configured
/// byte limit. This closes the session.
#[error("wire inbound byte limit exceeded: {0}")]
InboundByteLimitExceeded(usize),
}
impl From<transport::Error> for Error {
/// Wraps a transport error in an `Arc` so pending promises can share it.
fn from(error: transport::Error) -> Self {
Self::Transport(Arc::new(error))
}
}
impl From<schema::Error> for Error {
/// Wraps the peer's error code and message in `Error::Remote`.
fn from(error: schema::Error) -> Self {
Self::Remote(error)
}
}
impl From<Infallible> for Error {
/// Allows `Promise::wait()` to return `Message` without extracting a variant.
fn from(error: Infallible) -> Self {
match error {}
}
}
impl Error {
/// Whether a session or server ending with this error did so in an orderly
/// way, through a local close, a peer reset or the stream ending.
pub(super) fn orderly(&self) -> bool {
match self {
Self::Closed => true,
Self::Transport(error) => matches!(
**error,
transport::Error::SessionReset | transport::Error::Terminated
),
_ => false,
}
}
/// The error as a log reason, a transport failure named by the transport's
/// own error rather than by the wrapping one.
pub(super) fn reason(&self) -> &dyn std::fmt::Display {
match self {
Self::Transport(error) => error.as_ref(),
other => other,
}
}
}
impl schema::Error {
/// Builds an error with a numeric code and a human-readable message.
/// Codes from 0x100 are request-specific. Use [`Self::reserved`] for named
/// protocol errors.
pub fn new(code: u64, msg: impl Into<String>) -> Self {
Self {
code,
msg: msg.into(),
}
}
/// Builds an error from a reserved protocol code and a human-readable message.
pub fn reserved(code: schema::ReservedErrors, msg: impl Into<String>) -> Self {
Self::new(code as u64, msg)
}
}