Skip to main content

chc_service/
chc.rs

1use std::{
2    collections::BTreeMap,
3    net::{IpAddr, SocketAddr},
4    sync::Arc,
5};
6
7use anyhow::anyhow;
8use axum::{routing::post, Router};
9use holochain::{
10    conductor::chc::EncryptedEntry,
11    core::{hash_type::Action, HoloHash},
12    prelude::{CellId, Signature, SignedActionHashed},
13};
14use parking_lot::RwLock;
15use tokio::net::TcpListener;
16
17use crate::routes::{add_records, get_record_data, not_found};
18
19#[derive(Debug)]
20pub struct ChcService {
21    address: SocketAddr,
22    router: Router,
23}
24
25// Sourced from holochain sourcecode, original struct contains inacessible private fields
26// https://github.com/holochain/holochain/blob/60102a603b8039eb46e786d82dd6382f3a1b1c93/crates/holochain/src/conductor/chc/chc_local.rs#L33
27#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
28pub struct RecordItem {
29    pub action: SignedActionHashed,
30    pub encrypted_entry: Option<(Arc<EncryptedEntry>, Signature)>,
31}
32
33#[derive(Debug, Default)]
34pub struct AppState {
35    pub records: RwLock<BTreeMap<CellId, CellState>>,
36}
37
38#[derive(Debug, Default)]
39pub struct CellState {
40    pub records: Vec<RecordItem>,
41    pub latest_action_seq: u32,
42    pub latest_action_hash: Option<HoloHash<Action>>,
43}
44
45impl ChcService {
46    pub fn new(interface: impl Into<IpAddr>, port: u16) -> Self {
47        let address = SocketAddr::new(interface.into(), port);
48
49        let router = Router::new()
50            .route(
51                "/{dna_hash}/{agent_pubkey}/get_record_data",
52                post(get_record_data),
53            )
54            .route("/{dna_hash}/{agent_pubkey}/add_records", post(add_records))
55            .fallback(not_found)
56            .with_state(Arc::new(AppState::default()));
57
58        ChcService { address, router }
59    }
60
61    pub fn address(&self) -> SocketAddr {
62        self.address
63    }
64
65    pub async fn run(self) -> anyhow::Result<()> {
66        let listerner = TcpListener::bind(self.address)
67            .await
68            .map_err(|e| anyhow!("Failed to bind to address: {}", e))?;
69        axum::serve(listerner, self.router)
70            .await
71            .map_err(|e| anyhow!("Failed to start server: {}", e))?;
72
73        Ok(())
74    }
75}