Moved Display impl from types to cli crate. added pager to feed.
This commit is contained in:
parent
31faf60285
commit
2fcfbe9e67
|
@ -117,7 +117,7 @@ dependencies = [
|
|||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"textwrap 0.11.0",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
@ -126,12 +126,15 @@ dependencies = [
|
|||
name = "cli"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"minus",
|
||||
"rpassword",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shellexpand",
|
||||
"socialvoid",
|
||||
"socialvoid_rawclient",
|
||||
"socialvoid_types",
|
||||
"structopt",
|
||||
"tokio",
|
||||
]
|
||||
|
@ -161,6 +164,31 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0ebde6a9dd5e331cd6c6f48253254d117642c31653baa475e394657c59c1f7d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossterm_winapi",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm_winapi"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a6966607622438301997d3dac0d2f6e9a90c68bb6bc1785ea98456ab93c0507"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
|
@ -607,6 +635,17 @@ dependencies = [
|
|||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minus"
|
||||
version = "4.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0cfa68574733d70c28177f9608f2cd10f298ed109f55a900078886a90cbc265"
|
||||
dependencies = [
|
||||
"crossterm",
|
||||
"textwrap 0.13.4",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.7.13"
|
||||
|
@ -1157,6 +1196,27 @@ dependencies = [
|
|||
"dirs-next",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-mio"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"signal-hook",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.0"
|
||||
|
@ -1215,7 +1275,6 @@ dependencies = [
|
|||
name = "socialvoid_types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
|
@ -1295,6 +1354,35 @@ dependencies = [
|
|||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd05616119e612a8041ef58f2b578906cc2531a6069047ae092cfb86a325d835"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.43"
|
||||
|
|
|
@ -12,9 +12,12 @@ path = "src/main.rs"
|
|||
[dependencies]
|
||||
"socialvoid" = { path = "../client" }
|
||||
"socialvoid_rawclient" = { path = "../rawclient" }
|
||||
"socialvoid_types" = { path = "../types" }
|
||||
structopt = "0.3.23"
|
||||
serde = { version = "1.0", features = ["derive"]}
|
||||
serde_json = "1.0.67"
|
||||
shellexpand = "2.1.0"
|
||||
tokio = {version = "1.11.0", features = ["full"]}
|
||||
rpassword = "5.0.1"
|
||||
rpassword = "5.0.1"
|
||||
minus = { version = "4.0.2", features = ["static_output"] }
|
||||
chrono = "0.4.19"
|
|
@ -0,0 +1,145 @@
|
|||
use socialvoid_types::*;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
|
||||
pub struct SVPost(Post);
|
||||
pub struct SVProfile(Profile);
|
||||
|
||||
impl std::convert::From<Post> for SVPost {
|
||||
fn from(post: Post) -> Self {
|
||||
Self(post)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<Profile> for SVProfile {
|
||||
fn from(profile: Profile) -> Self {
|
||||
Self(profile)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SVPost {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Post Type: {}
|
||||
ID: {}
|
||||
Author: {}
|
||||
Source: {}
|
||||
----
|
||||
{}
|
||||
----
|
||||
{} attachment(s)
|
||||
Posted on: {}
|
||||
Likes: {}, Reposts: {}, Quotes: {}, Replies: {},
|
||||
Flags: ",
|
||||
match self.0.post_type {
|
||||
PostType::Reply => format!(
|
||||
"Reply to <{}>",
|
||||
match &self.0.reply_to_post {
|
||||
Some(reply_to_post) => reply_to_post.id.clone(),
|
||||
None => String::new(),
|
||||
}
|
||||
),
|
||||
PostType::Quote => format!(
|
||||
"Quoted post <{}>",
|
||||
match &self.0.quoted_post.as_ref() {
|
||||
Some(quoted_post) => quoted_post.id.clone(),
|
||||
None => String::new(),
|
||||
}
|
||||
),
|
||||
PostType::Repost => format!(
|
||||
"Reposted post <{}>",
|
||||
match &self.0.reposted_post.as_ref() {
|
||||
Some(reposted_post) => reposted_post.id.clone(),
|
||||
None => String::new(),
|
||||
}
|
||||
),
|
||||
_ => format!("{:?}", self.0.post_type),
|
||||
},
|
||||
self.0.id,
|
||||
self.0
|
||||
.peer
|
||||
.as_ref()
|
||||
.map(|x| x.username.to_string())
|
||||
.unwrap_or_else(|| "<unavailable>".to_string()),
|
||||
self.0
|
||||
.source
|
||||
.as_ref()
|
||||
.unwrap_or(&"<not applicable>".to_owned()),
|
||||
self.0.text.as_ref().unwrap_or(&"<no text>".to_string()),
|
||||
self.0.attachments.len(), //TODO: maybe show the document IDs
|
||||
{
|
||||
let d = UNIX_EPOCH + Duration::from_secs(self.0.posted_timestamp);
|
||||
// Create DateTime from SystemTime
|
||||
let datetime = DateTime::<Utc>::from(d);
|
||||
// Formats the combined date and time with the specified format string.
|
||||
datetime.format("%Y-%m-%d %H:%M:%S.%f").to_string()
|
||||
},
|
||||
self.0
|
||||
.like_count
|
||||
.map(|x| x.to_string())
|
||||
.unwrap_or_else(|| "<not applicable>".to_string()),
|
||||
self.0
|
||||
.repost_count
|
||||
.map(|x| x.to_string())
|
||||
.unwrap_or_else(|| "<not applicable>".to_string()),
|
||||
self.0
|
||||
.quote_count
|
||||
.map(|x| x.to_string())
|
||||
.unwrap_or_else(|| "<not applicable>".to_string()),
|
||||
self.0
|
||||
.reply_count
|
||||
.map(|x| x.to_string())
|
||||
.unwrap_or_else(|| "<not applicable>".to_string()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SVProfile {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"First Name: {}
|
||||
{}
|
||||
Name: {}
|
||||
{}
|
||||
{}
|
||||
{}
|
||||
Followers: {}
|
||||
Following: {}
|
||||
Display Picture: {}",
|
||||
self.0.first_name,
|
||||
self.0
|
||||
.last_name
|
||||
.as_ref()
|
||||
.map(|x| format!("Last Name: {}", x))
|
||||
.unwrap_or_else(|| String::from("[No last name set]")),
|
||||
self.0.name,
|
||||
self.0
|
||||
.biography
|
||||
.as_ref()
|
||||
.map(|x| format!("Biography: {}", x))
|
||||
.unwrap_or_else(|| String::from("[No biography set]")),
|
||||
self.0
|
||||
.location
|
||||
.as_ref()
|
||||
.map(|x| format!("Location: {}", x))
|
||||
.unwrap_or_else(|| String::from("[No location set]")),
|
||||
self.0
|
||||
.url
|
||||
.as_ref()
|
||||
.map(|x| format!("URL: {}", x))
|
||||
.unwrap_or_else(|| String::from("[No URL set]")),
|
||||
self.0.followers_count,
|
||||
self.0.following_count,
|
||||
if self.0.display_picture_sizes.is_empty() {
|
||||
String::from("not set")
|
||||
} else {
|
||||
let count = self.0.display_picture_sizes.len();
|
||||
let name = &self.0.display_picture_sizes[0].document.file_name;
|
||||
format!("'{}' ({} sizes available)", name, count)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
use socialvoid::session::RegisterRequest;
|
||||
use structopt::StructOpt;
|
||||
|
||||
mod entities;
|
||||
mod error;
|
||||
mod utils;
|
||||
use crate::entities::*;
|
||||
use crate::utils::*;
|
||||
use error::MyFriendlyError;
|
||||
|
||||
|
@ -166,7 +168,7 @@ async fn main() {
|
|||
}
|
||||
},
|
||||
SocialVoidCommand::Profile { peer } => match sv.network.get_profile(peer).await {
|
||||
Ok(profile) => println!("{}", profile),
|
||||
Ok(profile) => println!("{}", SVProfile::from(profile)),
|
||||
Err(err) => println!(
|
||||
"An error occurred while trying to get the profile.\n{}",
|
||||
MyFriendlyError::from(err)
|
||||
|
@ -196,10 +198,19 @@ async fn main() {
|
|||
}
|
||||
SocialVoidCommand::Feed { page } => match sv.timeline.retrieve_feed(page).await {
|
||||
Ok(feed) => {
|
||||
for post in feed.iter() {
|
||||
println!("================\n{}", post);
|
||||
let mut pager = minus::Pager::new().unwrap();
|
||||
|
||||
let n_posts = feed.len();
|
||||
for post in feed.into_iter() {
|
||||
let post = SVPost::from(post);
|
||||
pager.push_str(format!("================\n{}", post));
|
||||
}
|
||||
println!("----Retrieved {} post(s) from the timeline.\n", feed.len());
|
||||
pager.push_str(format!(
|
||||
"----Retrieved {} post(s) from the timeline.\n",
|
||||
n_posts
|
||||
));
|
||||
pager.set_prompt("Feed - Socialvoid");
|
||||
minus::page_all(pager).expect("Error with pager");
|
||||
}
|
||||
Err(err) => println!("{}", MyFriendlyError::from(err)),
|
||||
},
|
||||
|
@ -212,7 +223,7 @@ async fn main() {
|
|||
Err(err) => println!("{}", MyFriendlyError::from(err)),
|
||||
},
|
||||
SocialVoidCommand::GetPost { post_id } => match sv.timeline.get_post(post_id).await {
|
||||
Ok(post) => println!("{}", post),
|
||||
Ok(post) => println!("{}", SVPost::from(post)),
|
||||
Err(err) => println!("{}", MyFriendlyError::from(err)),
|
||||
},
|
||||
SocialVoidCommand::DeletePost { post_id } => match sv.timeline.delete(post_id).await {
|
||||
|
|
|
@ -8,5 +8,4 @@ edition = "2018"
|
|||
[dependencies]
|
||||
serde = { version = "1.0", features = ["derive"]}
|
||||
serde_json = "1.0.67"
|
||||
tokio = {version = "1.11.0", features = ["full"]}
|
||||
chrono = "0.4.19"
|
||||
tokio = {version = "1.11.0", features = ["full"]}
|
142
types/src/lib.rs
142
types/src/lib.rs
|
@ -1,6 +1,4 @@
|
|||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct SessionIdentification {
|
||||
|
@ -29,9 +27,9 @@ pub enum PeerType {
|
|||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct DisplayPictureSize {
|
||||
width: u32,
|
||||
height: u32,
|
||||
document: Document,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub document: Document,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
@ -116,15 +114,15 @@ pub struct ServerInformation {
|
|||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Profile {
|
||||
first_name: String,
|
||||
last_name: Option<String>,
|
||||
name: String,
|
||||
biography: Option<String>,
|
||||
location: Option<String>,
|
||||
url: Option<String>,
|
||||
followers_count: u32,
|
||||
following_count: u32,
|
||||
display_picture_sizes: Vec<DisplayPictureSize>,
|
||||
pub first_name: String,
|
||||
pub last_name: Option<String>,
|
||||
pub name: String,
|
||||
pub biography: Option<String>,
|
||||
pub location: Option<String>,
|
||||
pub url: Option<String>,
|
||||
pub followers_count: u32,
|
||||
pub following_count: u32,
|
||||
pub display_picture_sizes: Vec<DisplayPictureSize>,
|
||||
}
|
||||
|
||||
/// Relationship of a peer with another peer.
|
||||
|
@ -176,119 +174,3 @@ pub enum PostType {
|
|||
Quote,
|
||||
Repost,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Post {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Post Type: {}
|
||||
ID: {}
|
||||
Author: {}
|
||||
Source: {}
|
||||
----
|
||||
{}
|
||||
----
|
||||
{} attachment(s)
|
||||
Posted on: {}
|
||||
Likes: {}, Reposts: {}, Quotes: {}, Replies: {},
|
||||
Flags: ",
|
||||
match self.post_type {
|
||||
PostType::Reply => format!(
|
||||
"Reply to <{}>",
|
||||
match &self.reply_to_post {
|
||||
Some(reply_to_post) => reply_to_post.id.clone(),
|
||||
None => String::new(),
|
||||
}
|
||||
),
|
||||
PostType::Quote => format!(
|
||||
"Quoted post <{}>",
|
||||
match &self.quoted_post.as_ref() {
|
||||
Some(quoted_post) => quoted_post.id.clone(),
|
||||
None => String::new(),
|
||||
}
|
||||
),
|
||||
PostType::Repost => format!(
|
||||
"Reposted post <{}>",
|
||||
match &self.reposted_post.as_ref() {
|
||||
Some(reposted_post) => reposted_post.id.clone(),
|
||||
None => String::new(),
|
||||
}
|
||||
),
|
||||
_ => format!("{:?}", self.post_type),
|
||||
},
|
||||
self.id,
|
||||
self.peer
|
||||
.as_ref()
|
||||
.map(|x| format!("{}", x.username))
|
||||
.unwrap_or("<unavailable>".to_string()),
|
||||
self.source
|
||||
.as_ref()
|
||||
.unwrap_or(&"<not applicable>".to_owned()),
|
||||
self.text.as_ref().unwrap_or(&"<no text>".to_string()),
|
||||
self.attachments.len(), //TODO: maybe show the document IDs
|
||||
{
|
||||
let d = UNIX_EPOCH + Duration::from_secs(self.posted_timestamp);
|
||||
// Create DateTime from SystemTime
|
||||
let datetime = DateTime::<Utc>::from(d);
|
||||
// Formats the combined date and time with the specified format string.
|
||||
datetime.format("%Y-%m-%d %H:%M:%S.%f").to_string()
|
||||
},
|
||||
self.like_count
|
||||
.map(|x| x.to_string())
|
||||
.unwrap_or("<not applicable>".to_string()),
|
||||
self.repost_count
|
||||
.map(|x| x.to_string())
|
||||
.unwrap_or("<not applicable>".to_string()),
|
||||
self.quote_count
|
||||
.map(|x| x.to_string())
|
||||
.unwrap_or("<not applicable>".to_string()),
|
||||
self.reply_count
|
||||
.map(|x| x.to_string())
|
||||
.unwrap_or("<not applicable>".to_string()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Profile {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"First Name: {}
|
||||
{}
|
||||
Name: {}
|
||||
{}
|
||||
{}
|
||||
{}
|
||||
Followers: {}
|
||||
Following: {}
|
||||
Display Picture: {}",
|
||||
self.first_name,
|
||||
self.last_name
|
||||
.as_ref()
|
||||
.map(|x| format!("Last Name: {}", x))
|
||||
.unwrap_or_else(|| String::from("[No last name set]")),
|
||||
self.name,
|
||||
self.biography
|
||||
.as_ref()
|
||||
.map(|x| format!("Biography: {}", x))
|
||||
.unwrap_or_else(|| String::from("[No biography set]")),
|
||||
self.location
|
||||
.as_ref()
|
||||
.map(|x| format!("Location: {}", x))
|
||||
.unwrap_or_else(|| String::from("[No location set]")),
|
||||
self.url
|
||||
.as_ref()
|
||||
.map(|x| format!("URL: {}", x))
|
||||
.unwrap_or_else(|| String::from("[No URL set]")),
|
||||
self.followers_count,
|
||||
self.following_count,
|
||||
if self.display_picture_sizes.is_empty() {
|
||||
String::from("not set")
|
||||
} else {
|
||||
let count = self.display_picture_sizes.len();
|
||||
let name = &self.display_picture_sizes[0].document.file_name;
|
||||
format!("'{}' ({} sizes available)", name, count)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue