From 06a68e758c379366668f2e9951bbbd78098ac15e Mon Sep 17 00:00:00 2001 From: Yuki Kishimoto Date: Tue, 11 Jun 2024 16:43:33 -0400 Subject: [PATCH] Add `/event/` endpoint --- src/error.rs | 7 +++++- src/handler.rs | 61 ++++++++++++++++++++++++++++++++++---------------- src/main.rs | 1 + 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/src/error.rs b/src/error.rs index 5a07103..566781d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -23,6 +23,8 @@ where pub enum AppError { // Too many filters were provided in the request FilterError(usize), + // Too many filters were provided in the request + EventIdNotFound, // The request body contained invalid JSON JsonRejection(JsonRejection), // An Nostr Client error occurred @@ -38,8 +40,11 @@ impl IntoResponse for AppError { let (status, message) = match self { AppError::FilterError(max_filters) => ( StatusCode::BAD_REQUEST, - format!("Too many filters (max allowed {})", max_filters).to_string(), + format!("Too many filters (max allowed {max_filters})"), ), + AppError::EventIdNotFound => { + (StatusCode::BAD_REQUEST, String::from("Event ID not found")) + } AppError::JsonRejection(rejection) => (rejection.status(), rejection.body_text()), AppError::NostrClientError(err) => (StatusCode::BAD_REQUEST, err.to_string()), AppError::NostrEventError(err) => (StatusCode::BAD_REQUEST, err.to_string()), diff --git a/src/handler.rs b/src/handler.rs index 47b4d7d..768ee9d 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -1,17 +1,23 @@ // Copyright (c) 2023 Nostr Development Kit Devs // Distributed under the MIT software license -use axum::extract::State; +use axum::extract::{Path, State}; use axum::response::Json; use nostr_sdk::hashes::sha256::Hash as Sha256Hash; use nostr_sdk::hashes::Hash; -use nostr_sdk::{Event, Filter}; +use nostr_sdk::{Event, EventId, Filter}; use redis::AsyncCommands; +use serde::Deserialize; use serde_json::{json, Value}; use crate::error::{AppError, AppJson}; use crate::AppState; +#[derive(Deserialize)] +pub struct GetEventByIdParams { + event_id: EventId, +} + pub async fn ping() -> Json { Json(json!({ "success": true, @@ -44,19 +50,44 @@ pub async fn get_events( return Err(AppError::FilterError(state.config.limit.max_filters)); } + let events: Vec = get_events_by_filters(state, filters).await?; + + Ok(AppJson(json!({ + "success": true, + "message": format!("Got {} events", events.len()), + "data": events, + }))) +} + +pub async fn get_event_by_id( + state: State, + path: Path, +) -> Result, AppError> { + let event_id: EventId = path.event_id; + let filter: Filter = Filter::new().id(event_id); + let filters: Vec = vec![filter]; + let events: Vec = get_events_by_filters(state, filters).await?; + let event: &Event = events.first().ok_or(AppError::EventIdNotFound)?; + Ok(AppJson(json!({ + "success": true, + "message": "Got 1 events", + "data": event, + }))) +} + +async fn get_events_by_filters( + state: State, + filters: Vec, +) -> Result, AppError> { if let Some(redis) = &state.redis { - let mut connection = redis.get_multiplexed_async_connection().await.unwrap(); + let mut connection = redis.get_multiplexed_async_connection().await.unwrap(); // TODO: remove unwrap let hash: String = Sha256Hash::hash(format!("{filters:?}").as_bytes()).to_string(); let exists = connection.exists::<&str, bool>(&hash).await?; if exists { let result = connection.get(&hash).await?; let bytes: Vec = result; - let events: Vec = bincode::deserialize(&bytes).unwrap(); - Ok(AppJson(json!({ - "success": true, - "message": format!("Got {} events", events.len()), - "data": events, - }))) + let events: Vec = bincode::deserialize(&bytes).unwrap(); // TODO: remove unwrap + Ok(events) } else { let events = state.client.get_events_of(filters, None).await?; let encoded: Vec = bincode::serialize(&events).unwrap(); @@ -64,19 +95,11 @@ pub async fn get_events( .set_ex(hash, encoded, state.config.redis.expiration) .await .unwrap(); - Ok(AppJson(json!({ - "success": true, - "message": format!("Got {} events", events.len()), - "data": events, - }))) + Ok(events) } } else { // TODO: add a timeout let events = state.client.get_events_of(filters, None).await?; - Ok(AppJson(json!({ - "success": true, - "message": format!("Got {} events", events.len()), - "data": events, - }))) + Ok(events) } } diff --git a/src/main.rs b/src/main.rs index eca70a6..5f2a4ba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,6 +53,7 @@ async fn main() -> Result<()> { let app = Router::new() .route("/ping", get(handler::ping)) .route("/event", post(handler::publish_event)) + .route("/event/:event_id", get(handler::get_event_by_id)) .route("/events", post(handler::get_events)) .layer(if config.network.permissive_cors { CorsLayer::permissive()