: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