|
|
@@ -0,0 +1,101 @@
|
|
|
+use std::sync::Arc;
|
|
|
+use std::sync::atomic::{AtomicBool, Ordering};
|
|
|
+use actix_web::{web, App, HttpResponse, HttpServer, Responder, get};
|
|
|
+use serde::{Deserialize, Serialize};
|
|
|
+use serde_json::Value;
|
|
|
+use tracing::{info};
|
|
|
+use crate::json_db_utils::collect_special_trades_json;
|
|
|
+
|
|
|
+// 定义用于反序列化查询参数的结构体
|
|
|
+#[derive(Serialize, Deserialize, Clone)]
|
|
|
+pub struct TradesQuery {
|
|
|
+ symbol: Option<String>,
|
|
|
+ exchange: Option<String>,
|
|
|
+ start_time: Option<i64>,
|
|
|
+ end_time: Option<i64>,
|
|
|
+}
|
|
|
+
|
|
|
+impl TradesQuery {
|
|
|
+ pub fn validate(&self) -> bool {
|
|
|
+ if self.symbol.is_none() {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ if self.exchange.is_none() {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ if self.start_time.is_none() {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ if self.end_time.is_none() {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ true
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Serialize, Deserialize)]
|
|
|
+pub struct Response {
|
|
|
+ message: Option<String>,
|
|
|
+ query_string: Value,
|
|
|
+ data: Value,
|
|
|
+ code: i32,
|
|
|
+}
|
|
|
+
|
|
|
+// 句柄 GET 请求
|
|
|
+#[get("/trades")]
|
|
|
+async fn get_trades(query: web::Query<TradesQuery>) -> impl Responder {
|
|
|
+ if query.validate() {
|
|
|
+ let response_data = collect_special_trades_json(
|
|
|
+ query.start_time.clone().unwrap(),
|
|
|
+ query.end_time.clone().unwrap(),
|
|
|
+ query.exchange.clone().unwrap().as_str(),
|
|
|
+ query.symbol.clone().unwrap().as_str()
|
|
|
+ ).await;
|
|
|
+
|
|
|
+ let response = Response {
|
|
|
+ query_string: serde_json::to_value(&query.into_inner()).unwrap(),
|
|
|
+ message: Some("查询成功".to_string()),
|
|
|
+ code: 200,
|
|
|
+ data: response_data,
|
|
|
+ };
|
|
|
+
|
|
|
+ let json_string = serde_json::to_string(&response).unwrap();
|
|
|
+ HttpResponse::Ok().content_type("application/json").body(json_string)
|
|
|
+ } else {
|
|
|
+ let response = Response {
|
|
|
+ query_string: serde_json::to_value(&query.into_inner()).unwrap(),
|
|
|
+ message: Some("查询内容有误,必须包含四个参数:[symbol, exchange, start_time, end_time]".to_string()),
|
|
|
+ code: 400,
|
|
|
+ data: Value::Null,
|
|
|
+ };
|
|
|
+
|
|
|
+ let json_string = serde_json::to_string(&response).unwrap();
|
|
|
+ HttpResponse::BadRequest().content_type("application/json").body(json_string)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub fn run_server(port: u32, running: Arc<AtomicBool>) {
|
|
|
+ let addr = format!("0.0.0.0:{}", port);
|
|
|
+ info!("数据服务绑定地址:{}", addr);
|
|
|
+
|
|
|
+ // 启动server
|
|
|
+ let server_fut = HttpServer::new(move || {
|
|
|
+ App::new()
|
|
|
+ .service(get_trades)
|
|
|
+ })
|
|
|
+ .bind(addr)
|
|
|
+ .expect("Bind port error")
|
|
|
+ .run();
|
|
|
+
|
|
|
+ info!("数据仓库服务已运行。");
|
|
|
+
|
|
|
+ let r = running.clone();
|
|
|
+ tokio::spawn(async move {
|
|
|
+ server_fut.await.expect("error running the server");
|
|
|
+ r.store(false, Ordering::Relaxed);
|
|
|
+ });
|
|
|
+}
|