Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 3 remote pin api #102

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 135 additions & 2 deletions ipfs-api-prelude/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{read::LineDecoder, request, response, Backend, BoxStream};
use async_trait::async_trait;
use bytes::Bytes;
use common_multipart_rfc7578::client::multipart;
use futures::{future, FutureExt, TryStreamExt, AsyncRead};
use futures::{future, AsyncRead, FutureExt, TryStreamExt};
zu1k marked this conversation as resolved.
Show resolved Hide resolved
use std::{
fs::File,
io::{Cursor, Read},
Expand Down Expand Up @@ -80,7 +80,8 @@ pub trait IpfsApi: Backend {
where
R: 'static + AsyncRead + Send + Sync + Unpin,
{
self.add_async_with_options(data, request::Add::default()).await
self.add_async_with_options(data, request::Add::default())
.await
}

/// Add a file to IPFS with options.
Expand Down Expand Up @@ -2004,6 +2005,138 @@ pub trait IpfsApi: Backend {

// TODO /pin/verify

/// Pin object to remote pinning service.
///
/// - `service`: Name of the remote pinning service to use (mandatory).
///
/// - `name`: An optional name for the pin.
///
/// - `background`: Add to the queue on the remote service and
/// return immediately (does not wait for pinned status).
///
/// # Examples
///
/// ```no_run
/// use ipfs_api::{IpfsApi, IpfsClient};
zu1k marked this conversation as resolved.
Show resolved Hide resolved
///
/// let client = IpfsClient::default();
/// let res = client.pin_remote_add("QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", "pinata", Some("pin_task_name"), true);
/// ```
///
zu1k marked this conversation as resolved.
Show resolved Hide resolved
async fn pin_remote_add(
&self,
key: &str,
service: &str,
name: Option<&str>,
background: bool,
) -> Result<response::PinRemoteAddResponse, Self::Error> {
self.request(
request::PinRemoteAdd {
key,
service: Some(service),
name,
background: Some(background),
},
None,
)
.await
}

/// Returns a list objects pinned to remote pinning service.
///
/// - `service`: Name of the remote pinning service to use (mandatory).
///
/// - `name`: Return pins with names that contain the value provided (case-sensitive, exact match).
///
/// - `cid`: Return pins for the specified CIDs
///
/// - `status`: Return pins with the specified statuses (queued,pinning,pinned,failed), default [pinned].
///
/// # Examples
///
/// ```no_run
/// use ipfs_api::{IpfsApi, IpfsClient};
/// use ipfs_api_prelude::request::PinStatus;
///
/// let client = IpfsClient::default();
/// let res = client.pin_remote_ls("pinata", None, None, None);
///
/// let status = vec![PinStatus::Pinning, PinStatus::Pinned];
/// let res = client.pin_remote_ls(
/// "pinata",
/// None,
/// None,
/// Some(&status)
/// );
/// ```
///
zu1k marked this conversation as resolved.
Show resolved Hide resolved
async fn pin_remote_ls(
&self,
service: &str,
name: Option<&str>,
cid: Option<&[&str]>,
status: Option<&[request::PinStatus]>,
) -> Result<Vec<response::PinRemoteLsResponse>, Self::Error> {
let req = self.build_base_request(
request::PinRemoteLs {
service: Some(service),
name,
cid: cid.map(|cid| cid.into()),
status,
},
None,
)?;
self.request_stream_json(req).try_collect().await
}

/// Remove pins from remote pinning service.
///
/// - `service`: Name of the remote pinning service to use (mandatory).
///
/// - `name`: Remove pins with names that contain provided value (case-sensitive, exact match).
///
/// - `cid`: Remove pins for the specified CIDs.
///
/// - `status`: Remove pins with the specified statuses (queued,pinning,pinned,failed)
///
/// - `force`: Allow removal of multiple pins matching the query without additional confirmation.
///
/// # Examples
///
/// ```no_run
/// use ipfs_api::{IpfsApi, IpfsClient};
///
/// let client = IpfsClient::default();
/// let res = client.pin_remote_rm(
/// "pinata",
/// None,
/// None,
/// None,
/// true
/// );
/// ```
///
async fn pin_remote_rm(
&self,
service: &str,
name: Option<&str>,
cid: Option<&[&str]>,
status: Option<&[request::PinStatus]>,
force: bool,
) -> Result<String, Self::Error> {
self.request_string(
request::PinRemoteRm {
service: Some(service),
name,
cid: cid.map(|cid| cid.into()),
status,
force: Some(force),
},
None,
)
.await
}

/// Pings a peer.
///
/// ```no_run
Expand Down
129 changes: 129 additions & 0 deletions ipfs-api-prelude/src/request/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,132 @@ pub struct PinRm<'a> {
impl<'a> ApiRequest for PinRm<'a> {
const PATH: &'static str = "/pin/rm";
}

#[derive(Serialize)]
pub struct PinRemoteAdd<'a> {
#[serde(rename = "arg")]
pub key: &'a str,

pub service: Option<&'a str>,
pub name: Option<&'a str>,
pub background: Option<bool>,
}

impl<'a> ApiRequest for PinRemoteAdd<'a> {
const PATH: &'static str = "/pin/remote/add";
}

#[derive(Serialize)]
pub struct PinRemoteLs<'a> {
pub service: Option<&'a str>,
pub name: Option<&'a str>,
pub cid: Option<Cids<'a>>,
#[serde(
skip_serializing_if = "Option::is_none",
serialize_with = "serialize_pin_status"
)]
pub status: Option<&'a [PinStatus]>,
}

