2025-05-20 16:17:32 +02:00
|
|
|
// Copyright (C) 2024 Riften Labs AS
|
|
|
|
|
//
|
|
|
|
|
// This software is licensed under the GNU Affero General Public License (AGPL), version 3.0 or later.
|
|
|
|
|
// A copy of the license can be found in the LICENSE file or at https://www.gnu.org/licenses/agpl-3.0.html
|
|
|
|
|
|
2025-06-17 14:04:26 +00:00
|
|
|
use crate::db::oracle::{get_closest, get_range, get_range_with_step};
|
2025-05-20 16:17:32 +02:00
|
|
|
use crate::db::DB;
|
|
|
|
|
use crate::timeutil::time_now;
|
|
|
|
|
use bitcoin_hashes::hex::FromHex;
|
|
|
|
|
use bitcoincash::TokenID;
|
|
|
|
|
use rocket::http::Status;
|
|
|
|
|
use rocket::response::status::Custom;
|
|
|
|
|
use rocket::serde::json::Json;
|
|
|
|
|
use rocket::{get, State};
|
2025-06-17 14:04:26 +00:00
|
|
|
use serde_json::{json, Value};
|
2025-05-20 16:17:32 +02:00
|
|
|
|
|
|
|
|
#[get("/delphi/closest?<token_id>&<timestamp>")]
|
|
|
|
|
pub fn oracle_get_closest(
|
|
|
|
|
token_id: Option<String>,
|
|
|
|
|
timestamp: Option<i64>,
|
|
|
|
|
db: &State<DB>,
|
|
|
|
|
) -> Result<Json<serde_json::Value>, Custom<String>> {
|
|
|
|
|
let current_timestamp = timestamp.unwrap_or_else(time_now);
|
|
|
|
|
let conn = db
|
|
|
|
|
.oracle_r
|
|
|
|
|
.get()
|
|
|
|
|
.map_err(|e| Custom(Status::InternalServerError, e.to_string()))?;
|
|
|
|
|
let token_id = token_id
|
|
|
|
|
.map(|t| {
|
|
|
|
|
TokenID::from_hex(&t)
|
|
|
|
|
.map_err(|e| Custom(Status::BadRequest, format!("Invalid token ID: {}", e)))
|
|
|
|
|
})
|
|
|
|
|
.transpose()?;
|
|
|
|
|
let entry = get_closest(&conn, &token_id, current_timestamp)
|
|
|
|
|
.map_err(|e| Custom(Status::InternalServerError, e.to_string()))?;
|
|
|
|
|
Ok(Json(entry.map_or(serde_json::Value::Null, |e| {
|
|
|
|
|
serde_json::to_value(e).unwrap()
|
|
|
|
|
})))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[get("/delphi/range?<token_id>&<start>&<end>")]
|
|
|
|
|
pub fn oracle_get_range(
|
|
|
|
|
token_id: Option<String>,
|
|
|
|
|
start: Option<i64>,
|
|
|
|
|
end: Option<i64>,
|
|
|
|
|
db: &State<DB>,
|
|
|
|
|
) -> Result<Json<Vec<serde_json::Value>>, Custom<String>> {
|
|
|
|
|
let end_timestamp = end.unwrap_or_else(time_now);
|
|
|
|
|
let start_timestamp = start.unwrap_or_else(|| end_timestamp - 86400); // 1 day in seconds
|
|
|
|
|
let conn = db
|
|
|
|
|
.oracle_r
|
|
|
|
|
.get()
|
|
|
|
|
.map_err(|e| Custom(Status::InternalServerError, e.to_string()))?;
|
|
|
|
|
let token_id = token_id
|
|
|
|
|
.map(|t| {
|
|
|
|
|
TokenID::from_hex(&t)
|
|
|
|
|
.map_err(|e| Custom(Status::BadRequest, format!("Invalid token ID: {}", e)))
|
|
|
|
|
})
|
|
|
|
|
.transpose()?;
|
|
|
|
|
let entries = get_range(&conn, &token_id, start_timestamp, end_timestamp)
|
|
|
|
|
.map_err(|e| Custom(Status::InternalServerError, e.to_string()))?;
|
|
|
|
|
Ok(Json(
|
|
|
|
|
entries
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|e| serde_json::to_value(e).unwrap())
|
|
|
|
|
.collect(),
|
|
|
|
|
))
|
|
|
|
|
}
|
2025-06-17 14:04:26 +00:00
|
|
|
|
|
|
|
|
#[get("/delphi/<token>/history?<start>&<end>&<stepsize>")]
|
|
|
|
|
pub fn oracle_get_history(
|
|
|
|
|
token: &str,
|
|
|
|
|
start: Option<i64>,
|
|
|
|
|
end: Option<i64>,
|
|
|
|
|
stepsize: Option<i64>,
|
|
|
|
|
db: &State<DB>,
|
|
|
|
|
) -> Result<Json<Value>, Custom<String>> {
|
|
|
|
|
let current_timestamp = time_now();
|
|
|
|
|
|
|
|
|
|
let conn = db
|
|
|
|
|
.oracle_r
|
|
|
|
|
.get()
|
|
|
|
|
.map_err(|e| Custom(Status::InternalServerError, format!("DB error: {}", e)))?;
|
|
|
|
|
|
|
|
|
|
let token_id = token
|
|
|
|
|
.parse::<TokenID>()
|
|
|
|
|
.map_err(|e| Custom(Status::BadRequest, format!("Invalid token ID: {}", e)))?;
|
|
|
|
|
|
|
|
|
|
let start_ts = start.unwrap_or(current_timestamp - 30 * 24 * 3600); // default: 30 days ago
|
|
|
|
|
let end_ts = end.unwrap_or(current_timestamp);
|
|
|
|
|
|
|
|
|
|
let entries = if let Some(step) = stepsize {
|
|
|
|
|
get_range_with_step(&conn, &Some(token_id), start_ts, end_ts, step)
|
|
|
|
|
.map_err(|e| Custom(Status::BadRequest, format!("Query error: {}", e)))?
|
|
|
|
|
} else {
|
|
|
|
|
get_range(&conn, &Some(token_id), start_ts, end_ts)
|
|
|
|
|
.map_err(|e| Custom(Status::BadRequest, format!("Query error: {}", e)))?
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let json_entries: Vec<Value> = entries
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|entry| {
|
|
|
|
|
json!({
|
|
|
|
|
"time": entry.oracle_timestamp,
|
|
|
|
|
"price": entry.oracle_price,
|
|
|
|
|
"txid": entry.txid,
|
|
|
|
|
"blockhash": entry.blockhash,
|
|
|
|
|
"sequence": entry.oracle_sequence,
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
Ok(Json(serde_json::Value::Array(json_entries)))
|
|
|
|
|
}
|