1use std::time::{SystemTime, UNIX_EPOCH};
2
3use actix_web::{web, App as ActixApp, Error, HttpResponse, HttpServer};
4use futures::StreamExt;
5use log::{info, warn};
6use serde::Deserialize;
7
8use super::crypto::Crypto;
9use super::{App, RecvMessage};
10
11pub struct Builder<T: App> {
12 app: T,
13 token: String,
14 encoding_aes_key: String,
15 port: Option<u16>, }
17
18pub struct Server<T: App> {
19 app: T,
20 crypto: Crypto,
21 port: u16,
22}
23
24impl<T: App> Builder<T> {
25 pub fn new(app: T, token: impl ToString, encoding_aes_key: impl ToString) -> Self {
26 Builder {
27 app,
28 token: token.to_string(),
29 encoding_aes_key: encoding_aes_key.to_string(),
30 port: None,
31 }
32 }
33
34 pub fn port(mut self, p: u16) -> Self {
35 self.port = Some(p);
36 self
37 }
38
39 pub fn build(self) -> anyhow::Result<Server<T>> {
40 let app = self.app;
41 let crypto = Crypto::new(self.token, self.encoding_aes_key)?;
42 let port = self.port.unwrap_or(12349);
43 let s = Server { app, crypto, port };
44 Ok(s)
45 }
46}
47
48impl<T: App> Server<T> {
49 pub async fn run(self) -> std::io::Result<()> {
52 std::thread::spawn(move || run(self).expect("start server failed"));
53 let ret = futures::future::pending().await;
54 Ok(ret)
55 }
56}
57
58#[actix_web::main]
60async fn run<T: App>(s: Server<T>) -> std::io::Result<()> {
61 let server = web::Data::new(s);
62 let addr = format!("0.0.0.0:{}", server.port);
63 HttpServer::new(move || {
64 ActixApp::new()
65 .app_data(server.clone())
66 .route("/", web::get().to(validate::<T>))
67 .route("/", web::post().to(recv::<T>))
68 })
69 .bind(addr)?
70 .run()
71 .await?;
72 Ok(())
73}
74
75#[derive(Debug, Deserialize)]
76struct ValidateParams {
77 msg_signature: String,
78 timestamp: u64,
79 nonce: u64,
80 echostr: String,
81}
82
83#[derive(Debug, Deserialize)]
84struct RecvParams {
85 msg_signature: String,
86 timestamp: u64,
87 nonce: u64,
88}
89
90async fn validate<T: App>(
91 info: web::Query<ValidateParams>,
92 server: web::Data<Server<T>>,
93) -> HttpResponse {
94 info!("validate request: params: {:?}", info);
95
96 let crypto = &server.crypto;
97 let payload = match crypto.decrypt(&info.echostr) {
98 Ok(d) => d,
99 Err(e) => {
100 warn!("decrypt validate message failed, reason: {}", e);
101 return HttpResponse::BadRequest().finish();
102 }
103 };
104
105 HttpResponse::Ok().body(payload.data)
106}
107
108async fn recv<T: App>(
109 info: web::Query<RecvParams>,
110 mut body: web::Payload,
111 server: web::Data<Server<T>>,
112) -> Result<HttpResponse, Error> {
113 info!("receive request: params: {:?}", info);
114
115 let mut bytes = web::BytesMut::new();
116 while let Some(item) = body.next().await {
117 bytes.extend_from_slice(&item?);
118 }
119
120 let crypto = &server.crypto;
121 let msg = match RecvMessage::parse(
122 &bytes,
123 &crypto,
124 info.timestamp,
125 info.nonce,
126 &info.msg_signature,
127 ) {
128 Ok(d) => d,
129 Err(e) => {
130 warn!("parse message failed, reason: {}", e);
131 return Ok(HttpResponse::BadRequest().finish());
132 }
133 };
134
135 match server.app.handle(msg).await {
136 Some(m) => {
137 let msg = m
138 .serialize(current_timestamp(), gen_nonce(), crypto)
139 .unwrap();
140 Ok(HttpResponse::Ok().body(msg))
141 }
142 None => Ok(HttpResponse::Ok().finish()),
143 }
144}
145
146#[inline]
149fn current_timestamp() -> u64 {
150 SystemTime::now()
151 .duration_since(UNIX_EPOCH)
152 .unwrap()
153 .as_secs()
154}
155
156#[inline]
157fn gen_nonce() -> u64 {
158 rand::random()
159}