1#![allow(dead_code)]
2#![doc(html_root_url = "https://docs.rs/twilio-async/0.5.0")]
3#![allow(
4 clippy::cognitive_complexity,
5 clippy::large_enum_variant,
6 clippy::needless_doctest_main,
7 clippy::needless_lifetimes
8)]
9#![warn(
10 missing_debug_implementations,
11 rust_2018_idioms,
13 unreachable_pub
14)]
15#![deny(rustdoc::broken_intra_doc_links)]
16#![doc(test(
17 no_crate_inject,
18 attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
19))]
20#![cfg_attr(docsrs, feature(doc_cfg))]
21
22#[macro_use]
100mod macros;
101mod call;
102mod conference;
103pub mod error;
104mod message;
105mod recording;
106pub mod twiml;
107
108pub use crate::{call::*, conference::*, error::*, message::*, recording::*};
109
110use async_trait::async_trait;
111use hyper::{client::HttpConnector, Body, Client, Method, Request};
112use hyper_tls::HttpsConnector;
113use serde::Deserialize;
114use std::borrow::Borrow;
115
116pub use typed_headers::{Authorization, Credentials};
117pub use url::{form_urlencoded, Url};
118
119#[derive(Debug)]
120pub struct Twilio {
121 sid: String,
122 auth: Authorization,
123 client: Client<HttpsConnector<HttpConnector>, hyper::Body>,
124}
125
126pub type TwilioResp<T> = Result<T, TwilioErr>;
127
128impl Twilio {
129 pub fn new<S, P>(sid: S, token: P) -> TwilioResult<Twilio>
130 where
131 S: Into<String>,
132 P: AsRef<str>,
133 {
134 let sid = sid.into();
135 let client = Client::builder().build::<_, hyper::Body>(HttpsConnector::new());
136
137 Ok(Twilio {
138 auth: Authorization(Credentials::basic(&sid, token.as_ref())?),
139 sid,
140 client,
141 })
142 }
143
144 pub fn send_msg<'a>(&'a self, from: &'a str, to: &'a str, body: &'a str) -> SendMsg<'a> {
145 SendMsg {
146 msg: Msg::new(from, to, body),
147 client: self,
148 }
149 }
150
151 pub fn msg<'a>(&'a self, message_sid: &'a str) -> GetMessage<'a> {
152 GetMessage {
153 message_sid,
154 client: self,
155 }
156 }
157
158 pub fn msgs(&self) -> Messages<'_> {
159 Messages { client: self }
160 }
161
162 pub fn call<'a>(&'a self, from: &'a str, to: &'a str, url: &'a str) -> SendCall<'a> {
163 SendCall {
164 call: Call::new(from, to, url),
165 client: self,
166 }
167 }
168
169 pub fn conference<'a>(&'a self, sid: &'a str) -> GetConference<'a> {
170 GetConference {
171 conference: Conference::new(sid),
172 client: self,
173 }
174 }
175
176 pub fn conferences(&self) -> Conferences<'_> {
177 Conferences { client: self }
178 }
179
180 pub fn recording<'a>(&'a self, sid: &'a str) -> GetRecording<'a> {
181 GetRecording {
182 recording: Recording::new(sid),
183 client: self,
184 }
185 }
186
187 pub fn recordings(&self) -> Recordings<'_> {
188 Recordings { client: self }
189 }
190}
191
192#[derive(Debug, Deserialize)]
193#[serde(untagged)]
194pub enum TwilioJson<T> {
195 Success(T),
196 Fail {
197 code: usize,
198 message: String,
199 status: usize,
200 },
201}
202
203#[async_trait]
204pub trait Execute {
205 fn request<U>(
206 &self,
207 method: Method,
208 url: U,
209 body: Option<String>,
210 ) -> Result<Request<Body>, TwilioErr>
211 where
212 U: AsRef<str>;
213 async fn execute<U, D>(
214 &self,
215 method: Method,
216 url: U,
217 body: Option<String>,
218 ) -> TwilioResp<TwilioJson<D>>
219 where
220 U: AsRef<str> + Send,
221 D: for<'de> serde::Deserialize<'de>;
222}
223
224#[async_trait]
225pub trait TwilioRequest: Execute {
226 type Resp: for<'de> serde::Deserialize<'de>;
227 async fn run(&self) -> TwilioResp<TwilioJson<Self::Resp>>;
228}
229
230pub fn encode_pairs<I, K, V>(pairs: I) -> Option<String>
231where
232 K: AsRef<str>,
233 V: AsRef<str>,
234 I: IntoIterator,
235 I::Item: Borrow<(K, V)>,
236{
237 let mut partial = form_urlencoded::Serializer::new(String::new());
238 for pair in pairs {
239 let &(ref k, ref v) = pair.borrow();
240 partial.append_pair(k.as_ref(), v.as_ref());
241 }
242 let encoded = partial.finish();
243 Some(encoded)
244}
245
246pub fn url_encode<I, K, V>(pairs: I) -> String
247where
248 K: AsRef<str>,
249 V: AsRef<str>,
250 I: IntoIterator,
251 I::Item: Borrow<(K, V)>,
252{
253 pairs
254 .into_iter()
255 .map(|pair| {
256 let &(ref k, ref v) = pair.borrow();
257 format!("{}={}", k.as_ref(), v.as_ref())
258 })
259 .fold(String::new(), |mut acc, item| {
260 acc.push_str(&item);
261 acc.push('&');
262 acc
263 })
264}