feat: HTTP responses adjustments

This commit is contained in:
Ludo Galabru
2023-06-06 07:45:19 -04:00
parent 156c463cc0
commit 51572efd93
4 changed files with 101 additions and 98 deletions

View File

@@ -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,

View File

@@ -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()))?;

View File

@@ -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),

View File

@@ -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),