Working Error Logging
All checks were successful
Run Tests on Code / run-tests (push) Successful in 0s
All checks were successful
Run Tests on Code / run-tests (push) Successful in 0s
This commit is contained in:
parent
bba7fae8b9
commit
47e6cc59c0
7 changed files with 253 additions and 123 deletions
126
src/bot/mod.rs
126
src/bot/mod.rs
|
@ -1,10 +1,9 @@
|
|||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::sync::{Arc};
|
||||
use chrono::{DateTime, Duration, Timelike, Utc};
|
||||
use lemmy_db_schema::newtypes::{CommunityId, LanguageId};
|
||||
use lemmy_db_schema::PostFeatureType;
|
||||
use tokio::sync::{RwLock, RwLockWriteGuard};
|
||||
use tokio::sync::{RwLock};
|
||||
use crate::{jnovel, lemmy, Message, SharedData};
|
||||
use crate::config::{Config, PostBody, SeriesConfig};
|
||||
use crate::jnovel::PostInfo;
|
||||
|
@ -23,17 +22,20 @@ pub(crate) async fn run(data: Arc<RwLock<SharedData>>){
|
|||
let mut login_error: bool;
|
||||
let mut communities;
|
||||
{
|
||||
let mut shared_data = data.write().await;
|
||||
let mut write = data.write().await;
|
||||
|
||||
// Errors during bot init are likely unrecoverable and therefore should panic the bot
|
||||
// Does not really matter since the bot will get restarted anyway but this way the uptime url logs a downtime
|
||||
shared_data.config = match Config::load() {
|
||||
write.config = match Config::load() {
|
||||
Ok(data) => data,
|
||||
Err(e) => panic!("{}", e),
|
||||
};
|
||||
last_reload = Utc::now();
|
||||
}
|
||||
|
||||
lemmy = match lemmy::login(&credentials, shared_data.config.instance.as_str()).await {
|
||||
{
|
||||
let read = data.read().await;
|
||||
lemmy = match lemmy::login(&credentials, read.config.instance.as_str()).await {
|
||||
Ok(data) => data,
|
||||
Err(e) => panic!("{}", e),
|
||||
};
|
||||
|
@ -49,64 +51,101 @@ pub(crate) async fn run(data: Arc<RwLock<SharedData>>){
|
|||
sleep(Duration::milliseconds(100).to_std().unwrap()).await;
|
||||
}
|
||||
|
||||
{
|
||||
let mut write = data.write().await;
|
||||
write.start = Utc::now();
|
||||
}
|
||||
|
||||
loop {
|
||||
idle(&data).await;
|
||||
|
||||
let mut shared_data = data.write().await;
|
||||
{
|
||||
let mut write = data.write().await;
|
||||
|
||||
shared_data.start = Utc::now();
|
||||
write.start = Utc::now();
|
||||
|
||||
if shared_data.start - last_reload > Duration::seconds(shared_data.config.config_reload_seconds as i64) {
|
||||
shared_data.config = match Config::load() {
|
||||
if write.start - last_reload > Duration::seconds(write.config.config_reload_seconds as i64) {
|
||||
write.config = match Config::load() {
|
||||
Ok(data) => data,
|
||||
Err(e) => panic!("{}", e),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let read = data.read().await;
|
||||
if login_error {
|
||||
lemmy = match lemmy::login(&credentials, shared_data.config.instance.as_str()).await {
|
||||
lemmy = match lemmy::login(&credentials, read.config.instance.as_str()).await {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
shared_data.messages.push(Message::Error(format!("{}", e)));
|
||||
drop(read);
|
||||
let mut write = data.write().await;
|
||||
write.messages.push(Message::Error(e.to_string()));
|
||||
continue
|
||||
}
|
||||
};
|
||||
login_error = false;
|
||||
}
|
||||
}
|
||||
|
||||
if shared_data.start - last_reload > Duration::seconds(shared_data.config.config_reload_seconds as i64) {
|
||||
{
|
||||
let read = data.read().await;
|
||||
if read.start - last_reload > Duration::seconds(read.config.config_reload_seconds as i64) {
|
||||
communities = match lemmy.get_communities().await {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
login_error = true;
|
||||
shared_data.messages.push(Message::Error(format!("{}", e)));
|
||||
drop(read);
|
||||
let mut write = data.write().await;
|
||||
write.messages.push(Message::Error(e.to_string()));
|
||||
continue
|
||||
}
|
||||
};
|
||||
last_reload = Utc::now();
|
||||
}
|
||||
|
||||
shared_data.post_history = match SeriesHistory::load_history() {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
login_error = true;
|
||||
shared_data.messages.push(Message::Warning(format!("{}", e)));
|
||||
continue
|
||||
}
|
||||
};
|
||||
|
||||
for series in shared_data.config.series.clone() {
|
||||
match handle_series(&series, &communities, &lemmy, &mut shared_data).await {
|
||||
{
|
||||
let mut write = data.write().await;
|
||||
write.post_history = match SeriesHistory::load_history() {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
login_error = true;
|
||||
shared_data.messages.push(Message::Warning(format!("{}", e)));
|
||||
write.messages.push(Message::Warning(e.to_string()));
|
||||
continue
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let _ = shared_data.downgrade();
|
||||
{
|
||||
let read = data.read().await;
|
||||
let series = read.config.series.clone();
|
||||
drop(read);
|
||||
for series in series {
|
||||
match handle_series(&series, &communities, &lemmy, &data).await {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
login_error = true;
|
||||
let mut write = data.write().await;
|
||||
write.messages.push(Message::Warning(e.to_string()));
|
||||
continue
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let read = data.read().await;
|
||||
if read.messages.len() > 15 {
|
||||
let mut list = read.messages.clone();
|
||||
drop(read);
|
||||
list.reverse();
|
||||
while list.len() > 15 {
|
||||
list.pop();
|
||||
}
|
||||
list.reverse();
|
||||
let mut write = data.write().await;
|
||||
write.messages = list
|
||||
}
|
||||
|
||||
|
||||
idle(&data).await;
|
||||
}
|
||||
|
@ -124,7 +163,7 @@ async fn idle(data: &Arc<RwLock<SharedData>>) {
|
|||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
let mut write = data.write().await;
|
||||
write.messages.push(Message::Error(format!("{}", e)))
|
||||
write.messages.push(Message::Error(e.to_string()))
|
||||
},
|
||||
}
|
||||
};
|
||||
|
@ -134,26 +173,35 @@ async fn idle(data: &Arc<RwLock<SharedData>>) {
|
|||
}
|
||||
}
|
||||
|
||||
async fn handle_series<'a>(
|
||||
async fn handle_series(
|
||||
series: &SeriesConfig,
|
||||
communities: &HashMap<String, CommunityId>,
|
||||
lemmy: &Lemmy,
|
||||
data: &mut RwLockWriteGuard<'a, SharedData>,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
data: &Arc<RwLock<SharedData>>,
|
||||
) -> Result<(), String> {
|
||||
|
||||
let mut post_list = match jnovel::check_feed(series.slug.as_str(), series.parted).await {
|
||||
Ok(data) => data,
|
||||
Err(e) => panic!("{:#?}", e),
|
||||
Err(e) => {
|
||||
return Err(e.to_string());
|
||||
},
|
||||
};
|
||||
|
||||
for (index, post_info) in post_list.clone().iter().enumerate() { // todo .clone() likely not needed
|
||||
let post_part_info = post_info.get_part_info();
|
||||
let post_lemmy_info = post_info.get_lemmy_info();
|
||||
|
||||
if data.post_history.check_for_post(series.slug.as_str(), post_part_info.as_string().as_str(), post_lemmy_info.title.as_str()) {
|
||||
data.messages.push(Message::Info(format!("Skipping '{}' since already posted", post_lemmy_info.title)));
|
||||
|
||||
{
|
||||
let read = data.read().await;
|
||||
if read.post_history.check_for_post(series.slug.as_str(), post_part_info.as_string().as_str(), post_lemmy_info.title.as_str()) {
|
||||
drop(read);
|
||||
let mut write = data.write().await;
|
||||
write.messages.push(Message::Info(format!("Skipping '{}' since already posted", post_lemmy_info.title)));
|
||||
post_list.remove(index);
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
let post_series_config = match post_info {
|
||||
PostInfo::Chapter {..} => {&series.prepub_community},
|
||||
|
@ -200,8 +248,10 @@ async fn handle_series<'a>(
|
|||
lemmy.pin(post_id, PostFeatureType::Local).await?;
|
||||
}
|
||||
|
||||
let mut series_history = data.post_history.get_series(series.slug.as_str());
|
||||
let read = data.read().await;
|
||||
let mut series_history = read.post_history.get_series(series.slug.as_str());
|
||||
let mut part_history = series_history.get_part(post_part_info.as_string().as_str());
|
||||
drop(read);
|
||||
|
||||
match post_info {
|
||||
PostInfo::Chapter {..} => {
|
||||
|
@ -213,8 +263,12 @@ async fn handle_series<'a>(
|
|||
}
|
||||
|
||||
series_history.set_part(post_part_info.as_string().as_str(), part_history);
|
||||
data.post_history.set_series(series.slug.as_str(), series_history);
|
||||
let _ = data.post_history.save_history()?;
|
||||
let mut write = data.write().await;
|
||||
write.post_history.set_series(series.slug.as_str(), series_history);
|
||||
let _ = match write.post_history.save_history() {
|
||||
Ok(data) => data,
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use std::{error::Error};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use crate::config::PostBody::Description;
|
||||
|
||||
|
@ -11,8 +10,11 @@ pub(crate) struct Config {
|
|||
}
|
||||
|
||||
impl Config {
|
||||
pub(crate) fn load() -> Result<Self, Box<dyn Error>> {
|
||||
let cfg: Self = confy::load_path("./config.toml")?;
|
||||
pub(crate) fn load() -> Result<Self, String> {
|
||||
let cfg: Self = match confy::load_path("./config.toml") {
|
||||
Ok(data) => data,
|
||||
Err(_) => panic!("config.toml not found!"),
|
||||
};
|
||||
if cfg.instance.is_empty() {
|
||||
panic!("config.toml not found!")
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::ops::Sub;
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
@ -9,7 +8,7 @@ use crate::{HTTP_CLIENT};
|
|||
use crate::jnovel::PartInfo::{NoParts, Part};
|
||||
use crate::jnovel::PostInfo::{Chapter, Volume};
|
||||
|
||||
static PAST_DAYS_ELIGIBLE: u8 = 4;
|
||||
static PAST_DAYS_ELIGIBLE: u8 = 8;
|
||||
|
||||
macro_rules! api_url {
|
||||
() => {
|
||||
|
@ -223,15 +222,24 @@ impl PartialOrd for PostInfo {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn check_feed(series_slug: &str, series_has_parts: bool) -> Result<Vec<PostInfo>, Box<dyn Error>> {
|
||||
let response = HTTP_CLIENT
|
||||
pub(crate) async fn check_feed(series_slug: &str, series_has_parts: bool) -> Result<Vec<PostInfo>, String> {
|
||||
let response = match HTTP_CLIENT
|
||||
.get(api_url!() + "/series/" + series_slug + "/volumes?format=json")
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
.await {
|
||||
Ok(data) => {
|
||||
match data.text().await {
|
||||
Ok(data) => data,
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
}
|
||||
},
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
};
|
||||
|
||||
let mut volume_brief_data: VolumesWrapper = serde_json::from_str(&response)?;
|
||||
let mut volume_brief_data: VolumesWrapper = match serde_json::from_str(&response) {
|
||||
Ok(data) => data,
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
};
|
||||
volume_brief_data.volumes.reverse(); // Makes breaking out of the volume loop easier
|
||||
|
||||
// If no parts just use 0 as Part indicator as no Series with Parts has a Part 0
|
||||
|
@ -322,15 +330,25 @@ pub(crate) async fn check_feed(series_slug: &str, series_has_parts: bool) -> Res
|
|||
Ok(result_vec)
|
||||
}
|
||||
|
||||
async fn get_latest_prepub(volume_slug: &str) -> Result<Option<LemmyPostInfo>, Box<dyn Error>> {
|
||||
let response = HTTP_CLIENT
|
||||
async fn get_latest_prepub(volume_slug: &str) -> Result<Option<LemmyPostInfo>, String> {
|
||||
let response = match HTTP_CLIENT
|
||||
.get(api_url!() + "/volumes/" + volume_slug + "/parts?format=json")
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
.await {
|
||||
Ok(data) => {
|
||||
match data.text().await {
|
||||
Ok(data) => data,
|
||||
Err(e) => return Err(e.to_string())
|
||||
}
|
||||
},
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
};
|
||||
|
||||
let mut volume_prepub_parts_data: ChapterWrapper = serde_json::from_str(&response)?;
|
||||
|
||||
let mut volume_prepub_parts_data: ChapterWrapper = match serde_json::from_str(&response) {
|
||||
Ok(data) => data,
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
};
|
||||
volume_prepub_parts_data.parts.reverse(); // Makes breaking out of the parts loop easier
|
||||
|
||||
let mut post_details: Option<LemmyPostInfo> = None;
|
||||
|
|
124
src/lemmy/mod.rs
124
src/lemmy/mod.rs
|
@ -1,7 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::env::VarError;
|
||||
use std::error::Error;
|
||||
use lemmy_api_common::community::{ListCommunities};
|
||||
use lemmy_api_common::person::{Login, LoginResponse};
|
||||
use lemmy_api_common::post::{GetPosts};
|
||||
|
@ -42,18 +41,21 @@ pub(crate) struct Lemmy {
|
|||
instance: String,
|
||||
}
|
||||
|
||||
pub(crate) async fn login(credentials: &Credentials, instance: &str) -> Result<Lemmy, Box<dyn Error>> {
|
||||
pub(crate) async fn login(credentials: &Credentials, instance: &str) -> Result<Lemmy, String> {
|
||||
let login_params = Login {
|
||||
username_or_email: credentials.get_username(),
|
||||
password: credentials.get_password(),
|
||||
totp_2fa_token: None,
|
||||
};
|
||||
|
||||
let response = HTTP_CLIENT
|
||||
let response = match HTTP_CLIENT
|
||||
.post(instance.to_string() + "/api/v3/user/login")
|
||||
.json(&login_params)
|
||||
.send()
|
||||
.await?;
|
||||
.await {
|
||||
Ok(data) => data,
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
};
|
||||
|
||||
match response.status() {
|
||||
StatusCode::OK => {
|
||||
|
@ -71,40 +73,55 @@ pub(crate) async fn login(credentials: &Credentials, instance: &str) -> Result<L
|
|||
}
|
||||
|
||||
impl Lemmy {
|
||||
pub(crate) async fn post(&self, post: CustomCreatePost) -> Result<PostId, Box<dyn Error>> {
|
||||
let response = HTTP_CLIENT
|
||||
pub(crate) async fn post(&self, post: CustomCreatePost) -> Result<PostId, String> {
|
||||
let response = match HTTP_CLIENT
|
||||
.post(format!("{}/api/v3/post", &self.instance))
|
||||
.bearer_auth(&self.jwt_token.to_string())
|
||||
.json(&post)
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
.await {
|
||||
Ok(data) => {
|
||||
match data.text().await {
|
||||
Ok(data) => data,
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
}
|
||||
},
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
};
|
||||
|
||||
let json_data = serde_json::from_str::<HashMap<&str, CustomPostView>>(&response)?
|
||||
.remove("post_view")
|
||||
.expect("Element should be present");
|
||||
let json_data = match serde_json::from_str::<HashMap<&str, CustomPostView>>(&response) {
|
||||
Ok(mut data) => data.remove("post_view").expect("Element should be present"),
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
};
|
||||
|
||||
Ok(json_data.post.id)
|
||||
}
|
||||
|
||||
async fn feature(&self, params: CustomFeaturePost) -> Result<CustomPostView, Box<dyn Error>> {
|
||||
let response = HTTP_CLIENT
|
||||
async fn feature(&self, params: CustomFeaturePost) -> Result<CustomPostView, String> {
|
||||
let response = match HTTP_CLIENT
|
||||
.post(format!("{}/api/v3/post/feature", &self.instance))
|
||||
.bearer_auth(&self.jwt_token.to_string())
|
||||
.json(¶ms)
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
.await {
|
||||
Ok(data) => {
|
||||
match data.text().await {
|
||||
Ok(data) => data,
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
}
|
||||
},
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
};
|
||||
|
||||
let json_data = match serde_json::from_str::<HashMap<&str, CustomPostView>>(&response) {
|
||||
Ok(mut data) => data.remove("post_view").expect("Element should be present"),
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
};
|
||||
|
||||
let json_data = serde_json::from_str::<HashMap<&str, CustomPostView>>(&response)?
|
||||
.remove("post_view")
|
||||
.expect("Element should be present");
|
||||
Ok(json_data)
|
||||
}
|
||||
|
||||
pub(crate) async fn unpin(&self, post_id: PostId, location: PostFeatureType) -> Result<CustomPostView, Box<dyn Error>> {
|
||||
pub(crate) async fn unpin(&self, post_id: PostId, location: PostFeatureType) -> Result<CustomPostView, String> {
|
||||
let pin_params = CustomFeaturePost {
|
||||
post_id,
|
||||
featured: false,
|
||||
|
@ -113,7 +130,7 @@ impl Lemmy {
|
|||
self.feature(pin_params).await
|
||||
}
|
||||
|
||||
pub(crate) async fn pin(&self, post_id: PostId, location: PostFeatureType) -> Result<CustomPostView, Box<dyn Error>> {
|
||||
pub(crate) async fn pin(&self, post_id: PostId, location: PostFeatureType) -> Result<CustomPostView, String> {
|
||||
let pin_params = CustomFeaturePost {
|
||||
post_id,
|
||||
featured: true,
|
||||
|
@ -122,23 +139,32 @@ impl Lemmy {
|
|||
self.feature(pin_params).await
|
||||
}
|
||||
|
||||
pub(crate) async fn get_community_pinned(&self, community: CommunityId) -> Result<Vec<CustomPostView>, Box<dyn Error>> {
|
||||
pub(crate) async fn get_community_pinned(&self, community: CommunityId) -> Result<Vec<CustomPostView>, String> {
|
||||
let list_params = GetPosts {
|
||||
community_id: Some(community),
|
||||
type_: Some(ListingType::Local),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response = HTTP_CLIENT
|
||||
let response = match HTTP_CLIENT
|
||||
.get(format!("{}/api/v3/post/list", &self.instance))
|
||||
.bearer_auth(&self.jwt_token.to_string())
|
||||
.query(&list_params)
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
.await {
|
||||
Ok(data) => {
|
||||
match data.text().await {
|
||||
Ok(data) => data,
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
}
|
||||
},
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
};
|
||||
|
||||
let json_data: CustomGetPostsResponse = serde_json::from_str(&response)?;
|
||||
let json_data: CustomGetPostsResponse = match serde_json::from_str(&response) {
|
||||
Ok(data) => data,
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
};
|
||||
|
||||
Ok(json_data.posts.iter().filter(|post| {
|
||||
post.post.featured_community
|
||||
|
@ -148,22 +174,31 @@ impl Lemmy {
|
|||
)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_local_pinned(&self) -> Result<Vec<CustomPostView>, Box<dyn Error>> {
|
||||
pub(crate) async fn get_local_pinned(&self) -> Result<Vec<CustomPostView>, String> {
|
||||
let list_params = GetPosts {
|
||||
type_: Some(ListingType::Local),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response = HTTP_CLIENT
|
||||
let response = match HTTP_CLIENT
|
||||
.get(format!("{}/api/v3/post/list", &self.instance))
|
||||
.bearer_auth(&self.jwt_token.to_string())
|
||||
.query(&list_params)
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
.await {
|
||||
Ok(data) => {
|
||||
match data.text().await {
|
||||
Ok(data) => data,
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
}
|
||||
},
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
};
|
||||
|
||||
let json_data: CustomGetPostsResponse = serde_json::from_str(&response)?;
|
||||
let json_data: CustomGetPostsResponse = match serde_json::from_str(&response) {
|
||||
Ok(data) => data,
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
};
|
||||
|
||||
Ok(json_data.posts.iter().filter(|post| {
|
||||
post.post.featured_local
|
||||
|
@ -173,22 +208,31 @@ impl Lemmy {
|
|||
)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_communities(&self) -> Result<HashMap<String, CommunityId>, Box<dyn Error>> {
|
||||
pub(crate) async fn get_communities(&self) -> Result<HashMap<String, CommunityId>, String> {
|
||||
let list_params = ListCommunities {
|
||||
type_: Some(ListingType::Local),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response = HTTP_CLIENT
|
||||
let response = match HTTP_CLIENT
|
||||
.get(format!("{}/api/v3/community/list", &self.instance))
|
||||
.bearer_auth(&self.jwt_token.to_string())
|
||||
.query(&list_params)
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
.await {
|
||||
Ok(data) => {
|
||||
match data.text().await {
|
||||
Ok(data) => data,
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
}
|
||||
},
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
};
|
||||
|
||||
let json_data: CustomListCommunitiesResponse = serde_json::from_str(&response)?;
|
||||
let json_data: CustomListCommunitiesResponse = match serde_json::from_str(&response) {
|
||||
Ok(data) => data,
|
||||
Err(e) => return Err(format!("{}", e))
|
||||
};
|
||||
|
||||
let mut communities: HashMap<String, CommunityId> = HashMap::new();
|
||||
for community_view in json_data.communities {
|
||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -69,6 +69,16 @@ pub(crate) enum Message {
|
|||
Error(String),
|
||||
}
|
||||
|
||||
impl Message {
|
||||
pub(crate) fn content(&self) -> String {
|
||||
match self {
|
||||
Message::Info(msg) => msg.clone(),
|
||||
Message::Warning(msg) => msg.clone(),
|
||||
Message::Error(msg) => msg.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
dotenv().ok();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Write;
|
||||
|
@ -12,10 +11,13 @@ pub(crate) struct SeriesHistory {
|
|||
}
|
||||
|
||||
impl SeriesHistory {
|
||||
pub(crate) fn load_history() -> Result<Self, Box<dyn Error>> {
|
||||
pub(crate) fn load_history() -> Result<Self, String> {
|
||||
match Path::new("history.toml").exists() {
|
||||
true => {
|
||||
let file_contents: String = fs::read_to_string("history.toml")?;
|
||||
let file_contents: String = match fs::read_to_string("history.toml") {
|
||||
Ok(data) => data,
|
||||
Err(e) => return Err(format!("{}", e)),
|
||||
};
|
||||
|
||||
let history: Result<SeriesHistory, toml::de::Error> = match file_contents.len() {
|
||||
0 => return Ok(SeriesHistory {
|
||||
|
@ -26,7 +28,7 @@ impl SeriesHistory {
|
|||
|
||||
match history {
|
||||
Ok(data) => Ok(data),
|
||||
Err(e) => Err(Box::new(e))
|
||||
Err(e) => Err(format!("{}", e))
|
||||
}
|
||||
},
|
||||
false => {
|
||||
|
|
|
@ -79,10 +79,10 @@ async fn print_info<'a>(data: RwLockReadGuard<'a, SharedData>, min_len_series: &
|
|||
});
|
||||
println!("{:#<1$}", "", separator_width);
|
||||
for error in data.get_messages(true, true, false).iter() {
|
||||
println!("{}", error);
|
||||
println!("{}", error.content());
|
||||
}
|
||||
println!("{:#<1$}", "", separator_width);
|
||||
for message in data.get_messages(false, false, false).iter() {
|
||||
println!("{}", message);
|
||||
println!("{}", message.content());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue