Add a post fuct

This commit is contained in:
aprilthepink 2024-05-04 17:54:11 +02:00
parent 4c020229e4
commit 8ac9f7bd4b
4 changed files with 80 additions and 25 deletions

8
Cargo.lock generated
View file

@ -442,6 +442,12 @@ dependencies = [
"syn 2.0.58", "syn 2.0.58",
] ]
[[package]]
name = "async_once"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ce4f10ea3abcd6617873bae9f91d1c5332b4a778bd9ce34d0cd517474c1de82"
[[package]] [[package]]
name = "atoi" name = "atoi"
version = "2.0.0" version = "2.0.0"
@ -1812,10 +1818,12 @@ dependencies = [
"actix-web-prom", "actix-web-prom",
"anyhow", "anyhow",
"async-trait", "async-trait",
"async_once",
"chrono", "chrono",
"clap", "clap",
"enum_delegate", "enum_delegate",
"env_logger", "env_logger",
"lazy_static",
"num_cpus", "num_cpus",
"rand", "rand",
"sea-orm", "sea-orm",

View file

@ -27,6 +27,8 @@ num_cpus = "1.16.0"
actix-web-prom = { version = "0.8.0", features = ["process"] } actix-web-prom = { version = "0.8.0", features = ["process"] }
serde_json = "1.0.115" serde_json = "1.0.115"
chrono = "0.4.38" chrono = "0.4.38"
lazy_static = "1.4.0"
async_once = "0.2.6"
[dependencies.sea-orm] [dependencies.sea-orm]
version = "0.12.0" version = "0.12.0"

View file

@ -1,12 +1,14 @@
use activitypub_federation::{ use activitypub_federation::{
config::{FederationConfig, FederationMiddleware}, config::{Data, FederationConfig, FederationMiddleware}, fetch::{object_id::ObjectId, webfinger::webfinger_resolve_actor}, http_signatures::generate_actor_keypair, traits::Actor
http_signatures::generate_actor_keypair,
}; };
use actix_web::{get, http::KeepAlive, middleware, web, App, Error, HttpResponse, HttpServer}; use activitystreams_kinds::public;
use actix_web::{get, http::KeepAlive, middleware, post, web, App, Error, HttpResponse, HttpServer};
use actix_web_prom::PrometheusMetricsBuilder; use actix_web_prom::PrometheusMetricsBuilder;
use async_once::AsyncOnce;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use clap::Parser; use clap::Parser;
use database::Database; use database::Database;
use entities::post;
use http::{http_get_user, http_post_user_inbox, webfinger}; use http::{http_get_user, http_post_user_inbox, webfinger};
use objects::person::DbUser; use objects::person::DbUser;
use sea_orm::{ActiveModelTrait, DatabaseConnection, Set}; use sea_orm::{ActiveModelTrait, DatabaseConnection, Set};
@ -15,13 +17,17 @@ use std::{
collections::HashMap, collections::HashMap,
env, env,
net::ToSocketAddrs, net::ToSocketAddrs,
sync::{Arc, Mutex}, sync::{Arc, Mutex, OnceLock},
}; };
use tokio::signal; use tokio::signal;
use tracing::{info, instrument::WithSubscriber}; use tracing::{info, instrument::WithSubscriber};
use url::Url; use url::Url;
use crate::database::{Config, State}; use crate::{activities::create_post::CreatePost, database::{Config, State}, objects::post::{Mention, Note}};
use crate::entities::user;
use crate::utils::generate_object_id;
use lazy_static::lazy_static;
mod activities; mod activities;
mod database; mod database;
@ -54,26 +60,60 @@ async fn index(_: web::Data<State>) -> actix_web::Result<HttpResponse, Error> {
Ok(HttpResponse::Ok().json(Response { health: true })) Ok(HttpResponse::Ok().json(Response { health: true }))
} }
const DOMAIN: &str = "example.com"; #[post("/test/postmanually/{user}/{post}")]
async fn post_manually(
path: web::Path<(String, String)>,
state: web::Data<State>,
) -> actix_web::Result<HttpResponse, error::Error> {
let local_user = state.local_user().await?;
let data = FEDERATION_CONFIG.get().unwrap();
let creator = webfinger_resolve_actor::<State, user::Model>(path.0.as_str(), &data.to_request_data()).await?;
let mention = Mention {
href: Url::parse(&creator.id)?,
kind: Default::default(),
};
let id: ObjectId<post::Model> = generate_object_id(data.domain())?.into();
let note = Note {
kind: Default::default(),
id,
sensitive: false,
attributed_to: Url::parse(&data.local_user().await?.id).unwrap().into(),
to: vec![public()],
content: format!("Hello {}", creator.name),
tag: vec![mention],
in_reply_to: None,
};
CreatePost::send(note, creator.shared_inbox_or_inbox(), &data.to_request_data()).await?;
Ok(HttpResponse::Ok().json(Response { health: true }))
}
const DOMAIN_DEF: &str = "example.com";
const LOCAL_USER_NAME: &str = "example"; const LOCAL_USER_NAME: &str = "example";
lazy_static!{
static ref SERVER_URL: String = env::var("LISTEN").unwrap_or("127.0.0.1:8080".to_string());
static ref DATABASE_URL: String = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
static ref USERNAME: String = env::var("LOCAL_USER_NAME").unwrap_or(LOCAL_USER_NAME.to_string());
static ref DOMAIN: String = env::var("FEDERATED_DOMAIN").unwrap_or(DOMAIN_DEF.to_string());
}
static DB: OnceLock<DatabaseConnection> = OnceLock::new();
static FEDERATION_CONFIG: OnceLock<FederationConfig<State>> = OnceLock::new();
#[actix_web::main] #[actix_web::main]
async fn main() -> actix_web::Result<(), anyhow::Error> { async fn main() -> actix_web::Result<(), anyhow::Error> {
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
let server_url = env::var("LISTEN").unwrap_or("127.0.0.1:8080".to_string()); let ap_id = Url::parse(&format!("https://{}/{}", DOMAIN.to_string(), &USERNAME.to_string()))?;
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); let inbox = Url::parse(&format!("https://{}/{}/inbox", DOMAIN.to_string(), &USERNAME.to_string()))?;
let username = env::var("LOCAL_USER_NAME").unwrap_or(LOCAL_USER_NAME.to_string());
let domain = env::var("FEDERATED_DOMAIN").unwrap_or(DOMAIN.to_string());
let ap_id = Url::parse(&format!("https://{}/{}", domain, &username))?;
let inbox = Url::parse(&format!("https://{}/{}/inbox", domain, &username))?;
let keypair = generate_actor_keypair()?; let keypair = generate_actor_keypair()?;
let user = entities::user::ActiveModel { let user = entities::user::ActiveModel {
id: Set(ap_id.clone().into()), id: Set(ap_id.clone().into()),
username: Set(username), username: Set(USERNAME.to_string()),
name: Set("Test account <3".to_string()), name: Set("Test account <3".to_string()),
inbox: Set(inbox.to_string()), inbox: Set(inbox.to_string()),
public_key: Set(keypair.public_key.clone()), public_key: Set(keypair.public_key.clone()),
@ -87,11 +127,15 @@ async fn main() -> actix_web::Result<(), anyhow::Error> {
..Default::default() ..Default::default()
}; };
let db = sea_orm::Database::connect(database_url).await?; let db = sea_orm::Database::connect(DATABASE_URL.to_string()).await?;
info!("Connected to database: {:?}", db); info!("Connected to database: {:?}", db);
let user = user.insert(&db).await; DB.set(db).expect("We were not able to save the DB conn into memory");
let db = DB.get().unwrap();
let user = user.insert(db).await;
if let Err(err) = user { if let Err(err) = user {
eprintln!("Error inserting user: {:?}", err); eprintln!("Error inserting user: {:?}", err);
@ -100,7 +144,7 @@ async fn main() -> actix_web::Result<(), anyhow::Error> {
} }
let state: State = State { let state: State = State {
database_connection: db.into(), database_connection: Arc::new(db.clone()),
}; };
let data = FederationConfig::builder() let data = FederationConfig::builder()
@ -137,12 +181,13 @@ async fn main() -> actix_web::Result<(), anyhow::Error> {
.wrap(middleware::Logger::default()) // enable logger .wrap(middleware::Logger::default()) // enable logger
.wrap(prometheus.clone()) .wrap(prometheus.clone())
.wrap(FederationMiddleware::new(data.clone())) .wrap(FederationMiddleware::new(data.clone()))
.service(post_manually)
.route("/{user}", web::get().to(http_get_user)) .route("/{user}", web::get().to(http_get_user))
.route("/{user}/inbox", web::post().to(http_post_user_inbox)) .route("/{user}/inbox", web::post().to(http_post_user_inbox))
.route("/.well-known/webfinger", web::get().to(webfinger)) .route("/.well-known/webfinger", web::get().to(webfinger))
.service(index) .service(index)
}) })
.bind(&server_url)? .bind(SERVER_URL.to_string())?
.workers(num_cpus::get()) .workers(num_cpus::get())
.shutdown_timeout(20) .shutdown_timeout(20)
.keep_alive(KeepAlive::Os) .keep_alive(KeepAlive::Os)

View file

@ -31,15 +31,15 @@ pub struct DbPost {
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Note { pub struct Note {
#[serde(rename = "type")] #[serde(rename = "type")]
kind: NoteType, pub(crate) kind: NoteType,
id: ObjectId<post::Model>, pub(crate) id: ObjectId<post::Model>,
pub(crate) attributed_to: ObjectId<user::Model>, pub(crate) attributed_to: ObjectId<user::Model>,
#[serde(deserialize_with = "deserialize_one_or_many")] #[serde(deserialize_with = "deserialize_one_or_many")]
pub(crate) to: Vec<Url>, pub(crate) to: Vec<Url>,
content: String, pub(crate) content: String,
in_reply_to: Option<ObjectId<post::Model>>, pub(crate) in_reply_to: Option<ObjectId<post::Model>>,
tag: Vec<Mention>, pub(crate) tag: Vec<Mention>,
sensitive: bool, pub(crate) sensitive: bool,
} }
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]