From 80d1bfa591561353061d1ea8ac6085787c31e5bd Mon Sep 17 00:00:00 2001 From: Uttarayan Mondal Date: Mon, 15 Mar 2021 01:22:48 +0530 Subject: [PATCH] Initial commit with barely working stuff --- .gitignore | 3 ++ Cargo.toml | 14 ++++++ README.md | 7 +++ src/api.rs | 0 src/lib.rs | 17 +++++++ src/rapr.rs | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 180 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 src/api.rs create mode 100644 src/lib.rs create mode 100644 src/rapr.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ac2f8625 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +Cargo.lock +rust.json diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..c2f18ded --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "rapr" +version = "0.1.0" +authors = ["Uttarayan Mondal "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +reqwest = "0.11.*" +chrono = "0.4.*" +json = "0.12.*" +tokio = { version = "1.3.*", features = ["full"] } diff --git a/README.md b/README.md new file mode 100644 index 00000000..e9271e07 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# rapr-rs + +Reddit api wrapper in rust. + +Not usable currently. + +Currently doing this to learn rust. diff --git a/src/api.rs b/src/api.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..a4353bfc --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,17 @@ +mod rapr; +pub use crate::rapr::RaprClient; + +#[cfg(test)] +mod tests { + #[tokio::test] + async fn subreddit() { + use crate::rapr::RaprClient; + let client = RaprClient::new(); + let mut sub = RaprClient::subreddit("rust"); + client.fetch(10, &mut sub).await.unwrap(); + println!("{:#?}", sub.posts.len()); + client.fetch(5, &mut sub).await.unwrap(); + println!("{:#?}", sub.posts.len()); + println!("{:#?}", sub.pinned_posts()); + } +} diff --git a/src/rapr.rs b/src/rapr.rs new file mode 100644 index 00000000..1b300d9a --- /dev/null +++ b/src/rapr.rs @@ -0,0 +1,139 @@ +extern crate json; +extern crate reqwest; +extern crate tokio; +use chrono::{DateTime, Local}; +use std::fmt; + +#[derive(Debug)] +pub enum Error { + JsonParseError, + HttpGetError, +} + +#[derive(Clone)] +pub struct RaPost { + id: String, + datetime: DateTime, + title: String, + text: Option, + json: json::JsonValue, + pinned: bool, +} + +impl fmt::Debug for RaPost { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RaPost") + .field("id", &self.id) + .field("datetime", &self.datetime) + .field("title", &self.title) + .field("text", &self.text) + .finish() + } +} + +impl RaPost { + pub fn new(id: &str, title: &str, json: &json::JsonValue, pinned: bool) -> Self { + Self { + id: id.to_string(), + title: title.to_string(), + datetime: Local::now(), // Temp + text: Some(String::from("")), + json: json.clone(), + pinned, + } + } + pub fn parse(post: &json::JsonValue) -> Result { + Ok(RaPost::new( + json::stringify(post["name"].clone()).as_str(), + json::stringify(post["title"].clone()).as_str(), + post, + post["pinned"].as_bool().unwrap(), + )) + } +} + +#[derive(Debug)] +pub struct RaSub { + pub name: String, + pub posts: Vec, + after: Option, +} + +impl RaSub { + pub fn pinned_posts(&self) -> Option> { + let mut pinned_posts: Vec = Vec::new(); + for post in &self.posts { + if post.pinned { + pinned_posts.push(post.clone()); + } + } + if pinned_posts.is_empty() { + return None; + } else { + return Some(pinned_posts); + } + } +} + +#[derive(Debug)] +pub struct RaprClient { + oauth: Option, + rwclient: reqwest::Client, +} + +impl RaprClient { + pub fn new() -> Self { + Self { + oauth: None, + rwclient: reqwest::Client::new(), + } + } + pub fn subreddit(name: &str) -> RaSub { + RaSub { + name: String::from(name), + posts: Vec::new(), + after: None, + } + } + pub async fn fetch(&self, count: u32, sub: &mut RaSub) -> Result, Error> { + let url = match self.oauth { + None => format!("https://reddit.com/r/{}.json", sub.name), + Some(_) => format!("https://oauth.reddit.com/r/{}.json", sub.name), + }; + + let res = match &sub.after { + None => self + .rwclient + .get(url) + .query(&[("limit", count)]) + .send() + .await + .unwrap(), + Some(after) => self + .rwclient + .get(url) + .query(&[("limit", count.to_string()), ("after", after.to_string())]) + .send() + .await + .unwrap(), + }; + + let mut parsed = json::parse(res.text().await.unwrap().as_str()).unwrap(); + + let raw_posts: Vec = match parsed["data"]["children"].take() { + json::JsonValue::Array(arr) => arr, + _ => return Err(Error::JsonParseError), + }; + + let mut parsed_posts: Vec = Vec::new(); + + for post in raw_posts { + parsed_posts.push(RaPost::parse(&post["data"]).unwrap()); + } + if parsed["data"]["after"].is_string() { + sub.after = Some(parsed["data"]["after"].to_string()); + } + sub.posts.append(&mut parsed_posts); + Ok(parsed_posts) + } +}