vtx_sdk/
error.rs

1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4/// Plugin runtime error type (unified error model).
5///
6/// Defines all known errors that may occur during plugin execution.
7/// All errors support serialization and can be used for HTTP responses or log transmission.
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub enum VtxError {
10    /// Underlying database error (e.g., SQL execution failure, constraint conflicts).
11    DatabaseError(String),
12
13    /// Serialization or deserialization failure (e.g., JSON format mismatch).
14    SerializationError(String),
15
16    /// Authentication failed (includes suggested HTTP status code, e.g., 401 / 403).
17    AuthDenied(u16),
18
19    /// Insufficient permissions (e.g., attempting a write operation in a read-only environment).
20    PermissionDenied(String),
21
22    /// Resource not found (e.g., file, video, or user not found).
23    NotFound(String),
24
25    /// Internal plugin logic error (fallback type).
26    Internal(String),
27}
28
29impl VtxError {
30    /// Maps the `string` error message returned from the host side to a reasonably classified error type.
31    pub fn from_host_message(message: impl Into<String>) -> Self {
32        let msg = message.into();
33        let lower = msg.to_lowercase();
34
35        if lower.contains("permission denied") {
36            return VtxError::PermissionDenied(msg);
37        }
38
39        if lower.contains("uuid not found") || lower.contains("not found") {
40            return VtxError::NotFound(msg);
41        }
42
43        VtxError::Internal(msg)
44    }
45}
46
47impl fmt::Display for VtxError {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        match self {
50            VtxError::DatabaseError(msg) => write!(f, "Database error: {}", msg),
51            VtxError::SerializationError(msg) => write!(f, "Data serialization error: {}", msg),
52            VtxError::AuthDenied(code) => write!(f, "Authentication denied (Code: {})", code),
53            VtxError::PermissionDenied(msg) => write!(f, "Permission denied: {}", msg),
54            VtxError::NotFound(msg) => write!(f, "Resource not found: {}", msg),
55            VtxError::Internal(msg) => write!(f, "Internal error: {}", msg),
56        }
57    }
58}
59
60impl std::error::Error for VtxError {}
61
62/// Short alias for `VtxError`.
63pub type Error = VtxError;
64
65/// Plugin standard result type alias.
66///
67/// Recommended for use in all interfaces returning `VtxError` to ensure a unified error chain.
68pub type VtxResult<T> = std::result::Result<T, VtxError>;
69
70/// Short alias for `VtxResult`.
71pub type Result<T> = VtxResult<T>;
72
73#[cfg(test)]
74mod tests {
75    use super::VtxError;
76
77    #[test]
78    fn from_host_message_maps_permission_denied() {
79        let err = VtxError::from_host_message("Permission denied: read only");
80        match err {
81            VtxError::PermissionDenied(msg) => {
82                assert!(msg.contains("Permission denied"));
83            }
84            _ => panic!("expected PermissionDenied"),
85        }
86    }
87
88    #[test]
89    fn from_host_message_maps_not_found() {
90        let err = VtxError::from_host_message("UUID not found: 1234");
91        match err {
92            VtxError::NotFound(msg) => {
93                assert!(msg.contains("not found"));
94            }
95            _ => panic!("expected NotFound"),
96        }
97    }
98
99    #[test]
100    fn from_host_message_defaults_to_internal() {
101        let err = VtxError::from_host_message("something unexpected");
102        match err {
103            VtxError::Internal(msg) => {
104                assert!(msg.contains("unexpected"));
105            }
106            _ => panic!("expected Internal"),
107        }
108    }
109
110    #[test]
111    fn display_formats_errors() {
112        let err = VtxError::AuthDenied(401);
113        assert_eq!(err.to_string(), "Authentication denied (Code: 401)");
114
115        let err = VtxError::DatabaseError("boom".to_string());
116        assert_eq!(err.to_string(), "Database error: boom");
117    }
118}