1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use std::sync::Arc;
use ahash::AHashMap;
use ars_package::Asset;
use bytes::Bytes;

use crate::embedded_asset::EmbeddedAsset;
use crate::config::{SrvConfig, KeycloakConfig};

struct EmbeddedAssetMap {
    inner: AHashMap<Arc<str>, EmbeddedAsset>,
}

impl EmbeddedAssetMap {
    pub fn new(assets: &[Arc<Asset>], target_url: &str, public_url: &str, index: usize) -> anyhow::Result<Self> {
        let mut inner = AHashMap::default();
        for (idx, asset) in assets.iter().enumerate() {
            if idx != index {
                inner.insert(asset.path.clone(), EmbeddedAsset::new(asset, true, target_url, public_url)?);
            }
        }
        Ok(Self {
            inner,
        })
    }
}

pub type ServerConfig = SrvConfig<8000>;
pub struct AssetStore {
    not_found: Bytes,
    not_found_mime: Arc<str>,
    assets: Arc<EmbeddedAssetMap>,
    index: EmbeddedAsset,
    keycloak_config: EmbeddedAsset,
}

impl AssetStore {
    pub fn new(cfg: &ServerConfig, keycloak_config: &KeycloakConfig) -> anyhow::Result<Self> {
        let pkg_encoded = std::fs::read(cfg.asset_package())?;
        let pkg = ars_package::deflate_decode_raw(&pkg_encoded);
        let asset_package = ars_package::deserialize(&pkg)?;
        let index = asset_package.assets.get(asset_package.index as usize)
            .ok_or(anyhow::anyhow!("unable to find index.html"))?;

        let target_url = &asset_package.target_url;
        let public_url = cfg.public_url();
        let index = EmbeddedAsset::new(index, false, target_url, public_url)?;
        let assets = Arc::new(EmbeddedAssetMap::new(asset_package.assets.as_ref(), target_url, public_url, asset_package.index as usize)?);
        let not_found_mime: Arc<str> = Arc::from("text/plain");
        let not_found = Bytes::from_static(b"not found");
        let keycloak_config = EmbeddedAsset::json(keycloak_config)?;
        Ok(Self {
            not_found_mime,
            not_found,
            assets,
            index,
            keycloak_config,
        })
    }

    pub fn get(&self, id: &str) -> EmbeddedAsset {
        self.assets
            .inner
            .get(id)
            .cloned()
            .unwrap_or_else(|| EmbeddedAsset::not_found(self.not_found.clone(), self.not_found_mime.clone()))
    }

    pub fn index(&self) -> EmbeddedAsset {
        self.index.clone()
    }

    pub fn keycloak_config(&self) -> EmbeddedAsset {
        self.keycloak_config.clone()
    }
}

struct Inner {
    config: ServerConfig,
    store: AssetStore,    
}

#[derive(Clone)]
pub struct App {
    inner: Arc<Inner>,
}

impl App {
    pub fn new() -> anyhow::Result<Self> {
        let config = ServerConfig::from_env("SERVER_")?;
        let keycloak_config = envy::from_env()?;
        Ok(Self {
            inner: Arc::new(Inner {
                store: AssetStore::new(&config, &keycloak_config)?,
                config,
            })
        })
    }

    pub fn cfg(&self) -> &ServerConfig {
        &self.inner.config
    }

    pub fn store(&self) -> &AssetStore {
        &self.inner.store
    }
}