Create cli binary
Just has `add-feed` command so far.
This commit is contained in:
parent
b2a5bf5882
commit
89fdf8f95a
29
Cargo.lock
generated
29
Cargo.lock
generated
@ -37,6 +37,34 @@ version = "1.0.71"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "argh"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ab257697eb9496bf75526f0217b5ed64636a9cfafa78b8365c71bd283fcef93e"
|
||||||
|
dependencies = [
|
||||||
|
"argh_derive",
|
||||||
|
"argh_shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "argh_derive"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b382dbd3288e053331f03399e1db106c9fb0d8562ad62cb04859ae926f324fa6"
|
||||||
|
dependencies = [
|
||||||
|
"argh_shared",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "argh_shared"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "64cb94155d965e3d37ffbbe7cc5b82c3dd79dd33bd48e536f73d2cfb8d85506f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.68"
|
version = "0.1.68"
|
||||||
@ -225,6 +253,7 @@ name = "crawlect"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"argh",
|
||||||
"axum",
|
"axum",
|
||||||
"chrono",
|
"chrono",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
|
14
Cargo.toml
14
Cargo.toml
@ -2,18 +2,30 @@
|
|||||||
name = "crawlect"
|
name = "crawlect"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
default-run = "crawlect"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "lib"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
|
argh = "0.1"
|
||||||
axum = "0.6"
|
axum = "0.6"
|
||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
dotenvy = "0.15"
|
dotenvy = "0.15"
|
||||||
reqwest = { version = "0.11", features = ["json"] }
|
reqwest = { version = "0.11", features = ["json"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_with = "3"
|
serde_with = "3"
|
||||||
sqlx = { version = "0.6", features = ["runtime-tokio-native-tls", "postgres", "macros", "migrate", "chrono"] }
|
sqlx = { version = "0.6", features = [
|
||||||
|
"runtime-tokio-native-tls",
|
||||||
|
"postgres",
|
||||||
|
"macros",
|
||||||
|
"migrate",
|
||||||
|
"chrono",
|
||||||
|
] }
|
||||||
thiserror = "1"
|
thiserror = "1"
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
tower = "0.4"
|
tower = "0.4"
|
||||||
|
66
src/bin/cli.rs
Normal file
66
src/bin/cli.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use argh::FromArgs;
|
||||||
|
use dotenvy::dotenv;
|
||||||
|
use tracing::info;
|
||||||
|
use sqlx::postgres::PgPoolOptions;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
use lib::models::feed::{CreateFeed, FeedType};
|
||||||
|
use lib::commands::add_feed::add_feed;
|
||||||
|
|
||||||
|
#[derive(FromArgs)]
|
||||||
|
/// CLI for crawlect
|
||||||
|
struct Args {
|
||||||
|
#[argh(subcommand)]
|
||||||
|
commands: Commands,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromArgs)]
|
||||||
|
#[argh(subcommand)]
|
||||||
|
enum Commands {
|
||||||
|
AddFeed(AddFeed),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromArgs)]
|
||||||
|
/// Add a feed to the database
|
||||||
|
#[argh(subcommand, name = "add-feed")]
|
||||||
|
struct AddFeed {
|
||||||
|
#[argh(option)]
|
||||||
|
/// title of the feed (max 255 characters)
|
||||||
|
title: String,
|
||||||
|
#[argh(option)]
|
||||||
|
/// URL of the feed (max 2048 characters)
|
||||||
|
url: String,
|
||||||
|
#[argh(option, long = "type")]
|
||||||
|
/// type of the feed ('rss' or 'atom')
|
||||||
|
feed_type: FeedType,
|
||||||
|
#[argh(option)]
|
||||||
|
/// description of the feed
|
||||||
|
description: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
pub async fn main() -> Result<()> {
|
||||||
|
dotenv().ok();
|
||||||
|
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
|
let pool = PgPoolOptions::new()
|
||||||
|
.max_connections(env::var("DATABASE_MAX_CONNECTIONS")?.parse()?)
|
||||||
|
.connect(&env::var("DATABASE_URL")?)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let args: Args = argh::from_env();
|
||||||
|
|
||||||
|
if let Commands::AddFeed(add_feed_args) = args.commands {
|
||||||
|
add_feed(pool, CreateFeed {
|
||||||
|
title: add_feed_args.title,
|
||||||
|
url: add_feed_args.url,
|
||||||
|
feed_type: add_feed_args.feed_type,
|
||||||
|
description: add_feed_args.description,
|
||||||
|
}).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
8
src/commands/add_feed.rs
Normal file
8
src/commands/add_feed.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
use sqlx::PgPool;
|
||||||
|
|
||||||
|
use crate::models::feed::{create_feed, CreateFeed, Feed};
|
||||||
|
use crate::error::Result;
|
||||||
|
|
||||||
|
pub async fn add_feed(pool: PgPool, payload: CreateFeed) -> Result<Feed> {
|
||||||
|
create_feed(pool, payload).await
|
||||||
|
}
|
1
src/commands/mod.rs
Normal file
1
src/commands/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod add_feed;
|
4
src/lib.rs
Normal file
4
src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pub mod commands;
|
||||||
|
pub mod error;
|
||||||
|
pub mod handlers;
|
||||||
|
pub mod models;
|
@ -9,9 +9,7 @@ use tower::ServiceBuilder;
|
|||||||
use tower_http::trace::TraceLayer;
|
use tower_http::trace::TraceLayer;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
mod error;
|
use lib::handlers;
|
||||||
mod handlers;
|
|
||||||
mod models;
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
@ -13,29 +15,40 @@ pub enum FeedType {
|
|||||||
Rss,
|
Rss,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromStr for FeedType {
|
||||||
|
type Err = String;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"atom" => Ok(FeedType::Atom),
|
||||||
|
"rss" => Ok(FeedType::Rss),
|
||||||
|
_ => Err(format!("invalid feed type: {}", s)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct Feed {
|
pub struct Feed {
|
||||||
id: i32,
|
pub id: i32,
|
||||||
title: String,
|
pub title: String,
|
||||||
url: String,
|
pub url: String,
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
feed_type: FeedType,
|
pub feed_type: FeedType,
|
||||||
description: Option<String>,
|
pub description: Option<String>,
|
||||||
created_at: NaiveDateTime,
|
pub created_at: NaiveDateTime,
|
||||||
updated_at: NaiveDateTime,
|
pub updated_at: NaiveDateTime,
|
||||||
deleted_at: Option<NaiveDateTime>,
|
pub deleted_at: Option<NaiveDateTime>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Validate)]
|
#[derive(Debug, Deserialize, Validate)]
|
||||||
pub struct CreateFeed {
|
pub struct CreateFeed {
|
||||||
#[validate(length(max = 255))]
|
#[validate(length(max = 255))]
|
||||||
title: String,
|
pub title: String,
|
||||||
#[validate(url)]
|
#[validate(url)]
|
||||||
url: String,
|
pub url: String,
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
feed_type: FeedType,
|
pub feed_type: FeedType,
|
||||||
#[validate(length(max = 524288))]
|
#[validate(length(max = 524288))]
|
||||||
description: Option<String>,
|
pub description: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_feed(pool: PgPool, id: i32) -> Result<Feed> {
|
pub async fn get_feed(pool: PgPool, id: i32) -> Result<Feed> {
|
||||||
|
@ -7,26 +7,26 @@ use crate::error::{Error, Result};
|
|||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
id: i32,
|
pub id: i32,
|
||||||
title: String,
|
pub title: String,
|
||||||
url: String,
|
pub url: String,
|
||||||
description: Option<String>,
|
pub description: Option<String>,
|
||||||
feed_id: i32,
|
pub feed_id: i32,
|
||||||
created_at: NaiveDateTime,
|
pub created_at: NaiveDateTime,
|
||||||
updated_at: NaiveDateTime,
|
pub updated_at: NaiveDateTime,
|
||||||
deleted_at: Option<NaiveDateTime>,
|
pub deleted_at: Option<NaiveDateTime>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Validate)]
|
#[derive(Debug, Deserialize, Validate)]
|
||||||
pub struct CreateItem {
|
pub struct CreateItem {
|
||||||
#[validate(length(max = 255))]
|
#[validate(length(max = 255))]
|
||||||
title: String,
|
pub title: String,
|
||||||
#[validate(url)]
|
#[validate(url)]
|
||||||
url: String,
|
pub url: String,
|
||||||
#[validate(length(max = 524288))]
|
#[validate(length(max = 524288))]
|
||||||
description: Option<String>,
|
pub description: Option<String>,
|
||||||
#[validate(range(min = 1))]
|
#[validate(range(min = 1))]
|
||||||
feed_id: i32,
|
pub feed_id: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_item(pool: PgPool, id: i32) -> Result<Item> {
|
pub async fn get_item(pool: PgPool, id: i32) -> Result<Item> {
|
||||||
|
Loading…
Reference in New Issue
Block a user