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>, ) -> Result<(StatusCode, Json>), 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>, Path(symbol): Path, ) -> Result<(StatusCode, Json), 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>, Extension(broadcast_sender): Extension>, Json(request): Json, ) -> Result<(StatusCode, Json), 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::().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>, Extension(broadcast_sender): Extension>, Path(symbol): Path, ) -> Result { 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) }