Improve documentation some more
This commit is contained in:
parent
a209e404ea
commit
43b953d4df
21
Cargo.toml
21
Cargo.toml
|
@ -7,12 +7,12 @@ edition = "2021"
|
|||
|
||||
[features]
|
||||
default = ["utils"]
|
||||
actix-web = ["apub-actix-web"]
|
||||
awc = ["apub-awc"]
|
||||
background-jobs = ["apub-background-jobs"]
|
||||
openssl = ["apub-openssl"]
|
||||
reqwest = ["apub-reqwest"]
|
||||
rustcrypto = ["apub-rustcrypto"]
|
||||
with-actix-web = ["apub-actix-web"]
|
||||
with-awc = ["apub-awc"]
|
||||
with-background-jobs = ["apub-background-jobs"]
|
||||
with-openssl = ["apub-openssl"]
|
||||
with-reqwest = ["apub-reqwest"]
|
||||
with-rustcrypto = ["apub-rustcrypto"]
|
||||
utils = ["apub-breaker-session", "apub-deref-client"]
|
||||
|
||||
[dependencies]
|
||||
|
@ -26,6 +26,15 @@ apub-openssl = { version = "0.1.0", path = "./apub-openssl/", optional = true }
|
|||
apub-reqwest = { version = "0.1.0", path = "./apub-reqwest/", optional = true }
|
||||
apub-rustcrypto = { version = "0.1.0", path = "./apub-rustcrypto/", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
dashmap = "4.0.2"
|
||||
openssl = "0.10"
|
||||
reqwest = "0.11"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
tokio = { version = "1.14", features = ["full"] }
|
||||
url = { version = "2", features = ["serde"] }
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"apub-actix-web",
|
||||
|
|
|
@ -10,3 +10,14 @@ apub-core = { version = "0.1.0", path = "../apub-core/" }
|
|||
pin-project-lite = "0.2.7"
|
||||
thiserror = "1"
|
||||
url = "2"
|
||||
|
||||
[dev-dependencies]
|
||||
apub-openssl = { version = "0.1.0", path = "../apub-openssl/" }
|
||||
apub-reqwest = { version = "0.1.0", path = "../apub-reqwest/" }
|
||||
dashmap = "4.0.2"
|
||||
openssl = "0.10"
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
tokio = { version = "1.14", features = ["full"] }
|
||||
url = { version = "2", features = ["serde"] }
|
||||
|
|
|
@ -1,4 +1,109 @@
|
|||
//! A type to combine a remote Repo with a local Repo
|
||||
//!
|
||||
//! ```rust
|
||||
//! use apub_core::deref::{Dereference, Repo};
|
||||
//! use apub_deref_client::Client;
|
||||
//! use apub_openssl::OpenSsl;
|
||||
//! use apub_reqwest::{ReqwestClient, SignatureConfig};
|
||||
//! use dashmap::DashMap;
|
||||
//! use openssl::{
|
||||
//! pkey::PKey,
|
||||
//! rsa::Rsa,
|
||||
//! };
|
||||
//! use std::{
|
||||
//! future::{ready, Ready},
|
||||
//! sync::Arc,
|
||||
//! time::Duration,
|
||||
//! };
|
||||
//! use url::{Host, Url};
|
||||
//!
|
||||
//! #[derive(Clone, Debug, Default)]
|
||||
//! pub struct MemoryRepo {
|
||||
//! inner: Arc<DashMap<Url, serde_json::Value>>,
|
||||
//! }
|
||||
//!
|
||||
//! impl<'a, Id: Dereference + 'a> Repo<'a, Id> for MemoryRepo {
|
||||
//! type Error = serde_json::Error;
|
||||
//! type Future = Ready<Result<Option<Id::Output>, Self::Error>>;
|
||||
//!
|
||||
//! fn fetch(&'a self, id: Id) -> Self::Future {
|
||||
//! if let Some(value) = self.inner.get(id.url()) {
|
||||
//! ready(serde_json::from_value(value.clone()).map(Some))
|
||||
//! } else {
|
||||
//! ready(Ok(None))
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
//! #[serde(transparent)]
|
||||
//! struct MyId(Url);
|
||||
//!
|
||||
//! #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
//! struct MyObject {
|
||||
//! id: MyId,
|
||||
//! content: String,
|
||||
//! }
|
||||
//!
|
||||
//! impl Dereference for MyId {
|
||||
//! type Output = MyObject;
|
||||
//!
|
||||
//! fn url(&self) -> &Url {
|
||||
//! &self.0
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! #[tokio::main]
|
||||
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! let existing_url: Url = "http://localhost:8080/object/hi".parse()?;
|
||||
//! let existing_object = serde_json::to_value(MyObject {
|
||||
//! id: MyId(existing_url.clone()),
|
||||
//! content: String::from("hello"),
|
||||
//! })?;
|
||||
//!
|
||||
//! let missing_url: Url = "http://localhost:8080/object/hello".parse()?;
|
||||
//! let remote_url: Url = "https://masto.asonix.dog/users/asonix/statuses/107326693283572188".parse()?;
|
||||
//!
|
||||
//! let local_domain = Host::Domain(String::from("localhost"));
|
||||
//! let local_port = Some(8080);
|
||||
//!
|
||||
//! let mut local_repo = MemoryRepo::default();
|
||||
//! local_repo.inner.insert(
|
||||
//! existing_url.clone(),
|
||||
//! existing_object,
|
||||
//! );
|
||||
//!
|
||||
//! let signature_config = SignatureConfig::default();
|
||||
//! let private_key = PKey::from_rsa(Rsa::generate(1024)?)?;
|
||||
//! let crypto = OpenSsl::new("key-id".to_string(), private_key);
|
||||
//! let client = reqwest::Client::new();
|
||||
//! let remote_repo = ReqwestClient::new(&client, (), &signature_config, &crypto);
|
||||
//!
|
||||
//! let deref_client = Client::new(
|
||||
//! local_domain,
|
||||
//! local_port,
|
||||
//! &local_repo,
|
||||
//! &remote_repo,
|
||||
//! );
|
||||
//!
|
||||
//! let opt = deref_client.fetch(MyId(existing_url)).await?;
|
||||
//! assert!(opt.is_some());
|
||||
//! if let Some(my_object) = opt {
|
||||
//! println!("{:?}", my_object);
|
||||
//! }
|
||||
//!
|
||||
//! let opt = deref_client.fetch(MyId(missing_url)).await?;
|
||||
//! assert!(opt.is_none());
|
||||
//!
|
||||
//! let opt = deref_client.fetch(MyId(remote_url)).await?;
|
||||
//! assert!(opt.is_some());
|
||||
//! if let Some(my_object) = opt {
|
||||
//! println!("{:?}", my_object)
|
||||
//! }
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
actix-web = { version = "4.0.0-beta.11", default-features = false }
|
||||
apub = { version = "0.1.0", path = "../../", features = ["actix-web", "rustcrypto"] }
|
||||
apub = { version = "0.1.0", path = "../../", features = ["with-actix-web", "with-rustcrypto"] }
|
||||
dashmap = "4.0.2"
|
||||
env_logger = "0.9.0"
|
||||
example-types = { version = "0.1.0", path = "../example-types/" }
|
||||
|
|
|
@ -7,7 +7,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
actix-rt = "2.4.0"
|
||||
apub = { version = "0.1.0", path = "../../", features = ["awc", "rustcrypto"] }
|
||||
apub = { version = "0.1.0", path = "../../", features = ["with-awc", "with-rustcrypto"] }
|
||||
awc = { version = "3.0.0-beta.10", default-features = false, features = ["rustls"] }
|
||||
example-types = { version = "0.1.0", path = "../example-types/" }
|
||||
rand = "0.8.4"
|
||||
|
|
|
@ -7,7 +7,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
actix-rt = "2.4.0"
|
||||
apub = { version = "0.1.0", path = "../../", features = ["awc", "background-jobs", "rustcrypto"] }
|
||||
apub = { version = "0.1.0", path = "../../", features = ["with-awc", "with-background-jobs", "with-rustcrypto"] }
|
||||
anyhow = "1"
|
||||
awc = { version = "3.0.0-beta.10", default-features = false, features = ["rustls"] }
|
||||
background-jobs = "0.11.0"
|
||||
|
|
|
@ -6,7 +6,7 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
apub = { version = "0.1.0", path = "../../", features = ["reqwest", "openssl"] }
|
||||
apub = { version = "0.1.0", path = "../../", features = ["with-reqwest", "with-openssl"] }
|
||||
example-types = { version = "0.1.0", path = "../example-types/" }
|
||||
openssl = "0.10.13"
|
||||
reqwest = "0.11.6"
|
||||
|
|
139
src/lib.rs
139
src/lib.rs
|
@ -1,10 +1,147 @@
|
|||
pub mod clients {
|
||||
//! Types and traits for fetching and delivering objects
|
||||
//!
|
||||
//! Notable types are [`CombinedClient`] behind the `utils` feature, [`ReqwestClient`] behind
|
||||
//! the `with-reqwest` feature, and [`AwcClient`] behind the `awc` feature. Each of these types
|
||||
//! implements the [`Repo`] trait, which describes fetching an object from a given repository.
|
||||
//! While [`ReqwestClient`] and [`AwcClient`] both describe fetching objects from activitypub
|
||||
//! remotes, [`CombinedClient`] is designed to easily fetch an object from a local repository,
|
||||
//! such as a database or in-memory store, and fall back to an HTTP client for requests it can't
|
||||
//! satisfy itself.
|
||||
//!
|
||||
//! [`ReqwestClient`] and [`AwcClient`] also implement the [`Client`] trait, which describes
|
||||
//! delivering objects to activitypub remotes.
|
||||
//!
|
||||
//! Both [`ReqwestClient`] and [`AwcClient`] are built to use a generic [`Session`]
|
||||
//! implementation and a generic [`SignFactory`] impelementation to extend request behavior and
|
||||
//! support HTTP Signatures and HTTP Digests
|
||||
//!
|
||||
//! [`Session`]: crate::session::Session
|
||||
//! [`SignFactory`]: crate::crypto::SignFactory
|
||||
|
||||
pub use apub_core::deliver::{Activity, Client};
|
||||
pub use apub_core::deref::{Dereference, Repo};
|
||||
pub use apub_core::object_id::ObjectId;
|
||||
|
||||
#[cfg(feature = "apub-deref-client")]
|
||||
pub use apub_deref_client::{Client as CombinedClient, Error as CombinedError};
|
||||
/// The type that combines Local and Remote repos
|
||||
///
|
||||
/// when both `Local` and `Http` implement [`Repo`], so does Client<Local, Http>
|
||||
///
|
||||
/// ```rust
|
||||
/// use apub::{
|
||||
/// clients::{
|
||||
/// CombinedClient,
|
||||
/// Dereference,
|
||||
/// Repo,
|
||||
/// ReqwestClient,
|
||||
/// ReqwestSignatureConfig,
|
||||
/// },
|
||||
/// crypto::OpenSsl,
|
||||
/// };
|
||||
/// use dashmap::DashMap;
|
||||
/// use openssl::{
|
||||
/// pkey::PKey,
|
||||
/// rsa::Rsa,
|
||||
/// };
|
||||
/// use std::{
|
||||
/// future::{ready, Ready},
|
||||
/// sync::Arc,
|
||||
/// time::Duration,
|
||||
/// };
|
||||
/// use url::{Host, Url};
|
||||
///
|
||||
/// #[derive(Clone, Debug, Default)]
|
||||
/// pub struct MemoryRepo {
|
||||
/// inner: Arc<DashMap<Url, serde_json::Value>>,
|
||||
/// }
|
||||
///
|
||||
/// impl<'a, Id: Dereference + 'a> Repo<'a, Id> for MemoryRepo {
|
||||
/// type Error = serde_json::Error;
|
||||
/// type Future = Ready<Result<Option<Id::Output>, Self::Error>>;
|
||||
///
|
||||
/// fn fetch(&'a self, id: Id) -> Self::Future {
|
||||
/// if let Some(value) = self.inner.get(id.url()) {
|
||||
/// ready(serde_json::from_value(value.clone()).map(Some))
|
||||
/// } else {
|
||||
/// ready(Ok(None))
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
/// #[serde(transparent)]
|
||||
/// struct MyId(Url);
|
||||
///
|
||||
/// #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
/// struct MyObject {
|
||||
/// id: MyId,
|
||||
/// content: String,
|
||||
/// }
|
||||
///
|
||||
/// impl Dereference for MyId {
|
||||
/// type Output = MyObject;
|
||||
///
|
||||
/// fn url(&self) -> &Url {
|
||||
/// &self.0
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let existing_url: Url = "http://localhost:8080/object/hi".parse()?;
|
||||
/// let existing_object = serde_json::to_value(MyObject {
|
||||
/// id: MyId(existing_url.clone()),
|
||||
/// content: String::from("hello"),
|
||||
/// })?;
|
||||
///
|
||||
/// let missing_url: Url = "http://localhost:8080/object/hello".parse()?;
|
||||
/// let remote_url: Url = "https://masto.asonix.dog/users/asonix/statuses/107326693283572188".parse()?;
|
||||
///
|
||||
/// let local_domain = Host::Domain(String::from("localhost"));
|
||||
/// let local_port = Some(8080);
|
||||
///
|
||||
/// let mut local_repo = MemoryRepo::default();
|
||||
/// local_repo.inner.insert(
|
||||
/// existing_url.clone(),
|
||||
/// existing_object,
|
||||
/// );
|
||||
///
|
||||
/// let signature_config = ReqwestSignatureConfig::default();
|
||||
/// let private_key = PKey::from_rsa(Rsa::generate(1024)?)?;
|
||||
/// let crypto = OpenSsl::new("key-id".to_string(), private_key);
|
||||
/// let client = reqwest::Client::new();
|
||||
/// let remote_repo = ReqwestClient::new(&client, (), &signature_config, &crypto);
|
||||
///
|
||||
/// let deref_client = CombinedClient::new(
|
||||
/// local_domain,
|
||||
/// local_port,
|
||||
/// &local_repo,
|
||||
/// &remote_repo,
|
||||
/// );
|
||||
///
|
||||
/// let opt = deref_client.fetch(MyId(existing_url)).await?;
|
||||
/// assert!(opt.is_some());
|
||||
/// if let Some(my_object) = opt {
|
||||
/// println!("{:?}", my_object);
|
||||
/// }
|
||||
///
|
||||
/// let opt = deref_client.fetch(MyId(missing_url)).await?;
|
||||
/// assert!(opt.is_none());
|
||||
///
|
||||
/// let opt = deref_client.fetch(MyId(remote_url)).await?;
|
||||
/// assert!(opt.is_some());
|
||||
/// if let Some(my_object) = opt {
|
||||
/// println!("{:?}", my_object)
|
||||
/// }
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub use apub_deref_client::Client as CombinedClient;
|
||||
|
||||
#[cfg(feature = "apub-deref-client")]
|
||||
pub use apub_deref_client::Error as CombinedError;
|
||||
|
||||
#[cfg(feature = "apub-awc")]
|
||||
pub use apub_awc::{
|
||||
|
|
Loading…
Reference in a new issue