diff --git a/Cargo.toml b/Cargo.toml index d552ed0..00107b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,5 @@ members = [ "cli", "gui", - "jm_client_core", "tokencracker", ] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 7337fe3..79712a7 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -22,7 +22,7 @@ chrono = "0.4.19" clap = "2.33.3" env_logger = "0.8.2" fuzzy-matcher = "0.3.7" -jm_client_core = { path = "../jm_client_core" } +libjens = { git = "https://tilera.xyz/git/LordMZTE/libjens.git", rev = "d4a8b3" } log = "0.4.11" opener = "0.4.1" reqwest = { version = "0.11", features = ["stream", "multipart"] } @@ -33,4 +33,3 @@ term_size = "0.3.2" tokio = { version = "1.7.0", features = ["macros", "fs", "process", "rt-multi-thread"] } tokio-util = { version = "0.6.7", features = ["codec"] } url = "2.2.0" - diff --git a/cli/src/commands/cats.rs b/cli/src/commands/cats.rs index 3379759..1c8ee4d 100644 --- a/cli/src/commands/cats.rs +++ b/cli/src/commands/cats.rs @@ -1,5 +1,5 @@ use crate::table::{self, AsTableRow}; -use jm_client_core::JMClient; +use libjens::JMClient; pub async fn run(client: &JMClient) -> anyhow::Result<()> { // clone required, because for sorting the immutable reference will not work diff --git a/cli/src/commands/list.rs b/cli/src/commands/list.rs index f38b6a2..8e36158 100644 --- a/cli/src/commands/list.rs +++ b/cli/src/commands/list.rs @@ -8,7 +8,7 @@ use crate::{ table::{self, AsTableRow}, util, }; -use jm_client_core::{util::MemeSorting, JMClient}; +use libjens::{util::MemeSorting, JMClient}; pub async fn run( client: &JMClient, diff --git a/cli/src/commands/search.rs b/cli/src/commands/search.rs index 6717bcc..80b6d68 100644 --- a/cli/src/commands/search.rs +++ b/cli/src/commands/search.rs @@ -6,7 +6,7 @@ use crate::{ table::{self, AsTableRow}, util, }; -use jm_client_core::JMClient; +use libjens::JMClient; pub async fn run( client: &JMClient, diff --git a/cli/src/commands/up.rs b/cli/src/commands/up.rs index 85443c0..e893c7b 100644 --- a/cli/src/commands/up.rs +++ b/cli/src/commands/up.rs @@ -1,6 +1,6 @@ use crate::util; use anyhow::{bail, Result}; -use jm_client_core::{api::UpResp, JMClient}; +use libjens::{api::UpResp, JMClient}; use log::info; use reqwest::multipart::{Form, Part}; use reqwest::Body; diff --git a/cli/src/commands/users.rs b/cli/src/commands/users.rs index 022732d..3352776 100644 --- a/cli/src/commands/users.rs +++ b/cli/src/commands/users.rs @@ -1,6 +1,6 @@ use crate::table::{self, AsTableRow}; use anyhow::Result; -use jm_client_core::JMClient; +use libjens::JMClient; pub async fn run(client: &JMClient) -> Result<()> { let users = client.get_users().await?; diff --git a/cli/src/main.rs b/cli/src/main.rs index 05370a3..f03af5e 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use jm_client_core::{util::MemeSorting, JMClient}; +use libjens::{util::MemeSorting, JMClient}; use structopt::StructOpt; mod commands; diff --git a/cli/src/table.rs b/cli/src/table.rs index 21698d6..03e4772 100644 --- a/cli/src/table.rs +++ b/cli/src/table.rs @@ -1,5 +1,5 @@ use chrono::{Local, TimeZone}; -use jm_client_core::api::{Category, Meme, User}; +use libjens::api::{Category, Meme, User}; use term_table::{row::Row, table_cell::TableCell, Table, TableBuilder, TableStyle}; /// returns an empty table with the correct format settings for lists diff --git a/cli/src/util.rs b/cli/src/util.rs index 018b89a..efe6974 100644 --- a/cli/src/util.rs +++ b/cli/src/util.rs @@ -1,5 +1,5 @@ use anyhow::bail; -use jm_client_core::JMClient; +use libjens::JMClient; use tokio::process::Command; pub const NO_SUCH_CATEGORY_ERROR: &str = "The given Category does not exist!"; diff --git a/gui/Cargo.toml b/gui/Cargo.toml index 1812988..417c6ac 100644 --- a/gui/Cargo.toml +++ b/gui/Cargo.toml @@ -16,6 +16,6 @@ path = "src/main.rs" [dependencies] anyhow = "1.0.40" druid = "0.7.0" -jm_client_core = { path = "../jm_client_core" } -tokio = { version = "0.2.23", features = ["macros"] } +libjens = { git = "https://tilera.xyz/git/LordMZTE/libjens.git", rev = "d4a8b3" } reqwest = "0.10" +tokio = { version = "0.2.23", features = ["macros"] } diff --git a/gui/src/main.rs b/gui/src/main.rs index 310030b..e816d51 100644 --- a/gui/src/main.rs +++ b/gui/src/main.rs @@ -11,7 +11,7 @@ use druid::{ WidgetExt, WindowDesc, }; -use jm_client_core::{api::Meme, JMClient}; +use libjens::{api::Meme, JMClient}; pub(crate) mod util; diff --git a/jm_client_core/Cargo.toml b/jm_client_core/Cargo.toml deleted file mode 100644 index c06f9fa..0000000 --- a/jm_client_core/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "jm_client_core" -version = "0.1.6" -authors = ["LordMZTE "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -anyhow = "1.0.34" -env_logger = "0.8.2" -lazy_static = "1.4.0" -log = "0.4.11" -once_cell = "1.5.2" -reqwest = "0.11.3" -serde = { version = "1.0.117", features = ["derive"] } -serde_json = "1.0.60" -thiserror = "1.0.23" -tokio = { version = "1.7.0", features = ["macros", "fs", "rt-multi-thread"] } -url = "2.2.0" diff --git a/jm_client_core/src/api.rs b/jm_client_core/src/api.rs deleted file mode 100644 index b33c720..0000000 --- a/jm_client_core/src/api.rs +++ /dev/null @@ -1,105 +0,0 @@ -use anyhow::{anyhow, Result}; -use serde::{ - de::{self, Visitor}, - Deserialize, - Deserializer, -}; - -#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct UpResp { - pub files: Vec, -} - -#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct CatsResp { - pub categories: Vec, -} - -#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct UsersResp { - pub users: Vec, -} - -#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct MemesResp { - pub memes: Vec, -} - -#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct Category { - pub id: String, - pub name: String, -} - -#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct Meme { - pub id: String, - pub link: String, - pub path: String, - pub category: String, - pub user: String, - #[serde(deserialize_with = "deserialize_timestamp")] - pub timestamp: i64, -} - -impl Meme { - pub fn file_name(&self) -> Result<&str> { - self.path - .split('/') - .last() - .ok_or_else(|| anyhow!("failed to get file name. server response invalid")) - } -} - -#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct User { - pub name: String, - pub id: Option, - pub tokenhash: Option, - pub userdir: Option, - pub dayuploads: String, -} - -impl User { - pub fn get_id(&self) -> Option<&String> { - self.id - .as_ref() - .or_else(|| self.tokenhash.as_ref()) - .or_else(|| self.userdir.as_ref()) - } -} - -fn deserialize_timestamp<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - struct Vis; - - impl<'de> Visitor<'de> for Vis { - type Value = i64; - - fn expecting(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - fmt.write_str( - "A timestamp in the form of a string or i64 (because tilera doesn't know integers \ - exist)", - ) - } - - fn visit_i64(self, v: i64) -> Result - where - E: de::Error, - { - Ok(v) - } - - fn visit_borrowed_str(self, v: &'de str) -> Result - where - E: de::Error, - { - v.parse() - .map_err(|_| de::Error::invalid_value(de::Unexpected::Str(v), &self)) - } - } - - deserializer.deserialize_any(Vis) -} diff --git a/jm_client_core/src/client.rs b/jm_client_core/src/client.rs deleted file mode 100644 index 3bec8a4..0000000 --- a/jm_client_core/src/client.rs +++ /dev/null @@ -1,147 +0,0 @@ -use crate::api::{Category, CatsResp, Meme, MemesResp, User, UsersResp}; -use log::info; -use once_cell::sync::OnceCell; -use reqwest::Url; -use serde::Deserialize; -use std::sync::Arc; -use thiserror::Error; -use tokio::sync::Mutex; - -#[derive(Debug)] -pub struct JMClient { - pub http: reqwest::Client, - cache: Mutex, - endpoint: Url, -} - -macro_rules! init_cache { - ($cell:expr, $init_fn:expr) => {{ - let cell = &$cell; - Arc::clone(match cell.get() { - Some(x) => x, - None => { - let x = Arc::new($init_fn); - cell.get_or_init(|| x) - }, - }) - }}; -} - -impl JMClient { - pub fn new() -> Self { - Self::builder().build() - } - - pub fn builder() -> JMClientBuilder { - JMClientBuilder::default() - } - - /// clears the cache. all requests will be made again after this has been called. - pub async fn clear_cache(&mut self) { - self.cache.lock().await.clear(); - } - - async fn get_api_json( - &self, - cache: &OnceCell>, - endpoint: &str, - res_to_data: F, - ) -> Result, JMClientError> - where - for<'de> R: Deserialize<'de>, - F: FnOnce(R) -> T, - { - Ok(init_cache!(cache, { - info!("Requesting {} from server", endpoint); - let url = self.endpoint.join(endpoint)?; - let res = self.http.get(url).send().await?; - - let res = serde_json::from_slice(&res.bytes().await?)?; - res_to_data(res) - })) - } - - pub async fn get_cats(&self) -> Result>, JMClientError> { - self.get_api_json( - &self.cache.lock().await.cats, - "categories", - |r: CatsResp| r.categories, - ) - .await - } - - pub async fn get_memes(&self) -> Result>, JMClientError> { - self.get_api_json(&self.cache.lock().await.memes, "memes", |r: MemesResp| { - r.memes - }) - .await - } - - pub async fn get_users(&self) -> Result>, JMClientError> { - self.get_api_json(&self.cache.lock().await.users, "users", |r: UsersResp| { - r.users - }) - .await - } -} -impl Default for JMClient { - fn default() -> Self { - Self::new() - } -} - -#[derive(Debug, Error)] -pub enum JMClientError { - #[error("Error making http request: {0}")] - Http(#[from] reqwest::Error), - - #[error("Error deserializing JensMemes response: {0}")] - Deserialize(#[from] serde_json::Error), - - #[error("Failed parsing URL to make request to JensMemes: {0}")] - UrlParse(#[from] url::ParseError), -} - -#[derive(Debug, Default)] -struct Cache { - users: OnceCell>>, - cats: OnceCell>>, - memes: OnceCell>>, -} - -impl Cache { - fn clear(&mut self) { - self.users = OnceCell::default(); - self.cats = OnceCell::default(); - self.memes = OnceCell::default(); - } -} - -#[derive(Debug, Default)] -pub struct JMClientBuilder { - client: Option, - endpoint: Option, -} - -impl JMClientBuilder { - pub fn build(self) -> JMClient { - JMClient { - http: self.client.unwrap_or_else(reqwest::Client::new), - endpoint: self.endpoint.unwrap_or_else(|| { - // unwrapping is fine here, as the hardcoded input is known to work. - Url::parse(crate::util::consts::API_ENDPOINT).unwrap() - }), - cache: Mutex::new(Cache::default()), - } - } - - pub fn client(mut self, client: reqwest::Client) -> Self { - self.client = Some(client); - self - } - - pub fn endpoint(mut self, endpoint: impl Into) -> Self { - self.endpoint = Some(endpoint.into()); - self - } -} diff --git a/jm_client_core/src/lib.rs b/jm_client_core/src/lib.rs deleted file mode 100644 index d94352e..0000000 --- a/jm_client_core/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod api; -pub mod client; -pub mod util; - -pub use client::JMClient; diff --git a/jm_client_core/src/util.rs b/jm_client_core/src/util.rs deleted file mode 100644 index 14d3af0..0000000 --- a/jm_client_core/src/util.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::api::Meme; -use anyhow::bail; -use std::str::FromStr; - -pub mod consts { - pub const API_ENDPOINT: &str = "https://api.tilera.xyz/jensmemes/v1/"; -} - -pub enum MemeSorting { - Id, - Link, - Category, - User, - Timestamp, -} - -impl MemeSorting { - pub fn sort_with(&self, memes: &mut [&Meme]) { - macro_rules! sort { - ($list:ident, $field:ident) => { - $list.sort_by(|a, b| { - a.$field - .to_ascii_lowercase() - .cmp(&b.$field.to_ascii_lowercase()) - }); - }; - } - - match self { - Self::Id => sort!(memes, id), - Self::Link => sort!(memes, link), - Self::Category => sort!(memes, category), - Self::User => sort!(memes, user), - Self::Timestamp => memes.sort_by(|a, b| b.timestamp.cmp(&a.timestamp)), - } - } -} - -impl FromStr for MemeSorting { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_ref() { - "id" => Ok(Self::Id), - "link" => Ok(Self::Link), - "category" => Ok(Self::Category), - "user" => Ok(Self::User), - "timestamp" => Ok(Self::Timestamp), - _ => bail!("Invalid Meme sorting! options are id, link, category and user!"), - } - } -}