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
//! iSCPのエラー型を定義するモジュールです。

use std::fmt::Display;
use thiserror::Error;
use tokio::sync::{broadcast, mpsc::error as mpsc, oneshot};
use tungstenite::error as wserror;

use crate::message;

/// iSCPのエラーをもつ`Result`です。
pub type Result<T, E = Error> = core::result::Result<T, E>;

/// iSCPのエラー型です。
#[derive(Error, Clone, PartialEq, Debug)]
pub enum Error {
    // Connect represents an error on connecting to a host. The detail why is shown in the String.
    #[error("Connect: `{0}`")]
    Connect(String),

    // ConnectionClosed represents connection had already been closed.
    #[error("ConnectionClosed")]
    ConnectionClosed(String),

    // TimeOut represents the request was failed because timeout.
    #[error("TimeOut")]
    TimeOut,

    // StreamNotFound represents the target stream wat not found.
    #[error("Stream Not Found")]
    StreamNotFound,

    // Unexpected represents the unexpected error occurred. The detail why is shown in the String.
    // This error is almost internal client error.
    #[error("Unexpected: `{0}`")]
    Unexpected(String),

    // Encode represents the error occurred while encoding message. The detail why is shown in the String.
    // This error is almost internal client error.
    #[error("Encode: `{0}`")]
    Encode(String),

    // Decode represents the error occurred while encoding message. The detail why is shown in the String.
    // If this error occurred, the connecting broker may not be comply with ISCP protocol.
    #[error("Decode: `{0}`")]
    MalformedMessage(String),

    // FailedMessage represents the error in the ISCP protocol.
    #[error("Failed Message (ResultCode: {code:?}, detail: {detail:?})")]
    FailedMessage {
        code: message::ResultCode,
        detail: String,
    },

    // InvalidValue represents the value is invalid. The detail why is shown in the String.
    #[error("Invalid Value `{0}`")]
    InvalidValue(String),

    // MaxDataPointCount represents the current data point count was reached to max.
    // If more data points should be sent using upstream, current upstream must be closed and new upstream must be opened.
    #[error("Max Data Point Count")]
    MaxDataPointCount,

    // MaxSequenceNumber represents the current sequence number was reached to max.
    // If more data points should be sent using upstream, current upstream must be closed and new upstream must be opened.
    #[error("Max MaxSequence Number")]
    MaxSequenceNumber,

    // TLS error
    #[error("tls error")]
    Certificate(#[from] rustls::Error),

    // Certificate load failed
    #[error("invalid certificate")]
    CertificateLoad(String),
}

impl From<wserror::Error> for Error {
    fn from(e: wserror::Error) -> Self {
        use wserror::Error as err;
        match e {
            err::AlreadyClosed | err::ConnectionClosed => Self::ConnectionClosed("".into()),
            _ => Self::unexpected(e),
        }
    }
}

impl<T> From<mpsc::SendError<T>> for Error {
    fn from(e: mpsc::SendError<T>) -> Self {
        Error::Unexpected(e.to_string()) // channel closed
    }
}

impl From<oneshot::error::RecvError> for Error {
    fn from(e: oneshot::error::RecvError) -> Self {
        Error::unexpected(e) // channel closed
    }
}

impl From<broadcast::error::RecvError> for Error {
    fn from(e: broadcast::error::RecvError) -> Self {
        Error::unexpected(e)
    }
}

impl From<tokio::time::error::Elapsed> for Error {
    fn from(_e: tokio::time::error::Elapsed) -> Self {
        Error::TimeOut
    }
}

impl Error {
    pub fn unexpected<T: Display>(s: T) -> Self {
        Error::Unexpected(s.to_string())
    }

    pub fn invalid_value<T: Display>(s: T) -> Self {
        Error::InvalidValue(s.to_string())
    }

    pub fn failed_message<T: Display>(code: message::ResultCode, s: T) -> Self {
        Error::FailedMessage {
            code,
            detail: s.to_string(),
        }
    }

    pub fn connect<T: Display>(s: T) -> Self {
        Error::Connect(s.to_string())
    }

    pub fn encode<T: ToString>(s: T) -> Self {
        Error::Encode(s.to_string())
    }

    pub fn malformed_message<T: ToString>(s: T) -> Self {
        Error::MalformedMessage(s.to_string())
    }
}