Skip to content

Commit

Permalink
feat(maker): Get position information via HTTP API
Browse files Browse the repository at this point in the history
  • Loading branch information
luckysori committed Sep 21, 2023
1 parent 307b191 commit 78bd426
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 12 deletions.
4 changes: 2 additions & 2 deletions maker/src/bin/maker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,11 @@ async fn main() -> Result<()> {
opts.orderbook,
node_pubkey,
node.node_key(),
position_manager,
position_manager.clone(),
)
.spawn_supervised_connection();

let app = router(node, exporter, pool, health);
let app = router(node, exporter, position_manager, health);

// Start the metrics exporter
autometrics::prometheus_exporter::init();
Expand Down
27 changes: 26 additions & 1 deletion maker/src/position.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use async_trait::async_trait;
use rust_decimal::Decimal;
use serde::Serialize;
use std::collections::HashMap;
use std::collections::HashSet;
use std::fmt::Display;
use std::hash::Hash;
Expand Down Expand Up @@ -48,6 +50,12 @@ impl OrderTenTenOne {
}
}

pub struct GetPosition;

pub struct GetPositionResponse {
pub tentenone: HashMap<ContractSymbol, Decimal>,
}

#[async_trait]
impl xtra::Actor for Manager {
type Stop = ();
Expand Down Expand Up @@ -76,6 +84,23 @@ impl xtra::Handler<PositionUpdateTenTenOne> for Manager {
}
}

#[async_trait]
impl xtra::Handler<GetPosition> for Manager {
type Return = GetPositionResponse;

async fn handle(&mut self, _: GetPosition, _: &mut xtra::Context<Self>) -> Self::Return {
let tentenone =
HashMap::from_iter(self.position.tentenone.clone().into_iter().map(|position| {
(
position.contract_symbol(),
position.contracts().to_decimal(),
)
}));

GetPositionResponse { tentenone }
}
}

/// The overall position of the maker.
#[derive(Debug)]
struct Position {
Expand Down Expand Up @@ -119,7 +144,7 @@ impl Position {
}
}

#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, Serialize)]
pub enum ContractSymbol {
BtcUsd,
}
Expand Down
4 changes: 4 additions & 0 deletions maker/src/position/tentenone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ impl Position {
acc + Contracts::new(*contracts)
})
}

pub fn contract_symbol(&self) -> ContractSymbol {
self.contract_symbol
}
}

impl PartialEq for Position {
Expand Down
65 changes: 56 additions & 9 deletions maker/src/routes.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::health::Health;
use crate::health::OverallMakerHealth;
use crate::position;
use crate::position::ContractSymbol;
use crate::position::GetPosition;
use axum::extract::Path;
use axum::extract::State;
use axum::http::StatusCode;
Expand All @@ -10,40 +13,41 @@ use axum::routing::post;
use axum::Json;
use axum::Router;
use bitcoin::secp256k1::PublicKey;
use diesel::r2d2::ConnectionManager;
use diesel::r2d2::Pool;
use diesel::PgConnection;
use ln_dlc_node::node::InMemoryStore;
use ln_dlc_node::node::Node;
use ln_dlc_node::node::NodeInfo;
use ln_dlc_node::ChannelDetails;
use opentelemetry_prometheus::PrometheusExporter;
use prometheus::Encoder;
use prometheus::TextEncoder;
use rust_decimal::Decimal;
use serde::Deserialize;
use serde::Serialize;
use serde_json::json;
use std::collections::HashSet;
use std::hash::Hash;
use std::hash::Hasher;
use std::str::FromStr;
use std::sync::Arc;
use tokio::task::spawn_blocking;

pub struct AppState {
pub node: Arc<Node<InMemoryStore>>,
pub exporter: PrometheusExporter,
pub pool: Pool<ConnectionManager<PgConnection>>,
pub health: Health,
node: Arc<Node<InMemoryStore>>,
exporter: PrometheusExporter,
position_manager: xtra::Address<position::Manager>,
health: Health,
}

pub fn router(
node: Arc<Node<InMemoryStore>>,
exporter: PrometheusExporter,
pool: Pool<ConnectionManager<PgConnection>>,
position_manager: xtra::Address<position::Manager>,
health: Health,
) -> Router {
let app_state = Arc::new(AppState {
node,
exporter,
pool,
position_manager,
health,
});

Expand All @@ -56,6 +60,7 @@ pub fn router(
.route("/api/connect", post(connect_to_peer))
.route("/api/pay-invoice/:invoice", post(pay_invoice))
.route("/api/sync-on-chain", post(sync_on_chain))
.route("/api/position", get(get_position))
.route("/metrics", get(get_metrics))
.route("/health", get(get_health))
.with_state(app_state)
Expand Down Expand Up @@ -242,6 +247,48 @@ pub async fn sync_on_chain(State(state): State<Arc<AppState>>) -> Result<(), App
Ok(())
}

#[derive(Serialize)]
pub struct Position {
tentenone: HashSet<PositionForContractSymbol>,
}

#[derive(Serialize, Eq)]
pub struct PositionForContractSymbol {
contract_symbol: ContractSymbol,
contracts: Decimal,
}

impl Hash for PositionForContractSymbol {
fn hash<H: Hasher>(&self, state: &mut H) {
self.contract_symbol.hash(state);
}
}

impl PartialEq for PositionForContractSymbol {
fn eq(&self, other: &PositionForContractSymbol) -> bool {
self.contract_symbol == other.contract_symbol
}
}

pub async fn get_position(State(state): State<Arc<AppState>>) -> Result<Json<Position>, AppError> {
let position = state
.position_manager
.send(GetPosition)
.await
.map_err(|e| AppError::InternalServerError(format!("Failed to get position: {e:#}")))?;

let position = HashSet::from_iter(position.tentenone.into_iter().map(
|(contract_symbol, contracts)| PositionForContractSymbol {
contract_symbol,
contracts,
},
));

Ok(Json(Position {
tentenone: position,
}))
}

pub async fn get_metrics(State(state): State<Arc<AppState>>) -> impl IntoResponse {
let autometrics = match autometrics::prometheus_exporter::encode_to_string() {
Ok(metrics) => metrics,
Expand Down

0 comments on commit 78bd426

Please sign in to comment.