diff --git a/services/blob/src/http/handlers/blob.rs b/services/blob/src/http/handlers/blob.rs --- a/services/blob/src/http/handlers/blob.rs +++ b/services/blob/src/http/handlers/blob.rs @@ -12,8 +12,10 @@ }; use async_stream::try_stream; use base64::Engine; +use comm_lib::blob::types::http::{ + AssignHolderRequest, AssignHolderResponse, RemoveHolderRequest, +}; use comm_lib::http::multipart; -use serde::{Deserialize, Serialize}; use tokio_stream::StreamExt; use tracing::{debug, info, instrument, trace, warn}; use tracing_futures::Instrument; @@ -114,24 +116,13 @@ ) } -#[derive(Deserialize, Debug)] -pub struct AssignHolderPayload { - holder: String, - blob_hash: String, -} - -#[derive(Serialize)] -struct AssignHolderResponnse { - data_exists: bool, -} - #[instrument(name = "assign_holder", skip(service))] pub async fn assign_holder_handler( service: web::Data, - payload: web::Json, + payload: web::Json, ) -> actix_web::Result { info!("Assign holder request"); - let AssignHolderPayload { holder, blob_hash } = payload.into_inner(); + let AssignHolderRequest { holder, blob_hash } = payload.into_inner(); validate_identifier!(holder); validate_identifier!(blob_hash); @@ -142,7 +133,7 @@ service.assign_holder(blob_hash, holder).await?; - let response = AssignHolderResponnse { data_exists }; + let response = AssignHolderResponse { data_exists }; Ok(HttpResponse::Ok().json(web::Json(response))) } @@ -212,23 +203,13 @@ Ok(HttpResponse::NoContent().finish()) } -#[derive(Deserialize, Debug)] -pub struct RemoveHolderPayload { - holder: String, - blob_hash: String, - /// If true, the blob will be deleted intantly - /// after the last holder is revoked. - #[serde(default)] - instant_delete: bool, -} - #[instrument(name = "remove_holder", skip(service))] pub async fn remove_holder_handler( service: web::Data, - payload: web::Json, + payload: web::Json, ) -> actix_web::Result { info!("Revoke holder request"); - let RemoveHolderPayload { + let RemoveHolderRequest { holder, blob_hash, instant_delete, diff --git a/services/blob/src/http/handlers/holders.rs b/services/blob/src/http/handlers/holders.rs --- a/services/blob/src/http/handlers/holders.rs +++ b/services/blob/src/http/handlers/holders.rs @@ -1,56 +1,30 @@ use actix_web::error::ErrorBadRequest; use actix_web::{web, HttpResponse}; -use serde::{Deserialize, Serialize}; +use comm_lib::blob::types::http::{ + AssignHoldersRequest, AssignHoldersResponse, BlobInfo, + HolderAssignmentResult, RemoveHoldersRequest, RemoveHoldersResponse, +}; use tracing::{info, instrument, trace, warn}; use crate::service::BlobService; -#[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct BlobHashAndHolder { - blob_hash: String, - holder: String, -} - -#[derive(Deserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct AssignHoldersPayload { - requests: Vec, -} - -#[derive(Serialize, Debug)] -#[serde(rename_all = "camelCase")] -struct HolderAssignmentResult { - #[serde(flatten)] - request: BlobHashAndHolder, - success: bool, - data_exists: bool, - holder_already_exists: bool, -} -#[derive(Serialize, Debug)] -#[serde(rename_all = "camelCase")] -struct AssignHoldersResponse { - results: Vec, -} - #[instrument(name = "assign_multiple_holders", skip_all)] pub async fn assign_holders_handler( service: web::Data, - payload: web::Json, + payload: web::Json, ) -> actix_web::Result { use crate::database::DBError; use crate::service::BlobServiceError; - let AssignHoldersPayload { requests } = payload.into_inner(); + let AssignHoldersRequest { requests } = payload.into_inner(); info!("Assign holder request for {} holders", requests.len()); validate_request(&requests)?; let blob_hashes = requests.iter().map(|it| &it.blob_hash).collect(); let existing_blobs = service.find_existing_blobs(blob_hashes).await?; - let mut results = Vec::with_capacity(requests.len()); for item in requests { - let BlobHashAndHolder { blob_hash, holder } = &item; + let BlobInfo { blob_hash, holder } = &item; let data_exists = existing_blobs.contains(blob_hash); let result = match service.assign_holder(blob_hash, holder).await { Ok(()) => HolderAssignmentResult { @@ -84,26 +58,12 @@ Ok(HttpResponse::Ok().json(web::Json(response))) } -#[derive(Deserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct RemoveHoldersPayload { - requests: Vec, - #[serde(default)] - instant_delete: bool, -} - -#[derive(Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct RemoveHoldersResponse { - failed_requests: Vec, -} - #[instrument(name = "remove_multiple_holders", skip_all)] pub async fn remove_holders_handler( service: web::Data, - payload: web::Json, + payload: web::Json, ) -> actix_web::Result { - let RemoveHoldersPayload { + let RemoveHoldersRequest { requests, instant_delete, } = payload.into_inner(); @@ -121,7 +81,7 @@ for item in requests { trace!("Removing item: {:?}", &item); - let BlobHashAndHolder { holder, blob_hash } = &item; + let BlobInfo { holder, blob_hash } = &item; if let Err(err) = service .revoke_holder(blob_hash, holder, instant_delete) .await @@ -139,12 +99,11 @@ * have invalid format. See [`comm_lib::tools::is_valid_identifier`] for * valid format conditions */ -fn validate_request(items: &[BlobHashAndHolder]) -> actix_web::Result<()> { +fn validate_request(items: &[BlobInfo]) -> actix_web::Result<()> { use comm_lib::tools::is_valid_identifier; - let all_valid = - items.iter().all(|BlobHashAndHolder { holder, blob_hash }| { - is_valid_identifier(holder) && is_valid_identifier(blob_hash) - }); + let all_valid = items.iter().all(|BlobInfo { holder, blob_hash }| { + is_valid_identifier(holder) && is_valid_identifier(blob_hash) + }); if !all_valid { return Err(ErrorBadRequest("One or more requests have invalid format")); diff --git a/shared/comm-lib/src/blob/client.rs b/shared/comm-lib/src/blob/client.rs --- a/shared/comm-lib/src/blob/client.rs +++ b/shared/comm-lib/src/blob/client.rs @@ -13,7 +13,12 @@ pub use reqwest::StatusCode; pub use reqwest::Url; -use crate::auth::{AuthorizationCredential, UserIdentity}; +use crate::{ + auth::{AuthorizationCredential, UserIdentity}, + blob::types::http::{ + AssignHolderRequest, AssignHolderResponse, RemoveHolderRequest, + }, +}; #[derive(From, Error, Debug, Display)] pub enum BlobServiceError { @@ -216,9 +221,10 @@ debug!("Revoke holder request"); let url = self.get_blob_url(None)?; - let payload = RevokeHolderRequest { + let payload = RemoveHolderRequest { holder: holder.to_string(), blob_hash: blob_hash.to_string(), + instant_delete: false, }; debug!("Request payload: {:?}", payload); @@ -395,18 +401,6 @@ type BlobResult = Result; -#[derive(serde::Deserialize)] -struct AssignHolderResponse { - data_exists: bool, -} -#[derive(Debug, serde::Serialize)] -struct AssignHolderRequest { - blob_hash: String, - holder: String, -} -// they have the same layout so we can simply alias -type RevokeHolderRequest = AssignHolderRequest; - #[cfg(feature = "http")] impl crate::http::auth_service::HttpAuthenticatedService for BlobServiceClient { fn make_authenticated( diff --git a/shared/comm-lib/src/blob/types.rs b/shared/comm-lib/src/blob/types.rs --- a/shared/comm-lib/src/blob/types.rs +++ b/shared/comm-lib/src/blob/types.rs @@ -2,8 +2,73 @@ use hex::ToHex; use sha2::{Digest, Sha256}; +pub mod http { + use serde::{Deserialize, Serialize}; + + pub use super::BlobInfo; + + // Assign multiple holders + #[derive(Serialize, Deserialize, Debug)] + #[serde(rename_all = "camelCase")] + pub struct AssignHoldersRequest { + pub requests: Vec, + } + + #[derive(Serialize, Deserialize, Debug)] + #[serde(rename_all = "camelCase")] + pub struct HolderAssignmentResult { + #[serde(flatten)] + pub request: BlobInfo, + pub success: bool, + pub data_exists: bool, + pub holder_already_exists: bool, + } + #[derive(Serialize, Deserialize, Debug)] + #[serde(rename_all = "camelCase")] + pub struct AssignHoldersResponse { + pub results: Vec, + } + + // Remove multiple holders + #[derive(Deserialize, Debug)] + #[serde(rename_all = "camelCase")] + pub struct RemoveHoldersRequest { + pub requests: Vec, + #[serde(default)] + pub instant_delete: bool, + } + #[derive(Serialize, Debug)] + #[serde(rename_all = "camelCase")] + pub struct RemoveHoldersResponse { + pub failed_requests: Vec, + } + + // Single holder endpoint types + + #[derive(Serialize, Deserialize, Debug)] + pub struct AssignHolderRequest { + pub blob_hash: String, + pub holder: String, + } + #[derive(Serialize, Deserialize, Debug)] + pub struct AssignHolderResponse { + pub data_exists: bool, + } + + #[derive(Serialize, Deserialize, Debug)] + pub struct RemoveHolderRequest { + pub blob_hash: String, + pub holder: String, + /// If true, the blob will be deleted intantly + /// after the last holder is revoked. + #[serde(default)] + pub instant_delete: bool, + } +} + /// Blob owning information - stores both blob_hash and holder -#[derive(Clone, Debug, Constructor)] +#[derive(Clone, Debug, Constructor, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] pub struct BlobInfo { pub blob_hash: String, pub holder: String,