Update to actix 3.0

This commit is contained in:
asonix 2020-03-15 20:03:35 -05:00
parent 17cc4c9f21
commit 779b26e52e
5 changed files with 88 additions and 147 deletions

View file

@ -1,7 +1,7 @@
[package] [package]
name = "actix-webfinger" name = "actix-webfinger"
description = "Types and helpers to create and fetch Webfinger resources" description = "Types and helpers to create and fetch Webfinger resources"
version = "0.2.0" version = "0.3.0-alpha.0"
license = "GPL-3.0" license = "GPL-3.0"
authors = ["asonix <asonix@asonix.dog>"] authors = ["asonix <asonix@asonix.dog>"]
repository = "https://git.asonix.dog/Aardwolf/actix-webfinger" repository = "https://git.asonix.dog/Aardwolf/actix-webfinger"
@ -9,16 +9,14 @@ readme = "README.md"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
actix-http = "0.2.3" actix-http = "2.0.0-alpha.1"
actix-service = "0.4.1" actix-web = "3.0.0-alpha.1"
actix-web = "1.0.0"
failure = "0.1"
futures = "0.1"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
thiserror = "1.0"
[dev-dependencies] [dev-dependencies]
actix = "0.8" actix = "0.10.0-alpha.1"
actix-web = { version = "1.0.0", features = ["ssl"] } actix-rt = "1.0.0"
openssl = "0.10" actix-web = { version = "3.0.0-alpha.1", features = ["openssl"] }
serde_json = "1.0" serde_json = "1.0"

View file

