rhi

Coordinated trade for connected markets
git clone https://radroots.dev/git/rhi.git
Log | Files | Refs | README | LICENSE

commit 68296b4a2e60c98c1dc76f3701e2d8d99482c2a0
parent 160e24603ea94affc98e788bbcf437c1254bece1
Author: triesap <137732411+triesap@users.noreply.github.com>
Date:   Mon, 14 Apr 2025 17:59:39 +0000

Adds reference event parameters validation to job requests order handler and guards to ensure reference event can fulfill the job request.

Diffstat:
Msrc/events/job_request.rs | 14+++++++-------
Msrc/handlers/job_request_order.rs | 38++++++++++++++++++++++++++++++++++----
Msrc/utils/nostr.rs | 27+++++++++++++++++++++++----
3 files changed, 64 insertions(+), 15 deletions(-)

diff --git a/src/events/job_request.rs b/src/events/job_request.rs @@ -11,21 +11,21 @@ use crate::handlers::job_request_order::{JobRequestOrderError, handle_job_reques use crate::handlers::job_request_preview::handle_job_request_preview; use crate::handlers::job_request_quote::handle_job_request_quote; use crate::utils::nostr::{ - NostrTagsResolveError, nostr_event_job_request_feedback, nostr_filter_kind, - nostr_filter_new_events, nostr_tag_at_value, nostr_tag_first_value, nostr_tag_relays_parse, - nostr_tag_slice, nostr_tags_resolve, + NostrTagsResolveError, nostr_event_job_feedback, nostr_filter_kind, nostr_filter_new_events, + nostr_tag_at_value, nostr_tag_first_value, nostr_tag_relays_parse, nostr_tag_slice, + nostr_tags_resolve, }; use crate::utils::unit::MassUnitError; #[derive(thiserror::Error, Debug)] pub enum JobRequestError { - #[error("Order request error: {0}")] + #[error("Order: {0}")] JobRequestOrder(#[from] JobRequestOrderError), - #[error("Mass unit error: {0}")] + #[error("{0}")] MassUnit(#[from] MassUnitError), - #[error("Mass unit error: {0}")] + #[error("{0}")] NostrTagsResolve(#[from] NostrTagsResolveError), #[error("Invalid job request input type: {0}")] @@ -152,7 +152,7 @@ async fn handle_error( warn!("job_request handle_error error {}", error); warn!("job_request handle_error event {:?}", { event.clone() }); - let builder = nostr_event_job_request_feedback(&event, error, "error", None)?; + let builder = nostr_event_job_feedback(&event, error, "error", None)?; let event_id = client.send_event_builder(builder).await?; warn!("job_request handle_error sent feedback {:?}", { diff --git a/src/handlers/job_request_order.rs b/src/handlers/job_request_order.rs @@ -8,7 +8,7 @@ use tracing::info; use crate::{ events::job_request::{JobRequest, JobRequestError, JobRequestInput}, models::event_classified::EventClassified, - utils::nostr::nostr_fetch_event_by_id, + utils::nostr::{NostrEventError, nostr_event_job_result, nostr_fetch_event_by_id}, }; #[derive(Debug, Error)] @@ -21,6 +21,15 @@ pub enum JobRequestOrderError { #[error("Reference event not found {0}")] ReferenceEventMissing(String), + + #[error("Reference event does not satisfy requested {0}")] + ReferenceEventMissingRequested(String), + + #[error("Failure building the job response")] + ResponseEventBuildFailure(#[from] NostrEventError), + + #[error("Failure sending the job response")] + ResponseEventSendFailure(#[from] nostr_sdk::client::Error), } #[derive(Debug, Deserialize)] @@ -58,7 +67,7 @@ pub struct JobRequestOrderData { } pub async fn handle_job_request_order( - _event: Event, + event_job_request: Event, _keys: Keys, client: Client, _job_req: JobRequest, @@ -79,8 +88,6 @@ pub async fn handle_job_request_order( order_data.event.id.clone(), ))?; - info!("handle_job_request_order ref_event: {:?}", ref_event); - let ref_classified = EventClassified::from_event(ref_event) .map_err(|_| JobRequestOrderError::ReferenceEventParse(order_data.event.id.clone()))?; @@ -89,5 +96,28 @@ pub async fn handle_job_request_order( ref_classified ); + if ref_classified.prices.is_empty() { + return Err(JobRequestError::JobRequestOrder( + JobRequestOrderError::ReferenceEventMissingRequested("price".to_string()), + )); + } + + if ref_classified.quantities.is_empty() { + return Err(JobRequestError::JobRequestOrder( + JobRequestOrderError::ReferenceEventMissingRequested("quantity".to_string()), + )); + } + + let payload = "your order was received!"; + let event_result = nostr_event_job_result(&event_job_request.clone(), payload, 0, None, None) + .map_err(JobRequestOrderError::from)?; + let event_id = client + .send_event_builder(event_result) + .await + .map_err(JobRequestOrderError::from)?; + + info!("handle_job_request_order sent result {:?}", { + event_id.clone() + }); Ok(()) } diff --git a/src/utils/nostr.rs b/src/utils/nostr.rs @@ -103,16 +103,35 @@ pub fn nostr_tag_match_summary(tag: &Tag) -> Option<String> { } } -pub fn nostr_event_job_request_feedback( - event: &Event, +#[derive(Debug, thiserror::Error)] +pub enum NostrEventError { + #[error("Failed to build job result event: {0}")] + BuildError(#[from] nostr::event::builder::Error), +} + +pub fn nostr_event_job_result( + job_request: &Event, + payload: impl Into<String>, + millisats: u64, + bolt11: Option<String>, + tags: Option<Vec<Tag>>, +) -> Result<EventBuilder, NostrEventError> { + let builder = EventBuilder::job_result(job_request.clone(), payload, millisats, bolt11)? + .tags(tags.unwrap_or_default()); + Ok(builder) +} + +pub fn nostr_event_job_feedback( + job_request: &Event, error: JobRequestError, status: &str, tags: Option<Vec<Tag>>, -) -> anyhow::Result<EventBuilder> { +) -> Result<EventBuilder, NostrEventError> { let status = status .parse::<DataVendingMachineStatus>() .unwrap_or(DataVendingMachineStatus::Error); - let feedback_data = JobFeedbackData::new(&event, status).extra_info(error.to_string()); + let feedback_data = + JobFeedbackData::new(&job_request.clone(), status).extra_info(error.to_string()); let builder = EventBuilder::job_feedback(feedback_data).tags(tags.unwrap_or_default()); Ok(builder) }