#[macro_use]
extern crate serde_derive;
pub mod metas;
pub mod models;
pub mod traits;
pub mod types;
mod private_model;
#[cfg(feature = "default")]
pub mod psn {
use crossbeam_queue::SegQueue;
use derive_more::Display;
use reqwest::{Client, ClientBuilder, Error, Proxy};
use serde::de::DeserializeOwned;
use tang_rs::{Builder, Manager, ManagerFuture, Pool, PoolRef};
use crate::traits::PSNRequest;
use crate::types::PSNInner;
#[derive(Debug, Clone)]
pub struct PSN {
inner: Pool<PSNInnerManager>,
client: Client,
proxy_pool: Option<Pool<ProxyPoolManager>>,
}
#[derive(Debug, Display)]
pub enum PSNError {
#[display(fmt = "No http client is available and/or new client can't be made.")]
NoClient,
#[display(fmt = "No psn object is available")]
NoPSNInner,
#[display(fmt = "Failed to login in to PSN")]
AuthenticationFail,
#[display(fmt = "Request is timeout")]
TimeOut,
#[display(fmt = "Error from Reqwest: {}", _0)]
FromReqwest(Error),
#[display(fmt = "Error from PSN response: {}", _0)]
FromPSN(String),
#[display(fmt = "Error from Local: {}", _0)]
FromStd(std::io::Error),
}
pub struct PSNInnerManager {
inner: SegQueue<PSNInner>,
client: Client,
}
impl PSNInnerManager {
fn new() -> Self {
PSNInnerManager {
inner: SegQueue::new(),
client: ClientBuilder::new()
.build()
.expect("Failed to build http client for PSNInnerManager"),
}
}
fn add_psn_inner(&self, psn: PSNInner) {
self.inner.push(psn);
}
}
impl Manager for PSNInnerManager {
type Connection = PSNInner;
type Error = PSNError;
fn connect(&self) -> ManagerFuture<'_, Result<Self::Connection, Self::Error>> {
Box::pin(async move { self.inner.pop().map_err(|_| PSNError::NoClient) })
}
fn is_valid<'a>(
&'a self,
conn: &'a mut Self::Connection,
) -> ManagerFuture<'a, Result<(), Self::Error>> {
Box::pin(async move {
if conn.should_refresh() {
conn.gen_access_from_refresh(&self.client).await
} else {
Ok(())
}
})
}
fn is_closed(&self, _conn: &mut Self::Connection) -> bool {
false
}
}
pub struct ProxyPoolManager {
proxies: SegQueue<(String, Option<String>, Option<String>)>,
marker: &'static str,
}
impl ProxyPoolManager {
fn new() -> Self {
ProxyPoolManager {
proxies: SegQueue::new(),
marker: "www.google.com",
}
}
fn add_proxy(&self, address: &str, username: Option<&str>, password: Option<&str>) {
self.proxies.push((
address.into(),
username.map(Into::into),
password.map(Into::into),
));
}
}
impl Manager for ProxyPoolManager {
type Connection = Client;
type Error = PSNError;
fn connect(&self) -> ManagerFuture<'_, Result<Self::Connection, Self::Error>> {
Box::pin(async move {
let (address, username, password) =
self.proxies.pop().map_err(|_| PSNError::NoClient)?;
let proxy = match username {
Some(username) => Proxy::all(&address)
.map(|p| p.basic_auth(&username, password.as_deref().unwrap_or(""))),
None => Proxy::all(&address),
};
Client::builder()
.proxy(proxy.map_err(|_| PSNError::NoClient)?)
.build()
.map_err(|_| PSNError::NoClient)
})
}
fn is_valid<'a>(
&'a self,
conn: &'a mut Self::Connection,
) -> ManagerFuture<'a, Result<(), Self::Error>> {
Box::pin(async move {
let _ = conn.get(self.marker).send().await?;
Ok(())
})
}
fn is_closed(&self, _conn: &mut Self::Connection) -> bool {
false
}
}
impl From<Error> for PSNError {
fn from(e: Error) -> Self {
PSNError::FromReqwest(e)
}
}
impl From<tokio::time::Elapsed> for PSNError {
fn from(_: tokio::time::Elapsed) -> Self {
PSNError::TimeOut
}
}
impl PSN {
pub fn new_client() -> Result<Client, PSNError> {
ClientBuilder::new().build().map_err(|_| PSNError::NoClient)
}
pub async fn new(psn_inner: Vec<PSNInner>) -> Self {
let mgr = PSNInnerManager::new();
let size = psn_inner.len() as u8;
for inner in psn_inner.into_iter() {
mgr.add_psn_inner(inner);
}
let inner_pool = Builder::new()
.always_check(true)
.idle_timeout(None)
.max_lifetime(None)
.min_idle(size)
.max_size(size)
.build(mgr)
.await
.expect("Failed to build PSNInner pool");
PSN {
inner: inner_pool,
client: Self::new_client().expect("Failed to build http client"),
proxy_pool: None,
}
}
pub async fn init_proxy(
mut self,
proxies: Vec<(&str, Option<&str>, Option<&str>)>,
) -> Self {
let mgr = ProxyPoolManager::new();
let size = proxies.len() as u8;
for (address, username, password) in proxies.into_iter() {
mgr.add_proxy(address, username, password);
}
let pool = Builder::new()
.always_check(false)
.idle_timeout(None)
.max_lifetime(None)
.min_idle(size)
.max_size(size)
.build(mgr)
.await
.expect("Failed to build proxy pool");
self.proxy_pool = Some(pool);
self
}
pub fn add_proxy(&self, proxies: Vec<(&str, Option<&str>, Option<&str>)>) {
if let Some(pool) = &self.proxy_pool {
for (address, username, password) in proxies.into_iter() {
pool.get_manager().add_proxy(address, username, password);
}
}
}
pub async fn get_profile<T: DeserializeOwned + 'static>(
&self,
online_id: &str,
) -> Result<T, PSNError> {
let (client, psn_inner) = self.get().await?;
psn_inner.get_profile(&client, online_id).await
}
pub async fn get_titles<T: DeserializeOwned + 'static>(
&self,
online_id: &str,
offset: u32,
) -> Result<T, PSNError> {
let (client, psn_inner) = self.get().await?;
psn_inner.get_titles(&client, online_id, offset).await
}
pub async fn get_trophy_set<T: DeserializeOwned + 'static>(
&self,
online_id: &str,
np_communication_id: &str,
) -> Result<T, PSNError> {
let (client, psn_inner) = self.get().await?;
psn_inner
.get_trophy_set(&client, online_id, np_communication_id)
.await
}
pub async fn get_message_threads<T: DeserializeOwned + 'static>(
&self,
offset: u32,
) -> Result<T, PSNError> {
let (client, psn_inner) = self.get().await?;
psn_inner.get_message_threads(&client, offset).await
}
pub async fn get_message_thread<T: DeserializeOwned + 'static>(
&self,
thread_id: &str,
) -> Result<T, PSNError> {
let (client, psn_inner) = self.get().await?;
psn_inner.get_message_thread(&client, thread_id).await
}
pub async fn generate_message_thread(&self, online_id: &str) -> Result<(), PSNError> {
let (client, psn_inner) = self.get().await?;
psn_inner.generate_message_thread(&client, online_id).await
}
pub async fn leave_message_thread(&self, thread_id: &str) -> Result<(), PSNError> {
let (client, psn_inner) = self.get().await?;
psn_inner.leave_message_thread(&client, thread_id).await
}
pub async fn send_message(
&self,
online_id: &str,
msg: Option<&str>,
path: Option<&str>,
thread_id: &str,
) -> Result<(), PSNError> {
let (client, psn_inner) = self.get().await?;
psn_inner
.send_message(&client, online_id, msg, path, thread_id)
.await
}
pub async fn search_store_items<T: DeserializeOwned + 'static>(
&self,
lang: &str,
region: &str,
age: &str,
name: &str,
) -> Result<T, PSNError> {
let (client, psn_inner) = self.get().await?;
psn_inner
.search_store_items(&client, lang, region, age, name)
.await
}
async fn get(&self) -> Result<(Client, PoolRef<'_, PSNInnerManager>), PSNError> {
let proxy_ref = self.get_proxy_cli().await?;
let inner_ref = self.inner.get().await?;
let client = match proxy_ref.as_ref() {
Some(proxy_ref) => (&**proxy_ref).clone(),
None => (&self.client).clone(),
};
drop(proxy_ref);
Ok((client, inner_ref))
}
async fn get_proxy_cli(&self) -> Result<Option<PoolRef<'_, ProxyPoolManager>>, PSNError> {
let fut = match self.proxy_pool.as_ref() {
Some(pool) => pool.get(),
None => return Ok(None),
};
let pool_ref = fut.await?;
Ok(Some(pool_ref))
}
pub fn clients_state(&self) -> u8 {
self.proxy_pool
.as_ref()
.map(|pool| pool.state().idle_connections)
.unwrap_or(0)
}
}
}