1use std::sync::Arc;
2use ahash::AHashMap;
3use ars_package::Asset;
4use bytes::Bytes;
5
6use crate::embedded_asset::EmbeddedAsset;
7use crate::config::{SrvConfig, KeycloakConfig};
8
9struct EmbeddedAssetMap {
10 inner: AHashMap<Arc<str>, EmbeddedAsset>,
11}
12
13impl EmbeddedAssetMap {
14 pub fn new(assets: &[Arc<Asset>], target_url: &str, public_url: &str, index: usize) -> anyhow::Result<Self> {
15 let mut inner = AHashMap::default();
16 for (idx, asset) in assets.iter().enumerate() {
17 if idx != index {
18 inner.insert(asset.path.clone(), EmbeddedAsset::new(asset, true, target_url, public_url)?);
19 }
20 }
21 Ok(Self {
22 inner,
23 })
24 }
25}
26
27pub type ServerConfig = SrvConfig<8000>;
28pub struct AssetStore {
29 not_found: Bytes,
30 not_found_mime: Arc<str>,
31 assets: Arc<EmbeddedAssetMap>,
32 index: EmbeddedAsset,
33 keycloak_config: EmbeddedAsset,
34}
35
36impl AssetStore {
37 pub fn new(cfg: &ServerConfig, keycloak_config: &KeycloakConfig) -> anyhow::Result<Self> {
38 let pkg_encoded = std::fs::read(cfg.asset_package())?;
39 let pkg = ars_package::deflate_decode_raw(&pkg_encoded);
40 let asset_package = ars_package::deserialize(&pkg)?;
41 let index = asset_package.assets.get(asset_package.index as usize)
42 .ok_or(anyhow::anyhow!("unable to find index.html"))?;
43
44 let target_url = &asset_package.target_url;
45 let public_url = cfg.public_url();
46 let index = EmbeddedAsset::new(index, false, target_url, public_url)?;
47 let assets = Arc::new(EmbeddedAssetMap::new(asset_package.assets.as_ref(), target_url, public_url, asset_package.index as usize)?);
48 let not_found_mime: Arc<str> = Arc::from("text/plain");
49 let not_found = Bytes::from_static(b"not found");
50 let keycloak_config = EmbeddedAsset::json(keycloak_config)?;
51 Ok(Self {
52 not_found_mime,
53 not_found,
54 assets,
55 index,
56 keycloak_config,
57 })
58 }
59
60 pub fn get(&self, id: &str) -> EmbeddedAsset {
61 self.assets
62 .inner
63 .get(id)
64 .cloned()
65 .unwrap_or_else(|| EmbeddedAsset::not_found(self.not_found.clone(), self.not_found_mime.clone()))
66 }
67
68 pub fn index(&self) -> EmbeddedAsset {
69 self.index.clone()
70 }
71
72 pub fn keycloak_config(&self) -> EmbeddedAsset {
73 self.keycloak_config.clone()
74 }
75}
76
77struct Inner {
78 config: ServerConfig,
79 store: AssetStore,
80}
81
82#[derive(Clone)]
83pub struct App {
84 inner: Arc<Inner>,
85}
86
87impl App {
88 pub fn new() -> anyhow::Result<Self> {
89 let config = ServerConfig::from_env("SERVER_")?;
90 let keycloak_config = envy::from_env()?;
91 Ok(Self {
92 inner: Arc::new(Inner {
93 store: AssetStore::new(&config, &keycloak_config)?,
94 config,
95 })
96 })
97 }
98
99 pub fn cfg(&self) -> &ServerConfig {
100 &self.inner.config
101 }
102
103 pub fn store(&self) -> &AssetStore {
104 &self.inner.store
105 }
106}