impl<'a> ApiRequest for PinRemoteLs<'a> {
const PATH: &'static str = "/pin/remote/ls";
}

#[derive(Serialize)]
pub struct PinRemoteRm<'a> {
pub service: Option<&'a str>,
pub name: Option<&'a str>,
pub cid: Option<Cids<'a>>,
#[serde(
skip_serializing_if = "Option::is_none",
serialize_with = "serialize_pin_status"
)]
pub status: Option<&'a [PinStatus]>,
pub force: Option<bool>,
}

impl<'a> ApiRequest for PinRemoteRm<'a> {
const PATH: &'static str = "/pin/remote/rm";
}

pub struct Cids<'a>(&'a [&'a str]);

impl<'a> From<&'a [&'a str]> for Cids<'a> {
fn from(data: &'a [&'a str]) -> Self {
Self(data)
}
}

impl<'a> Serialize for Cids<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let cids = self.0.join(",");
serializer.serialize_str(&cids)
}
}

#[derive(Serialize)]
pub enum PinStatus {
Queued,
Pinning,
Pinned,
Failed,
}

impl Default for PinStatus {
zu1k marked this conversation as resolved.
Show resolved Hide resolved
fn default() -> Self {
Self::Pinned
}
}

fn serialize_pin_status<S>(
pin_status: &Option<&[PinStatus]>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let pin_status = pin_status.unwrap();
let pin_status = pin_status
.iter()
.map(|item| match *item {
zu1k marked this conversation as resolved.
Show resolved Hide resolved
PinStatus::Failed => "failed",
PinStatus::Queued => "queued",
PinStatus::Pinning => "pinning",
PinStatus::Pinned => "pinned",
})
.collect::<Vec<&str>>()
.join(",");
serializer.serialize_str(&format!("[{pin_status}]"))
}

#[cfg(test)]
mod tests {
use super::*;

serialize_url_test!(
test_serializes_pin_remote_rm,
PinRemoteRm {
service: Some("Pinata"),
name: None,
cid: Some((&vec!["bafybeiaq3hspbuvhvg7nlxjjvsnzit6m6hevrjwedoj4jbx6uycgkkexni"] as &[&str]).into()),
status: Some(&vec![PinStatus::Pinned, PinStatus::Pinning]),
force: Some(true)
},
"service=Pinata&cid=bafybeiaq3hspbuvhvg7nlxjjvsnzit6m6hevrjwedoj4jbx6uycgkkexni&status=%5Bpinned%2Cpinning%5D&force=true"
);

serialize_url_test!(
test_serializes_pin_remote_rm_multi_cid,
PinRemoteRm {
service: Some("Pinata"),
name: None,
cid: Some((&vec!["bafybeiaq3hspbuvhvg7nlxjjvsnzit6m6hevrjwedoj4jbx6uycgkkexni", "QmfWC6JwVxmjVQfPpSiTsxFaSBdPTtFCd1B4aqMqRgaeMU"] as &[&str]).into()),
status:None,
force: None
},
"service=Pinata&cid=bafybeiaq3hspbuvhvg7nlxjjvsnzit6m6hevrjwedoj4jbx6uycgkkexni%2CQmfWC6JwVxmjVQfPpSiTsxFaSBdPTtFCd1B4aqMqRgaeMU"
);
}
16 changes: 16 additions & 0 deletions ipfs-api-prelude/src/response/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,22 @@ pub struct PinRmResponse {
pub pins: Vec<String>,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct PinRemoteAddResponse {
pub cid: String,
pub name: String,
pub status: String,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct PinRemoteLsResponse {
pub cid: String,
pub name: String,
pub status: String,
}

#[cfg(test)]
mod tests {
deserialize_test!(v0_pin_ls_0, PinLsResponse);
Expand Down