diff options
| author | Bryan Newbold <bnewbold@robocracy.org> | 2022-11-01 19:44:09 -0700 | 
|---|---|---|
| committer | Bryan Newbold <bnewbold@robocracy.org> | 2022-11-01 19:44:09 -0700 | 
| commit | f3fdc7ba600c65fdb05efc2fd5e9a651b4b9956e (patch) | |
| tree | cf2522e44a56fb621a5e72364951ab7a1c29ef45 /adenosine-pds | |
| parent | 96c6dbc6c500a7ca3ebefe4ee4fb91fcb8c1713c (diff) | |
| download | adenosine-f3fdc7ba600c65fdb05efc2fd5e9a651b4b9956e.tar.gz adenosine-f3fdc7ba600c65fdb05efc2fd5e9a651b4b9956e.zip | |
pds: refactor repo code
Diffstat (limited to 'adenosine-pds')
| -rw-r--r-- | adenosine-pds/src/atp_db.sql | 11 | ||||
| -rw-r--r-- | adenosine-pds/src/bin/adenosine-pds.rs | 2 | ||||
| -rw-r--r-- | adenosine-pds/src/db.rs | 4 | ||||
| -rw-r--r-- | adenosine-pds/src/lib.rs | 5 | ||||
| -rw-r--r-- | adenosine-pds/src/mst.rs | 26 | ||||
| -rw-r--r-- | adenosine-pds/src/repo.rs | 156 | ||||
| -rw-r--r-- | adenosine-pds/tests/test_repro_mst.rs | 2 | 
7 files changed, 181 insertions, 25 deletions
| diff --git a/adenosine-pds/src/atp_db.sql b/adenosine-pds/src/atp_db.sql index 918a89c..a6fce1c 100644 --- a/adenosine-pds/src/atp_db.sql +++ b/adenosine-pds/src/atp_db.sql @@ -6,7 +6,7 @@ CREATE TABLE account(      username            TEXT NOT NULL,      email               TEXT NOT NULL,      password_bcrypt     TEXT NOT NULL, -    signing_key         TEXT NOT NULL, +    signing_key         TEXT NOT NULL  );  CREATE UNIQUE INDEX account_username_uniq_idx on account(lower(username));  CREATE UNIQUE INDEX account_email_uniq_idx on account(lower(email)); @@ -14,19 +14,19 @@ CREATE UNIQUE INDEX account_email_uniq_idx on account(lower(email));  CREATE TABLE did_doc(      did                 TEXT PRIMARY KEY NOT NULL,      doc_json            TEXT NOT NULL, -    seen_at             TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, +    seen_at             TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT ( DATETIME('now') )  );  CREATE TABLE session(      did                 TEXT NOT NULL,      jwt                 TEXT NOT NULL, -    created_at          TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL, +    created_at          TIMESTAMP WITH TIME ZONE  NOT NULL DEFAULT ( DATETIME('now') ),      PRIMARY KEY(did, jwt)  );  CREATE TABLE repo(      did                 TEXT PRIMARY KEY NOT NULL, -    head_commit         TEXT NOT NULL, +    head_commit         TEXT NOT NULL  );  CREATE TABLE record( @@ -44,7 +44,6 @@ CREATE TABLE password_reset(      PRIMARY KEY(did, token)  ); -  ----------- bsky app/index tables - +-- TODO diff --git a/adenosine-pds/src/bin/adenosine-pds.rs b/adenosine-pds/src/bin/adenosine-pds.rs index b76d015..0159ab7 100644 --- a/adenosine-pds/src/bin/adenosine-pds.rs +++ b/adenosine-pds/src/bin/adenosine-pds.rs @@ -83,6 +83,6 @@ fn main() -> Result<()> {              run_server(port, &opt.blockstore_db_path, &opt.atp_db_path)          }          Command::Import { car_path } => load_car_to_sqlite(&opt.blockstore_db_path, &car_path), -        Command::Inspect {} => dump_mst_keys(&opt.blockstore_db_path), +        Command::Inspect {} => mst::dump_mst_keys(&opt.blockstore_db_path),      }  } diff --git a/adenosine-pds/src/db.rs b/adenosine-pds/src/db.rs index 1d6d4ed..905210c 100644 --- a/adenosine-pds/src/db.rs +++ b/adenosine-pds/src/db.rs @@ -61,7 +61,7 @@ impl AtpDatabase {      pub fn get_record(&mut self, did: &str, collection: &str, tid: &str) -> Result<Value> {          let mut stmt = self.conn.prepare_cached( -            "SELECT record_json FROM record WHERE did = ?1 collection = ?2 tid = ?3", +            "SELECT record_json FROM record WHERE did = ?1 AND collection = ?2 AND tid = ?3",          )?;          Ok(stmt.query_row(params!(did, collection, tid), |row| {              row.get(0).map(|v: String| Value::from_str(&v)) @@ -71,7 +71,7 @@ impl AtpDatabase {      pub fn get_record_list(&mut self, did: &str, collection: &str) -> Result<Vec<String>> {          let mut stmt = self              .conn -            .prepare_cached("SELECT tid FROM record WHERE did = ?1 collection = ?2")?; +            .prepare_cached("SELECT tid FROM record WHERE did = ?1 AND collection = ?2")?;          let ret = stmt              .query_and_then(params!(did, collection), |row| {                  let v: String = row.get(0)?; diff --git a/adenosine-pds/src/lib.rs b/adenosine-pds/src/lib.rs index a8dc46a..0ef081d 100644 --- a/adenosine-pds/src/lib.rs +++ b/adenosine-pds/src/lib.rs @@ -9,12 +9,13 @@ use ipfs_sqlite_block_store::BlockStore;  mod car;  mod db;  mod models; -mod mst; +pub mod mst; +mod repo;  pub use car::{load_car_to_blockstore, load_car_to_sqlite};  pub use db::AtpDatabase;  pub use models::*; -pub use mst::{dump_mst_keys, repro_mst}; +pub use repo::{RepoCommit, RepoStore};  pub fn run_server(port: u16, blockstore_db_path: &PathBuf, atp_db_path: &PathBuf) -> Result<()> {      // TODO: some static files? https://github.com/tomaka/rouille/blob/master/examples/static-files.rs diff --git a/adenosine-pds/src/mst.rs b/adenosine-pds/src/mst.rs index 429d8c8..3e01a92 100644 --- a/adenosine-pds/src/mst.rs +++ b/adenosine-pds/src/mst.rs @@ -12,25 +12,25 @@ use std::collections::BTreeMap;  use std::path::PathBuf;  #[derive(Debug, DagCbor, PartialEq, Eq)] -struct CommitNode { -    root: Cid, -    sig: Box<[u8]>, +pub struct CommitNode { +    pub root: Cid, +    pub sig: Box<[u8]>,  }  #[derive(Debug, DagCbor, PartialEq, Eq)] -struct RootNode { -    auth_token: Option<String>, -    prev: Option<Cid>, +pub struct RootNode { +    pub auth_token: Option<String>, +    pub prev: Option<Cid>,      // TODO: not 'metadata'? -    meta: Cid, -    data: Cid, +    pub meta: Cid, +    pub data: Cid,  }  #[derive(Debug, DagCbor, PartialEq, Eq)] -struct MetadataNode { -    datastore: String, // "mst" -    did: String, -    version: u8, // 1 +pub struct MetadataNode { +    pub datastore: String, // "mst" +    pub did: String, +    pub version: u8, // 1  }  #[derive(Debug, DagCbor, PartialEq, Eq)] @@ -132,7 +132,7 @@ pub fn dump_mst_keys(db_path: &PathBuf) -> Result<()> {      Ok(())  } -fn collect_mst_keys( +pub fn collect_mst_keys(      db: &mut BlockStore<libipld::DefaultParams>,      cid: &Cid,      map: &mut BTreeMap<String, Cid>, diff --git a/adenosine-pds/src/repo.rs b/adenosine-pds/src/repo.rs new file mode 100644 index 0000000..e5de504 --- /dev/null +++ b/adenosine-pds/src/repo.rs @@ -0,0 +1,156 @@ +use crate::mst::{collect_mst_keys, CommitNode, MetadataNode, RootNode}; +use anyhow::{anyhow, Result}; +use ipfs_sqlite_block_store::BlockStore; +use libipld::cbor::DagCborCodec; +use libipld::multihash::Code; +use libipld::prelude::Codec; +use libipld::store::DefaultParams; +use libipld::{Block, Cid, DagCbor, Ipld}; +use std::borrow::Cow; +use std::collections::BTreeMap; +use std::path::PathBuf; +use std::str::FromStr; + +pub struct RepoCommit { +    pub sig: Box<[u8]>, +    pub did: String, +    pub prev: Option<String>, +    pub mst_cid: String, +} + +pub struct RepoStore { +    db: BlockStore<libipld::DefaultParams>, +} + +impl RepoStore { +    pub fn open(db_path: &PathBuf) -> Result<Self> { +        Ok(RepoStore { +            db: BlockStore::open(db_path, Default::default())?, +        }) +    } + +    pub fn open_ephemeral() -> Result<Self> { +        Ok(RepoStore { +            db: BlockStore::open_path(ipfs_sqlite_block_store::DbPath::Memory, Default::default())?, +        }) +    } + +    pub fn get_ipld(&mut self, cid: &str) -> Result<Ipld> { +        let ipld_cid = Cid::from_str(cid)?; +        if let Some(b) = self.db.get_block(&ipld_cid)? { +            let block: Block<DefaultParams> = Block::new(ipld_cid, b)?; +            block.ipld() +        } else { +            Err(anyhow!("missing IPLD CID: {}", cid)) +        } +    } + +    pub fn get_blob(&mut self, cid: &str) -> Result<Option<Vec<u8>>> { +        let cid = Cid::from_str(cid)?; +        Ok(self.db.get_block(&cid)?) +    } + +    /// Returns CID that was inserted +    pub fn put_ipld(&mut self, record: &Ipld) -> Result<String> { +        let block = Block::<DefaultParams>::encode(DagCborCodec, Code::Sha2_256, record)?; +        let cid = block.cid().clone(); +        self.db.put_block(block, None)?; +        Ok(cid.to_string()) +    } + +    /// Returns CID that was inserted +    pub fn put_blob(&mut self, data: Vec<u8>) -> Result<String> { +        let block = Block::<DefaultParams>::encode(libipld::raw::RawCodec, Code::Sha2_256, &data)?; +        let cid = block.cid().clone(); +        self.db.put_block(block, None)?; +        Ok(cid.to_string()) +    } + +    /// Quick alias lookup +    pub fn get_root(&mut self, did: &str) -> Result<Option<String>> { +        Ok(self +            .db +            .resolve(Cow::from(did.as_bytes()))? +            .map(|cid| cid.to_string())) +    } + +    pub fn get_commit(&mut self, commit_cid: &str) -> Result<RepoCommit> { +        // read records by CID: commit, root, meta +        let commit_node: CommitNode = DagCborCodec.decode( +            &self +                .db +                .get_block(&Cid::from_str(commit_cid)?)? +                .ok_or(anyhow!("expected commit block in store"))?, +        )?; +        let root_node: RootNode = DagCborCodec.decode( +            &self +                .db +                .get_block(&commit_node.root)? +                .ok_or(anyhow!("expected root block in store"))?, +        )?; +        let metadata_node: MetadataNode = DagCborCodec.decode( +            &self +                .db +                .get_block(&root_node.meta)? +                .ok_or(anyhow!("expected metadata block in store"))?, +        )?; +        assert_eq!(metadata_node.datastore, "mst"); +        assert_eq!(metadata_node.version, 1); +        Ok(RepoCommit { +            sig: commit_node.sig, +            did: metadata_node.did, +            prev: root_node.prev.map(|cid| cid.to_string()), +            mst_cid: root_node.data.to_string(), +        }) +    } + +    pub fn get_record_by_key(&mut self, commit_cid: &str, key: &str) -> Result<Option<Ipld>> { +        let map = self.as_map(commit_cid)?; +        if let Some(cid) = map.get(key) { +            self.get_ipld(&cid.to_string()).map(|v| Some(v)) +        } else { +            Ok(None) +        } +    } + +    pub fn write_root(&mut self, did: &str, mst_cid: &str, prev: Option<&str>) -> Result<String> { +        unimplemented!() +    } + +    pub fn write_commit(&mut self, did: &str, root_cid: &str, sig: &str) -> Result<String> { +        // TODO: also update alias to point to new commit +        unimplemented!() +    } + +    pub fn write_map(&self, map: Result<BTreeMap<String, String>>) -> Result<String> { +        unimplemented!() +    } + +    fn as_cid_map(&mut self, commit_cid: &str) -> Result<BTreeMap<String, Cid>> { +        let commit = self.get_commit(commit_cid)?; +        let mut cid_map: BTreeMap<String, Cid> = Default::default(); +        let mst_cid = Cid::from_str(&commit.mst_cid)?; +        collect_mst_keys(&mut self.db, &mst_cid, &mut cid_map)?; +        Ok(cid_map) +    } + +    /// Returns all the keys for a directory, as a sorted vec of strings +    pub fn as_map(&mut self, commit_cid: &str) -> Result<BTreeMap<String, String>> { +        let cid_map = self.as_cid_map(commit_cid)?; +        let ret_map: BTreeMap<String, String> = +            BTreeMap::from_iter(cid_map.into_iter().map(|(k, v)| (k, v.to_string()))); +        Ok(ret_map) +    } + +    /// Exports in CAR format to a Writer +    /// +    /// The "from" commit CID feature is not implemented. +    pub fn write_car<W: std::io::Write>( +        &mut self, +        did: &str, +        _from_commit_cid: Option<&str>, +        out: &mut W, +    ) -> Result<()> { +        unimplemented!() +    } +} diff --git a/adenosine-pds/tests/test_repro_mst.rs b/adenosine-pds/tests/test_repro_mst.rs index ad5fba1..9a23c03 100644 --- a/adenosine-pds/tests/test_repro_mst.rs +++ b/adenosine-pds/tests/test_repro_mst.rs @@ -1,4 +1,4 @@ -use adenosine_pds::repro_mst; +use adenosine_pds::mst::repro_mst;  use std::path::PathBuf;  use std::str::FromStr; | 
