diff --git a/http/src/v0.rs b/http/src/v0.rs index 53e2a39a9..68039bc4e 100644 --- a/http/src/v0.rs +++ b/http/src/v0.rs @@ -6,6 +6,7 @@ pub mod bitswap; pub mod block; pub mod dag; pub mod id; +pub mod pin; pub mod pubsub; pub mod refs; pub mod swarm; @@ -73,7 +74,7 @@ pub fn routes( warp::path!("key" / ..).and_then(not_implemented), warp::path!("name" / ..).and_then(not_implemented), warp::path!("object" / ..).and_then(not_implemented), - warp::path!("pin" / ..).and_then(not_implemented), + pin::add_pin(ipfs), warp::path!("ping" / ..).and_then(not_implemented), pubsub::routes(ipfs), refs::local(ipfs), diff --git a/http/src/v0/pin.rs b/http/src/v0/pin.rs new file mode 100644 index 000000000..6911761a2 --- /dev/null +++ b/http/src/v0/pin.rs @@ -0,0 +1,71 @@ +use crate::v0::support::with_ipfs; +use futures::future::join_all; +use ipfs::{Cid, Ipfs, IpfsTypes}; +use serde::ser::SerializeStruct; +use serde::{Deserialize, Serialize, Serializer}; +use std::str::FromStr; +use warp::{path, query, reply, Filter, Rejection, Reply}; + +#[derive(Debug, Deserialize)] +struct AddRequest { + args: Vec, + recursive: bool, + progress: bool, +} + +#[derive(Debug)] +struct AddResponse { + pins: Vec, + progress: usize, +} + +#[derive(Debug)] +struct InvalidCID; +impl warp::reject::Reject for InvalidCID {} + +impl Serialize for AddResponse { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_struct("AddResponse", 2)?; + let serialized_pins: Vec = self.pins.iter().map(|x| x.to_string()).collect(); + state.serialize_field("pins", &serialized_pins)?; + state.serialize_field("progress", &self.progress)?; + state.end() + } +} + +async fn pin_block_request( + ipfs: Ipfs, + request: AddRequest, +) -> Result { + let cids: Vec = request + .args + .iter() + .map(|x| Cid::from_str(&x)) + .collect::, _>>() + .map_err(|_err| warp::reject::custom(InvalidCID))?; + let dispatched_pins = cids.iter().map(|x| ipfs.pin_block(&x)); + let completed = join_all(dispatched_pins).await; + let pins: Vec = completed + .iter() + .zip(cids) + .filter(|x| x.0.is_ok()) + .map(|x| x.1.to_string()) + .collect(); + let response: AddResponse = AddResponse { + pins, + progress: 100, + }; + Ok(reply::json(&response)) +} + +pub fn add_pin( + ipfs: &Ipfs, +) -> impl Filter + Clone { + path!("pin" / "add") + .and(with_ipfs(ipfs)) + .and(query::()) + .and_then(pin_block_request) +}