mirror of
https://github.com/alexgo-io/bitcoin-indexer.git
synced 2026-06-14 00:22:19 +08:00
feat: HTTP responses adjustments
This commit is contained in:
@@ -3,7 +3,7 @@ use std::collections::{HashMap, VecDeque};
|
||||
use crate::{
|
||||
archive::download_stacks_dataset_if_required,
|
||||
block::{Record, RecordKind},
|
||||
config::{Config, PredicatesApi, PredicatesApiConfig},
|
||||
config::{Config, PredicatesApi},
|
||||
service::{
|
||||
open_readwrite_predicates_db_conn_or_panic, update_predicate_status, PredicateStatus,
|
||||
ScanningData,
|
||||
@@ -15,7 +15,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use chainhook_event_observer::{
|
||||
chainhooks::{stacks::evaluate_stacks_chainhook_on_blocks, types::ChainhookSpecification},
|
||||
chainhooks::stacks::evaluate_stacks_chainhook_on_blocks,
|
||||
indexer::{self, stacks::standardize_stacks_serialized_block_header, Indexer},
|
||||
rocksdb::DB,
|
||||
utils::Context,
|
||||
|
||||
@@ -79,7 +79,7 @@ pub async fn start_predicate_api_server(
|
||||
#[openapi(tag = "Chainhooks")]
|
||||
#[get("/ping")]
|
||||
fn handle_ping(ctx: &State<Context>) -> Json<JsonValue> {
|
||||
ctx.try_log(|logger| slog::info!(logger, "GET /ping"));
|
||||
ctx.try_log(|logger| slog::info!(logger, "Handling HTTP GET /ping"));
|
||||
Json(json!({
|
||||
"status": 200,
|
||||
"result": "Ok",
|
||||
@@ -92,42 +92,21 @@ fn handle_get_predicates(
|
||||
predicate_db: &State<Arc<RwLock<Connection>>>,
|
||||
ctx: &State<Context>,
|
||||
) -> Json<JsonValue> {
|
||||
ctx.try_log(|logger| slog::info!(logger, "GET /v1/chainhooks"));
|
||||
if let Ok(chainhook_store_reader) = chainhook_store.inner().read() {
|
||||
let mut predicates = vec![];
|
||||
let mut stacks_predicates = chainhook_store_reader
|
||||
.predicates
|
||||
.get_serialized_stacks_predicates()
|
||||
.iter()
|
||||
.map(|(uuid, network, predicate)| {
|
||||
json!({
|
||||
"chain": "stacks",
|
||||
"uuid": uuid,
|
||||
"network": network,
|
||||
"predicate": predicate,
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
predicates.append(&mut stacks_predicates);
|
||||
ctx.try_log(|logger| slog::info!(logger, "Handling HTTP GET /v1/chainhooks"));
|
||||
if let Ok(mut predicates_db_conn) = predicate_db.inner().write() {
|
||||
let predicates = match get_entries_from_predicates_db(&mut predicates_db_conn, &ctx) {
|
||||
Ok(predicates) => predicates,
|
||||
Err(e) => unimplemented!(),
|
||||
};
|
||||
|
||||
let mut bitcoin_predicates = chainhook_store_reader
|
||||
.predicates
|
||||
.get_serialized_bitcoin_predicates()
|
||||
let serialized_predicates = predicates
|
||||
.iter()
|
||||
.map(|(uuid, network, predicate)| {
|
||||
json!({
|
||||
"chain": "bitcoin",
|
||||
"uuid": uuid,
|
||||
"network": network,
|
||||
"predicate": predicate,
|
||||
})
|
||||
})
|
||||
.map(|(p, _)| p.into_serialized_json())
|
||||
.collect::<Vec<_>>();
|
||||
predicates.append(&mut bitcoin_predicates);
|
||||
|
||||
Json(json!({
|
||||
"status": 200,
|
||||
"result": predicates
|
||||
"result": serialized_predicates
|
||||
}))
|
||||
} else {
|
||||
Json(json!({
|
||||
@@ -145,7 +124,7 @@ fn handle_create_predicate(
|
||||
background_job_tx: &State<Arc<Mutex<Sender<ObserverCommand>>>>,
|
||||
ctx: &State<Context>,
|
||||
) -> Json<JsonValue> {
|
||||
ctx.try_log(|logger| slog::info!(logger, "POST /v1/chainhooks"));
|
||||
ctx.try_log(|logger| slog::info!(logger, "Handling HTTP POST /v1/chainhooks"));
|
||||
let predicate = predicate.into_inner();
|
||||
if let Err(e) = predicate.validate() {
|
||||
return Json(json!({
|
||||
@@ -155,7 +134,11 @@ fn handle_create_predicate(
|
||||
}
|
||||
|
||||
if let Ok(mut predicates_db_conn) = predicate_db.inner().write() {
|
||||
match get_entry_from_predicates_db(&predicate.get_uuid(), &mut predicates_db_conn, &ctx) {
|
||||
match get_entry_from_predicates_db(
|
||||
&ChainhookSpecification::either_stx_or_btc_key(predicate.get_uuid()),
|
||||
&mut predicates_db_conn,
|
||||
&ctx,
|
||||
) {
|
||||
Ok(Some(_)) => {
|
||||
return Json(json!({
|
||||
"status": 409,
|
||||
@@ -187,28 +170,44 @@ fn handle_get_predicate(
|
||||
predicate_db: &State<Arc<RwLock<Connection>>>,
|
||||
ctx: &State<Context>,
|
||||
) -> Json<JsonValue> {
|
||||
ctx.try_log(|logger| slog::info!(logger, "GET /v1/chainhooks/{}", predicate_uuid));
|
||||
ctx.try_log(|logger| {
|
||||
slog::info!(
|
||||
logger,
|
||||
"Handling HTTP GET /v1/chainhooks/{}",
|
||||
predicate_uuid
|
||||
)
|
||||
});
|
||||
|
||||
if let Ok(mut predicates_db_conn) = predicate_db.inner().write() {
|
||||
match get_entry_from_predicates_db(&predicate_uuid, &mut predicates_db_conn, &ctx) {
|
||||
Ok(Some((ChainhookSpecification::Stacks(spec), status))) => Json(json!({
|
||||
let entry = match get_entry_from_predicates_db(
|
||||
&ChainhookSpecification::either_stx_or_btc_key(&predicate_uuid),
|
||||
&mut predicates_db_conn,
|
||||
&ctx,
|
||||
) {
|
||||
Ok(Some((ChainhookSpecification::Stacks(spec), status))) => json!({
|
||||
"chain": "stacks",
|
||||
"uuid": spec.uuid,
|
||||
"network": spec.network,
|
||||
"predicate": spec.predicate,
|
||||
"status": status
|
||||
})),
|
||||
Ok(Some((ChainhookSpecification::Bitcoin(spec), status))) => Json(json!({
|
||||
}),
|
||||
Ok(Some((ChainhookSpecification::Bitcoin(spec), status))) => json!({
|
||||
"chain": "bitcoin",
|
||||
"uuid": spec.uuid,
|
||||
"network": spec.network,
|
||||
"predicate": spec.predicate,
|
||||
"status": status
|
||||
})),
|
||||
_ => Json(json!({
|
||||
"status": 404,
|
||||
})),
|
||||
}
|
||||
}),
|
||||
_ => {
|
||||
return Json(json!({
|
||||
"status": 404,
|
||||
}))
|
||||
}
|
||||
};
|
||||
Json(json!({
|
||||
"status": 200,
|
||||
"result": entry
|
||||
}))
|
||||
} else {
|
||||
Json(json!({
|
||||
"status": 500,
|
||||
@@ -224,7 +223,13 @@ fn handle_delete_stacks_predicate(
|
||||
background_job_tx: &State<Arc<Mutex<Sender<ObserverCommand>>>>,
|
||||
ctx: &State<Context>,
|
||||
) -> Json<JsonValue> {
|
||||
ctx.try_log(|logger| slog::info!(logger, "DELETE /v1/chainhooks/stacks/{}", predicate_uuid));
|
||||
ctx.try_log(|logger| {
|
||||
slog::info!(
|
||||
logger,
|
||||
"Handling HTTP DELETE /v1/chainhooks/stacks/{}",
|
||||
predicate_uuid
|
||||
)
|
||||
});
|
||||
|
||||
let background_job_tx = background_job_tx.inner();
|
||||
match background_job_tx.lock() {
|
||||
@@ -247,7 +252,13 @@ fn handle_delete_bitcoin_predicate(
|
||||
background_job_tx: &State<Arc<Mutex<Sender<ObserverCommand>>>>,
|
||||
ctx: &State<Context>,
|
||||
) -> Json<JsonValue> {
|
||||
ctx.try_log(|logger| slog::info!(logger, "DELETE /v1/chainhooks/bitcoin/{}", predicate_uuid));
|
||||
ctx.try_log(|logger| {
|
||||
slog::info!(
|
||||
logger,
|
||||
"Handling HTTP DELETE /v1/chainhooks/bitcoin/{}",
|
||||
predicate_uuid
|
||||
)
|
||||
});
|
||||
|
||||
let background_job_tx = background_job_tx.inner();
|
||||
match background_job_tx.lock() {
|
||||
@@ -264,19 +275,17 @@ fn handle_delete_bitcoin_predicate(
|
||||
}
|
||||
|
||||
pub fn get_entry_from_predicates_db(
|
||||
uuid: &str,
|
||||
predicate_key: &str,
|
||||
predicate_db_conn: &mut Connection,
|
||||
_ctx: &Context,
|
||||
) -> Result<Option<(ChainhookSpecification, PredicateStatus)>, String> {
|
||||
let entry: HashMap<String, String> = predicate_db_conn
|
||||
.hgetall(ChainhookSpecification::either_stx_or_btc_key(uuid))
|
||||
.map_err(|e| {
|
||||
format!(
|
||||
"unable to load chainhook associated with key {}: {}",
|
||||
uuid,
|
||||
e.to_string()
|
||||
)
|
||||
})?;
|
||||
let entry: HashMap<String, String> = predicate_db_conn.hgetall(predicate_key).map_err(|e| {
|
||||
format!(
|
||||
"unable to load chainhook associated with key {}: {}",
|
||||
predicate_key,
|
||||
e.to_string()
|
||||
)
|
||||
})?;
|
||||
|
||||
let encoded_spec = match entry.get("specification") {
|
||||
None => return Ok(None),
|
||||
@@ -294,7 +303,7 @@ pub fn get_entry_from_predicates_db(
|
||||
};
|
||||
|
||||
let status = match serde_json::from_str(&encoded_status) {
|
||||
Err(e) => unimplemented!(),
|
||||
Err(e) => unimplemented!(), // TODO
|
||||
Ok(status) => status,
|
||||
};
|
||||
|
||||
@@ -304,7 +313,7 @@ pub fn get_entry_from_predicates_db(
|
||||
pub fn get_entries_from_predicates_db(
|
||||
predicate_db_conn: &mut Connection,
|
||||
ctx: &Context,
|
||||
) -> Result<Vec<ChainhookSpecification>, String> {
|
||||
) -> Result<Vec<(ChainhookSpecification, PredicateStatus)>, String> {
|
||||
let chainhooks_to_load: Vec<String> = predicate_db_conn
|
||||
.scan_match(ChainhookSpecification::either_stx_or_btc_key("*"))
|
||||
.map_err(|e| format!("unable to connect to redis: {}", e.to_string()))?
|
||||
@@ -312,25 +321,21 @@ pub fn get_entries_from_predicates_db(
|
||||
.collect();
|
||||
|
||||
let mut predicates = vec![];
|
||||
for key in chainhooks_to_load.iter() {
|
||||
let chainhook = match predicate_db_conn.hget::<_, _, String>(key, "specification") {
|
||||
Ok(spec) => match ChainhookSpecification::deserialize_specification(&spec) {
|
||||
Ok(spec) => spec,
|
||||
Err(e) => {
|
||||
error!(
|
||||
ctx.expect_logger(),
|
||||
"unable to load chainhook associated with key {}: {}",
|
||||
key,
|
||||
e.to_string()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
},
|
||||
for predicate_key in chainhooks_to_load.iter() {
|
||||
let chainhook = match get_entry_from_predicates_db(predicate_key, predicate_db_conn, ctx) {
|
||||
Ok(Some((spec, status))) => (spec, status),
|
||||
Ok(None) => {
|
||||
warn!(
|
||||
ctx.expect_logger(),
|
||||
"unable to load chainhook associated with key {}", predicate_key,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
error!(
|
||||
ctx.expect_logger(),
|
||||
"unable to load chainhook associated with key {}: {}",
|
||||
key,
|
||||
predicate_key,
|
||||
e.to_string()
|
||||
);
|
||||
continue;
|
||||
@@ -344,7 +349,7 @@ pub fn get_entries_from_predicates_db(
|
||||
pub fn load_predicates_from_redis(
|
||||
config: &crate::config::Config,
|
||||
ctx: &Context,
|
||||
) -> Result<Vec<ChainhookSpecification>, String> {
|
||||
) -> Result<Vec<(ChainhookSpecification, PredicateStatus)>, String> {
|
||||
let redis_uri: &str = config.expected_api_database_uri();
|
||||
let client = redis::Client::open(redis_uri.clone())
|
||||
.map_err(|e| format!("unable to connect to redis: {}", e.to_string()))?;
|
||||
|
||||
@@ -49,7 +49,7 @@ impl Service {
|
||||
vec![]
|
||||
}
|
||||
};
|
||||
for predicate in registered_predicates.into_iter() {
|
||||
for (predicate, _status) in registered_predicates.into_iter() {
|
||||
let predicate_uuid = predicate.uuid().to_string();
|
||||
match chainhook_config.register_specification(predicate, true) {
|
||||
Ok(_) => {
|
||||
@@ -327,6 +327,7 @@ impl Service {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum PredicateStatus {
|
||||
Scanning(ScanningData),
|
||||
Streaming(StreamingData),
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use chainhook_types::{BitcoinNetwork, StacksNetwork};
|
||||
use clarity_repl::clarity::util::hash::hex_bytes;
|
||||
use reqwest::Url;
|
||||
use serde::ser::{SerializeSeq, Serializer};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use chainhook_types::{BitcoinNetwork, StacksNetwork};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use schemars::JsonSchema;
|
||||
|
||||
@@ -44,26 +44,6 @@ impl ChainhookConfig {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_serialized_stacks_predicates(
|
||||
&self,
|
||||
) -> Vec<(&String, &StacksNetwork, &StacksPredicate)> {
|
||||
let mut stacks = vec![];
|
||||
for chainhook in self.stacks_chainhooks.iter() {
|
||||
stacks.push((&chainhook.uuid, &chainhook.network, &chainhook.predicate));
|
||||
}
|
||||
stacks
|
||||
}
|
||||
|
||||
pub fn get_serialized_bitcoin_predicates(
|
||||
&self,
|
||||
) -> Vec<(&String, &BitcoinNetwork, &BitcoinPredicateType)> {
|
||||
let mut bitcoin = vec![];
|
||||
for chainhook in self.bitcoin_chainhooks.iter() {
|
||||
bitcoin.push((&chainhook.uuid, &chainhook.network, &chainhook.predicate));
|
||||
}
|
||||
bitcoin
|
||||
}
|
||||
|
||||
pub fn register_full_specification(
|
||||
&mut self,
|
||||
networks: (&BitcoinNetwork, &StacksNetwork),
|
||||
@@ -203,6 +183,23 @@ impl ChainhookSpecification {
|
||||
format!("predicate:{}", uuid)
|
||||
}
|
||||
|
||||
pub fn into_serialized_json(&self) -> JsonValue {
|
||||
match &self {
|
||||
Self::Bitcoin(data) => json!({
|
||||
"chain": "stacks",
|
||||
"uuid": data.uuid,
|
||||
"network": data.network,
|
||||
"predicate": data.predicate,
|
||||
}),
|
||||
Self::Stacks(data) => json!({
|
||||
"chain": "bitcoin",
|
||||
"uuid": data.uuid,
|
||||
"network": data.network,
|
||||
"predicate": data.predicate,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn key(&self) -> String {
|
||||
match &self {
|
||||
Self::Bitcoin(data) => Self::bitcoin_key(&data.uuid),
|
||||
|
||||
Reference in New Issue
Block a user