1use crate::config::Config;
2use crate::docker::DockerClient;
3use anyhow::Result;
4use minifly_core::models::{App, Machine, Lease};
5use minifly_litefs::manager::LiteFSManager;
6use minifly_network::InternalDnsResolver;
7use sqlx::sqlite::{SqlitePool, SqlitePoolOptions};
8use std::collections::HashMap;
9use std::sync::{Arc, RwLock};
10use std::path::PathBuf;
11use std::time::Instant;
12
13#[derive(Clone)]
14pub struct AppState {
15 pub config: Config,
16 pub db: SqlitePool,
17 pub docker: DockerClient,
18 pub litefs: Arc<LiteFSManager>,
19 pub dns_resolver: Arc<InternalDnsResolver>,
20 pub leases: Arc<RwLock<HashMap<String, Lease>>>,
21 pub machines: Arc<RwLock<HashMap<String, Machine>>>,
22 pub apps: Arc<RwLock<HashMap<String, App>>>,
23 pub start_time: Instant,
24}
25
26impl AppState {
27 pub async fn new(config: Config) -> Result<Self> {
28 let db = SqlitePoolOptions::new()
30 .max_connections(5)
31 .connect(&config.database_url)
32 .await?;
33
34 sqlx::migrate!("./migrations").run(&db).await?;
36
37 let docker = DockerClient::new(config.docker_host.as_deref())?;
39
40 let litefs_base_dir = PathBuf::from(&config.data_dir).join("litefs");
42 let litefs = Arc::new(LiteFSManager::new(litefs_base_dir).await?);
43
44 let dns_resolver = Arc::new(InternalDnsResolver::new());
46
47 Ok(Self {
48 config,
49 db,
50 docker,
51 litefs,
52 dns_resolver,
53 leases: Arc::new(RwLock::new(HashMap::new())),
54 machines: Arc::new(RwLock::new(HashMap::new())),
55 apps: Arc::new(RwLock::new(HashMap::new())),
56 start_time: Instant::now(),
57 })
58 }
59
60 pub fn generate_machine_id(&self) -> String {
61 use rand::Rng;
63 let mut rng = rand::thread_rng();
64 let bytes: Vec<u8> = (0..8).map(|_| rng.gen()).collect();
65 hex::encode(bytes)[..15].to_string()
66 }
67
68 pub fn generate_instance_id(&self) -> String {
69 use rand::Rng;
71 let mut rng = rand::thread_rng();
72 let chars: String = (0..26)
73 .map(|_| {
74 let idx = rng.gen_range(0..36);
75 if idx < 10 {
76 (b'0' + idx) as char
77 } else {
78 (b'A' + idx - 10) as char
79 }
80 })
81 .collect();
82 chars
83 }
84
85 pub fn generate_private_ip(&self, app_id: &str, machine_index: u32) -> String {
86 let app_hash = {
88 use sha2::{Sha256, Digest};
89 let mut hasher = Sha256::new();
90 hasher.update(app_id);
91 let result = hasher.finalize();
92 format!("{:x}", u16::from_be_bytes([result[0], result[1]]))
93 };
94
95 format!("{}{}:a7b:{}::2", self.config.internal_network_prefix, app_hash, machine_index)
96 }
97}