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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! Error handling for Tramex Tools

#[derive(serde::Deserialize, Debug, Clone)]
/// Error codes for Tramex Tools
pub enum ErrorCode {
    /// Not set
    NotSet = 0,

    /// WebSocket: Failed to connect
    WebSocketFailedToConnect,

    /// WebSocket: Error encoding message
    WebSocketErrorEncodingMessage,

    /// WebSocket: Error decoding message
    WebSocketErrorDecodingMessage,

    /// WebSocket: Unknown message received
    WebSocketUnknownMessageReceived,

    /// WebSocket: Unknown binary message received
    WebSocketUnknownBinaryMessageReceived,

    /// WebSocket: Error
    WebSocketError,

    /// WebSocket: Closed
    WebSocketClosed,

    /// WebSocket: Error closing
    WebSocketErrorClosing,

    /// File: No file selected
    FileNotSelected,

    /// File: Error reading file
    FileErrorReadingFile,

    /// File: Not ready
    FileNotReady,

    /// File: Invalid encoding (wrong UTF-8)
    FileInvalidEncoding,

    /// Hexe decoding failed
    HexeDecodingError,

    /// File : End of the file
    EndOfFile,

    /// File: Error while parsing the file
    FileParsing,

    /// Request error
    RequestError,

    /// ParsingLayerNotImplemented
    ParsingLayerNotImplemented,
}

impl Default for ErrorCode {
    fn default() -> Self {
        Self::NotSet
    }
}

impl std::fmt::Display for ErrorCode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // use to_string() to get the string representation of the error code
        let str = match self {
            Self::WebSocketFailedToConnect => "WebSocket: Failed to connect",
            Self::WebSocketErrorEncodingMessage => "WebSocket: Error encoding message",
            Self::WebSocketErrorDecodingMessage => "WebSocket: Error decoding message",
            Self::WebSocketUnknownMessageReceived => "WebSocket: Unknown message received",
            Self::WebSocketUnknownBinaryMessageReceived => "WebSocket: Unknown binary message received",
            Self::WebSocketError => "WebSocket: Error",
            Self::WebSocketClosed => "WebSocket: Closed",
            Self::WebSocketErrorClosing => "WebSocket: Error closing",
            Self::FileNotSelected => "File: No file selected",
            Self::FileErrorReadingFile => "File: Error reading file",
            Self::FileNotReady => "File: Not ready",
            Self::FileInvalidEncoding => "File: Invalid encoding (wrong UTF-8)",
            Self::NotSet => "Error code not set, please create an issue",
            Self::HexeDecodingError => "Hexe decoding error",
            Self::EndOfFile => "End of File",
            Self::FileParsing => "File: Parsing error",
            Self::RequestError => "Request error",
            Self::ParsingLayerNotImplemented => "Parsing layer not implemented",
        };
        write!(f, "{}", str)
    }
}

impl ErrorCode {
    /// Check if the error is recoverable
    pub fn is_recoverable(&self) -> bool {
        !matches!(self, Self::FileInvalidEncoding | Self::WebSocketClosed)
    }
}

#[derive(serde::Deserialize, Debug, Default, Clone)]
/// Error structure for Tramex Tools
pub struct TramexError {
    /// Error message (human readable)
    pub message: String,

    /// Debug information
    pub debug: String,

    /// Error code
    code: ErrorCode,
}

impl TramexError {
    /// Create a new error
    pub fn new(message: String, code: ErrorCode) -> Self {
        log::debug!("Error: {} - {}\n{}", code, message, std::backtrace::Backtrace::capture());
        Self {
            message,
            code,
            debug: String::new(),
        }
    }

    /// Create a new error
    pub fn new_with_line(message: String, code: ErrorCode, debug: String) -> Self {
        Self { message, code, debug }
    }

    /// Check if the error is recoverable
    pub fn is_recoverable(&self) -> bool {
        self.code.is_recoverable()
    }

    /// Get the error message
    pub fn get_msg(&self) -> String {
        format!("[{}] {}", self.code, self.message)
    }

    /// Get the error code
    pub fn get_code(&self) -> ErrorCode {
        self.code.clone()
    }
}

/// Macro to get the file and line number
#[macro_export]
macro_rules! tramex_error {
    ($msg:expr, $code:expr) => {
        TramexError::new_with_line($msg, $code, format!("{}:{}", file!(), line!()))
    };
}