Skip to main content

privchat_protocol/
error_code.rs

1// Copyright 2025 Shanghai Boyu Information Technology Co., Ltd.
2// https://privchat.dev
3//
4// Author: zoujiaqing <zoujiaqing@gmail.com>
5//
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10//     http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18/// PrivChat IM Error Code v3.0
19///
20/// Error code design (priority-based):
21/// - 0: Success
22/// - 1-999: System errors (protocol, version, runtime stability) ⭐ First priority
23/// - 10000-19999: Common errors (authentication, parameters, permissions, rate limiting)
24/// - 20000-65535: Business errors (freely defined, allocated as needed)
25///
26/// Design principles: Simple and practical, flexible extension, within 65535 (u16 range)
27///
28/// **Important**: Error codes cannot be changed once published. New error codes must use new values.
29
30#[repr(u32)]
31#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
32pub enum ErrorCode {
33    // ==================== Success ====================
34    /// Operation successful
35    Ok = 0,
36
37    // ==================== System Errors (1-999) ⭐ First Priority ====================
38
39    // System Runtime (1-99)
40    /// System error
41    SystemError = 1,
42    /// System busy, please retry later
43    SystemBusy = 2,
44    /// Service unavailable
45    ServiceUnavailable = 3,
46    /// Internal error
47    InternalError = 4,
48    /// Operation timeout
49    Timeout = 5,
50    /// System maintenance
51    Maintenance = 6,
52    /// Database error
53    DatabaseError = 7,
54    /// Cache error
55    CacheError = 8,
56    /// Network error
57    NetworkError = 9,
58
59    // Protocol Related (100-199)
60    /// Protocol error
61    ProtocolError = 100,
62    /// Unsupported protocol version
63    UnsupportedProtocol = 101,
64    /// Invalid packet
65    InvalidPacket = 102,
66    /// Packet too large
67    PacketTooLarge = 103,
68    /// Encoding error
69    EncodingError = 104,
70    /// Decoding error
71    DecodingError = 105,
72
73    // Version Compatibility (200-299)
74    /// Version error
75    VersionError = 200,
76    /// Client version too old
77    ClientVersionTooOld = 201,
78    /// Client version too new
79    ClientVersionTooNew = 202,
80    /// Incompatible version
81    IncompatibleVersion = 203,
82    /// API deprecated
83    DeprecatedApi = 204,
84
85    // ==================== Common Errors (10000-19999) ====================
86    // Every 100 codes per segment
87
88    // Authentication/Authorization (10000-10099)
89    /// Authentication required
90    AuthRequired = 10000,
91    /// Invalid token
92    InvalidToken = 10001,
93    /// Token expired
94    TokenExpired = 10002,
95    /// Token revoked
96    TokenRevoked = 10003,
97    /// Permission denied
98    PermissionDenied = 10004,
99    /// Session expired
100    SessionExpired = 10005,
101    /// Session not found
102    SessionNotFound = 10006,
103    /// User banned
104    UserBanned = 10007,
105    /// IP address not allowed
106    IpNotAllowed = 10008,
107
108    // Request Parameters (10100-10199)
109    /// Invalid parameters
110    InvalidParams = 10100,
111    /// Missing required parameter
112    MissingRequiredParam = 10101,
113    /// Invalid parameter type
114    InvalidParamType = 10102,
115    /// Parameter out of range
116    ParamOutOfRange = 10103,
117    /// Invalid format
118    InvalidFormat = 10104,
119    /// Invalid JSON format
120    InvalidJson = 10105,
121    /// Payload too large
122    PayloadTooLarge = 10106,
123
124    // Business Rules (10200-10299)
125    /// Operation not allowed
126    OperationNotAllowed = 10200,
127    /// Resource not found
128    ResourceNotFound = 10201,
129    /// Resource already exists
130    ResourceAlreadyExists = 10202,
131    /// Resource deleted
132    ResourceDeleted = 10203,
133    /// Duplicate operation
134    DuplicateOperation = 10204,
135    /// Operation conflict
136    OperationConflict = 10205,
137
138    // Rate Limiting (10300-10399)
139    /// Rate limit exceeded
140    RateLimitExceeded = 10300,
141    /// Daily quota exceeded
142    DailyQuotaExceeded = 10301,
143    /// Monthly quota exceeded
144    MonthlyQuotaExceeded = 10302,
145    /// Concurrent limit exceeded
146    ConcurrentLimitExceeded = 10303,
147
148    // ==================== Business Errors (20000-65535) ====================
149    // Every 100 codes per segment, starting from 20000
150
151    // Message Basics (20000-20099)
152    /// Message not found
153    MessageNotFound = 20000,
154    /// Message deleted
155    MessageDeleted = 20001,
156    /// Message revoked
157    MessageRevoked = 20002,
158    /// Message send failed
159    MessageSendFailed = 20003,
160    /// Message too large
161    MessageTooLarge = 20004,
162    /// Invalid message type
163    MessageTypeInvalid = 20005,
164    /// Invalid message content
165    MessageContentInvalid = 20006,
166    /// Message cannot be revoked (timeout)
167    MessageCannotRevoke = 20007,
168    /// Message already read
169    MessageAlreadyRead = 20008,
170    /// Send message too fast
171    SendMessageTooFast = 20009,
172
173    // Offline Messages (20100-20199)
174    /// Offline message queue full
175    OfflineMessageFull = 20100,
176    /// Offline message expired
177    OfflineMessageExpired = 20101,
178
179    // User Basics (20200-20299)
180    /// User not found
181    UserNotFound = 20200,
182    /// User already exists
183    UserAlreadyExists = 20201,
184    /// User deleted
185    UserDeleted = 20202,
186    /// User banned
187    UserBannedAlt = 20203,
188    /// User not active
189    UserNotActive = 20204,
190    /// Invalid nickname
191    NicknameInvalid = 20205,
192    /// Invalid avatar
193    AvatarInvalid = 20206,
194
195    // Group Basics (20300-20399)
196    /// Group not found
197    GroupNotFound = 20300,
198    /// Group deleted
199    GroupDeleted = 20301,
200    /// Group full
201    GroupFull = 20302,
202    /// Not a group member
203    NotGroupMember = 20303,
204    /// Not a group admin
205    NotGroupAdmin = 20304,
206    /// Not a group owner
207    NotGroupOwner = 20305,
208    /// Group muted
209    GroupMuted = 20306,
210    /// Member muted
211    MemberMuted = 20307,
212    /// Member already in group
213    MemberAlreadyInGroup = 20308,
214    /// Cannot remove owner
215    CannotRemoveOwner = 20309,
216    /// Join approval required
217    JoinApprovalRequired = 20310,
218
219    // Friend Basics (20400-20499)
220    /// Friend not found
221    FriendNotFound = 20400,
222    /// Already friends
223    AlreadyFriends = 20401,
224    /// Blocked by user
225    BlockedByUser = 20402,
226    /// User in blacklist
227    UserInBlacklist = 20403,
228    /// Friend request expired
229    FriendRequestExpired = 20404,
230
231    // Channel Basics (20500-20599)
232    /// Channel not found
233    ChannelNotFound = 20500,
234    /// Channel deleted
235    ChannelDeleted = 20501,
236    /// Channel muted
237    ChannelMuted = 20502,
238
239    // File Basics (20600-20699)
240    /// File not found
241    FileNotFound = 20600,
242    /// File upload failed
243    FileUploadFailed = 20601,
244    /// File too large
245    FileTooLarge = 20602,
246    /// File type not allowed
247    FileTypeNotAllowed = 20603,
248    /// Upload token invalid
249    UploadTokenInvalid = 20604,
250    /// Upload token expired
251    UploadTokenExpired = 20605,
252    /// Storage quota exceeded
253    StorageQuotaExceeded = 20606,
254
255    // QR Code (20700-20799)
256    /// QR code not found
257    QRCodeNotFound = 20700,
258    /// QR code expired
259    QRCodeExpired = 20701,
260    /// QR code used
261    QRCodeUsed = 20702,
262    /// QR code revoked
263    QRCodeRevoked = 20703,
264    /// QR code limit exceeded
265    QRCodeLimitExceeded = 20704,
266
267    // Device (20800-20899)
268    /// Device not found
269    DeviceNotFound = 20800,
270    /// Device limit exceeded
271    DeviceLimitExceeded = 20801,
272    /// Device not verified
273    DeviceNotVerified = 20802,
274}
275
276impl ErrorCode {
277    /// Get the error code value
278    pub fn code(&self) -> u32 {
279        *self as u32
280    }
281
282    /// Get the error code message
283    pub fn message(&self) -> &'static str {
284        match self {
285            // Success
286            Self::Ok => "Operation successful",
287
288            // System Errors (1-999)
289            Self::SystemError => "System error",
290            Self::SystemBusy => "System busy, please retry later",
291            Self::ServiceUnavailable => "Service unavailable",
292            Self::InternalError => "Internal error",
293            Self::Timeout => "Operation timeout",
294            Self::Maintenance => "System maintenance",
295            Self::DatabaseError => "Database error",
296            Self::CacheError => "Cache error",
297            Self::NetworkError => "Network error",
298            Self::ProtocolError => "Protocol error",
299            Self::UnsupportedProtocol => "Unsupported protocol version",
300            Self::InvalidPacket => "Invalid packet",
301            Self::PacketTooLarge => "Packet too large",
302            Self::EncodingError => "Encoding error",
303            Self::DecodingError => "Decoding error",
304            Self::VersionError => "Version error",
305            Self::ClientVersionTooOld => "Client version too old",
306            Self::ClientVersionTooNew => "Client version too new",
307            Self::IncompatibleVersion => "Incompatible version",
308            Self::DeprecatedApi => "API deprecated",
309
310            // Common Errors (10000-19999)
311            Self::AuthRequired => "Authentication required",
312            Self::InvalidToken => "Invalid token",
313            Self::TokenExpired => "Token expired",
314            Self::TokenRevoked => "Token revoked",
315            Self::PermissionDenied => "Permission denied",
316            Self::SessionExpired => "Session expired",
317            Self::SessionNotFound => "Session not found",
318            Self::UserBanned => "User banned",
319            Self::IpNotAllowed => "IP address not allowed",
320            Self::InvalidParams => "Invalid parameters",
321            Self::MissingRequiredParam => "Missing required parameter",
322            Self::InvalidParamType => "Invalid parameter type",
323            Self::ParamOutOfRange => "Parameter out of range",
324            Self::InvalidFormat => "Invalid format",
325            Self::InvalidJson => "Invalid JSON format",
326            Self::PayloadTooLarge => "Payload too large",
327            Self::OperationNotAllowed => "Operation not allowed",
328            Self::ResourceNotFound => "Resource not found",
329            Self::ResourceAlreadyExists => "Resource already exists",
330            Self::ResourceDeleted => "Resource deleted",
331            Self::DuplicateOperation => "Duplicate operation",
332            Self::OperationConflict => "Operation conflict",
333            Self::RateLimitExceeded => "Rate limit exceeded",
334            Self::DailyQuotaExceeded => "Daily quota exceeded",
335            Self::MonthlyQuotaExceeded => "Monthly quota exceeded",
336            Self::ConcurrentLimitExceeded => "Concurrent limit exceeded",
337
338            // Business Errors (20000-65535)
339            Self::MessageNotFound => "Message not found",
340            Self::MessageDeleted => "Message deleted",
341            Self::MessageRevoked => "Message revoked",
342            Self::MessageSendFailed => "Message send failed",
343            Self::MessageTooLarge => "Message too large",
344            Self::MessageTypeInvalid => "Invalid message type",
345            Self::MessageContentInvalid => "Invalid message content",
346            Self::MessageCannotRevoke => "Message cannot be revoked (timeout)",
347            Self::MessageAlreadyRead => "Message already read",
348            Self::SendMessageTooFast => "Send message too fast",
349            Self::OfflineMessageFull => "Offline message queue full",
350            Self::OfflineMessageExpired => "Offline message expired",
351            Self::UserNotFound => "User not found",
352            Self::UserAlreadyExists => "User already exists",
353            Self::UserDeleted => "User deleted",
354            Self::UserBannedAlt => "User banned",
355            Self::UserNotActive => "User not active",
356            Self::NicknameInvalid => "Invalid nickname",
357            Self::AvatarInvalid => "Invalid avatar",
358            Self::GroupNotFound => "Group not found",
359            Self::GroupDeleted => "Group deleted",
360            Self::GroupFull => "Group full",
361            Self::NotGroupMember => "Not a group member",
362            Self::NotGroupAdmin => "Not a group admin",
363            Self::NotGroupOwner => "Not a group owner",
364            Self::GroupMuted => "Group muted",
365            Self::MemberMuted => "Member muted",
366            Self::MemberAlreadyInGroup => "Member already in group",
367            Self::CannotRemoveOwner => "Cannot remove owner",
368            Self::JoinApprovalRequired => "Join approval required",
369            Self::FriendNotFound => "Friend not found",
370            Self::AlreadyFriends => "Already friends",
371            Self::BlockedByUser => "Blocked by user",
372            Self::UserInBlacklist => "User in blacklist",
373            Self::FriendRequestExpired => "Friend request expired",
374            Self::ChannelNotFound => "Channel not found",
375            Self::ChannelDeleted => "Channel deleted",
376            Self::ChannelMuted => "Channel muted",
377            Self::FileNotFound => "File not found",
378            Self::FileUploadFailed => "File upload failed",
379            Self::FileTooLarge => "File too large",
380            Self::FileTypeNotAllowed => "File type not allowed",
381            Self::UploadTokenInvalid => "Upload token invalid",
382            Self::UploadTokenExpired => "Upload token expired",
383            Self::StorageQuotaExceeded => "Storage quota exceeded",
384            Self::QRCodeNotFound => "QR code not found",
385            Self::QRCodeExpired => "QR code expired",
386            Self::QRCodeUsed => "QR code used",
387            Self::QRCodeRevoked => "QR code revoked",
388            Self::QRCodeLimitExceeded => "QR code limit exceeded",
389            Self::DeviceNotFound => "Device not found",
390            Self::DeviceLimitExceeded => "Device limit exceeded",
391            Self::DeviceNotVerified => "Device not verified",
392        }
393    }
394
395    /// Convert from u32 to ErrorCode
396    pub fn from_code(code: u32) -> Option<Self> {
397        match code {
398            // Success
399            0 => Some(Self::Ok),
400
401            // System errors (1-999)
402            1 => Some(Self::SystemError),
403            2 => Some(Self::SystemBusy),
404            3 => Some(Self::ServiceUnavailable),
405            4 => Some(Self::InternalError),
406            5 => Some(Self::Timeout),
407            6 => Some(Self::Maintenance),
408            7 => Some(Self::DatabaseError),
409            8 => Some(Self::CacheError),
410            9 => Some(Self::NetworkError),
411            100 => Some(Self::ProtocolError),
412            101 => Some(Self::UnsupportedProtocol),
413            102 => Some(Self::InvalidPacket),
414            103 => Some(Self::PacketTooLarge),
415            104 => Some(Self::EncodingError),
416            105 => Some(Self::DecodingError),
417            200 => Some(Self::VersionError),
418            201 => Some(Self::ClientVersionTooOld),
419            202 => Some(Self::ClientVersionTooNew),
420            203 => Some(Self::IncompatibleVersion),
421            204 => Some(Self::DeprecatedApi),
422
423            // Common errors (10000-19999)
424            10000 => Some(Self::AuthRequired),
425            10001 => Some(Self::InvalidToken),
426            10002 => Some(Self::TokenExpired),
427            10003 => Some(Self::TokenRevoked),
428            10004 => Some(Self::PermissionDenied),
429            10005 => Some(Self::SessionExpired),
430            10006 => Some(Self::SessionNotFound),
431            10007 => Some(Self::UserBanned),
432            10008 => Some(Self::IpNotAllowed),
433            10100 => Some(Self::InvalidParams),
434            10101 => Some(Self::MissingRequiredParam),
435            10102 => Some(Self::InvalidParamType),
436            10103 => Some(Self::ParamOutOfRange),
437            10104 => Some(Self::InvalidFormat),
438            10105 => Some(Self::InvalidJson),
439            10106 => Some(Self::PayloadTooLarge),
440            10200 => Some(Self::OperationNotAllowed),
441            10201 => Some(Self::ResourceNotFound),
442            10202 => Some(Self::ResourceAlreadyExists),
443            10203 => Some(Self::ResourceDeleted),
444            10204 => Some(Self::DuplicateOperation),
445            10205 => Some(Self::OperationConflict),
446            10300 => Some(Self::RateLimitExceeded),
447            10301 => Some(Self::DailyQuotaExceeded),
448            10302 => Some(Self::MonthlyQuotaExceeded),
449            10303 => Some(Self::ConcurrentLimitExceeded),
450
451            // Business errors (20000-65535)
452            20000 => Some(Self::MessageNotFound),
453            20001 => Some(Self::MessageDeleted),
454            20002 => Some(Self::MessageRevoked),
455            20003 => Some(Self::MessageSendFailed),
456            20004 => Some(Self::MessageTooLarge),
457            20005 => Some(Self::MessageTypeInvalid),
458            20006 => Some(Self::MessageContentInvalid),
459            20007 => Some(Self::MessageCannotRevoke),
460            20008 => Some(Self::MessageAlreadyRead),
461            20009 => Some(Self::SendMessageTooFast),
462            20100 => Some(Self::OfflineMessageFull),
463            20101 => Some(Self::OfflineMessageExpired),
464            20200 => Some(Self::UserNotFound),
465            20201 => Some(Self::UserAlreadyExists),
466            20202 => Some(Self::UserDeleted),
467            20203 => Some(Self::UserBannedAlt),
468            20204 => Some(Self::UserNotActive),
469            20205 => Some(Self::NicknameInvalid),
470            20206 => Some(Self::AvatarInvalid),
471            20300 => Some(Self::GroupNotFound),
472            20301 => Some(Self::GroupDeleted),
473            20302 => Some(Self::GroupFull),
474            20303 => Some(Self::NotGroupMember),
475            20304 => Some(Self::NotGroupAdmin),
476            20305 => Some(Self::NotGroupOwner),
477            20306 => Some(Self::GroupMuted),
478            20307 => Some(Self::MemberMuted),
479            20308 => Some(Self::MemberAlreadyInGroup),
480            20309 => Some(Self::CannotRemoveOwner),
481            20310 => Some(Self::JoinApprovalRequired),
482            20400 => Some(Self::FriendNotFound),
483            20401 => Some(Self::AlreadyFriends),
484            20402 => Some(Self::BlockedByUser),
485            20403 => Some(Self::UserInBlacklist),
486            20404 => Some(Self::FriendRequestExpired),
487            20500 => Some(Self::ChannelNotFound),
488            20501 => Some(Self::ChannelDeleted),
489            20502 => Some(Self::ChannelMuted),
490            20600 => Some(Self::FileNotFound),
491            20601 => Some(Self::FileUploadFailed),
492            20602 => Some(Self::FileTooLarge),
493            20603 => Some(Self::FileTypeNotAllowed),
494            20604 => Some(Self::UploadTokenInvalid),
495            20605 => Some(Self::UploadTokenExpired),
496            20606 => Some(Self::StorageQuotaExceeded),
497            20700 => Some(Self::QRCodeNotFound),
498            20701 => Some(Self::QRCodeExpired),
499            20702 => Some(Self::QRCodeUsed),
500            20703 => Some(Self::QRCodeRevoked),
501            20704 => Some(Self::QRCodeLimitExceeded),
502            20800 => Some(Self::DeviceNotFound),
503            20801 => Some(Self::DeviceLimitExceeded),
504            20802 => Some(Self::DeviceNotVerified),
505
506            _ => None,
507        }
508    }
509
510    /// Check if this is a system error (first priority)
511    pub fn is_system_error(&self) -> bool {
512        let code = self.code();
513        code >= 1 && code < 1000
514    }
515
516    /// Check if this is a common error
517    pub fn is_common_error(&self) -> bool {
518        let code = self.code();
519        code >= 10000 && code < 20000
520    }
521
522    /// Check if this is a business error
523    pub fn is_business_error(&self) -> bool {
524        let code = self.code();
525        code >= 20000
526    }
527}
528
529impl Default for ErrorCode {
530    fn default() -> Self {
531        Self::Ok
532    }
533}
534
535impl std::fmt::Display for ErrorCode {
536    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
537        write!(f, "[{}] {}", self.code(), self.message())
538    }
539}
540
541#[cfg(test)]
542mod tests {
543    use super::*;
544
545    #[test]
546    fn test_error_code_values() {
547        assert_eq!(ErrorCode::Ok.code(), 0);
548
549        // System errors (1-999)
550        assert_eq!(ErrorCode::SystemBusy.code(), 2);
551        assert_eq!(ErrorCode::ProtocolError.code(), 100);
552        assert_eq!(ErrorCode::ClientVersionTooOld.code(), 201);
553
554        // Common errors (10000-19999)
555        assert_eq!(ErrorCode::AuthRequired.code(), 10000);
556        assert_eq!(ErrorCode::InvalidParams.code(), 10100);
557        assert_eq!(ErrorCode::RateLimitExceeded.code(), 10300);
558
559        // Business errors (20000+)
560        assert_eq!(ErrorCode::MessageNotFound.code(), 20000);
561        assert_eq!(ErrorCode::OfflineMessageFull.code(), 20100);
562        assert_eq!(ErrorCode::UserNotFound.code(), 20200);
563        assert_eq!(ErrorCode::GroupNotFound.code(), 20300);
564        assert_eq!(ErrorCode::FriendNotFound.code(), 20400);
565        assert_eq!(ErrorCode::FileNotFound.code(), 20600);
566    }
567
568    #[test]
569    fn test_error_code_messages() {
570        assert_eq!(ErrorCode::Ok.message(), "Operation successful");
571        assert_eq!(
572            ErrorCode::SystemBusy.message(),
573            "System busy, please retry later"
574        );
575        assert_eq!(ErrorCode::AuthRequired.message(), "Authentication required");
576        assert_eq!(ErrorCode::MessageNotFound.message(), "Message not found");
577    }
578
579    #[test]
580    fn test_error_code_classification() {
581        // System errors (first priority)
582        assert!(ErrorCode::SystemBusy.is_system_error());
583        assert!(!ErrorCode::SystemBusy.is_common_error());
584        assert!(!ErrorCode::SystemBusy.is_business_error());
585
586        // Common errors
587        assert!(!ErrorCode::AuthRequired.is_system_error());
588        assert!(ErrorCode::AuthRequired.is_common_error());
589        assert!(!ErrorCode::AuthRequired.is_business_error());
590
591        // Business errors
592        assert!(!ErrorCode::MessageNotFound.is_system_error());
593        assert!(!ErrorCode::MessageNotFound.is_common_error());
594        assert!(ErrorCode::MessageNotFound.is_business_error());
595    }
596
597    #[test]
598    fn test_error_code_from_code() {
599        assert_eq!(ErrorCode::from_code(0), Some(ErrorCode::Ok));
600        assert_eq!(ErrorCode::from_code(2), Some(ErrorCode::SystemBusy));
601        assert_eq!(ErrorCode::from_code(10000), Some(ErrorCode::AuthRequired));
602        assert_eq!(ErrorCode::from_code(10100), Some(ErrorCode::InvalidParams));
603        assert_eq!(
604            ErrorCode::from_code(20000),
605            Some(ErrorCode::MessageNotFound)
606        );
607        assert_eq!(ErrorCode::from_code(99999), None);
608    }
609
610    #[test]
611    fn test_error_code_display() {
612        let err = ErrorCode::AuthRequired;
613        assert_eq!(err.to_string(), "[10000] Authentication required");
614
615        let err = ErrorCode::SystemBusy;
616        assert_eq!(err.to_string(), "[2] System busy, please retry later");
617
618        let err = ErrorCode::GroupNotFound;
619        assert_eq!(err.to_string(), "[20300] Group not found");
620    }
621}