103 lines
3.1 KiB
Rust
103 lines
3.1 KiB
Rust
use crate::config::{Config, ALPACA_ASSET_API_URL};
|
|
use crate::database;
|
|
use crate::types::{
|
|
alpaca::api::incoming::{self, asset::Status},
|
|
asset, Asset, BroadcastMessage,
|
|
};
|
|
use axum::{extract::Path, Extension, Json};
|
|
use http::StatusCode;
|
|
use log::info;
|
|
use serde::Deserialize;
|
|
use std::sync::Arc;
|
|
use tokio::sync::broadcast::Sender;
|
|
|
|
pub async fn get(
|
|
Extension(app_config): Extension<Arc<Config>>,
|
|
) -> Result<(StatusCode, Json<Vec<Asset>>), StatusCode> {
|
|
let assets = database::assets::select(&app_config.clickhouse_client).await;
|
|
Ok((StatusCode::OK, Json(assets)))
|
|
}
|
|
|
|
pub async fn get_where_symbol(
|
|
Extension(app_config): Extension<Arc<Config>>,
|
|
Path(symbol): Path<String>,
|
|
) -> Result<(StatusCode, Json<Asset>), StatusCode> {
|
|
let asset = database::assets::select_where_symbol(&app_config.clickhouse_client, &symbol).await;
|
|
asset.map_or(Err(StatusCode::NOT_FOUND), |asset| {
|
|
Ok((StatusCode::OK, Json(asset)))
|
|
})
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
pub struct AddAssetRequest {
|
|
symbol: String,
|
|
}
|
|
|
|
pub async fn add(
|
|
Extension(app_config): Extension<Arc<Config>>,
|
|
Extension(broadcast_sender): Extension<Sender<BroadcastMessage>>,
|
|
Json(request): Json<AddAssetRequest>,
|
|
) -> Result<(StatusCode, Json<Asset>), StatusCode> {
|
|
if database::assets::select_where_symbol(&app_config.clickhouse_client, &request.symbol)
|
|
.await
|
|
.is_some()
|
|
{
|
|
return Err(StatusCode::CONFLICT);
|
|
}
|
|
|
|
app_config.alpaca_rate_limit.until_ready().await;
|
|
let asset = app_config
|
|
.alpaca_client
|
|
.get(&format!("{}/{}", ALPACA_ASSET_API_URL, request.symbol))
|
|
.send()
|
|
.await
|
|
.map_err(|e| {
|
|
if e.status() == Some(reqwest::StatusCode::NOT_FOUND) {
|
|
StatusCode::NOT_FOUND
|
|
} else {
|
|
panic!()
|
|
}
|
|
})
|
|
.unwrap();
|
|
|
|
let asset = asset.json::<incoming::asset::Asset>().await.unwrap();
|
|
|
|
if asset.status != Status::Active || !asset.tradable || !asset.fractionable {
|
|
return Err(StatusCode::FORBIDDEN);
|
|
}
|
|
|
|
let asset = Asset::from(asset);
|
|
database::assets::insert(&app_config.clickhouse_client, &asset).await;
|
|
|
|
broadcast_sender
|
|
.send(BroadcastMessage::Asset(asset::BroadcastMessage::Added(
|
|
asset.clone(),
|
|
)))
|
|
.unwrap();
|
|
|
|
info!("Added asset {}.", asset.symbol);
|
|
Ok((StatusCode::CREATED, Json(asset)))
|
|
}
|
|
|
|
pub async fn delete(
|
|
Extension(app_config): Extension<Arc<Config>>,
|
|
Extension(broadcast_sender): Extension<Sender<BroadcastMessage>>,
|
|
Path(symbol): Path<String>,
|
|
) -> Result<StatusCode, StatusCode> {
|
|
let asset = database::assets::select_where_symbol(&app_config.clickhouse_client, &symbol)
|
|
.await
|
|
.ok_or(StatusCode::NOT_FOUND)
|
|
.unwrap();
|
|
|
|
broadcast_sender
|
|
.send(BroadcastMessage::Asset(asset::BroadcastMessage::Deleted(
|
|
asset,
|
|
)))
|
|
.unwrap();
|
|
|
|
database::assets::delete_where_symbol(&app_config.clickhouse_client, &symbol).await;
|
|
|
|
info!("Deleted asset {}.", symbol);
|
|
Ok(StatusCode::NO_CONTENT)
|
|
}
|