Skip to main content

max / makenotwork

2.5 KB · 82 lines History Blame Raw
1 //! Crate error type.
2 //!
3 //! [`ChatError::Host`] is the seam for the host app: a trait impl that fails in
4 //! the database or in its own authz layer boxes that error rather than the crate
5 //! trying to name every failure either consumer might have.
6
7 use std::time::Duration;
8
9 /// Which budget a connection ran out of.
10 ///
11 /// Worth distinguishing: [`LimitScope::User`] means this client should close a
12 /// tab, while [`LimitScope::Global`] means the process is saturated and is a
13 /// signal an operator needs, not an end user.
14 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
15 pub enum LimitScope {
16 /// This user holds too many concurrent connections.
17 User,
18 /// The process is at its total connection budget.
19 Global,
20 }
21
22 impl std::fmt::Display for LimitScope {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 match self {
25 Self::User => f.write_str("per-user"),
26 Self::Global => f.write_str("global"),
27 }
28 }
29 }
30
31 /// Anything that can go wrong in the crate or in a host's trait impl.
32 #[derive(Debug, thiserror::Error)]
33 pub enum ChatError {
34 #[error(
35 "retention exceeds the crate ceiling (asked for {max_age:?} / {max_messages} messages)"
36 )]
37 RetentionTooLong {
38 max_age: Duration,
39 max_messages: usize,
40 },
41
42 #[error("retention must be non-zero in both bounds")]
43 RetentionTooShort,
44
45 #[error("message is {len} characters, over the {max} character limit")]
46 MessageTooLong { len: usize, max: usize },
47
48 #[error("message is empty")]
49 MessageEmpty,
50
51 #[error("invalid send nonce")]
52 InvalidNonce,
53
54 #[error("room is closed")]
55 RoomClosed,
56
57 #[error("room is read-only")]
58 RoomReadOnly,
59
60 /// At capacity. The caller has already passed authz by this point, so this is
61 /// a resource refusal and belongs in the 503 family, not the 403 one.
62 #[error("connection limit reached ({0})")]
63 ConnectionLimit(LimitScope),
64
65 /// The sender did something the room refused. Distinct from a host error:
66 /// this is expected traffic, not a fault, and should not be logged as one.
67 #[error("send rejected: {0:?}")]
68 Rejected(crate::send::SendRejection),
69
70 /// An error from the host app's trait impl: a query failure, a session
71 /// lookup, anything the crate has no vocabulary for.
72 #[error("host error: {0}")]
73 Host(#[source] Box<dyn std::error::Error + Send + Sync>),
74 }
75
76 impl ChatError {
77 /// Wrap a host-side error.
78 pub fn host<E: std::error::Error + Send + Sync + 'static>(err: E) -> Self {
79 Self::Host(Box::new(err))
80 }
81 }
82