scematica_protocol/
server.rs1use axum::{middleware, routing::get, Json, Router};
2use std::{net::SocketAddr, sync::Arc};
3use tracing::info;
4
5use crate::{
6 facilitator::Facilitator,
7 middleware::{payment_middleware, PaymentGate},
8 types::PaymentRequirements,
9};
10
11pub struct ProtocolServer {
12 gate: Arc<PaymentGate>,
13 addr: SocketAddr,
14}
15
16impl ProtocolServer {
17 pub fn new(
18 facilitator: Arc<Facilitator>,
19 requirements: Vec<PaymentRequirements>,
20 addr: SocketAddr,
21 ) -> Self {
22 let gate = Arc::new(PaymentGate {
23 facilitator,
24 requirements,
25 });
26 Self { gate, addr }
27 }
28
29 pub async fn run(self) -> anyhow::Result<()> {
30 let gate = self.gate.clone();
31
32 let paid = Router::new()
34 .route("/signals/pools", get(pools_handler))
35 .route("/signals/trades", get(trades_handler))
36 .route("/stats/nn", get(nn_stats_handler))
37 .route("/stats/metrics", get(metrics_handler))
38 .layer(middleware::from_fn_with_state(
39 gate.clone(),
40 payment_middleware,
41 ));
42
43 let accepts = gate.requirements.clone();
45 let free = Router::new().route("/health", get(health_handler)).route(
46 "/supported",
47 get(move || {
48 let a = accepts.clone();
49 async move { Json(serde_json::json!({ "accepts": a })) }
50 }),
51 );
52
53 let app = Router::new().merge(paid).merge(free);
54
55 info!("🌐 Scematica Protocol API on {}", self.addr);
56 axum::Server::bind(&self.addr)
57 .serve(app.into_make_service())
58 .await?;
59 Ok(())
60 }
61}
62
63async fn pools_handler() -> Json<serde_json::Value> {
66 let data = read_json("scematica-filter-stats.json");
67 Json(serde_json::json!({
68 "pool_stats": data,
69 "timestamp": chrono::Utc::now(),
70 }))
71}
72
73async fn trades_handler() -> Json<serde_json::Value> {
74 let trades: Vec<serde_json::Value> = std::fs::read_to_string("scematica-trades.jsonl")
75 .unwrap_or_default()
76 .lines()
77 .filter_map(|l| serde_json::from_str(l).ok())
78 .collect::<Vec<_>>()
79 .into_iter()
80 .rev()
81 .take(200)
82 .collect();
83 let count = trades.len();
84 Json(serde_json::json!({ "trades": trades, "count": count, "timestamp": chrono::Utc::now() }))
85}
86
87async fn nn_stats_handler() -> Json<serde_json::Value> {
88 Json(serde_json::json!({
89 "nn_stats": read_json("scematica-nn-stats.json"),
90 "timestamp": chrono::Utc::now(),
91 }))
92}
93
94async fn metrics_handler() -> Json<serde_json::Value> {
95 Json(serde_json::json!({
96 "metrics": read_json("scematica-metrics.json"),
97 "strategy": read_json("scematica-strategy.json"),
98 "timestamp": chrono::Utc::now(),
99 }))
100}
101
102async fn health_handler() -> Json<serde_json::Value> {
105 Json(serde_json::json!({
106 "status": "ok",
107 "protocol": "scematica-x402",
108 "version": crate::types::X402_VERSION,
109 }))
110}
111
112fn read_json(path: &str) -> serde_json::Value {
115 std::fs::read_to_string(path)
116 .ok()
117 .and_then(|s| serde_json::from_str(&s).ok())
118 .unwrap_or(serde_json::Value::Null)
119}