Remove `HttpSend` and `HttpSender`

this was maybe a good idea, but it isn't really needed
master
Paul Woolcock 4 years ago
parent cfe810be4e
commit d66c63dd28
  1. 2
      README.md
  2. 4
      src/apps.rs
  3. 14
      src/entities/itemsiter.rs
  4. 4
      src/helpers/cli.rs
  5. 26
      src/http_send.rs
  6. 72
      src/lib.rs
  7. 6
      src/macros.rs
  8. 57
      src/mastodon_client.rs
  9. 32
      src/page.rs
  10. 50
      src/registration.rs
  11. 2
      src/requests/filter.rs
  12. 14
      src/scopes.rs

@ -76,7 +76,7 @@ use elefren::entities::event::Event;
use std::error::Error;
fn main() -> Result<(), Box<Error>> {
fn main() -> Result<(), Box<dyn Error>> {
let data = Data {
base: "".into(),
client_id: "".into(),

@ -61,7 +61,7 @@ impl App {
/// use elefren::apps::App;
/// use std::error::Error;
///
/// # fn main() -> Result<(), Box<Error>> {
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let mut builder = App::builder();
/// builder.client_name("elefren_test");
/// let app = builder.build()?;
@ -120,7 +120,7 @@ impl<'a> AppBuilder<'a> {
Ok(App {
client_name: self
.client_name
.ok_or_else(|| Error::MissingField("client_name"))?
.ok_or(Error::MissingField("client_name"))?
.into(),
redirect_uris: self
.redirect_uris

@ -1,4 +1,4 @@
use crate::{http_send::HttpSend, page::Page};
use crate::page::Page;
use serde::Deserialize;
/// Abstracts away the `next_page` logic into a single stream of items
@ -7,7 +7,7 @@ use serde::Deserialize;
/// # extern crate elefren;
/// # use elefren::prelude::*;
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<Error>> {
/// # fn main() -> Result<(), Box<dyn Error>> {
/// # let data = Data {
/// # base: "".into(),
/// # client_id: "".into(),
@ -24,15 +24,15 @@ use serde::Deserialize;
/// # }
/// ```
#[derive(Debug, Clone)]
pub(crate) struct ItemsIter<'a, T: Clone + for<'de> Deserialize<'de>, H: 'a + HttpSend> {
page: Page<'a, T, H>,
pub(crate) struct ItemsIter<'a, T: Clone + for<'de> Deserialize<'de>> {
page: Page<'a, T>,
buffer: Vec<T>,
cur_idx: usize,
use_initial: bool,
}
impl<'a, T: Clone + for<'de> Deserialize<'de>, H: HttpSend> ItemsIter<'a, T, H> {
pub(crate) fn new(page: Page<'a, T, H>) -> ItemsIter<'a, T, H> {
impl<'a, T: Clone + for<'de> Deserialize<'de>> ItemsIter<'a, T> {
pub(crate) fn new(page: Page<'a, T>) -> ItemsIter<'a, T> {
ItemsIter {
page,
buffer: vec![],
@ -64,7 +64,7 @@ impl<'a, T: Clone + for<'de> Deserialize<'de>, H: HttpSend> ItemsIter<'a, T, H>
}
}
impl<'a, T: Clone + for<'de> Deserialize<'de>, H: HttpSend> Iterator for ItemsIter<'a, T, H> {
impl<'a, T: Clone + for<'de> Deserialize<'de>> Iterator for ItemsIter<'a, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {

@ -1,10 +1,10 @@
use std::io::{self, BufRead, Write};
use crate::{errors::Result, http_send::HttpSend, registration::Registered, Mastodon};
use crate::{errors::Result, registration::Registered, Mastodon};
/// Finishes the authentication process for the given `Registered` object,
/// using the command-line
pub fn authenticate<H: HttpSend>(registration: Registered<H>) -> Result<Mastodon<H>> {
pub fn authenticate(registration: Registered) -> Result<Mastodon> {
let url = registration.authorize_url()?;
let stdout = io::stdout();

@ -1,26 +0,0 @@
use crate::Result;
use reqwest::{Client, Request, RequestBuilder, Response};
use std::fmt::Debug;
/// Abstracts away the process of turning an HTTP request into an HTTP response
pub trait HttpSend: Clone + Debug {
/// Converts an HTTP request into an HTTP response
fn execute(&self, client: &Client, request: Request) -> Result<Response>;
/// Convenience method so that .build() doesn't have to be called at every
/// call site
fn send(&self, client: &Client, builder: RequestBuilder) -> Result<Response> {
let request = builder.build()?;
self.execute(client, request)
}
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct HttpSender;
impl HttpSend for HttpSender {
fn execute(&self, client: &Client, request: Request) -> Result<Response> {
Ok(client.execute(request)?)
}
}

@ -36,7 +36,7 @@
//! # use elefren::prelude::*;
//! # use std::error::Error;
//! use elefren::entities::event::Event;
//! # fn main() -> Result<(), Box<Error>> {
//! # fn main() -> Result<(), Box<dyn Error>> {
//! # let data = Data {
//! # base: "".into(),
//! # client_id: "".into(),
@ -77,11 +77,7 @@ use reqwest::{Client, RequestBuilder, Response};
use tap_reader::Tap;
use tungstenite::client::AutoStream;
use crate::{
entities::prelude::*,
http_send::{HttpSend, HttpSender},
page::Page,
};
use crate::{entities::prelude::*, page::Page};
pub use crate::{
data::Data,
@ -110,8 +106,6 @@ pub mod entities;
pub mod errors;
/// Collection of helpers for serializing/deserializing `Data` objects
pub mod helpers;
/// Contains trait for converting `reqwest::Request`s to `reqwest::Response`s
pub mod http_send;
mod mastodon_client;
/// Constructing media attachments for a status.
pub mod media_builder;
@ -143,14 +137,13 @@ pub mod prelude {
/// Your mastodon application client, handles all requests to and from Mastodon.
#[derive(Clone, Debug)]
pub struct Mastodon<H: HttpSend = HttpSender> {
pub struct Mastodon {
client: Client,
http_sender: H,
/// Raw data about your mastodon instance.
pub data: Data,
}
impl<H: HttpSend> Mastodon<H> {
impl Mastodon {
methods![get, post, delete,];
fn route(&self, url: &str) -> String {
@ -158,16 +151,15 @@ impl<H: HttpSend> Mastodon<H> {
}
pub(crate) fn send(&self, req: RequestBuilder) -> Result<Response> {
Ok(self
.http_sender
.send(&self.client, req.bearer_auth(&self.token))?)
let request = req.bearer_auth(&self.token).build()?;
Ok(self.client.execute(request)?)
}
}
impl From<Data> for Mastodon<HttpSender> {
impl From<Data> for Mastodon {
/// Creates a mastodon instance from the data struct.
fn from(data: Data) -> Mastodon<HttpSender> {
let mut builder = MastodonBuilder::new(HttpSender);
fn from(data: Data) -> Mastodon {
let mut builder = MastodonBuilder::new();
builder.data(data);
builder
.build()
@ -175,7 +167,7 @@ impl From<Data> for Mastodon<HttpSender> {
}
}
impl<H: HttpSend> MastodonClient<H> for Mastodon<H> {
impl MastodonClient for Mastodon {
type Stream = EventReader<WebSocket>;
paged_routes! {
@ -307,7 +299,7 @@ impl<H: HttpSend> MastodonClient<H> for Mastodon<H> {
/// Get timeline filtered by a hashtag(eg. `#coffee`) either locally or
/// federated.
fn get_hashtag_timeline(&self, hashtag: &str, local: bool) -> Result<Page<Status, H>> {
fn get_hashtag_timeline(&self, hashtag: &str, local: bool) -> Result<Page<Status>> {
let base = "/api/v1/timelines/tag/";
let url = if local {
self.route(&format!("{}{}?local=1", base, hashtag))
@ -327,7 +319,7 @@ impl<H: HttpSend> MastodonClient<H> for Mastodon<H> {
/// # extern crate elefren;
/// # use elefren::prelude::*;
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<Error>> {
/// # fn main() -> Result<(), Box<dyn Error>> {
/// # let data = Data {
/// # base: "".into(),
/// # client_id: "".into(),
@ -345,7 +337,7 @@ impl<H: HttpSend> MastodonClient<H> for Mastodon<H> {
/// # extern crate elefren;
/// # use elefren::prelude::*;
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<Error>> {
/// # fn main() -> Result<(), Box<dyn Error>> {
/// # let data = Data {
/// # base: "".into(),
/// # client_id: "".into(),
@ -360,7 +352,7 @@ impl<H: HttpSend> MastodonClient<H> for Mastodon<H> {
/// # Ok(())
/// # }
/// ```
fn statuses<'a, 'b: 'a, S>(&'b self, id: &'b str, request: S) -> Result<Page<Status, H>>
fn statuses<'a, 'b: 'a, S>(&'b self, id: &'b str, request: S) -> Result<Page<Status>>
where
S: Into<Option<StatusesRequest<'a>>>,
{
@ -377,7 +369,7 @@ impl<H: HttpSend> MastodonClient<H> for Mastodon<H> {
/// Returns the client account's relationship to a list of other accounts.
/// Such as whether they follow them or vice versa.
fn relationships(&self, ids: &[&str]) -> Result<Page<Relationship, H>> {
fn relationships(&self, ids: &[&str]) -> Result<Page<Relationship>> {
let mut url = self.route("/api/v1/accounts/relationships?");
if ids.len() == 1 {
@ -423,13 +415,13 @@ impl<H: HttpSend> MastodonClient<H> for Mastodon<H> {
}
/// Get all accounts that follow the authenticated user
fn follows_me(&self) -> Result<Page<Account, H>> {
fn follows_me(&self) -> Result<Page<Account>> {
let me = self.verify_credentials()?;
Ok(self.followers(&me.id)?)
}
/// Get all accounts that the authenticated user follows
fn followed_by_me(&self) -> Result<Page<Account, H>> {
fn followed_by_me(&self) -> Result<Page<Account>> {
let me = self.verify_credentials()?;
Ok(self.following(&me.id)?)
}
@ -444,7 +436,7 @@ impl<H: HttpSend> MastodonClient<H> for Mastodon<H> {
/// # use elefren::prelude::*;
/// # use std::error::Error;
/// use elefren::entities::event::Event;
/// # fn main() -> Result<(), Box<Error>> {
/// # fn main() -> Result<(), Box<dyn Error>> {
/// # let data = Data {
/// # base: "".into(),
/// # client_id: "".into(),
@ -737,7 +729,7 @@ impl<R: EventStream> EventReader<R> {
}
}
impl<H: HttpSend> ops::Deref for Mastodon<H> {
impl ops::Deref for Mastodon {
type Target = Data;
fn deref(&self) -> &Self::Target {
@ -745,16 +737,14 @@ impl<H: HttpSend> ops::Deref for Mastodon<H> {
}
}
struct MastodonBuilder<H: HttpSend> {
struct MastodonBuilder {
client: Option<Client>,
http_sender: H,
data: Option<Data>,
}
impl<H: HttpSend> MastodonBuilder<H> {
pub fn new(sender: H) -> Self {
impl MastodonBuilder {
pub fn new() -> Self {
MastodonBuilder {
http_sender: sender,
client: None,
data: None,
}
@ -770,11 +760,10 @@ impl<H: HttpSend> MastodonBuilder<H> {
self
}
pub fn build(self) -> Result<Mastodon<H>> {
pub fn build(self) -> Result<Mastodon> {
Ok(if let Some(data) = self.data {
Mastodon {
client: self.client.unwrap_or_else(Client::new),
http_sender: self.http_sender,
data,
}
} else {
@ -785,15 +774,14 @@ impl<H: HttpSend> MastodonBuilder<H> {
/// Client that can make unauthenticated calls to a mastodon instance
#[derive(Clone, Debug)]
pub struct MastodonUnauth<H: HttpSend = HttpSender> {
pub struct MastodonUnauth {
client: Client,
http_sender: H,
base: url::Url,
}
impl MastodonUnauth<HttpSender> {
impl MastodonUnauth {
/// Create a new unauthenticated client
pub fn new(base: &str) -> Result<MastodonUnauth<HttpSender>> {
pub fn new(base: &str) -> Result<MastodonUnauth> {
let base = if base.starts_with("https://") {
base.to_string()
} else {
@ -801,19 +789,19 @@ impl MastodonUnauth<HttpSender> {
};
Ok(MastodonUnauth {
client: Client::new(),
http_sender: HttpSender,
base: url::Url::parse(&base)?,
})
}
}
impl<H: HttpSend> MastodonUnauth<H> {
impl MastodonUnauth {
fn route(&self, url: &str) -> Result<url::Url> {
Ok(self.base.join(url)?)
}
fn send(&self, req: RequestBuilder) -> Result<Response> {
Ok(self.http_sender.send(&self.client, req)?)
let req = req.build()?;
Ok(self.client.execute(req)?)
}
/// Get a stream of the public timeline
@ -835,7 +823,7 @@ impl<H: HttpSend> MastodonUnauth<H> {
}
}
impl<H: HttpSend> MastodonUnauthenticated<H> for MastodonUnauth<H> {
impl MastodonUnauthenticated for MastodonUnauth {
/// GET /api/v1/statuses/:id
fn get_status(&self, id: &str) -> Result<Status> {
let route = self.route("/api/v1/statuses")?;

@ -40,7 +40,7 @@ macro_rules! paged_routes {
"# }\n",
"```"
),
fn $name(&self) -> Result<Page<$ret, H>> {
fn $name(&self) -> Result<Page<$ret>> {
let url = self.route(concat!("/api/v1/", $url));
let response = self.send(
self.client.$method(&url)
@ -61,7 +61,7 @@ macro_rules! paged_routes {
$url,
"`\n# Errors\nIf `access_token` is not set."
),
fn $name<'a>(&self, $($param: $typ,)*) -> Result<Page<$ret, H>> {
fn $name<'a>(&self, $($param: $typ,)*) -> Result<Page<$ret>> {
use serde_urlencoded;
use serde::Serialize;
@ -315,7 +315,7 @@ macro_rules! paged_routes_with_id {
"# }\n",
"```"
),
fn $name(&self, id: &str) -> Result<Page<$ret, H>> {
fn $name(&self, id: &str) -> Result<Page<$ret>> {
let url = self.route(&format!(concat!("/api/v1/", $url), id));
let response = self.send(
self.client.$method(&url)

@ -3,7 +3,6 @@ use std::borrow::Cow;
use crate::{
entities::prelude::*,
errors::Result,
http_send::{HttpSend, HttpSender},
media_builder::MediaBuilder,
page::Page,
requests::{
@ -19,60 +18,60 @@ use crate::{
/// Represents the set of methods that a Mastodon Client can do, so that
/// implementations might be swapped out for testing
#[allow(unused)]
pub trait MastodonClient<H: HttpSend = HttpSender> {
pub trait MastodonClient {
/// Type that wraps streaming API streams
type Stream: Iterator<Item = Event>;
/// GET /api/v1/favourites
fn favourites(&self) -> Result<Page<Status, H>> {
fn favourites(&self) -> Result<Page<Status>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/blocks
fn blocks(&self) -> Result<Page<Account, H>> {
fn blocks(&self) -> Result<Page<Account>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/domain_blocks
fn domain_blocks(&self) -> Result<Page<String, H>> {
fn domain_blocks(&self) -> Result<Page<String>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/follow_requests
fn follow_requests(&self) -> Result<Page<Account, H>> {
fn follow_requests(&self) -> Result<Page<Account>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/timelines/home
fn get_home_timeline(&self) -> Result<Page<Status, H>> {
fn get_home_timeline(&self) -> Result<Page<Status>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/custom_emojis
fn get_emojis(&self) -> Result<Page<Emoji, H>> {
fn get_emojis(&self) -> Result<Page<Emoji>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/mutes
fn mutes(&self) -> Result<Page<Account, H>> {
fn mutes(&self) -> Result<Page<Account>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/notifications
fn notifications(&self) -> Result<Page<Notification, H>> {
fn notifications(&self) -> Result<Page<Notification>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/reports
fn reports(&self) -> Result<Page<Report, H>> {
fn reports(&self) -> Result<Page<Report>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/accounts/:id/followers
fn followers(&self, id: &str) -> Result<Page<Account, H>> {
fn followers(&self, id: &str) -> Result<Page<Account>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/accounts/:id/following
fn following(&self, id: &str) -> Result<Page<Account, H>> {
fn following(&self, id: &str) -> Result<Page<Account>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/statuses/:id/reblogged_by
fn reblogged_by(&self, id: &str) -> Result<Page<Account, H>> {
fn reblogged_by(&self, id: &str) -> Result<Page<Account>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/statuses/:id/favourited_by
fn favourited_by(&self, id: &str) -> Result<Page<Account, H>> {
fn favourited_by(&self, id: &str) -> Result<Page<Account>> {
unimplemented!("This method was not implemented");
}
/// DELETE /api/v1/domain_blocks
@ -200,26 +199,26 @@ pub trait MastodonClient<H: HttpSend = HttpSender> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/timelines/public?local=true
fn get_local_timeline(&self) -> Result<Page<Status, H>> {
fn get_local_timeline(&self) -> Result<Page<Status>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/timelines/public?local=false
fn get_federated_timeline(&self) -> Result<Page<Status, H>> {
fn get_federated_timeline(&self) -> Result<Page<Status>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/timelines/tag/:hashtag
fn get_hashtag_timeline(&self, hashtag: &str, local: bool) -> Result<Page<Status, H>> {
fn get_hashtag_timeline(&self, hashtag: &str, local: bool) -> Result<Page<Status>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/accounts/:id/statuses
fn statuses<'a, 'b: 'a, S>(&'b self, id: &'b str, request: S) -> Result<Page<Status, H>>
fn statuses<'a, 'b: 'a, S>(&'b self, id: &'b str, request: S) -> Result<Page<Status>>
where
S: Into<Option<StatusesRequest<'a>>>,
{
unimplemented!("This method was not implemented");
}
/// GET /api/v1/accounts/relationships
fn relationships(&self, ids: &[&str]) -> Result<Page<Relationship, H>> {
fn relationships(&self, ids: &[&str]) -> Result<Page<Relationship>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/accounts/search?q=:query&limit=:limit&following=:following
@ -228,7 +227,7 @@ pub trait MastodonClient<H: HttpSend = HttpSender> {
query: &str,
limit: Option<u64>,
following: bool,
) -> Result<Page<Account, H>> {
) -> Result<Page<Account>> {
unimplemented!("This method was not implemented");
}
/// POST /api/v1/push/subscription
@ -276,7 +275,7 @@ pub trait MastodonClient<H: HttpSend = HttpSender> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/endorsements
fn get_endorsements(&self) -> Result<Page<Account, H>> {
fn get_endorsements(&self) -> Result<Page<Account>> {
unimplemented!("This method was not implemented");
}
/// POST /api/v1/accounts/:id/pin
@ -293,7 +292,7 @@ pub trait MastodonClient<H: HttpSend = HttpSender> {
/// # extern crate elefren;
/// # use std::error::Error;
/// # use elefren::prelude::*;
/// # fn main() -> Result<(), Box<Error>> {
/// # fn main() -> Result<(), Box<dyn Error>> {
/// # let data = Data {
/// # base: "".into(),
/// # client_id: "".into(),
@ -305,7 +304,7 @@ pub trait MastodonClient<H: HttpSend = HttpSender> {
/// let follows_me = client.follows_me()?;
/// # Ok(())
/// # }
fn follows_me(&self) -> Result<Page<Account, H>> {
fn follows_me(&self) -> Result<Page<Account>> {
unimplemented!("This method was not implemented");
}
/// Shortcut for
@ -315,7 +314,7 @@ pub trait MastodonClient<H: HttpSend = HttpSender> {
/// # extern crate elefren;
/// # use std::error::Error;
/// # use elefren::prelude::*;
/// # fn main() -> Result<(), Box<Error>> {
/// # fn main() -> Result<(), Box<dyn Error>> {
/// # let data = Data {
/// # base: "".into(),
/// # client_id: "".into(),
@ -327,7 +326,7 @@ pub trait MastodonClient<H: HttpSend = HttpSender> {
/// let follows_me = client.followed_by_me()?;
/// # Ok(())
/// # }
fn followed_by_me(&self) -> Result<Page<Account, H>> {
fn followed_by_me(&self) -> Result<Page<Account>> {
unimplemented!("This method was not implemented");
}
@ -371,7 +370,7 @@ pub trait MastodonClient<H: HttpSend = HttpSender> {
/// Trait that represents clients that can make unauthenticated calls to a
/// mastodon instance
#[allow(unused)]
pub trait MastodonUnauthenticated<H: HttpSend> {
pub trait MastodonUnauthenticated {
/// GET /api/v1/statuses/:id
fn get_status(&self, id: &str) -> Result<Status> {
unimplemented!("This method was not implemented");
@ -385,11 +384,11 @@ pub trait MastodonUnauthenticated<H: HttpSend> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/statuses/:id/reblogged_by
fn reblogged_by(&self, id: &str) -> Result<Page<Account, H>> {
fn reblogged_by(&self, id: &str) -> Result<Page<Account>> {
unimplemented!("This method was not implemented");
}
/// GET /api/v1/statuses/:id/favourited_by
fn favourited_by(&self, id: &str) -> Result<Page<Account, H>> {
fn favourited_by(&self, id: &str) -> Result<Page<Account>> {
unimplemented!("This method was not implemented");
}
}

@ -5,8 +5,6 @@ use reqwest::{header::LINK, Response};
use serde::Deserialize;
use url::Url;
use crate::http_send::HttpSend;
macro_rules! pages {
($($direction:ident: $fun:ident),*) => {
@ -42,7 +40,6 @@ macro_rules! pages {
/// # extern crate elefren;
/// # use elefren::Mastodon;
/// # use elefren::page::OwnedPage;
/// # use elefren::http_send::HttpSender;
/// # use elefren::entities::status::Status;
/// # use std::cell::RefCell;
/// # use elefren::prelude::*;
@ -56,7 +53,7 @@ macro_rules! pages {
/// # };
/// struct HomeTimeline {
/// client: Mastodon,
/// page: RefCell<Option<OwnedPage<Status, HttpSender>>>,
/// page: RefCell<Option<OwnedPage<Status>>>,
/// }
/// let client = Mastodon::from(data);
/// let home = client.get_home_timeline()?.into_owned();
@ -68,23 +65,23 @@ macro_rules! pages {
/// # }
/// ```
#[derive(Debug, Clone)]
pub struct OwnedPage<T: for<'de> Deserialize<'de>, H: HttpSend> {
mastodon: Mastodon<H>,
pub struct OwnedPage<T: for<'de> Deserialize<'de>> {
mastodon: Mastodon,
next: Option<Url>,
prev: Option<Url>,
/// Initial set of items
pub initial_items: Vec<T>,
}
impl<T: for<'de> Deserialize<'de>, H: HttpSend> OwnedPage<T, H> {
impl<T: for<'de> Deserialize<'de>> OwnedPage<T> {
pages! {
next: next_page,
prev: prev_page
}
}
impl<'a, T: for<'de> Deserialize<'de>, H: HttpSend> From<Page<'a, T, H>> for OwnedPage<T, H> {
fn from(page: Page<'a, T, H>) -> OwnedPage<T, H> {
impl<'a, T: for<'de> Deserialize<'de>> From<Page<'a, T>> for OwnedPage<T> {
fn from(page: Page<'a, T>) -> OwnedPage<T> {
OwnedPage {
mastodon: page.mastodon.clone(),
next: page.next,
@ -96,21 +93,21 @@ impl<'a, T: for<'de> Deserialize<'de>, H: HttpSend> From<Page<'a, T, H>> for Own
/// Represents a single page of API results
#[derive(Debug, Clone)]
pub struct Page<'a, T: for<'de> Deserialize<'de>, H: 'a + HttpSend> {
mastodon: &'a Mastodon<H>,
pub struct Page<'a, T: for<'de> Deserialize<'de>> {
mastodon: &'a Mastodon,
next: Option<Url>,
prev: Option<Url>,
/// Initial set of items
pub initial_items: Vec<T>,
}
impl<'a, T: for<'de> Deserialize<'de>, H: HttpSend> Page<'a, T, H> {
impl<'a, T: for<'de> Deserialize<'de>> Page<'a, T> {
pages! {
next: next_page,
prev: prev_page
}
pub(crate) fn new(mastodon: &'a Mastodon<H>, response: Response) -> Result<Self> {
pub(crate) fn new(mastodon: &'a Mastodon, response: Response) -> Result<Self> {
let (prev, next) = get_links(&response)?;
Ok(Page {
initial_items: deserialise(response)?,
@ -121,7 +118,7 @@ impl<'a, T: for<'de> Deserialize<'de>, H: HttpSend> Page<'a, T, H> {
}
}
impl<'a, T: Clone + for<'de> Deserialize<'de>, H: HttpSend> Page<'a, T, H> {
impl<'a, T: Clone + for<'de> Deserialize<'de>> Page<'a, T> {
/// Returns an owned version of this struct that doesn't borrow the client
/// that created it
///
@ -131,7 +128,6 @@ impl<'a, T: Clone + for<'de> Deserialize<'de>, H: HttpSend> Page<'a, T, H> {
/// # extern crate elefren;
/// # use elefren::Mastodon;
/// # use elefren::page::OwnedPage;
/// # use elefren::http_send::HttpSender;
/// # use elefren::entities::status::Status;
/// # use std::cell::RefCell;
/// # use elefren::prelude::*;
@ -145,7 +141,7 @@ impl<'a, T: Clone + for<'de> Deserialize<'de>, H: HttpSend> Page<'a, T, H> {
/// # };
/// struct HomeTimeline {
/// client: Mastodon,
/// page: RefCell<Option<OwnedPage<Status, HttpSender>>>,
/// page: RefCell<Option<OwnedPage<Status>>>,
/// }
/// let client = Mastodon::from(data);
/// let home = client.get_home_timeline()?.into_owned();
@ -156,7 +152,7 @@ impl<'a, T: Clone + for<'de> Deserialize<'de>, H: HttpSend> Page<'a, T, H> {
/// # Ok(())
/// # }
/// ```
pub fn into_owned(self) -> OwnedPage<T, H> {
pub fn into_owned(self) -> OwnedPage<T> {
OwnedPage::from(self)
}
@ -176,7 +172,7 @@ impl<'a, T: Clone + for<'de> Deserialize<'de>, H: HttpSend> Page<'a, T, H> {
/// # extern crate elefren;
/// # use std::error::Error;
/// use elefren::prelude::*;
/// # fn main() -> Result<(), Box<Error>> {
/// # fn main() -> Result<(), Box<dyn Error>> {
/// # let data = Data {
/// # base: "".into(),
/// # client_id: "".into(),

@ -7,7 +7,6 @@ use url::percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
use crate::{
apps::{App, AppBuilder},
http_send::{HttpSend, HttpSender},
scopes::Scopes,
Data,
Error,
@ -21,12 +20,11 @@ const DEFAULT_REDIRECT_URI: &str = "urn:ietf:wg:oauth:2.0:oob";
/// Handles registering your mastodon app to your instance. It is recommended
/// you cache your data struct to avoid registering on every run.
#[derive(Debug, Clone)]
pub struct Registration<'a, H: HttpSend = HttpSender> {
pub struct Registration<'a> {
base: String,
client: Client,
app_builder: AppBuilder<'a>,
force_login: bool,
http_sender: H,
}
#[derive(Deserialize)]
@ -46,7 +44,7 @@ struct AccessToken {
access_token: String,
}
impl<'a> Registration<'a, HttpSender> {
impl<'a> Registration<'a> {
/// Construct a new registration process to the instance of the `base` url.
/// ```
/// use elefren::prelude::*;
@ -59,23 +57,11 @@ impl<'a> Registration<'a, HttpSender> {
client: Client::new(),
app_builder: AppBuilder::new(),
force_login: false,
http_sender: HttpSender,
}
}
}
impl<'a, H: HttpSend> Registration<'a, H> {
#[allow(dead_code)]
pub(crate) fn with_sender<I: Into<String>>(base: I, http_sender: H) -> Self {
Registration {
base: base.into(),
client: Client::new(),
app_builder: AppBuilder::new(),
force_login: false,
http_sender,
}
}
impl<'a> Registration<'a> {
/// Sets the name of this app
///
/// This is required, and if this isn't set then the AppBuilder::build
@ -113,7 +99,8 @@ impl<'a, H: HttpSend> Registration<'a, H> {
}
fn send(&self, req: RequestBuilder) -> Result<Response> {
Ok(self.http_sender.send(&self.client, req)?)
let req = req.build()?;
Ok(self.client.execute(req)?)
}
/// Register the given application
@ -137,7 +124,7 @@ impl<'a, H: HttpSend> Registration<'a, H> {
/// # Ok(())
/// # }
/// ```
pub fn register<I: TryInto<App>>(&mut self, app: I) -> Result<Registered<H>>
pub fn register<I: TryInto<App>>(&mut self, app: I) -> Result<Registered>
where
Error: From<<I as TryInto<App>>::Err>,
{
@ -152,7 +139,6 @@ impl<'a, H: HttpSend> Registration<'a, H> {
redirect: oauth.redirect_uri,
scopes: app.scopes().clone(),
force_login: self.force_login,
http_sender: self.http_sender.clone(),
})
}
@ -176,7 +162,7 @@ impl<'a, H: HttpSend> Registration<'a, H> {
/// # Ok(())
/// # }
/// ```
pub fn build(&mut self) -> Result<Registered<H>> {
pub fn build(&mut self) -> Result<Registered> {
let app: App = self.app_builder.clone().build()?;
let oauth = self.send_app(&app)?;
@ -188,7 +174,6 @@ impl<'a, H: HttpSend> Registration<'a, H> {
redirect: oauth.redirect_uri,
scopes: app.scopes().clone(),
force_login: self.force_login,
http_sender: self.http_sender.clone(),
})
}
@ -198,7 +183,7 @@ impl<'a, H: HttpSend> Registration<'a, H> {
}
}
impl Registered<HttpSender> {
impl Registered {
/// Skip having to retrieve the client id and secret from the server by
/// creating a `Registered` struct directly
///
@ -234,7 +219,7 @@ impl Registered<HttpSender> {
redirect: &str,
scopes: Scopes,
force_login: bool,
) -> Registered<HttpSender> {
) -> Registered {
Registered {
base: base.to_string(),
client: Client::new(),
@ -243,14 +228,14 @@ impl Registered<HttpSender> {
redirect: redirect.to_string(),
scopes,
force_login,
http_sender: HttpSender,
}
}
}
impl<H: HttpSend> Registered<H> {
impl Registered {
fn send(&self, req: RequestBuilder) -> Result<Response> {
Ok(self.http_sender.send(&self.client, req)?)
let req = req.build()?;
Ok(self.client.execute(req)?)
}
/// Returns the parts of the `Registered` struct that can be used to
@ -324,7 +309,7 @@ impl<H: HttpSend> Registered<H> {
/// Create an access token from the client id, client secret, and code
/// provided by the authorisation url.
pub fn complete(&self, code: &str) -> Result<Mastodon<H>> {
pub fn complete(&self, code: &str) -> Result<Mastodon> {
let url = format!(
"{}/oauth/token?client_id={}&client_secret={}&code={}&grant_type=authorization_code&\
redirect_uri={}",
@ -341,7 +326,7 @@ impl<H: HttpSend> Registered<H> {
token: token.access_token.into(),
};
let mut builder = MastodonBuilder::new(self.http_sender.clone());
let mut builder = MastodonBuilder::new();
builder.client(self.client.clone()).data(data);
Ok(builder.build()?)
}
@ -350,7 +335,7 @@ impl<H: HttpSend> Registered<H> {
/// Represents the state of the auth flow when the app has been registered but
/// the user is not authenticated
#[derive(Debug, Clone)]
pub struct Registered<H: HttpSend> {
pub struct Registered {
base: String,
client: Client,
client_id: String,
@ -358,7 +343,6 @@ pub struct Registered<H: HttpSend> {
redirect: String,
scopes: Scopes,
force_login: bool,
http_sender: H,
}
#[cfg(test)]
@ -370,15 +354,13 @@ mod tests {
let r = Registration::new("https://example.com");
assert_eq!(r.base, "https://example.com".to_string());
assert_eq!(r.app_builder, AppBuilder::new());
assert_eq!(r.http_sender, HttpSender);
}
#[test]
fn test_registration_with_sender() {
let r = Registration::with_sender("https://example.com", HttpSender);
let r = Registration::new("https://example.com");
assert_eq!(r.base, "https://example.com".to_string());
assert_eq!(r.app_builder, AppBuilder::new());
assert_eq!(r.http_sender, HttpSender);
}
#[test]

@ -10,7 +10,7 @@ use std::time::Duration;
/// # extern crate elefren;
/// # use std::error::Error;
/// use elefren::{entities::filter::FilterContext, requests::AddFilterRequest};
/// # fn main() -> Result<(), Box<Error>> {
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let request = AddFilterRequest::new("foo", FilterContext::Home);
/// # Ok(())
/// # }

@ -90,7 +90,7 @@ impl Scopes {
/// # use std::error::Error;
/// use elefren::scopes::Scopes;
///
/// # fn main() -> Result<(), Box<Error>> {
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let scope = Scopes::all();
/// assert_eq!(&format!("{}", scope), "read write follow push");
/// # Ok(())
@ -107,7 +107,7 @@ impl Scopes {
/// # use std::error::Error;
/// use elefren::scopes::Scopes;
///
/// # fn main() -> Result<(), Box<Error>> {
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let scope = Scopes::read_all();
/// assert_eq!(&format!("{}", scope), "read");
/// # Ok(())
@ -124,7 +124,7 @@ impl Scopes {
/// # use std::error::Error;
/// use elefren::scopes::{Read, Scopes};
///
/// # fn main() -> Result<(), Box<Error>> {
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let scope = Scopes::read(Read::Accounts);
/// assert_eq!(&format!("{}", scope), "read:accounts");
/// # Ok(())
@ -141,7 +141,7 @@ impl Scopes {
/// # use std::error::Error;
/// use elefren::scopes::Scopes;
///
/// # fn main() -> Result<(), Box<Error>> {
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let scope = Scopes::write_all();
/// assert_eq!(&format!("{}", scope), "write");
/// # Ok(())
@ -158,7 +158,7 @@ impl Scopes {
/// # use std::error::Error;
/// use elefren::scopes::{Scopes, Write};
///
/// # fn main() -> Result<(), Box<Error>> {
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let scope = Scopes::write(Write::Accounts);
/// assert_eq!(&format!("{}", scope), "write:accounts");
/// # Ok(())
@ -175,7 +175,7 @@ impl Scopes {
/// # use std::error::Error;
/// use elefren::scopes::Scopes;
///
/// # fn main() -> Result<(), Box<Error>> {
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let scope = Scopes::follow();
/// assert_eq!(&format!("{}", scope), "follow");
/// # Ok(())
@ -192,7 +192,7 @@ impl Scopes {
/// # use std::error::Error;
/// use elefren::scopes::Scopes;
///
/// # fn main() -> Result<(), Box<Error>> {
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let scope = Scopes::push();
/// assert_eq!(&format!("{}", scope), "push");
/// # Ok(())

Loading…
Cancel
Save