:wInitial rusty commit
This commit is contained in:
parent
6342553d54
commit
84667e348b
2 changed files with 149 additions and 0 deletions
19
Cargo.toml
Normal file
19
Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "webmention-filer"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
#webmention = { version = "0.5", features = ["receive"] }
|
||||
webmention = { git = "https://github.com/DanielMowitz/webmention.git", features = [ "receive" ] }
|
||||
native-tls = "0.2"
|
||||
url = { version = "2.2", features = [ "serde" ] } # working with URLs
|
||||
anyhow = "1" # wrapping errors
|
||||
rocket = "=0.5.0-rc.3"
|
||||
clap = { version = "4.3", features = [ "derive" ] } # for CLI
|
||||
tokio = "1"
|
||||
chrono = "0.4"
|
||||
async-std = "1.12"
|
||||
|
130
src/main.rs
Normal file
130
src/main.rs
Normal file
|
@ -0,0 +1,130 @@
|
|||
#[macro_use] extern crate rocket;
|
||||
|
||||
use url::Url;
|
||||
use clap::Parser;
|
||||
|
||||
mod storage {
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use webmention::{Webmention, storage::WebmentionStorage, error::WebmentionError};
|
||||
use url::Url;
|
||||
use std::fs::{OpenOptions, create_dir_all};
|
||||
use std::io::prelude::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DailyFileStorage {
|
||||
storage_dir: String,
|
||||
mentions: Arc<Mutex<Vec<Webmention>>>,
|
||||
}
|
||||
|
||||
impl DailyFileStorage {
|
||||
pub fn new(storage_dir: String) -> Self {
|
||||
DailyFileStorage {
|
||||
storage_dir,
|
||||
mentions: Arc::new(Mutex::new(Vec::new())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WebmentionStorage for DailyFileStorage {
|
||||
fn store(&self, mention: Webmention) -> Result<(), WebmentionError> {
|
||||
{
|
||||
let now = chrono::offset::Local::now();
|
||||
let daily_file_name = format!("{}/{}",
|
||||
self.storage_dir,
|
||||
now.date_naive());
|
||||
let mention_line = format!("{}\t{} mentioned {}",
|
||||
now.time(),
|
||||
mention.source,
|
||||
mention.target);
|
||||
|
||||
create_dir_all(self.storage_dir.clone()).unwrap();
|
||||
let mut daily_file = OpenOptions::new()
|
||||
.write(true)
|
||||
.append(true)
|
||||
.create(true)
|
||||
.open(daily_file_name)
|
||||
.unwrap();
|
||||
|
||||
if let Err(e) = writeln!(daily_file, "{}", mention_line) {
|
||||
eprintln!("Couldn't write to file: {}", e);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn lookup_by_target(&self, url: Url) -> Result<Vec<Webmention>, WebmentionError> {
|
||||
let mut view: Vec<Webmention> = Vec::new();
|
||||
let lock = self.mentions.lock().unwrap();
|
||||
for mention in lock.iter() {
|
||||
if mention.target.eq(&url) {
|
||||
view.push(mention.clone());
|
||||
}
|
||||
}
|
||||
Ok(view)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod receive {
|
||||
use rocket::{form::Form, State};
|
||||
use url::Url;
|
||||
use crate::storage::DailyFileStorage;
|
||||
|
||||
#[derive(FromForm)]
|
||||
pub struct WebmentionAttempt {
|
||||
source: String,
|
||||
target: String,
|
||||
}
|
||||
|
||||
#[post("/webmention", data = "<webmention>")]
|
||||
pub async fn webmention_endpoint(
|
||||
storage: &State<DailyFileStorage>,
|
||||
config_url: &State<Url>,
|
||||
webmention: Form<WebmentionAttempt>,
|
||||
) -> Option<&'static str> {
|
||||
let urls = (
|
||||
Url::parse(&webmention.source),
|
||||
Url::parse(&webmention.target),
|
||||
);
|
||||
|
||||
if let Ok(source_url) = urls.0 {
|
||||
if let Ok(target_url) = urls.1 {
|
||||
if target_url.domain() != config_url.domain() {
|
||||
return None;
|
||||
}
|
||||
|
||||
println!("Calling store with source {} and target {}", &source_url, &target_url);
|
||||
match webmention::receive_webmention(
|
||||
&**storage,
|
||||
&source_url,
|
||||
&target_url,
|
||||
).await {
|
||||
Ok(true) => return Some("OK"),
|
||||
Ok(false) => {println!("Webmention check did not succeed!"); return None},
|
||||
Err(e) => {println!("{:?}", e); return None},
|
||||
}
|
||||
}
|
||||
}
|
||||
return None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
struct Args {
|
||||
#[arg(short, long)]
|
||||
domain: String,
|
||||
#[arg(short, long, default_value_t = String::from("/tmp/webmention-storage"))]
|
||||
storage_dir: String,
|
||||
}
|
||||
|
||||
#[launch]
|
||||
fn rocket() -> _ {
|
||||
let args = Args::parse();
|
||||
|
||||
rocket::build()
|
||||
.manage(crate::storage::DailyFileStorage::new(args.storage_dir))
|
||||
.manage(Url::parse(&args.domain).unwrap())
|
||||
.mount("/", routes![receive::webmention_endpoint])
|
||||
}
|
Loading…
Reference in a new issue