| 17 |
17 |
|
use makenotwork::email::{EmailClient, EmailConfig};
|
| 18 |
18 |
|
use makenotwork::payments::{PaymentProvider, StripeClient};
|
| 19 |
19 |
|
use makenotwork::scanning::ScanPipeline;
|
| 20 |
|
- |
use makenotwork::{build_app, AppCaches, AppLimiters, AppState, AppStorage};
|
|
20 |
+ |
use makenotwork::{build_app, AppState, AppStateParts, AppStorage};
|
| 21 |
21 |
|
use sqlx::PgPool;
|
| 22 |
22 |
|
use std::sync::Arc;
|
| 23 |
|
- |
use std::time::Instant;
|
| 24 |
23 |
|
use tower_sessions::cookie::time::Duration as CookieDuration;
|
| 25 |
24 |
|
use tower_sessions::cookie::SameSite;
|
| 26 |
25 |
|
use tower_sessions::{Expiry, SessionManagerLayer};
|
| 375 |
374 |
|
// no bucket isolation) so the cross-bucket image promote resolves.
|
| 376 |
375 |
|
let public_s3 = s3.clone();
|
| 377 |
376 |
|
|
| 378 |
|
- |
let state = AppState {
|
|
377 |
+ |
// Route through the same `AppState::build` constructor production uses
|
|
378 |
+ |
// (main.rs), so the derived in-memory state — start timestamps, the empty
|
|
379 |
+ |
// cache maps, the concurrency semaphores — has a single source of truth.
|
|
380 |
+ |
// The harness only supplies the externally-wired dependencies.
|
|
381 |
+ |
let state = AppState::build(AppStateParts {
|
| 379 |
382 |
|
db: pool.clone(),
|
| 380 |
383 |
|
config,
|
|
384 |
+ |
storage: AppStorage {
|
|
385 |
+ |
s3,
|
|
386 |
+ |
synckit_s3,
|
|
387 |
+ |
public_s3,
|
|
388 |
+ |
},
|
|
389 |
+ |
stripe: opts.stripe_client,
|
|
390 |
+ |
email,
|
|
391 |
+ |
docs: Arc::new(DocLoader::load(std::path::Path::new("."), &docengine::DocLoaderConfig {
|
|
392 |
+ |
sections: vec![],
|
|
393 |
+ |
link_prefix: "/docs".to_string(),
|
|
394 |
+ |
unpublished_pattern: None,
|
|
395 |
+ |
examples_path: None,
|
|
396 |
+ |
pre_process: None,
|
|
397 |
+ |
})),
|
| 381 |
398 |
|
tier_prices: {
|
| 382 |
399 |
|
// Install the process-global TierPrices so handler code paths
|
| 383 |
400 |
|
// that call CreatorTier::{price_cents,max_file_bytes,
|
| 390 |
407 |
|
pricing_comparison: makenotwork::pricing_comparison::PricingComparison::load(
|
| 391 |
408 |
|
"docs/business/assumptions.toml",
|
| 392 |
409 |
|
),
|
| 393 |
|
- |
stripe: opts.stripe_client,
|
| 394 |
|
- |
email,
|
| 395 |
|
- |
docs: Arc::new(DocLoader::load(std::path::Path::new("."), &docengine::DocLoaderConfig {
|
| 396 |
|
- |
sections: vec![],
|
| 397 |
|
- |
link_prefix: "/docs".to_string(),
|
| 398 |
|
- |
unpublished_pattern: None,
|
| 399 |
|
- |
examples_path: None,
|
| 400 |
|
- |
pre_process: None,
|
| 401 |
|
- |
})),
|
| 402 |
410 |
|
scanner: opts.scanner,
|
| 403 |
411 |
|
webauthn,
|
| 404 |
412 |
|
syntax: None,
|
| 405 |
|
- |
started_at: chrono::Utc::now(),
|
| 406 |
|
- |
start_instant: Instant::now(),
|
| 407 |
413 |
|
mt_client: opts.mt_base_url.zip(opts.internal_shared_secret).map(
|
| 408 |
414 |
|
|(url, secret)| makenotwork::mt_client::MtClient::new(url, secret),
|
| 409 |
415 |
|
),
|
| 410 |
416 |
|
wam: None,
|
| 411 |
|
- |
restart_at: Arc::new(std::sync::atomic::AtomicI64::new(0)),
|
|
417 |
+ |
domain_cache: Arc::new(dashmap::DashMap::new()),
|
| 412 |
418 |
|
metrics_handle: None,
|
| 413 |
419 |
|
page_view_tx: makenotwork::db::page_views::spawn_batcher(pool.clone()),
|
| 414 |
420 |
|
bg: makenotwork::background::spawn_pool_detached(),
|
| 415 |
|
- |
storage: AppStorage {
|
| 416 |
|
- |
s3,
|
| 417 |
|
- |
synckit_s3,
|
| 418 |
|
- |
public_s3,
|
| 419 |
|
- |
},
|
| 420 |
|
- |
caches: AppCaches {
|
| 421 |
|
- |
session_cache: Arc::new(dashmap::DashMap::new()),
|
| 422 |
|
- |
domain_cache: Arc::new(dashmap::DashMap::new()),
|
| 423 |
|
- |
sync_notify: Arc::new(dashmap::DashMap::new()),
|
| 424 |
|
- |
sse_connections: Arc::new(dashmap::DashMap::new()),
|
| 425 |
|
- |
},
|
| 426 |
|
- |
limiters: AppLimiters {
|
| 427 |
|
- |
scan_semaphore: Arc::new(tokio::sync::Semaphore::new(4)),
|
| 428 |
|
- |
caddy_ask_semaphore: Arc::new(tokio::sync::Semaphore::new(8)),
|
| 429 |
|
- |
git_smart_http_semaphore: Arc::new(tokio::sync::Semaphore::new(
|
| 430 |
|
- |
makenotwork::constants::GIT_SMART_HTTP_MAX_CONCURRENT,
|
| 431 |
|
- |
)),
|
| 432 |
|
- |
},
|
| 433 |
|
- |
};
|
|
421 |
+ |
});
|
| 434 |
422 |
|
|
| 435 |
423 |
|
// Capture scan deps before `build_app` consumes `state`.
|
| 436 |
424 |
|
let scan_deps = match (state.scanner.clone(), state.storage.s3.clone()) {
|