refactor(presentation): pure HTTP library — remove concrete adapter deps and binary
This commit is contained in:
@@ -88,7 +88,6 @@ pub async fn build(cfg: &Config) -> Infrastructure {
|
|||||||
auth: Arc::new(auth::JwtAuthService::new(cfg.jwt_secret.clone(), 86400 * 30)),
|
auth: Arc::new(auth::JwtAuthService::new(cfg.jwt_secret.clone(), 86400 * 30)),
|
||||||
hasher: Arc::new(auth::Argon2PasswordHasher),
|
hasher: Arc::new(auth::Argon2PasswordHasher),
|
||||||
events: event_publisher,
|
events: event_publisher,
|
||||||
fed_config: fed_config.clone(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Infrastructure { state, fed_config }
|
Infrastructure { state, fed_config }
|
||||||
|
|||||||
@@ -3,21 +3,11 @@ name = "presentation"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "thoughts"
|
|
||||||
path = "src/main.rs"
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
domain = { workspace = true }
|
domain = { workspace = true }
|
||||||
application = { workspace = true }
|
application = { workspace = true }
|
||||||
api-types = { workspace = true }
|
api-types = { workspace = true }
|
||||||
postgres = { workspace = true }
|
|
||||||
postgres-search = { workspace = true }
|
|
||||||
auth = { workspace = true }
|
|
||||||
nats = { workspace = true }
|
|
||||||
async-nats = { workspace = true }
|
|
||||||
axum = { workspace = true }
|
axum = { workspace = true }
|
||||||
sqlx = { workspace = true }
|
|
||||||
tower-http = { workspace = true }
|
tower-http = { workspace = true }
|
||||||
tokio = { workspace = true, features = ["full"] }
|
tokio = { workspace = true, features = ["full"] }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
@@ -25,14 +15,10 @@ serde_json = { workspace = true }
|
|||||||
uuid = { workspace = true }
|
uuid = { workspace = true }
|
||||||
chrono = { workspace = true }
|
chrono = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
tracing-subscriber = { workspace = true }
|
|
||||||
dotenvy = { workspace = true }
|
|
||||||
async-trait = { workspace = true }
|
async-trait = { workspace = true }
|
||||||
sha2 = "0.10"
|
sha2 = "0.10"
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
activitypub = { workspace = true }
|
|
||||||
activitypub-base = { workspace = true }
|
activitypub-base = { workspace = true }
|
||||||
postgres-federation = { workspace = true }
|
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
activitypub_federation = "0.7.0-beta.11"
|
activitypub_federation = "0.7.0-beta.11"
|
||||||
utoipa = { version = "5.5.0", features = ["axum_extras", "uuid", "chrono"] }
|
utoipa = { version = "5.5.0", features = ["axum_extras", "uuid", "chrono"] }
|
||||||
|
|||||||
@@ -1,87 +1,6 @@
|
|||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub mod openapi;
|
|
||||||
pub mod extractors;
|
pub mod extractors;
|
||||||
pub mod handlers;
|
pub mod handlers;
|
||||||
|
pub mod openapi;
|
||||||
pub mod routes;
|
pub mod routes;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use sqlx::PgPool;
|
|
||||||
use domain::{errors::DomainError, events::DomainEvent, ports::EventPublisher};
|
|
||||||
use postgres_search::PgSearchRepository;
|
|
||||||
use activitypub_base::{ApFederationConfig, FederationData};
|
|
||||||
use activitypub::ThoughtsObjectHandler;
|
|
||||||
use postgres::activitypub::PgActivityPubRepository;
|
|
||||||
use postgres_federation::{PostgresApUserRepository, PostgresFederationRepository};
|
|
||||||
use state::AppState;
|
|
||||||
|
|
||||||
struct NoOpEventPublisher;
|
|
||||||
#[async_trait]
|
|
||||||
impl EventPublisher for NoOpEventPublisher {
|
|
||||||
async fn publish(&self, _e: &DomainEvent) -> Result<(), DomainError> { Ok(()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn build_state(pool: PgPool, jwt_secret: String) -> AppState {
|
|
||||||
let event_publisher: Arc<dyn EventPublisher> = match std::env::var("NATS_URL") {
|
|
||||||
Ok(url) => match async_nats::connect(&url).await {
|
|
||||||
Ok(client) => {
|
|
||||||
tracing::info!("Connected to NATS at {url}");
|
|
||||||
Arc::new(nats::NatsEventPublisher::new(client))
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
tracing::warn!("Failed to connect to NATS at {url}: {e} — using no-op publisher");
|
|
||||||
Arc::new(NoOpEventPublisher)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(_) => {
|
|
||||||
tracing::info!("NATS_URL not set — using no-op event publisher");
|
|
||||||
Arc::new(NoOpEventPublisher)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let base_url = std::env::var("BASE_URL")
|
|
||||||
.unwrap_or_else(|_| "http://localhost:3000".into());
|
|
||||||
let allow_registration = std::env::var("ALLOW_REGISTRATION")
|
|
||||||
.map(|v| v == "true")
|
|
||||||
.unwrap_or(true);
|
|
||||||
let fed_debug = std::env::var("RUST_ENV")
|
|
||||||
.map(|v| v != "production")
|
|
||||||
.unwrap_or(true);
|
|
||||||
|
|
||||||
let fed_data = FederationData::new(
|
|
||||||
Arc::new(PostgresFederationRepository::new(pool.clone())),
|
|
||||||
Arc::new(PostgresApUserRepository::new(pool.clone(), base_url.clone())),
|
|
||||||
Arc::new(ThoughtsObjectHandler::new(
|
|
||||||
std::sync::Arc::new(PgActivityPubRepository::new(pool.clone())),
|
|
||||||
&base_url,
|
|
||||||
)),
|
|
||||||
base_url,
|
|
||||||
allow_registration,
|
|
||||||
"thoughts".to_string(),
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
let fed_config = ApFederationConfig::new(fed_data, fed_debug).await
|
|
||||||
.expect("federation config failed");
|
|
||||||
|
|
||||||
AppState {
|
|
||||||
users: Arc::new(postgres::user::PgUserRepository::new(pool.clone())),
|
|
||||||
thoughts: Arc::new(postgres::thought::PgThoughtRepository::new(pool.clone())),
|
|
||||||
likes: Arc::new(postgres::like::PgLikeRepository::new(pool.clone())),
|
|
||||||
boosts: Arc::new(postgres::boost::PgBoostRepository::new(pool.clone())),
|
|
||||||
follows: Arc::new(postgres::follow::PgFollowRepository::new(pool.clone())),
|
|
||||||
blocks: Arc::new(postgres::block::PgBlockRepository::new(pool.clone())),
|
|
||||||
tags: Arc::new(postgres::tag::PgTagRepository::new(pool.clone())),
|
|
||||||
api_keys: Arc::new(postgres::api_key::PgApiKeyRepository::new(pool.clone())),
|
|
||||||
top_friends: Arc::new(postgres::top_friend::PgTopFriendRepository::new(pool.clone())),
|
|
||||||
notifications: Arc::new(postgres::notification::PgNotificationRepository::new(pool.clone())),
|
|
||||||
remote_actors: Arc::new(postgres::remote_actor::PgRemoteActorRepository::new(pool.clone())),
|
|
||||||
feed: Arc::new(postgres::feed::PgFeedRepository::new(pool.clone())),
|
|
||||||
search: Arc::new(PgSearchRepository::new(pool.clone())),
|
|
||||||
auth: Arc::new(auth::JwtAuthService::new(jwt_secret, 86400 * 30)),
|
|
||||||
hasher: Arc::new(auth::Argon2PasswordHasher),
|
|
||||||
events: event_publisher,
|
|
||||||
fed_config,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
use sqlx::PgPool;
|
|
||||||
use tower_http::cors::CorsLayer;
|
|
||||||
use tracing_subscriber::EnvFilter;
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() {
|
|
||||||
dotenvy::dotenv().ok();
|
|
||||||
tracing_subscriber::fmt()
|
|
||||||
.with_env_filter(EnvFilter::from_default_env())
|
|
||||||
.init();
|
|
||||||
|
|
||||||
let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL required");
|
|
||||||
let jwt_secret = std::env::var("JWT_SECRET").expect("JWT_SECRET required");
|
|
||||||
let port = std::env::var("PORT").unwrap_or_else(|_| "3000".into());
|
|
||||||
|
|
||||||
let pool = PgPool::connect(&database_url).await.expect("DB connect failed");
|
|
||||||
sqlx::migrate!("../adapters/postgres/migrations").run(&pool).await.expect("Migrations failed");
|
|
||||||
|
|
||||||
let state = presentation::build_state(pool, jwt_secret).await;
|
|
||||||
let app = presentation::routes::router(&state.fed_config)
|
|
||||||
.with_state(state)
|
|
||||||
.layer(CorsLayer::permissive());
|
|
||||||
|
|
||||||
let addr = format!("0.0.0.0:{port}");
|
|
||||||
tracing::info!("Listening on {addr}");
|
|
||||||
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
|
|
||||||
axum::serve(listener, app).await.unwrap();
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use domain::ports::*;
|
use domain::ports::*;
|
||||||
use activitypub_base::ApFederationConfig;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
@@ -20,5 +19,4 @@ pub struct AppState {
|
|||||||
pub auth: Arc<dyn AuthService>,
|
pub auth: Arc<dyn AuthService>,
|
||||||
pub hasher: Arc<dyn PasswordHasher>,
|
pub hasher: Arc<dyn PasswordHasher>,
|
||||||
pub events: Arc<dyn EventPublisher>,
|
pub events: Arc<dyn EventPublisher>,
|
||||||
pub fed_config: ApFederationConfig,
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user