diff --git a/src/bin/openapi.rs b/src/bin/openapi.rs index 7e7dad69..e0da6aa3 100644 --- a/src/bin/openapi.rs +++ b/src/bin/openapi.rs @@ -1,28 +1,55 @@ use actix_web::{App, HttpServer}; -use paperclip::actix::{ - api_v2_operation, - web::{self, Json}, - Apiv2Schema, OpenApiExt, -}; -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Apiv2Schema)] -struct Pet { - name: String, - id: Option, -} - -#[api_v2_operation] -async fn echo_pet(body: Json) -> Result, actix_web::Error> { - Ok(body) -} +use dingir_exchange::openapi::user::get_user; +use dingir_exchange::restapi::state::{AppCache, AppState}; +use fluidex_common::non_blocking_tracing; +use paperclip::actix::web::{self}; +use paperclip::actix::{api_v2_operation, OpenApiExt}; +use sqlx::postgres::Postgres; +use sqlx::Pool; +use std::collections::HashMap; +use std::convert::TryFrom; +use std::sync::Mutex; #[actix_web::main] async fn main() -> std::io::Result<()> { - HttpServer::new(|| { + dotenv::dotenv().ok(); + let _guard = non_blocking_tracing::setup(); + + let db_url = dingir_exchange::config::Settings::new().db_history; + log::debug!("Prepared DB connection: {}", &db_url); + + let config = dingir_exchange::restapi::config::Settings::default(); + let manage_channel = if let Some(ep_str) = &config.manage_endpoint { + log::info!("Connect to manage channel {}", ep_str); + Some( + tonic::transport::Endpoint::try_from(ep_str.clone()) + .ok() + .unwrap() + .connect() + .await + .unwrap(), + ) + } else { + None + }; + + let user_map = web::Data::new(AppState { + user_addr_map: Mutex::new(HashMap::new()), + manage_channel, + db: Pool::::connect(&db_url).await.unwrap(), + config, + }); + + HttpServer::new(move || { App::new() + .app_data(user_map.clone()) + .app_data(AppCache::new()) .wrap_api() - .service(web::resource("/pets").route(web::post().to(echo_pet))) + .service( + web::scope("/openapi") + .route("/ping", web::get().to(ping)) + .route("/user/{l1addr_or_l2pubkey}", web::get().to(get_user)), + ) .with_json_spec_at("/api/spec") .build() }) @@ -30,3 +57,8 @@ async fn main() -> std::io::Result<()> { .run() .await } + +#[api_v2_operation] +async fn ping() -> Result<&'static str, actix_web::Error> { + Ok("pong") +} diff --git a/src/lib.rs b/src/lib.rs index a66eb58b..fc2a210c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ pub mod storage; pub use storage::{database, models, sqlxextend}; pub mod config; pub mod message; +pub mod openapi; pub mod restapi; pub mod types; pub mod utils; diff --git a/src/openapi/mod.rs b/src/openapi/mod.rs new file mode 100644 index 00000000..22d12a38 --- /dev/null +++ b/src/openapi/mod.rs @@ -0,0 +1 @@ +pub mod user; diff --git a/src/openapi/user.rs b/src/openapi/user.rs new file mode 100644 index 00000000..9a810a19 --- /dev/null +++ b/src/openapi/user.rs @@ -0,0 +1,33 @@ +use crate::models::{tablenames::ACCOUNT, AccountDesc}; +use crate::restapi::errors::RpcError; +use crate::restapi::state::AppState; +use paperclip::actix::api_v2_operation; +use paperclip::actix::web::{self, HttpRequest, Json}; + +#[api_v2_operation] +pub async fn get_user(req: HttpRequest, data: web::Data) -> Result, actix_web::Error> { + let user_id: &str = req.match_info().get("l1addr_or_l2pubkey").unwrap(); + let mut user_map = data.user_addr_map.lock().unwrap(); + if user_map.contains_key(user_id) { + let user_info = &*user_map.get(user_id).unwrap(); + return Ok(Json(user_info.clone())); + } + + let sql_query = format!("select * from {} where l1_address = $1 OR l2_pubkey = $1", ACCOUNT); + let user: AccountDesc = sqlx::query_as(&sql_query).bind(user_id).fetch_one(&data.db).await.map_err(|e| { + log::error!("{:?}", e); + RpcError::bad_request("invalid user id or address") + })?; + + // update cache + user_map.insert( + user.l1_address.clone(), + AccountDesc { + id: user.id, + l1_address: user.l1_address.clone(), + l2_pubkey: user.l2_pubkey.clone(), + }, + ); + + Ok(Json(user)) +} diff --git a/src/storage/models.rs b/src/storage/models.rs index 4fefeea5..ab1841b2 100644 --- a/src/storage/models.rs +++ b/src/storage/models.rs @@ -1,6 +1,7 @@ use crate::types::OrderSide; use chrono::NaiveDateTime; -use serde::Serialize; +use paperclip::actix::Apiv2Schema; +use serde::{Deserialize, Serialize}; pub type DecimalDbType = fluidex_common::rust_decimal::Decimal; // https://github.com/launchbadge/sqlx/blob/master/sqlx-core/src/postgres/types/mod.rs @@ -51,7 +52,7 @@ pub struct MarketDesc { pub market_name: Option, } -#[derive(sqlx::FromRow, Debug, Clone, Serialize)] +#[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize, Apiv2Schema)] pub struct AccountDesc { pub id: i32, // TODO: i32 or i64? pub l1_address: String,