use super::EventLoop;
use crate::{types::parameters::UpdateKind, Bot};
use hyper::{
body::{Body, HttpBody},
Method, Request, Response,
};
use std::{
net::{IpAddr, Ipv4Addr},
sync::Arc,
time::Duration,
};
mod http;
pub mod https;
pub use http::Http;
pub use https::Https;
#[must_use = "webhook does not start unless `start` is called"]
pub struct Webhook<'a, C> {
event_loop: EventLoop<C>,
ip: IpAddr,
port: u16,
request_timeout: Duration,
url: &'a str,
certificate: Option<&'a str>,
max_connections: Option<u8>,
allowed_updates: Option<&'a [UpdateKind]>,
}
impl<'a, C> Webhook<'a, C> {
pub(crate) fn new(
event_loop: EventLoop<C>,
url: &'a str,
port: u16,
) -> Self {
Self {
event_loop,
ip: IpAddr::V4(Ipv4Addr::LOCALHOST),
port,
request_timeout: Duration::from_secs(60),
url,
certificate: None,
max_connections: None,
allowed_updates: None,
}
}
pub const fn ip(mut self, ip: IpAddr) -> Self {
self.ip = ip;
self
}
pub fn certificate(mut self, certificate: &'a str) -> Self {
self.certificate = Some(certificate);
self
}
pub fn max_connections(mut self, max: u8) -> Self {
self.max_connections = Some(max);
self
}
pub fn allowed_updates(mut self, updates: &'a [UpdateKind]) -> Self {
self.allowed_updates = Some(updates);
self
}
pub const fn request_timeout(mut self, timeout: Duration) -> Self {
self.request_timeout = timeout;
self
}
pub const fn http(self) -> Http<'a, C> {
Http::new(self)
}
pub const fn https(
self,
#[cfg(feature = "tls")] identity: https::Identity,
#[cfg(feature = "rustls")] config: https::ServerConfig,
) -> Https<'a, C> {
Https::new(
self,
#[cfg(feature = "tls")]
identity,
#[cfg(feature = "rustls")]
config,
)
}
}
fn is_request_correct(request: &Request<Body>) -> bool {
let content_type = request.headers().get("Content-Type");
request.method() == Method::POST
&& request.uri() == "/"
&& content_type.map(|x| x == "application/json") == Some(true)
}
async fn handle<C>(
bot: Arc<Bot<C>>,
event_loop: Arc<EventLoop<C>>,
request: Request<Body>,
) -> Result<Response<Body>, hyper::Error>
where
C: Send + Sync + 'static,
{
if is_request_correct(&request) {
let (parts, mut body) = request.into_parts();
let mut request = parts
.headers
.get("Content-Length")
.and_then(|x| x.to_str().ok().and_then(|x| x.parse().ok()))
.map_or_else(Vec::new, Vec::with_capacity);
while let Some(chunk) = body.data().await {
request.extend(chunk?);
}
let update =
serde_json::from_slice(&request[..]).unwrap_or_else(|error| {
panic!("\n[tbot] Received invalid JSON: {:#?}\n", error);
});
event_loop.handle_update(bot, update);
}
Ok(Response::new(Body::empty()))
}