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
use reqwest::Client;

/// A struct representing authentication credentials.
pub struct Auth {
    /// The username for authentication.
    pub username: String,
    /// The password for authentication.
    pub password: String,
}

/// A struct representing the configuration for making requests to the MTA service.
pub struct Mta {
    /// The IP address of the MTA server.
    pub ip: String,
    /// The port number of the MTA server.
    pub port: u16,
    /// The authentication credentials for accessing the MTA server.
    pub auth: Auth,
    /// Determines whether HTTP or HTTPS should be used for requests.
    pub http: bool,
}

impl Mta{
    /// Creates a new `Mta` instance.
    ///
    /// # Arguments
    ///
    /// * `ip` - The IP address of the MTA server.
    /// * `port` - The port number of the MTA server.
    /// * `auth` - Authentication credentials for accessing the MTA server.
    /// * `http` - Whether to use HTTP (`true`) or HTTPS (`false`) for requests.
    ///
    /// # Example
    ///```rust
    /// use mta_sdk::client;
    ///
    /// let auth = client::Auth {
    ///     username: "user".to_string(),
    ///     password: "pass".to_string(),
    /// };
    ///
    /// let mta = client::Mta::new("127.0.0.1".to_string(), 22005, auth, true);
    ///```
    pub fn new(ip: String, port: u16, auth: Auth, http: bool) -> Mta {
        Mta {
            ip,
            port,
            auth,
            http
        }
    }

        /// Makes a remote call to the MTA service.
        ///
        /// This method sends a POST request to the specified resource and function
        /// on the MTA server, passing the provided arguments.
        ///
        /// # Arguments
        ///
        /// * `resource` - The resource to call.
        /// * `function` - The function to invoke.
        /// * `args` - The arguments for the function call.
        ///
        /// # Returns
        ///
        /// Returns a `Result` containing the response text if the request is successful,
        /// or an `Errors` enum if an error occurs during the request.
        ///
        /// # Errors
        ///
        /// Returns an `HTTP404ERROR` variant of the `Errors` enum if there is a request error.
        ///
        /// # Example
        ///
        /// ```rust
        /// use mta_sdk::client;
        ///
        /// #[tokio::main]
        /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
        ///     let auth = client::Auth {
        ///         username: "user".to_string(),
        ///         password: "pass".to_string(),
        ///     };
        ///
        ///     let mta_instance = client::Mta::new("127.0.0.1".to_string(), 22005, auth, true);
        ///     let response = mta_instance.call("resource", "function", vec!["arg1".to_string()]).await?;
        ///     println!("Response: {}", response);
        ///
        ///     Ok(())
        /// }
        /// ```
    pub async fn call(&self, resource: &str, function: &str, args: Vec<String>) -> Result<String, crate::error::Errors> {
        let url = format!("{}{}/call/{}", self.get_uri(), resource, function);

        let client = Client::new();
        let res = client.post(&url)
            .header("Content-Type", "application/json")
            .basic_auth(&self.auth.username, Some(&self.auth.password))
            .json(&args)
            .send()
            .await;

        match res {
            Ok(res) => {
                let status = res.status().to_string();
                if status == "200 OK" {
                    let body = res.text().await.unwrap();
                    Ok(body)
                } else {
                    let err = crate::error::Errors::RequestError(format!("The server returned an error. Status: {} 🛑 .", status));
                    Err(err)
                }
            },
            Err(_err) => {
                let err = crate::error::Errors::RequestError("There was a failure in transmitting your request to the server. We recommend checking the connection and trying again.".to_string());
                Err(err)
            }
        }
    }

    /// Returns the URI based on the configured HTTP/HTTPS setting.
    ///
    ///
    /// # Example
    ///
    /// ```rust
    /// use mta_sdk::client;
    ///
    /// let auth = client::Auth {
    ///     username: "user".to_string(),
    ///     password: "pass".to_string(),
    /// };
    ///
    /// let instance = client::Mta::new("127.0.0.1".to_string(), 22005, auth, true);
    ///
    /// let uri = instance.get_uri();
    /// println!("URI: {}", uri);
    /// ```
    pub fn get_uri (&self) -> String {
        if self.http {
            format!("http://{}:{}/", self.ip, self.port)
        } else {
            format!("https://{}:{}/", self.ip, self.port)
        }
    }
}