summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--adenosine-pds/src/atp_db.sql11
-rw-r--r--adenosine-pds/src/bin/adenosine-pds.rs2
-rw-r--r--adenosine-pds/src/db.rs4
-rw-r--r--adenosine-pds/src/lib.rs5
-rw-r--r--adenosine-pds/src/mst.rs26
-rw-r--r--adenosine-pds/src/repo.rs156
-rw-r--r--adenosine-pds/tests/test_repro_mst.rs2
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;