refactor: ♻️ Split main function into modules
This commit is contained in:
parent
92cc323f93
commit
ac67753f01
@ -16,5 +16,6 @@ chrono = "0.4.38"
|
|||||||
env_logger = "0.11.3"
|
env_logger = "0.11.3"
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
reqwest = { version = "0.12.5", features = ["blocking"] }
|
reqwest = { version = "0.12.5", features = ["blocking"] }
|
||||||
regex = "1.10.5"
|
# regex = "1.10.5"
|
||||||
|
# polodb_core = "4.4.1"
|
||||||
|
|
||||||
|
2
rust-toolchain.toml
Normal file
2
rust-toolchain.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "nightly"
|
18
src/args.rs
Normal file
18
src/args.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
#[clap(author, version, about, long_about = None)]
|
||||||
|
pub struct Args {
|
||||||
|
#[clap(short, long, required = true)]
|
||||||
|
pub input: String,
|
||||||
|
|
||||||
|
#[clap(short, long, default_value_t=String::new())]
|
||||||
|
pub output: String,
|
||||||
|
|
||||||
|
#[clap(short, long, default_value_t = false)]
|
||||||
|
pub pretty: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_args()-> Args {
|
||||||
|
return Args::parse();
|
||||||
|
}
|
30
src/channel_lib.rs
Normal file
30
src/channel_lib.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufReader, Cursor};
|
||||||
|
|
||||||
|
use log::{error, info};
|
||||||
|
use rss::Channel;
|
||||||
|
|
||||||
|
pub fn build_channel(input: String) -> Channel {
|
||||||
|
let channel: Channel;
|
||||||
|
|
||||||
|
if input.starts_with("http://") || input.starts_with("https://") {
|
||||||
|
// process download
|
||||||
|
match reqwest::blocking::get(input).unwrap().bytes() {
|
||||||
|
Ok(content) => {
|
||||||
|
info!("Extracted {} bytes", content.len());
|
||||||
|
let cursor = Cursor::new(content);
|
||||||
|
channel = Channel::read_from(cursor).unwrap();
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("{}", e);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// read locale file
|
||||||
|
let file = File::open(input).unwrap();
|
||||||
|
channel = Channel::read_from(BufReader::new(file)).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
return channel;
|
||||||
|
}
|
68
src/json_lib.rs
Normal file
68
src/json_lib.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
use chrono::DateTime;
|
||||||
|
use json::{object, JsonValue};
|
||||||
|
use log::error;
|
||||||
|
use rss::Channel;
|
||||||
|
|
||||||
|
pub fn build_json(channel: Channel) -> JsonValue {
|
||||||
|
// Initialize root object with channel informations, using object macro from json crate
|
||||||
|
let mut data = object! {
|
||||||
|
channel: object!{
|
||||||
|
title: channel.title(),
|
||||||
|
link: channel.link(),
|
||||||
|
description: channel.description(),
|
||||||
|
last_build_date: channel.last_build_date(),
|
||||||
|
language: channel.language(),
|
||||||
|
copyright: channel.copyright(),
|
||||||
|
generator: channel.generator()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// declare an mutable array to populate it with channel item data
|
||||||
|
let mut items_data = json::JsonValue::new_array();
|
||||||
|
|
||||||
|
// populate the items array
|
||||||
|
for item in channel.items() {
|
||||||
|
let pub_datetime = DateTime::parse_from_rfc2822(item.pub_date().unwrap()).unwrap();
|
||||||
|
|
||||||
|
// create object to hold item data
|
||||||
|
let mut item_data = object! {
|
||||||
|
title: item.title(),
|
||||||
|
link: item.link(),
|
||||||
|
pub_date: item.pub_date(),
|
||||||
|
pub_ts: pub_datetime.timestamp(),
|
||||||
|
description: item.description(),
|
||||||
|
// author: item.author()
|
||||||
|
};
|
||||||
|
|
||||||
|
// populate categories
|
||||||
|
let mut categories = json::JsonValue::new_array();
|
||||||
|
|
||||||
|
for category in item.categories() {
|
||||||
|
match categories.push(category.name()) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
// memory overflow ? as a beginner, style puzzled by rust
|
||||||
|
error!("Error pushing to items_data {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item_data["categories"] = categories;
|
||||||
|
|
||||||
|
if item.content().is_some() {
|
||||||
|
item_data["content"] = json::JsonValue::String(item.content().unwrap().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
match items_data.push(item_data) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
// memory overflow ? as a beginner, style puzzled by rust
|
||||||
|
error!("Error pushing to items_data {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// attach the items to the json data root
|
||||||
|
data["items"] = items_data;
|
||||||
|
return data;
|
||||||
|
}
|
118
src/main.rs
118
src/main.rs
@ -1,122 +1,34 @@
|
|||||||
/**
|
/**
|
||||||
* A simple personnal tutorial for my first baby steps with Rust.
|
* A simple personnal tutorial for my first baby steps with Rust.
|
||||||
*/
|
*/
|
||||||
|
// TODO refactor and unit tests to improve code while knowledge grows !
|
||||||
|
// TODO handle remote http feed discovery by parsing index and search for the feed link
|
||||||
|
// TODO serialize to local document database CRUD
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::File;
|
|
||||||
use std::io::{BufReader, Cursor};
|
|
||||||
|
|
||||||
|
use json::JsonValue;
|
||||||
use chrono::DateTime;
|
|
||||||
use clap::Parser;
|
|
||||||
use json::object;
|
|
||||||
use rss::Channel;
|
use rss::Channel;
|
||||||
|
|
||||||
// use log::debug;
|
// use log::{debug, info, warn, error };
|
||||||
use log::error;
|
use log::{error, info};
|
||||||
use log::info;
|
|
||||||
// use log::warn;
|
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
mod args;
|
||||||
#[clap(author, version, about, long_about = None)]
|
use crate::args::parse_args;
|
||||||
struct Args {
|
|
||||||
#[clap(short, long, required = true)]
|
|
||||||
input: String,
|
|
||||||
|
|
||||||
#[clap(short, long, default_value_t=String::new())]
|
mod channel_lib;
|
||||||
output: String,
|
use crate::channel_lib::build_channel;
|
||||||
|
|
||||||
#[clap(short, long, default_value_t = false)]
|
mod json_lib;
|
||||||
pretty: bool,
|
use crate::json_lib::build_json;
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
let args = Args::parse();
|
let args = parse_args();
|
||||||
|
|
||||||
// TODO handle remote http feed discovery by parsing index and search for the feed link
|
let channel: Channel = build_channel(args.input);
|
||||||
|
|
||||||
let channel: Channel;
|
let data: JsonValue = build_json(channel);
|
||||||
|
|
||||||
if args.input.starts_with("http://") || args.input.starts_with("https://") {
|
|
||||||
// process download
|
|
||||||
match reqwest::blocking::get(args.input).unwrap().bytes() {
|
|
||||||
Ok(content) => {
|
|
||||||
info!("Extracted {} bytes", content.len());
|
|
||||||
let cursor = Cursor::new(content);
|
|
||||||
channel = Channel::read_from(cursor).unwrap();
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
error!("{}", e);
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// read locale file
|
|
||||||
let file = File::open(args.input).unwrap();
|
|
||||||
channel = Channel::read_from(BufReader::new(file)).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize root object with channel informations, using object macro from json crate
|
|
||||||
let mut data = object! {
|
|
||||||
channel: object!{
|
|
||||||
title: channel.title(),
|
|
||||||
link: channel.link(),
|
|
||||||
description: channel.description(),
|
|
||||||
last_build_date: channel.last_build_date(),
|
|
||||||
language: channel.language(),
|
|
||||||
copyright: channel.copyright(),
|
|
||||||
generator: channel.generator()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// declare an mutable array to populate it with channel item data
|
|
||||||
let mut items_data = json::JsonValue::new_array();
|
|
||||||
|
|
||||||
// populate the items array
|
|
||||||
for item in channel.items() {
|
|
||||||
let pub_datetime = DateTime::parse_from_rfc2822(item.pub_date().unwrap()).unwrap();
|
|
||||||
|
|
||||||
// create object to hold item data
|
|
||||||
let mut item_data = object! {
|
|
||||||
title: item.title(),
|
|
||||||
link: item.link(),
|
|
||||||
pub_date: item.pub_date(),
|
|
||||||
pub_ts: pub_datetime.timestamp(),
|
|
||||||
description: item.description(),
|
|
||||||
// author: item.author()
|
|
||||||
};
|
|
||||||
|
|
||||||
// populate categories
|
|
||||||
let mut categories = json::JsonValue::new_array();
|
|
||||||
|
|
||||||
for category in item.categories() {
|
|
||||||
match categories.push(category.name()) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) => {
|
|
||||||
// memory overflow ? as a beginner, style puzzled by rust
|
|
||||||
error!("Error pushing to items_data {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
item_data["categories"] = categories;
|
|
||||||
|
|
||||||
if item.content().is_some() {
|
|
||||||
item_data["content"] = json::JsonValue::String(item.content().unwrap().to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
match items_data.push(item_data) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) => {
|
|
||||||
// memory overflow ? as a beginner, style puzzled by rust
|
|
||||||
error!("Error pushing to items_data {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// attach the items to the json data root
|
|
||||||
data["items"] = items_data;
|
|
||||||
|
|
||||||
// output result
|
// output result
|
||||||
let output_string: String = if args.pretty {
|
let output_string: String = if args.pretty {
|
||||||
|
Loading…
Reference in New Issue
Block a user