cosmic_space/artifact/
asynch.rs

1use crate::artifact::ArtRef;
2use crate::config::mechtron::MechtronConfig;
3use crate::loc::ToSurface;
4use crate::wave::core::cmd::CmdMethod;
5use crate::wave::exchange::asynch::ProtoTransmitter;
6use crate::wave::DirectedProto;
7use crate::{Bin, BindConfig, SpaceErr, Stub, Substance};
8use dashmap::DashMap;
9use serde::Serialize;
10use std::collections::HashMap;
11use std::sync::Arc;
12use tokio::sync::watch;
13use crate::point::Point;
14
15#[derive(Clone)]
16pub struct ArtifactApi {
17    binds: Arc<DashMap<Point, Arc<BindConfig>>>,
18    mechtrons: Arc<DashMap<Point, Arc<MechtronConfig>>>,
19    wasm: Arc<DashMap<Point, Bin>>,
20    fetcher_tx: Arc<watch::Sender<Arc<dyn ArtifactFetcher>>>,
21    fetcher_rx: watch::Receiver<Arc<dyn ArtifactFetcher>>,
22}
23
24impl ArtifactApi {
25    pub fn no_fetcher() -> Self {
26        let fetcher = Arc::new(NoDiceArtifactFetcher);
27        Self::new(fetcher)
28    }
29
30    pub fn new(fetcher: Arc<dyn ArtifactFetcher>) -> Self {
31        let (fetcher_tx, fetcher_rx) = watch::channel(fetcher);
32        let fetcher_tx = Arc::new(fetcher_tx);
33        Self {
34            binds: Arc::new(DashMap::new()),
35            mechtrons: Arc::new(DashMap::new()),
36            wasm: Arc::new(DashMap::new()),
37            fetcher_tx,
38            fetcher_rx,
39        }
40    }
41
42    pub async fn set_fetcher(&self, fetcher: Arc<dyn ArtifactFetcher>) {
43        self.fetcher_tx.send(fetcher);
44    }
45
46    fn get_fetcher(&self) -> Arc<dyn ArtifactFetcher> {
47        self.fetcher_rx.borrow().clone()
48    }
49
50    pub async fn mechtron(&self, point: &Point) -> Result<ArtRef<MechtronConfig>, SpaceErr> {
51        {
52            if self.mechtrons.contains_key(point) {
53                let mechtron = self.mechtrons.get(point).unwrap().clone();
54                return Ok(ArtRef::new(mechtron, point.clone()));
55            }
56        }
57
58        let mechtron: Arc<MechtronConfig> = Arc::new(self.fetch(point).await?);
59        self.mechtrons.insert(point.clone(), mechtron.clone());
60        return Ok(ArtRef::new(mechtron, point.clone()));
61    }
62
63    pub async fn bind(&self, point: &Point) -> Result<ArtRef<BindConfig>, SpaceErr> {
64        {
65            if self.binds.contains_key(point) {
66                let bind = self.binds.get(point).unwrap().clone();
67                return Ok(ArtRef::new(bind, point.clone()));
68            }
69        }
70
71        let bind: Arc<BindConfig> = Arc::new(self.fetch(point).await?);
72        {
73            self.binds.insert(point.clone(), bind.clone());
74        }
75        return Ok(ArtRef::new(bind, point.clone()));
76    }
77
78    pub async fn wasm(&self, point: &Point) -> Result<ArtRef<Bin>, SpaceErr> {
79        {
80            if self.wasm.contains_key(point) {
81                let wasm = self.wasm.get(point).unwrap().clone();
82                return Ok(ArtRef::new(Arc::new(wasm), point.clone()));
83            }
84        }
85
86        let wasm = self.get_fetcher().fetch(point).await?;
87        {
88            self.wasm.insert(point.clone(), wasm.clone());
89        }
90        return Ok(ArtRef::new(Arc::new(wasm), point.clone()));
91    }
92
93    async fn fetch<A>(&self, point: &Point) -> Result<A, SpaceErr>
94    where
95        A: TryFrom<Bin, Error = SpaceErr>,
96    {
97        if !point.has_bundle() {
98            return Err("point is not from a bundle".into());
99        }
100        let bin = self.get_fetcher().fetch(point).await?;
101        Ok(A::try_from(bin)?)
102    }
103}
104
105pub struct FetchChamber {
106    pub fetcher: Box<dyn ArtifactFetcher>,
107}
108
109impl FetchChamber {
110    pub fn set(&mut self, fetcher: Box<dyn ArtifactFetcher>) {
111        self.fetcher = fetcher;
112    }
113}
114
115#[async_trait]
116pub trait ArtifactFetcher: Send + Sync {
117    async fn stub(&self, point: &Point) -> Result<Stub, SpaceErr>;
118    async fn fetch(&self, point: &Point) -> Result<Bin, SpaceErr>;
119}
120
121pub struct NoDiceArtifactFetcher;
122
123#[async_trait]
124impl ArtifactFetcher for NoDiceArtifactFetcher {
125    async fn stub(&self, point: &Point) -> Result<Stub, SpaceErr> {
126        Err("cannot pull artifacts right now".into())
127    }
128
129    async fn fetch(&self, point: &Point) -> Result<Bin, SpaceErr> {
130        Err("cannot pull artifacts right now".into())
131    }
132}
133
134pub struct ReadArtifactFetcher {
135    transmitter: ProtoTransmitter,
136}
137
138impl ReadArtifactFetcher {
139    pub fn new(transmitter: ProtoTransmitter) -> Self {
140        Self { transmitter }
141    }
142}
143
144#[async_trait]
145impl ArtifactFetcher for ReadArtifactFetcher {
146    async fn stub(&self, point: &Point) -> Result<Stub, SpaceErr> {
147        Err(SpaceErr::from_status(404u16))
148    }
149
150    async fn fetch(&self, point: &Point) -> Result<Bin, SpaceErr> {
151        let mut directed = DirectedProto::ping();
152        directed.to(point.clone().to_surface());
153        directed.method(CmdMethod::Read);
154        let pong = self.transmitter.ping(directed).await?;
155        pong.core.ok_or()?;
156        match pong.variant.core.body {
157            Substance::Bin(bin) => Ok(bin),
158            other => Err(SpaceErr::server_error(format!(
159                "expected Bin, encountered unexpected substance {} when fetching Artifact",
160                other.kind().to_string()
161            ))),
162        }
163    }
164}
165
166pub struct MapFetcher {
167    pub map: HashMap<Point, Bin>,
168}
169
170#[async_trait]
171impl ArtifactFetcher for MapFetcher {
172    async fn stub(&self, point: &Point) -> Result<Stub, SpaceErr> {
173        todo!()
174    }
175
176    async fn fetch(&self, point: &Point) -> Result<Bin, SpaceErr> {
177        let rtn = self.map.get(point).ok_or(SpaceErr::not_found(format!(
178            "could not find {}",
179            point.to_string()
180        )))?;
181        Ok(rtn.clone())
182    }
183}
184
185impl MapFetcher {
186    pub fn new() -> Self {
187        Self {
188            map: HashMap::new(),
189        }
190    }
191    pub fn ser<S: Serialize>(&mut self, point: &Point, bin: S) {
192        let bin = Arc::new(bincode::serialize(&bin).unwrap());
193        self.map.insert(point.clone(), bin);
194    }
195
196    pub fn str<S: ToString>(&mut self, point: &Point, string: S) {
197        let bin = Arc::new(string.to_string().into_bytes());
198        self.map.insert(point.clone(), bin);
199    }
200}