@ -3,7 +3,7 @@ A library to aid in resolving and providing webfinger objects with the Actix Web
- [Read the documentation on docs.rs](https://docs.rs/actix-webfinger) - [Read the documentation on docs.rs](https://docs.rs/actix-webfinger)
- [Find the crate on crates.io](https://crates.io/crates/actix-webfinger) - [Find the crate on crates.io](https://crates.io/crates/actix-webfinger)
- [Join the discussion on Matrix](https://matrix.to/#/!JjjAVnljvJsHxWlnXP:asonix.dog?via=asonix.dog) - [Hit me up on Mastodon](https://asonix.dog/@asonix)
The main functionality this crate provides is through the `Webfinger::fetch` method for Actix The main functionality this crate provides is through the `Webfinger::fetch` method for Actix
Web-based clients, and the `Resolver<S>` trait for Actix Web-based servers. Web-based clients, and the `Resolver<S>` trait for Actix Web-based servers.
@ -13,41 +13,25 @@ First, add Actix Webfinger as a dependency
```toml ```toml
[dependencies] [dependencies]
actix = "0.8" actix = "0.10.0-alpha.1"
actix-web = "1.0.0" actix-web = "3.0.0-alpha.1"
actix-webfinger = "0.2.0" actix-webfinger = "0.3.0-alpha.0"
``` ```
Then use it in your application Then use it in your application
#### Client Example #### Client Example
```rust ```rust
use actix::System; use actix_web::client::Client;
use actix_web::client::Connector;
use actix_webfinger::Webfinger; use actix_webfinger::Webfinger;
use futures::{future::lazy, Future};
use openssl::ssl::{SslConnector, SslMethod};
use std::error::Error; use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> { #[actix_rt::main]
let sys = System::new("sir-boops"); async fn main() -> Result<(), Box<dyn Error>> {
let client = Client::default();
let wf = Webfinger::fetch(&client, "asonix@asonix.dog", "localhost:8000", false).await?;
let ssl_conn = SslConnector::builder(SslMethod::tls())?.build(); println!("asonix's webfinger:\n{:#?}", wf);
let conn = Connector::new().ssl(ssl_conn).finish();
let fut = lazy(move || {
Webfinger::fetch(conn, "asonix@asonix.dog", "localhost:8000", false)
.map(move |w: Webfinger| {
println!("asonix's webfinger:\n{:#?}", w);
System::current().stop();
})
.map_err(|e| eprintln!("Error: {}", e))
});
actix::spawn(fut);
sys.run()?;
Ok(()) Ok(())
} }
``` ```
@ -56,8 +40,7 @@ fn main() -> Result<(), Box<dyn Error>> {
```rust ```rust
use actix_web::{web::Data, App, HttpServer}; use actix_web::{web::Data, App, HttpServer};
use actix_webfinger::{Resolver, Webfinger}; use actix_webfinger::{Resolver, Webfinger};
use futures::{future::IntoFuture, Future}; use std::{error::Error, future::Future, pin::Pin};
use std::error::Error;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MyState { pub struct MyState {
@ -73,18 +56,19 @@ impl Resolver<Data<MyState>> for MyResolver {
account: &str, account: &str,
domain: &str, domain: &str,
state: &Data<MyState>, state: &Data<MyState>,
) -> Box<dyn Future<Item = Option<Webfinger>, Error = Self::Error>> { ) -> Pin<Box<dyn Future<Output = Result<Option<Webfinger>, Self::Error>>>> {
let w = if domain == state.domain { let w = if domain == state.domain {
Some(Webfinger::new(&format!("{}@{}", account, domain))) Some(Webfinger::new(&format!("{}@{}", account, domain)))
} else { } else {
None None
}; };
Box::new(Ok(w).into_future()) Box::pin(async move { Ok(w) })
} }
} }
fn main() -> Result<(), Box<dyn Error>> { #[actix_rt::main]
async fn main() -> Result<(), Box<dyn Error>> {
HttpServer::new(|| { HttpServer::new(|| {
App::new() App::new()
.data(MyState { .data(MyState {
@ -93,7 +77,8 @@ fn main() -> Result<(), Box<dyn Error>> {
.service(actix_webfinger::resource::<_, MyResolver>()) .service(actix_webfinger::resource::<_, MyResolver>())
}) })
.bind("127.0.0.1:8000")? .bind("127.0.0.1:8000")?
.run()?; .run()
.await?;
Ok(()) Ok(())
} }
@ -104,7 +89,7 @@ Feel free to open issues for anything you find an issue with. Please note that a
### License ### License
Copyright © 2019 Riley Trautman Copyright © 2020 Riley Trautman
Actix Webfinger is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Actix Webfinger is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

View file

@ -1,28 +1,12 @@
use actix::System; use actix_web::client::Client;
use actix_web::client::Connector;
use actix_webfinger::Webfinger; use actix_webfinger::Webfinger;
use futures::{future::lazy, Future};
use openssl::ssl::{SslConnector, SslMethod};
use std::error::Error; use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> { #[actix_rt::main]
let sys = System::new("sir-boops"); async fn main() -> Result<(), Box<dyn Error>> {
let client = Client::default();
let wf = Webfinger::fetch(&client, "asonix@asonix.dog", "localhost:8000", false).await?;
let ssl_conn = SslConnector::builder(SslMethod::tls())?.build(); println!("asonix's webfinger:\n{:#?}", wf);
let conn = Connector::new().ssl(ssl_conn).finish();
let fut = lazy(move || {
Webfinger::fetch(conn, "asonix@asonix.dog", "localhost:8000", false)
.map(move |w: Webfinger| {
println!("asonix's webfinger:\n{:#?}", w);
System::current().stop();
})
.map_err(|e| eprintln!("Error: {}", e))
});
actix::spawn(fut);
sys.run()?;
Ok(()) Ok(())
} }

View file

@ -1,7 +1,6 @@
use actix_web::{web::Data, App, HttpServer}; use actix_web::{web::Data, App, HttpServer};
use actix_webfinger::{Resolver, Webfinger}; use actix_webfinger::{Resolver, Webfinger};
use futures::{future::IntoFuture, Future}; use std::{error::Error, future::Future, pin::Pin};
use std::error::Error;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MyState { pub struct MyState {
@ -17,18 +16,19 @@ impl Resolver<Data<MyState>> for MyResolver {
account: &str, account: &str,
domain: &str, domain: &str,
state: &Data<MyState>, state: &Data<MyState>,
) -> Box<dyn Future<Item = Option<Webfinger>, Error = Self::Error>> { ) -> Pin<Box<dyn Future<Output = Result<Option<Webfinger>, Self::Error>>>> {
let w = if domain == state.domain { let w = if domain == state.domain {
Some(Webfinger::new(&format!("{}@{}", account, domain))) Some(Webfinger::new(&format!("{}@{}", account, domain)))
} else { } else {
None None
}; };
Box::new(Ok(w).into_future()) Box::pin(async move { Ok(w) })
} }
} }
fn main() -> Result<(), Box<dyn Error>> { #[actix_rt::main]
async fn main() -> Result<(), Box<dyn Error>> {
HttpServer::new(|| { HttpServer::new(|| {
App::new() App::new()
.data(MyState { .data(MyState {
@ -37,7 +37,8 @@ fn main() -> Result<(), Box<dyn Error>> {
.service(actix_webfinger::resource::<_, MyResolver>()) .service(actix_webfinger::resource::<_, MyResolver>())
}) })
.bind("127.0.0.1:8000")? .bind("127.0.0.1:8000")?
.run()?; .run()
.await?;
Ok(()) Ok(())
} }

View file

@ -9,45 +9,29 @@
//! //!
//! - [Read the documentation on docs.rs](https://docs.rs/actix-webfinger) //! - [Read the documentation on docs.rs](https://docs.rs/actix-webfinger)
//! - [Find the crate on crates.io](https://crates.io/crates/actix-webfinger) //! - [Find the crate on crates.io](https://crates.io/crates/actix-webfinger)
//! - [Join the discussion on Matrix](https://matrix.to/#/!JjjAVnljvJsHxWlnXP:asonix.dog?via=asonix.dog) //! - [Hit me up on Mastodon](https://asonix.dog/@asonix)
//! //!
//! ```toml //! ```toml
//! [dependencies] //! [dependencies]
//! actix = "0.8" //! actix = "0.10.0-alpha.1"
//! actix-web = "1.0.0" //! actix-web = "3.0.0-alpha.1"
//! actix-webfinger = "0.2.0" //! actix-webfinger = "0.3.0-alpha.0"
//! ``` //! ```
//! //!
//! Then use it in your application //! Then use it in your application
//! //!
//! #### Client Example //! #### Client Example
//! ```rust,ignore //! ```rust,ignore
//! use actix::System; //! use actix_web::client::Client;
//! use actix_web::client::Connector;
//! use actix_webfinger::Webfinger; //! use actix_webfinger::Webfinger;
//! use futures::{future::lazy, Future};
//! use openssl::ssl::{SslConnector, SslMethod};
//! use std::error::Error; //! use std::error::Error;
//! //!
//! fn main() -> Result<(), Box<dyn Error>> { //! #[actix_rt::main]
//! let sys = System::new("asonix"); //! async fn main() -> Result<(), Box<dyn Error>> {
//! let client = Client::default();
//! let wf = Webfinger::fetch(&client, "asonix@asonix.dog", "localhost:8000", false).await?;
//! //!
//! let ssl_conn = SslConnector::builder(SslMethod::tls())?.build(); //! println!("asonix's webfinger:\n{:#?}", wf);
//! let conn = Connector::new().ssl(ssl_conn).finish();
//!
//! let fut = lazy(move || {
//! Webfinger::fetch(conn, "asonix@asonix.dog", "localhost:8000", false)
//! .map(move |w: Webfinger| {
//! println!("asonix's webfinger:\n{:#?}", w);
//!
//! System::current().stop();
//! })
//! .map_err(|e| eprintln!("Error: {}", e))
//! });
//!
//! actix::spawn(fut);
//!
//! sys.run()?;
//! Ok(()) //! Ok(())
//! } //! }
//! ``` //! ```
@ -56,8 +40,7 @@
//! ```rust,ignore //! ```rust,ignore
//! use actix_web::{web::Data, App, HttpServer}; //! use actix_web::{web::Data, App, HttpServer};
//! use actix_webfinger::{Resolver, Webfinger}; //! use actix_webfinger::{Resolver, Webfinger};
//! use futures::{future::IntoFuture, Future}; //! use std::{error::Error, future::Future, pin::Pin};
//! use std::error::Error;
//! //!
//! #[derive(Clone, Debug)] //! #[derive(Clone, Debug)]
//! pub struct MyState { //! pub struct MyState {
@ -73,18 +56,19 @@
//! account: &str, //! account: &str,
//! domain: &str, //! domain: &str,
//! state: &Data<MyState>, //! state: &Data<MyState>,
//! ) -> Box<dyn Future<Item = Option<Webfinger>, Error = Self::Error>> { //! ) -> Pin<Box<dyn Future<Output = Result<Option<Webfinger>, Self::Error>>>> {
//! let w = if domain == state.domain { //! let w = if domain == state.domain {
//! Some(Webfinger::new(&format!("{}@{}", account, domain))) //! Some(Webfinger::new(&format!("{}@{}", account, domain)))
//! } else { //! } else {
//! None //! None
//! }; //! };
//! //!
//! Box::new(Ok(w).into_future()) //! Box::pin(async move { Ok(w) })
//! } //! }
//! } //! }
//! //!
//! fn main() -> Result<(), Box<dyn Error>> { //! #[actix_rt::main]
//! async fn main() -> Result<(), Box<dyn Error>> {
//! HttpServer::new(|| { //! HttpServer::new(|| {
//! App::new() //! App::new()
//! .data(MyState { //! .data(MyState {
@ -93,7 +77,8 @@
//! .service(actix_webfinger::resource::<_, MyResolver>()) //! .service(actix_webfinger::resource::<_, MyResolver>())
//! }) //! })
//! .bind("127.0.0.1:8000")? //! .bind("127.0.0.1:8000")?
//! .run()?; //! .run()
//! .await?;
//! //!
//! Ok(()) //! Ok(())
//! } //! }
@ -104,15 +89,13 @@
//! //!
//! ### License //! ### License
//! //!
//! Copyright © 2019 Riley Trautman //! Copyright © 2020 Riley Trautman
//! //!
//! Actix Webfinger is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. //! Actix Webfinger is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
//! //!
//! Actix Webfinger is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. This file is part of Tokio ZMQ. //! Actix Webfinger is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. This file is part of Tokio ZMQ.
//! //!
//! You should have received a copy of the GNU General Public License along with Actix Webfinger. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/). //! You should have received a copy of the GNU General Public License along with Actix Webfinger. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/).
use actix_http::client::{Connect, ConnectError, Connection};
use actix_service::Service;
use actix_web::{ use actix_web::{
client::Client, client::Client,
dev::RequestHead, dev::RequestHead,
@ -122,9 +105,8 @@ use actix_web::{
web::{get, Query}, web::{get, Query},
FromRequest, HttpResponse, Resource, FromRequest, HttpResponse, Resource,
}; };
use failure::Fail;
use futures::Future;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::{future::Future, pin::Pin};
/// A predicate for Actix Web route filters /// A predicate for Actix Web route filters
/// ///
@ -239,8 +221,8 @@ where
/// - `asonix` /// - `asonix`
/// ///
/// This error type captures the invalid string for inspection /// This error type captures the invalid string for inspection
#[derive(Clone, Debug, Fail)] #[derive(Clone, Debug, thiserror::Error)]
#[fail(display = "Resource {} is invalid", _0)] #[error("Resource {0} is invalid")]
pub struct InvalidResource(String); pub struct InvalidResource(String);
/// A type representing a valid resource query /// A type representing a valid resource query
@ -328,7 +310,7 @@ pub struct WebfingerQuery {
/// ///
/// ```rust,ignore /// ```rust,ignore
/// use actix_webfinger::{Resolver, Webfinger}; /// use actix_webfinger::{Resolver, Webfinger};
/// use futures::{Future, future::IntoFuture}; /// use std::{future::Future, pin::Pin};
/// ///
/// struct MyResolver; /// struct MyResolver;
/// ///
@ -342,36 +324,32 @@ pub struct WebfingerQuery {
/// account: &str, /// account: &str,
/// domain: &str, /// domain: &str,
/// _state: S /// _state: S
/// ) -> Box<dyn Future<Item = Option<Webfinger>, Error = Self::Error>> { /// ) -> Pin<Box<dyn Future<Output = Result<Option<Webfinger>, Self::Error>>>> {
/// let webfinger = Webfinger::new(&format!("{}@{}", account, domain)); /// let webfinger = Webfinger::new(&format!("{}@{}", account, domain));
/// ///
/// // do something /// // do something
/// ///
/// let f = Ok(Some(webfinger)).into_future(); /// Box::pin(async move { Ok(Some(webfinger)) })
///
/// Box::new(f)
/// } /// }
/// } /// }
/// ///
/// fn main() -> Result<(), Box<dyn std::error::Error>> { /// #[actix_rt::main]
/// let sys = System::new("asonix"); /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
///
/// HttpServer::new(|| { /// HttpServer::new(|| {
/// App::new() /// App::new()
/// .data(()) /// .data(())
/// .service(resource::<Data<()>, MyResolver>()) /// .service(resource::<Data<()>, MyResolver>())
/// }) /// })
/// .bind("127.0.0.1:8000")? /// .bind("127.0.0.1:8000")?
/// .start(); /// .run()
/// /// .await?;
/// sys.run()?;
/// ///
/// Ok(()) /// Ok(())
/// } /// }
/// ``` /// ```
pub trait Resolver<S> pub trait Resolver<S>
where where
S: FromRequest, S: FromRequest + 'static,
{ {
type Error: ResponseError + 'static; type Error: ResponseError + 'static;
@ -379,17 +357,19 @@ where
account: &str, account: &str,
domain: &str, domain: &str,
state: &S, state: &S,
) -> Box<dyn Future<Item = Option<Webfinger>, Error = Self::Error>>; ) -> Pin<Box<dyn Future<Output = Result<Option<Webfinger>, Self::Error>>>>;
fn endpoint( fn endpoint(
(query, state): (Query<WebfingerQuery>, S), (query, state): (Query<WebfingerQuery>, S),
) -> Box<dyn Future<Item = HttpResponse, Error = Self::Error>> { ) -> Pin<Box<dyn Future<Output = Result<HttpResponse, Self::Error>>>> {
let WebfingerResource { account, domain } = query.into_inner().resource; let WebfingerResource { account, domain } = query.into_inner().resource;
Box::new(Self::find(&account, &domain, &state).map(|w| match w { Box::pin(async move {
Some(w) => w.respond(), match Self::find(&account, &domain, &state).await? {
None => HttpResponse::NotFound().finish(), Some(w) => Ok(w.respond()),
})) None => Ok(HttpResponse::NotFound().finish()),
}
})
} }
} }
@ -600,19 +580,14 @@ impl Webfinger {
/// Fetch a webfinger with subject `user` from a given `domain` /// Fetch a webfinger with subject `user` from a given `domain`
/// ///
/// This method takes an `Service` so derivative works can provide their own SSL /// This method takes a `Client` so derivative works can provide their own configured clients
/// connector implemenation (currently with OpenSSL or Rustls) /// rather this library generating it's own http clients.
pub fn fetch<T>( pub async fn fetch(
conn: T, client: &Client,
user: &str, user: &str,
domain: &str, domain: &str,
https: bool, https: bool,
) -> Box<dyn Future<Item = Self, Error = FetchError>> ) -> Result<Self, FetchError> {
where
T: Service<Request = Connect, Error = ConnectError> + Clone + 'static,
<T as Service>::Response: Connection,
<T as Service>::Future: 'static,
{
let url = format!( let url = format!(
"{}://{}/.well-known/webfinger?resource=acct:{}", "{}://{}/.well-known/webfinger?resource=acct:{}",
if https { "https" } else { "http" }, if https { "https" } else { "http" },
@ -620,24 +595,22 @@ impl Webfinger {
user user
); );
let fut = Client::build() let mut res = client
.connector(conn)
.header("Accept", "application/jrd+json")
.finish()
.get(url) .get(url)
.header("Accept", "application/jrd+json")
.send() .send()
.map_err(|_| FetchError::Send) .await
.and_then(|mut res| res.json::<Webfinger>().map_err(|_| FetchError::Parse)); .map_err(|_| FetchError::Send)?;
Box::new(fut) res.json::<Webfinger>().await.map_err(|_| FetchError::Parse)
} }
} }
#[derive(Clone, Debug, Fail)] #[derive(Clone, Debug, thiserror::Error)]
pub enum FetchError { pub enum FetchError {
#[fail(display = "Failed to send request")] #[error("Failed to send request")]
Send, Send,
#[fail(display = "Failed to parse response JSON")] #[error("Failed to parse response JSON")]
Parse, Parse,
} }