cli

Command-line interface for Radroots
git clone https://radroots.dev/git/cli.git
Log | Files | Refs | README | LICENSE

validation.rs (6360B)


      1 use serde::Serialize;
      2 use serde_json::{Value, json};
      3 
      4 use crate::ops::{
      5     OperationAdapterError, OperationRequest, OperationRequestData, OperationRequestPayload,
      6     OperationResult, OperationResultData, OperationService, ValidationReceiptGetRequest,
      7     ValidationReceiptGetResult, ValidationReceiptListRequest, ValidationReceiptListResult,
      8     ValidationReceiptVerifyRequest, ValidationReceiptVerifyResult,
      9 };
     10 use crate::runtime::config::RuntimeConfig;
     11 use crate::runtime::validation_receipt::{
     12     ValidationReceiptEventArgs, ValidationReceiptInspectionView, ValidationReceiptListArgs,
     13     ValidationReceiptListView,
     14 };
     15 use crate::view::runtime::CommandDisposition;
     16 
     17 pub struct ValidationOperationService<'a> {
     18     config: &'a RuntimeConfig,
     19 }
     20 
     21 impl<'a> ValidationOperationService<'a> {
     22     pub fn new(config: &'a RuntimeConfig) -> Self {
     23         Self { config }
     24     }
     25 }
     26 
     27 impl OperationService<ValidationReceiptGetRequest> for ValidationOperationService<'_> {
     28     type Result = ValidationReceiptGetResult;
     29 
     30     fn execute(
     31         &self,
     32         request: OperationRequest<ValidationReceiptGetRequest>,
     33     ) -> Result<OperationResult<Self::Result>, OperationAdapterError> {
     34         let args = validation_receipt_event_args(&request)?;
     35         let view = crate::runtime::validation_receipt::get(self.config, &args);
     36         validation_receipt_inspection_result::<ValidationReceiptGetResult>(
     37             "validation.receipt.get",
     38             &view,
     39         )
     40     }
     41 }
     42 
     43 impl OperationService<ValidationReceiptListRequest> for ValidationOperationService<'_> {
     44     type Result = ValidationReceiptListResult;
     45 
     46     fn execute(
     47         &self,
     48         request: OperationRequest<ValidationReceiptListRequest>,
     49     ) -> Result<OperationResult<Self::Result>, OperationAdapterError> {
     50         let args = validation_receipt_list_args(&request)?;
     51         let view = crate::runtime::validation_receipt::list(self.config, &args);
     52         validation_receipt_list_result(&view)
     53     }
     54 }
     55 
     56 impl OperationService<ValidationReceiptVerifyRequest> for ValidationOperationService<'_> {
     57     type Result = ValidationReceiptVerifyResult;
     58 
     59     fn execute(
     60         &self,
     61         request: OperationRequest<ValidationReceiptVerifyRequest>,
     62     ) -> Result<OperationResult<Self::Result>, OperationAdapterError> {
     63         let args = validation_receipt_event_args(&request)?;
     64         let view = crate::runtime::validation_receipt::verify(self.config, &args);
     65         validation_receipt_inspection_result::<ValidationReceiptVerifyResult>(
     66             "validation.receipt.verify",
     67             &view,
     68         )
     69     }
     70 }
     71 
     72 fn validation_receipt_event_args<P>(
     73     request: &OperationRequest<P>,
     74 ) -> Result<ValidationReceiptEventArgs, OperationAdapterError>
     75 where
     76     P: OperationRequestPayload + OperationRequestData,
     77 {
     78     Ok(ValidationReceiptEventArgs {
     79         receipt_event_id: required_string(request, "receipt_event_id")?,
     80     })
     81 }
     82 
     83 fn validation_receipt_list_args<P>(
     84     request: &OperationRequest<P>,
     85 ) -> Result<ValidationReceiptListArgs, OperationAdapterError>
     86 where
     87     P: OperationRequestPayload + OperationRequestData,
     88 {
     89     Ok(ValidationReceiptListArgs {
     90         order_id: required_string(request, "order_id")?,
     91     })
     92 }
     93 
     94 fn validation_receipt_inspection_result<R>(
     95     operation_id: &str,
     96     view: &ValidationReceiptInspectionView,
     97 ) -> Result<OperationResult<R>, OperationAdapterError>
     98 where
     99     R: OperationResultData,
    100 {
    101     match view.disposition() {
    102         CommandDisposition::Success => serialized_operation_result::<R, _>(view),
    103         disposition => Err(validation_receipt_view_error(
    104             operation_id,
    105             disposition,
    106             view,
    107             view.reason.as_deref(),
    108         )),
    109     }
    110 }
    111 
    112 fn validation_receipt_list_result(
    113     view: &ValidationReceiptListView,
    114 ) -> Result<OperationResult<ValidationReceiptListResult>, OperationAdapterError> {
    115     match view.disposition() {
    116         CommandDisposition::Success => {
    117             serialized_operation_result::<ValidationReceiptListResult, _>(view)
    118         }
    119         disposition => Err(validation_receipt_view_error(
    120             "validation.receipt.list",
    121             disposition,
    122             view,
    123             view.reason.as_deref(),
    124         )),
    125     }
    126 }
    127 
    128 fn validation_receipt_view_error<T>(
    129     operation_id: &str,
    130     disposition: CommandDisposition,
    131     view: &T,
    132     reason: Option<&str>,
    133 ) -> OperationAdapterError
    134 where
    135     T: Serialize,
    136 {
    137     let detail = serde_json::to_value(view).unwrap_or_else(|_| json!({}));
    138     let message = reason
    139         .map(str::to_owned)
    140         .unwrap_or_else(|| format!("`{operation_id}` validation receipt operation failed"));
    141     match disposition {
    142         CommandDisposition::NotFound => {
    143             OperationAdapterError::not_found_with_detail(operation_id, message, detail)
    144         }
    145         CommandDisposition::ValidationFailed => {
    146             OperationAdapterError::validation_failed_with_detail(operation_id, message, detail)
    147         }
    148         CommandDisposition::Unconfigured => {
    149             OperationAdapterError::operation_unavailable_with_detail(operation_id, message, detail)
    150         }
    151         CommandDisposition::ExternalUnavailable => {
    152             OperationAdapterError::network_unavailable_with_detail(operation_id, message, detail)
    153         }
    154         CommandDisposition::Unsupported => OperationAdapterError::InvalidInput {
    155             operation_id: operation_id.to_owned(),
    156             message,
    157         },
    158         CommandDisposition::InternalError | CommandDisposition::Success => {
    159             OperationAdapterError::Runtime(message)
    160         }
    161     }
    162 }
    163 
    164 fn required_string<P>(
    165     request: &OperationRequest<P>,
    166     key: &str,
    167 ) -> Result<String, OperationAdapterError>
    168 where
    169     P: OperationRequestPayload + OperationRequestData,
    170 {
    171     request
    172         .payload
    173         .input()
    174         .get(key)
    175         .and_then(Value::as_str)
    176         .map(str::trim)
    177         .filter(|value| !value.is_empty())
    178         .map(str::to_owned)
    179         .ok_or_else(|| OperationAdapterError::InvalidInput {
    180             operation_id: request.operation_id().to_owned(),
    181             message: format!("missing required `{key}` input"),
    182         })
    183 }
    184 
    185 fn serialized_operation_result<R, T>(value: &T) -> Result<OperationResult<R>, OperationAdapterError>
    186 where
    187     R: OperationResultData,
    188     T: Serialize,
    189 {
    190     OperationResult::new(R::from_serializable(value)?)
    191 }