(Re-)introduce Threading, Add support for different Config (Settings) Sources, Remove Async leftovers
This commit is contained in:
parent
2ae6468ad8
commit
5976bd59a7
15 changed files with 634 additions and 329 deletions
src
131
src/lemmy.rs
131
src/lemmy.rs
|
@ -1,5 +1,5 @@
|
|||
use std::cmp::Ordering;
|
||||
use crate::config::{Config, PostBody, PostConfig, SeriesConfig};
|
||||
use crate::config::{PostConfig, SeriesConfig};
|
||||
use crate::{HTTP_CLIENT};
|
||||
use lemmy_api_common::community::{ListCommunities, ListCommunitiesResponse};
|
||||
use lemmy_api_common::lemmy_db_views::structs::PostView;
|
||||
|
@ -9,28 +9,10 @@ use lemmy_db_schema::newtypes::{CommunityId, LanguageId, PostId};
|
|||
use lemmy_db_schema::{ListingType, PostFeatureType};
|
||||
use reqwest::StatusCode;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{RwLock};
|
||||
use lemmy_db_schema::sensitive::SensitiveString;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use systemd_journal_logger::connected_to_journal;
|
||||
|
||||
macro_rules! debug {
|
||||
($msg:tt) => {
|
||||
match connected_to_journal() {
|
||||
true => log::debug!("[DEBUG] {}", $msg),
|
||||
false => println!("[DEBUG] {}", $msg),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! error {
|
||||
($msg:tt) => {
|
||||
match connected_to_journal() {
|
||||
true => log::error!("[ERROR] {}", $msg),
|
||||
false => eprintln!("[ERROR] {}", $msg),
|
||||
}
|
||||
};
|
||||
}
|
||||
use crate::logging::Logging;
|
||||
use crate::settings::{BotSettings, PostBody};
|
||||
|
||||
pub(crate) struct Lemmy {
|
||||
jwt_token: SensitiveString,
|
||||
|
@ -107,7 +89,7 @@ impl PartialOrd for PartInfo {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub(crate) enum PostType {
|
||||
Chapter,
|
||||
Volume
|
||||
|
@ -207,26 +189,24 @@ impl PartialOrd for PostInfo {
|
|||
|
||||
impl Lemmy {
|
||||
pub(crate) fn get_community_id(&self, name: &str) -> CommunityId {
|
||||
*self.communities.get(name).expect("Given community is invalid")
|
||||
*self.communities.get(name).expect(format!("Community '{name}' is invalid").as_str())
|
||||
}
|
||||
pub(crate) async fn new(config: &RwLock<Config>) -> Result<Self, ()> {
|
||||
let read_config = config.read().expect("Read Lock Failed").clone();
|
||||
pub(crate) fn new(config: &BotSettings) -> Result<Self, ()> {
|
||||
let login_params = Login {
|
||||
username_or_email: read_config.get_username(),
|
||||
password: read_config.get_password(),
|
||||
username_or_email: config.username(),
|
||||
password: config.password(),
|
||||
totp_2fa_token: None,
|
||||
};
|
||||
|
||||
let response = match HTTP_CLIENT
|
||||
.post(read_config.instance.to_owned() + "/api/v3/user/login")
|
||||
.post(config.instance().to_owned() + "/api/v3/user/login")
|
||||
.json(&login_params)
|
||||
.send()
|
||||
.await
|
||||
{
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
let err_msg = format!("{e}");
|
||||
error!(err_msg);
|
||||
Logging::error(err_msg.as_str());
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
@ -235,40 +215,41 @@ impl Lemmy {
|
|||
StatusCode::OK => {
|
||||
let data: LoginResponse = response
|
||||
.json()
|
||||
.await
|
||||
.expect("Successful Login Request should return JSON");
|
||||
match data.jwt {
|
||||
Some(token) => Ok(Lemmy {
|
||||
jwt_token: token.clone(),
|
||||
instance: read_config.instance.to_owned(),
|
||||
instance: config.instance().to_owned(),
|
||||
communities: HashMap::new(),
|
||||
}),
|
||||
None => {
|
||||
let err_msg = "Login did not return JWT token. Are the credentials valid?".to_owned();
|
||||
error!(err_msg);
|
||||
Logging::error("Login did not return JWT token. Are the credentials valid?");
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
status => {
|
||||
let err_msg = format!("Unexpected HTTP Status '{}' during Login", status);
|
||||
error!(err_msg);
|
||||
Logging::error(err_msg.as_str());
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn logout(&self) {
|
||||
let _ = self.post_data_json("/api/v3/user/logout", &"").await;
|
||||
pub fn logout(&self) {
|
||||
let _ = self.post_data_json("/api/v3/user/logout", &"");
|
||||
}
|
||||
|
||||
pub fn login(&self) {
|
||||
|
||||
}
|
||||
|
||||
pub(crate) async fn post(&self, post: CreatePost) -> Option<PostId> {
|
||||
let response: String = match self.post_data_json("/api/v3/post", &post).await {
|
||||
pub fn post(&self, post: CreatePost) -> Option<PostId> {
|
||||
let response: String = match self.post_data_json("/api/v3/post", &post) {
|
||||
Some(data) => data,
|
||||
None => return None,
|
||||
};
|
||||
let json_data: PostView = match self.parse_json_map(&response).await {
|
||||
let json_data: PostView = match self.parse_json_map(&response) {
|
||||
Some(data) => data,
|
||||
None => return None,
|
||||
};
|
||||
|
@ -276,12 +257,12 @@ impl Lemmy {
|
|||
Some(json_data.post.id)
|
||||
}
|
||||
|
||||
async fn feature(&self, params: FeaturePost) -> Option<PostView> {
|
||||
let response: String = match self.post_data_json("/api/v3/post/feature", ¶ms).await {
|
||||
fn feature(&self, params: FeaturePost) -> Option<PostView> {
|
||||
let response: String = match self.post_data_json("/api/v3/post/feature", ¶ms) {
|
||||
Some(data) => data,
|
||||
None => return None,
|
||||
};
|
||||
let json_data: PostView = match self.parse_json_map(&response).await {
|
||||
let json_data: PostView = match self.parse_json_map(&response) {
|
||||
Some(data) => data,
|
||||
None => return None,
|
||||
};
|
||||
|
@ -289,36 +270,36 @@ impl Lemmy {
|
|||
Some(json_data)
|
||||
}
|
||||
|
||||
pub(crate) async fn unpin(&self, post_id: PostId, location: PostFeatureType) -> Option<PostView> {
|
||||
pub(crate) fn unpin(&self, post_id: PostId, location: PostFeatureType) -> Option<PostView> {
|
||||
let pin_params = FeaturePost {
|
||||
post_id,
|
||||
featured: false,
|
||||
feature_type: location,
|
||||
};
|
||||
self.feature(pin_params).await
|
||||
self.feature(pin_params)
|
||||
}
|
||||
|
||||
pub(crate) async fn pin(&self, post_id: PostId, location: PostFeatureType) -> Option<PostView> {
|
||||
pub(crate) fn pin(&self, post_id: PostId, location: PostFeatureType) -> Option<PostView> {
|
||||
let pin_params = FeaturePost {
|
||||
post_id,
|
||||
featured: true,
|
||||
feature_type: location,
|
||||
};
|
||||
self.feature(pin_params).await
|
||||
self.feature(pin_params)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_community_pinned(&self, community: CommunityId) -> Option<Vec<PostView>> {
|
||||
pub(crate) fn get_community_pinned(&self, community: CommunityId) -> Option<Vec<PostView>> {
|
||||
let list_params = GetPosts {
|
||||
community_id: Some(community),
|
||||
type_: Some(ListingType::Local),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response: String = match self.get_data_query("/api/v3/post/list", &list_params).await {
|
||||
let response: String = match self.get_data_query("/api/v3/post/list", &list_params) {
|
||||
Some(data) => data,
|
||||
None => return None,
|
||||
};
|
||||
let json_data: GetPostsResponse = match self.parse_json(&response).await {
|
||||
let json_data: GetPostsResponse = match self.parse_json(&response) {
|
||||
Some(data) => data,
|
||||
None => return None,
|
||||
};
|
||||
|
@ -331,17 +312,17 @@ impl Lemmy {
|
|||
.collect())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_local_pinned(&self) -> Option<Vec<PostView>> {
|
||||
pub(crate) fn get_local_pinned(&self) -> Option<Vec<PostView>> {
|
||||
let list_params = GetPosts {
|
||||
type_: Some(ListingType::Local),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response: String = match self.get_data_query("/api/v3/post/list", &list_params).await {
|
||||
let response: String = match self.get_data_query("/api/v3/post/list", &list_params) {
|
||||
Some(data) => data,
|
||||
None => return None,
|
||||
};
|
||||
let json_data: GetPostsResponse = match self.parse_json(&response).await {
|
||||
let json_data: GetPostsResponse = match self.parse_json(&response) {
|
||||
Some(data) => data,
|
||||
None => return None,
|
||||
};
|
||||
|
@ -354,17 +335,17 @@ impl Lemmy {
|
|||
.collect())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_communities(&mut self) {
|
||||
pub(crate) fn get_communities(&mut self) {
|
||||
let list_params = ListCommunities {
|
||||
type_: Some(ListingType::Local),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response: String = match self.get_data_query("/api/v3/community/list", &list_params).await {
|
||||
let response: String = match self.get_data_query("/api/v3/community/list", &list_params) {
|
||||
Some(data) => data,
|
||||
None => return,
|
||||
};
|
||||
let json_data: ListCommunitiesResponse = match self.parse_json::<ListCommunitiesResponse>(&response).await {
|
||||
let json_data: ListCommunitiesResponse = match self.parse_json::<ListCommunitiesResponse>(&response) {
|
||||
Some(data) => data,
|
||||
None => return,
|
||||
};
|
||||
|
@ -378,71 +359,71 @@ impl Lemmy {
|
|||
self.communities = communities;
|
||||
}
|
||||
|
||||
async fn post_data_json<T: Serialize>(&self, route: &str, json: &T ) -> Option<String> {
|
||||
fn post_data_json<T: Serialize>(&self, route: &str, json: &T ) -> Option<String> {
|
||||
let res = HTTP_CLIENT
|
||||
.post(format!("{}{route}", &self.instance))
|
||||
.bearer_auth(&self.jwt_token.to_string())
|
||||
.json(&json)
|
||||
.send()
|
||||
.await;
|
||||
self.extract_data(res).await
|
||||
.send();
|
||||
self.extract_data(res)
|
||||
}
|
||||
|
||||
async fn get_data_query<T: Serialize>(&self, route: &str, param: &T ) -> Option<String> {
|
||||
fn get_data_query<T: Serialize>(&self, route: &str, param: &T ) -> Option<String> {
|
||||
let res = HTTP_CLIENT
|
||||
.get(format!("{}{route}", &self.instance))
|
||||
.bearer_auth(&self.jwt_token.to_string())
|
||||
.query(¶m)
|
||||
.send()
|
||||
.await;
|
||||
self.extract_data(res).await
|
||||
.send();
|
||||
self.extract_data(res)
|
||||
}
|
||||
|
||||
async fn extract_data(&self, response: Result<reqwest::Response, reqwest::Error>) -> Option<String> {
|
||||
fn extract_data(&self, response: Result<reqwest::blocking::Response, reqwest::Error>) -> Option<String> {
|
||||
match response {
|
||||
Ok(data) => {
|
||||
let msg = format!("Status Code: '{}'", data.status().clone());
|
||||
Logging::debug(msg.as_str());
|
||||
if data.status().is_success() {
|
||||
match data.text().await {
|
||||
match data.text() {
|
||||
Ok(data) => Some(data),
|
||||
Err(e) => {
|
||||
let err_msg = format!("{e}");
|
||||
error!(err_msg);
|
||||
Logging::error(err_msg.as_str());
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
let err_msg = format!("HTTP Request failed: {}", data.text().await.unwrap());
|
||||
error!(err_msg);
|
||||
let err_msg = format!("HTTP Request failed: {}", data.text().unwrap());
|
||||
Logging::error(err_msg.as_str());
|
||||
None
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
let err_msg = format!("{e}");
|
||||
error!(err_msg);
|
||||
Logging::error(err_msg.as_str());
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn parse_json<'a, T: Deserialize<'a>>(&self, response: &'a str) -> Option<T> {
|
||||
fn parse_json<'a, T: Deserialize<'a>>(&self, response: &'a str) -> Option<T> {
|
||||
match serde_json::from_str::<T>(response) {
|
||||
Ok(data) => Some(data),
|
||||
Err(e) => {
|
||||
let err_msg = format!("while parsing JSON: {e} ");
|
||||
error!(err_msg);
|
||||
Logging::error(err_msg.as_str());
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn parse_json_map<'a, T: Deserialize<'a>>(&self, response: &'a str) -> Option<T> {
|
||||
debug!(response);
|
||||
fn parse_json_map<'a, T: Deserialize<'a>>(&self, response: &'a str) -> Option<T> {
|
||||
Logging::debug(response);
|
||||
match serde_json::from_str::<HashMap<&str, T>>(response) {
|
||||
Ok(mut data) => Some(data.remove("post_view").expect("Element should be present")),
|
||||
Err(e) => {
|
||||
let err_msg = format!("while parsing JSON HashMap: {e}");
|
||||
error!(err_msg);
|
||||
Logging::error(err_msg.as_str());
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue