UTMFRRHQR4RXI4SJBHUUXPFJXQKOTD7LFT5X6NXD3INLXTCENILQC EVIOKGS2YYV4SQ2COOC4M76ODWTGN76NX5VNABM2RVSEAJCA6VQAC T5VMNBHRAIXCQAQUMMJDJAL6Z4422GG4MLAO4IRI4RGB6J3HF36QC 3EKAR2UJ2OUTH3HZY2F42CI5I3QU2GQUK6CH6VOIF4CFXF64RKPAC OJ4HP746XEDXQSLFLZ3X32PURC6ONMOJDZIWLOF7AKMET3UVCUKQC TGO4TIWURN54UFBLMUX4EZTZBG3TE5F4VRL56BTLOINCKJEUDD7QC S7A7LHUN2YLV3HEQBHOSYQCRBMDTX6AJ4WTWLKQZY7547LEGFCUQC RNQTHBRIVBDC25NEWEZLM62EZD7KOQHIZFHVHOLEXDXWUAPNTEPQC GVI6M6SCKQ6AMWMEILSCWBSNHAFFBOUMOT5IQSFY6OSTHQCJGO5QC OX5ZPQRFYBCNEHISBUT3X447VABMTDMK3D2SW6LC42KKGP2QKT5QC 4XX74XB3SUY6EZPPBQ45YQGKHHC4UOZEWROKJJS2Q6ULC4QQS36AC WXPEN4YC3DSUWFOVO74HGHK6E7RZD3DB3VCSJ7USJHYI7ZEHI2GQC YCYYN7MFSM5IKC36MOSUCDDODRQEQXMFS4PVVHH7SHWKJODUNEQAC HTJ7H7Z6Y3QMQVY3D4W4BGQFVQ5BRUM4TPLHWOER4BSP4MCCUI3QC PO3H34B6Y74XWLHBSMOCDYREJQLNHPQGG7U2DI4ZFCP2IVX7O2TQC K7XUYBRZX4RHRGYH3E3O7AWA6723O5JCWHPVR5YBV3TUIJCDZSDQC BBX3ELGVDVA43GKPUIYT4EIEXCVZ6X3FEX2FGPNWBP6SR5KPAQZAC MEXG7XQM62JXWGJLOYBTG66XMTLKRGFT355WA7W5NUCKAJYUC2LQC /// Return future with body converted to Stringasync fn body_to_string(req: Request<Body>) -> Result<String, failure::Error> {let whole_body = hyper::body::to_bytes(req.into_body()).await?;std::str::from_utf8(&whole_body).map(std::string::ToString::to_string).map_err(std::convert::Into::into)
async fn payload_to_string(payload: web::Payload) -> Result<String, failure::Error> {match payload.to_bytes_limited(4096).await {Ok(Ok(bytes)) => {let message = String::from_utf8(bytes.to_vec());match message {Ok(m) => Ok(m),Err(e) => Err(e.into()),}}Ok(Err(e)) => Err(failure::format_err!("{}", e)),Err(e) => Err(e.into()),}
struct ServiceCmd {cmd_send: tokio::sync::mpsc::Sender<XmppCommand>,
fn req_xmpp_to(req: &HttpRequest) -> Result<jid::Jid, failure::Error> {let xmpp_to_opt = req.headers().get("X-XMPP-To");let xmpp_to_res: Result<jid::Jid, failure::Error> = xmpp_to_opt.map_or_else(|| Err(failure::format_err!("No X-XMPP-To header")),|xmpp_to| {std::str::from_utf8(xmpp_to.as_bytes()).map_err(std::convert::Into::into).and_then(|s| std::str::FromStr::from_str(s).map_err(std::convert::Into::into))},);xmpp_to_res
impl hyper::service::Service<Request<Body>> for ServiceCmd {type Response = Response<Body>;type Error = failure::Error;type Future = std::pin::Pin<Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>> + Send>,>;
async fn ping(req: HttpRequest,data: web::Data<tokio::sync::mpsc::Sender<XmppCommand>>,) -> HttpResponse {let xmpp_to_res = req_xmpp_to(&req);
fn poll_ready(&mut self,_: &mut std::task::Context,) -> std::task::Poll<Result<(), Self::Error>> {std::task::Poll::Ready(Ok(()))
match xmpp_to_res {Ok(xmpp_to) => {info!("Got ping request");let cmd_send = data.clone();match cmd_send.send(XmppCommand::Ping {opt_xmpp_to: Some(xmpp_to),}).await{Ok(_) => HttpResponse::Ok().body("Accepted"),Err(e) => {error!("Cann't send ping command: {}", e);HttpResponse::BadRequest().body("Cann't send ping")}}}_ => HttpResponse::BadRequest().body("Cann't send ping, missing X-XMPP-To"),
fn call(&mut self, req: Request<Body>) -> Self::Future {let xmpp_to_opt = req.headers().get("X-XMPP-To");let xmpp_to_res: Result<jid::Jid, failure::Error> = xmpp_to_opt.map_or_else(|| Err(failure::format_err!("No X-XMPP-To header")),|xmpp_to| {std::str::from_utf8(xmpp_to.as_bytes())
async fn index(req: HttpRequest,data: web::Data<tokio::sync::mpsc::Sender<XmppCommand>>,payload: web::Payload,) -> HttpResponse {let xmpp_to_res = req_xmpp_to(&req);let xmpp_muc_opt = req.headers().get("X-XMPP-Muc").map(|h| h.to_str().map(std::string::ToString::to_string));let xmpp_pres_opt = req.headers().get("X-XMPP-Presence");let xmpp_pres_res: Result<xmpp_parsers::presence::Show, failure::Error> = xmpp_pres_opt.map_or_else(|| Err(failure::format_err!("No X-XMPP-Presence header")),|show| {std::str::from_utf8(show.as_bytes())
let xmpp_muc_opt = req.headers().get("X-XMPP-Muc").map(|h| h.to_str().map(std::string::ToString::to_string));
match (xmpp_muc_opt, xmpp_to_res, xmpp_pres_res) {(None, Err(err), Err(err2)) => {warn!("Unknown destination: {}", err);warn!("Unknown destination2: {}", err2);
let xmpp_pres_opt = req.headers().get("X-XMPP-Presence");let xmpp_pres_res: Result<xmpp_parsers::presence::Show, failure::Error> = xmpp_pres_opt.map_or_else(|| Err(failure::format_err!("No X-XMPP-Presence header")),|show| {std::str::from_utf8(show.as_bytes()).map_err(std::convert::Into::into).and_then(|s| {std::str::FromStr::from_str(s).map_err(|e| failure::format_err!("Incorrect presence {}", e))})
HttpResponse::BadRequest().body(format!("Unknown destination: {}\nUnknown destination2: {}",err, err2,))}(None, _, Ok(show)) => {info!("Got presence request. Reading body...");let cmd_send = data.clone();match payload_to_string(payload).await {Ok(message) => match cmd_send.send(XmppCommand::Presence { show, message }).await {Ok(_) => HttpResponse::Ok().body("Accepted".to_string()),Err(e) => {error!("Cann't send presence command: {}", e);HttpResponse::BadRequest().body("Cann't get presence text")}
);match (xmpp_muc_opt, xmpp_to_res, xmpp_pres_res) {(None, Err(err), Err(err2)) => {warn!("Unknown destination: {}", err);warn!("Unknown destination2: {}", err2);Box::pin(async move {Response::builder().status(hyper::StatusCode::BAD_REQUEST).body(Body::from(format!("Unknown destination: {}\nUnknown destination2: {}",err, err2,))).map_err(std::convert::Into::into)})
Err(_) => HttpResponse::BadRequest().body("Cann't get presence text"),
(None, _, Ok(show)) => {info!("Got presence request. Reading body...");let cmd_send = self.cmd_send.clone();Box::pin(async move {match body_to_string(req).await {Ok(message) => {match cmd_send.send(XmppCommand::Presence { show, message }).await {Ok(_) => Response::builder().body(Body::from("Accepted".to_string())).map_err(std::convert::Into::into),Err(e) => {error!("Cann't send presence command: {}", e);Response::builder().status(hyper::StatusCode::BAD_REQUEST).body(Body::from("Cann't get presence text".to_string())).map_err(std::convert::Into::into)}}}Err(_) => Response::builder().status(hyper::StatusCode::BAD_REQUEST).body(Body::from("Cann't get presence text".to_string())).map_err(std::convert::Into::into),
}(None, Ok(xmpp_to), _) => {info!("Got message request. Reading body...");let cmd_send = data.clone();match payload_to_string(payload).await {Ok(message) => match cmd_send.send(XmppCommand::Chat { xmpp_to, message }).await {Ok(_) => HttpResponse::Ok().body("Accepted"),Err(e) => {error!("Cann't send message command: {}", e);HttpResponse::BadRequest().body("Cann't get message text")
(None, Ok(xmpp_to), _) => {if req.uri().path() == "/ping" {info!("Got ping request");let cmd_send = self.cmd_send.clone();Box::pin(async move {match cmd_send.send(XmppCommand::Ping {opt_xmpp_to: Some(xmpp_to),}).await{Ok(_) => Response::builder().body(Body::from("Accepted".to_string())).map_err(std::convert::Into::into),Err(e) => {error!("Cann't send ping command: {}", e);Response::builder().status(hyper::StatusCode::BAD_REQUEST).body(Body::from("Cann't send ping".to_string())).map_err(std::convert::Into::into)}}})} else {info!("Got message request. Reading body...");let cmd_send = self.cmd_send.clone();Box::pin(async move {match body_to_string(req).await {Ok(message) => {match cmd_send.send(XmppCommand::Chat { xmpp_to, message }).await {Ok(_) => Response::builder().body(Body::from("Accepted".to_string())).map_err(std::convert::Into::into),Err(e) => {error!("Cann't send message command: {}", e);Response::builder().status(hyper::StatusCode::BAD_REQUEST).body(Body::from("Cann't get message text".to_string())).map_err(std::convert::Into::into)}}}Err(_) => Response::builder().status(hyper::StatusCode::BAD_REQUEST).body(Body::from("Cann't get message text".to_string())).map_err(std::convert::Into::into),}})}}(Some(Ok(muc_id)), _, Ok(show)) => {info!("Got chat presence request. Reading body...");let cmd_send = self.cmd_send.clone();Box::pin(async move {match body_to_string(req).await {Ok(message) => {match cmd_send.send(XmppCommand::ChatroomPresence {muc_id,show,message,}).await{Ok(_) => Response::builder().body(Body::from("Accepted".to_string())).map_err(std::convert::Into::into),Err(e) => {error!("Cann't send chat presence command: {}", e);Response::builder().status(hyper::StatusCode::BAD_REQUEST).body(Body::from("Cann't get chat presence text".to_string(),)).map_err(std::convert::Into::into)}}
}(Some(Ok(muc_id)), _, Ok(show)) => {info!("Got chat presence request. Reading body...");let cmd_send = data.clone();match payload_to_string(payload).await {Ok(message) => {match cmd_send.send(XmppCommand::ChatroomPresence {muc_id,show,message,}).await{Ok(_) => HttpResponse::Ok().body("Accepted"),Err(e) => {error!("Cann't send chat presence command: {}", e);HttpResponse::BadRequest().body("Cann't get chat presence text")
Err(_) => Response::builder().status(hyper::StatusCode::BAD_REQUEST).body(Body::from("Cann't get chat presence text".to_string())).map_err(std::convert::Into::into),
(Some(Ok(muc_id)), _, _) => {info!("Got chat message request. Reading body...");let cmd_send = self.cmd_send.clone();Box::pin(async move {match body_to_string(req).await {Ok(message) => {match cmd_send.send(XmppCommand::Chatroom { muc_id, message }).await{Ok(_) => Response::builder().body(Body::from("Accepted".to_string())).map_err(std::convert::Into::into),Err(e) => {error!("Cann't send chat message command: {}", e);Response::builder().status(hyper::StatusCode::BAD_REQUEST).body(Body::from("Cann't get chat message text".to_string(),)).map_err(std::convert::Into::into)}}
}(Some(Ok(muc_id)), _, _) => {info!("Got chat message request. Reading body...");let cmd_send = data.clone();match payload_to_string(payload).await {Ok(message) => {match cmd_send.send(XmppCommand::Chatroom { muc_id, message }).await{Ok(_) => HttpResponse::Ok().body("Accepted"),Err(e) => {error!("Cann't send chat message command: {}", e);HttpResponse::BadRequest().body("Cann't get chat message text")
Err(_) => Response::builder().status(hyper::StatusCode::BAD_REQUEST).body(Body::from("Cann't get chat message text".to_string())).map_err(std::convert::Into::into),
})}(Some(Err(err)), _, _) => {warn!("Unknown destination: {}", err);Box::pin(async move {Response::builder().status(hyper::StatusCode::BAD_REQUEST).body(Body::from(format!("Unknown destination: {}", err,))).map_err(std::convert::Into::into)})
}Err(_) => HttpResponse::BadRequest().body("Cann't get chat message text"),
}}struct MakeServiceCmd {cmd_send: tokio::sync::mpsc::Sender<XmppCommand>,}impl<T> hyper::service::Service<T> for MakeServiceCmd {type Response = ServiceCmd;type Error = failure::Error;type Future = std::pin::Pin<Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>> + Send>,>;fn poll_ready(&mut self,_: &mut std::task::Context,) -> std::task::Poll<Result<(), Self::Error>> {std::task::Poll::Ready(Ok(()))}fn call(&mut self, _: T) -> Self::Future {let cmd_send = self.cmd_send.clone();let fut = async move { Ok(ServiceCmd { cmd_send }) };Box::pin(fut)
(Some(Err(err)), _, _) => {warn!("Unknown destination: {}", err);HttpResponse::BadRequest().body(format!("Unknown destination: {}", err,))}
let http_server = Server::bind(&config.http).serve(MakeServiceCmd {cmd_send: cmd_send.clone(),}).with_graceful_shutdown(ctrl_c.clone());
let http_cmd_send = cmd_send.clone();let http_server = HttpServer::new(move || {let logger =middleware::Logger::new("%{r}a \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\" %T");App::new()// Enable the logger..wrap(logger).app_data(web::Data::new(http_cmd_send.clone())).route("/ping", web::get().to(ping)).route("/", web::post().to(index))});
[[package]]name = "actix-codec"version = "0.5.2"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a"dependencies = ["bitflags 2.9.0","bytes","futures-core","futures-sink","memchr","pin-project-lite","tokio","tokio-util","tracing",][[package]]name = "actix-http"version = "3.10.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "0fa882656b67966045e4152c634051e70346939fced7117d5f0b52146a7c74c9"dependencies = ["actix-codec","actix-rt","actix-service","actix-utils","base64","bitflags 2.9.0","brotli","bytes","bytestring","derive_more","encoding_rs","flate2","foldhash","futures-core","h2","http","httparse","httpdate","itoa","language-tags","local-channel","mime","percent-encoding","pin-project-lite","rand 0.9.0","sha1","smallvec","tokio","tokio-util","tracing","zstd",][[package]]name = "actix-macros"version = "0.2.4"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"dependencies = ["quote","syn 2.0.100",][[package]]name = "actix-router"version = "0.5.3"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8"dependencies = ["bytestring","cfg-if","http","regex","regex-lite","serde","tracing",][[package]]name = "actix-rt"version = "2.10.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208"dependencies = ["futures-core","tokio",][[package]]name = "actix-server"version = "2.5.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "6398974fd4284f4768af07965701efbbb5fdc0616bff20cade1bb14b77675e24"dependencies = ["actix-rt","actix-service","actix-utils","futures-core","futures-util","mio","socket2","tokio","tracing",][[package]]name = "actix-service"version = "2.0.3"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "9e46f36bf0e5af44bdc4bdb36fbbd421aa98c79a9bce724e1edeb3894e10dc7f"dependencies = ["futures-core","pin-project-lite",][[package]]name = "actix-utils"version = "3.0.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8"dependencies = ["local-waker","pin-project-lite",][[package]]name = "actix-web"version = "4.10.2"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "f2e3b15b3dc6c6ed996e4032389e9849d4ab002b1e92fbfe85b5f307d1479b4d"dependencies = ["actix-codec","actix-http","actix-macros","actix-router","actix-rt","actix-server","actix-service","actix-utils","actix-web-codegen","bytes","bytestring","cfg-if","cookie","derive_more","encoding_rs","foldhash","futures-core","futures-util","impl-more","itoa","language-tags","log","mime","once_cell","pin-project-lite","regex","regex-lite","serde","serde_json","serde_urlencoded","smallvec","socket2","time","tracing","url",][[package]]name = "actix-web-codegen"version = "4.3.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "f591380e2e68490b5dfaf1dd1aa0ebe78d84ba7067078512b4ea6e4492d622b8"dependencies = ["actix-router","proc-macro2","quote","syn 2.0.100",]
][[package]]name = "alloc-no-stdlib"version = "2.0.4"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"[[package]]name = "alloc-stdlib"version = "0.2.2"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"dependencies = ["alloc-no-stdlib",
name = "brotli"version = "7.0.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd"dependencies = ["alloc-no-stdlib","alloc-stdlib","brotli-decompressor",][[package]]name = "brotli-decompressor"version = "4.0.2"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37"dependencies = ["alloc-no-stdlib","alloc-stdlib",][[package]]
[[package]]name = "deranged"version = "0.4.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058"dependencies = ["powerfmt",][[package]]name = "derive_more"version = "2.0.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"dependencies = ["derive_more-impl",]
"wasi",
"wasi 0.11.0+wasi-snapshot-preview1",][[package]]name = "getrandom"version = "0.3.2"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"dependencies = ["cfg-if","libc","r-efi","wasi 0.14.2+wasi-0.2.4",
][[package]]name = "http-body"version = "0.4.6"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"dependencies = ["bytes","http","pin-project-lite",
[[package]]name = "hyper"version = "0.14.32"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7"dependencies = ["bytes","futures-channel","futures-core","futures-util","h2","http","http-body","httparse","httpdate","itoa","pin-project-lite","socket2","tokio","tower-service","tracing","want",]
[[package]]name = "pkg-config"version = "0.3.32"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"[[package]]name = "powerfmt"version = "0.2.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
"rand_chacha","rand_core",
"rand_chacha 0.3.1","rand_core 0.6.4",][[package]]name = "rand"version = "0.9.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"dependencies = ["rand_chacha 0.9.0","rand_core 0.9.3","zerocopy",
"rand_core",
"rand_core 0.6.4",][[package]]name = "rand_chacha"version = "0.9.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"dependencies = ["ppv-lite86","rand_core 0.9.3",
][[package]]name = "time"version = "0.3.41"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"dependencies = ["deranged","itoa","num-conv","powerfmt","serde","time-core","time-macros",][[package]]name = "time-core"version = "0.1.4"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"[[package]]name = "time-macros"version = "0.2.22"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"dependencies = ["num-conv","time-core",
name = "tower-service"version = "0.3.3"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"[[package]]
name = "try-lock"version = "0.2.5"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"[[package]]
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"dependencies = ["try-lock",]
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]name = "zstd"version = "0.13.3"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"dependencies = ["zstd-safe",][[package]]name = "zstd-safe"version = "7.2.4"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"dependencies = ["zstd-sys",][[package]]name = "zstd-sys"version = "2.0.15+zstd.1.5.7"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"dependencies = ["cc","pkg-config",]