use crate::{
BlockStoreError, MAX_BLOCK_SIZE,
utils::{Arc, CondSend, CondSync},
};
use bytes::Bytes;
use cid::Cid;
use futures::Future;
use ipld_core::cid::Version;
use multihash::Multihash;
use parking_lot::Mutex;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
pub const CODEC_DAG_JSON: u64 = 0x0129;
pub const CODEC_DAG_CBOR: u64 = 0x71;
pub const CODEC_DAG_PB: u64 = 0x70;
pub const CODEC_RAW: u64 = 0x55;
pub const MULTIHASH_BLAKE3: u64 = 0x1e;
pub trait BlockStore: CondSync {
fn get_block(
&self,
cid: &Cid,
) -> impl Future<Output = Result<Bytes, BlockStoreError>> + CondSend;
fn put_block(
&self,
bytes: impl Into<Bytes> + CondSend,
codec: u64,
) -> impl Future<Output = Result<Cid, BlockStoreError>> + CondSend {
let bytes = bytes.into();
async move {
let cid = self.create_cid(&bytes, codec)?;
self.put_block_keyed(cid, bytes).await?;
Ok(cid)
}
}
fn put_block_keyed(
&self,
cid: Cid,
bytes: impl Into<Bytes> + CondSend,
) -> impl Future<Output = Result<(), BlockStoreError>> + CondSend;
fn has_block(
&self,
cid: &Cid,
) -> impl Future<Output = Result<bool, BlockStoreError>> + CondSend;
fn create_cid(&self, bytes: &[u8], codec: u64) -> Result<Cid, BlockStoreError> {
if bytes.len() > MAX_BLOCK_SIZE {
return Err(BlockStoreError::MaximumBlockSizeExceeded(bytes.len()));
}
let hash = Multihash::wrap(MULTIHASH_BLAKE3, blake3::hash(bytes).as_bytes()).unwrap();
let cid = Cid::new(Version::V1, codec, hash)?;
Ok(cid)
}
}
impl<B: BlockStore> BlockStore for &B {
async fn get_block(&self, cid: &Cid) -> Result<Bytes, BlockStoreError> {
(**self).get_block(cid).await
}
async fn put_block(
&self,
bytes: impl Into<Bytes> + CondSend,
codec: u64,
) -> Result<Cid, BlockStoreError> {
(**self).put_block(bytes, codec).await
}
async fn put_block_keyed(
&self,
cid: Cid,
bytes: impl Into<Bytes> + CondSend,
) -> Result<(), BlockStoreError> {
(**self).put_block_keyed(cid, bytes).await
}
async fn has_block(&self, cid: &Cid) -> Result<bool, BlockStoreError> {
(**self).has_block(cid).await
}
fn create_cid(&self, bytes: &[u8], codec: u64) -> Result<Cid, BlockStoreError> {
(**self).create_cid(bytes, codec)
}
}
impl<B: BlockStore> BlockStore for Box<B> {
async fn get_block(&self, cid: &Cid) -> Result<Bytes, BlockStoreError> {
(**self).get_block(cid).await
}
async fn put_block(
&self,
bytes: impl Into<Bytes> + CondSend,
codec: u64,
) -> Result<Cid, BlockStoreError> {
(**self).put_block(bytes, codec).await
}
async fn put_block_keyed(
&self,
cid: Cid,
bytes: impl Into<Bytes> + CondSend,
) -> Result<(), BlockStoreError> {
(**self).put_block_keyed(cid, bytes).await
}
async fn has_block(&self, cid: &Cid) -> Result<bool, BlockStoreError> {
(**self).has_block(cid).await
}
fn create_cid(&self, bytes: &[u8], codec: u64) -> Result<Cid, BlockStoreError> {
(**self).create_cid(bytes, codec)
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct MemoryBlockStore(
#[serde(serialize_with = "crate::utils::serialize_cid_map")]
#[serde(deserialize_with = "crate::utils::deserialize_cid_map")]
pub(crate) Arc<Mutex<HashMap<Cid, Bytes>>>,
);
impl MemoryBlockStore {
pub fn new() -> Self {
Self::default()
}
}
impl BlockStore for MemoryBlockStore {
async fn get_block(&self, cid: &Cid) -> Result<Bytes, BlockStoreError> {
let bytes = self
.0
.lock()
.get(cid)
.ok_or(BlockStoreError::CIDNotFound(*cid))?
.clone();
Ok(bytes)
}
async fn put_block_keyed(
&self,
cid: Cid,
bytes: impl Into<Bytes> + CondSend,
) -> Result<(), BlockStoreError> {
self.0.lock().insert(cid, bytes.into());
Ok(())
}
async fn has_block(&self, cid: &Cid) -> Result<bool, BlockStoreError> {
Ok(self.0.lock().contains_key(cid))
}
}