mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-29 19:58:10 -07:00
global: cleanup
This commit is contained in:
@@ -24,7 +24,7 @@ color-eyre = { workspace = true }
|
||||
log = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
toml = "0.9.2"
|
||||
toml = "0.9.3"
|
||||
|
||||
[[bin]]
|
||||
name = "brk"
|
||||
|
||||
@@ -8,7 +8,6 @@ homepage.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
bincode = { workspace = true }
|
||||
bitcoin = { workspace = true }
|
||||
bitcoincore-rpc = { workspace = true }
|
||||
brk_core = { workspace = true }
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
fs::{self, File},
|
||||
io::{BufReader, BufWriter},
|
||||
fs,
|
||||
io::{Cursor, Read},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use bincode::{Decode, Encode, config, decode_from_std_read, encode_into_std_write};
|
||||
use brk_core::{Dollars, Height, Result, Sats};
|
||||
use brk_core::{Dollars, Error, Height, Result, Sats};
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zerocopy::{FromBytes, IntoBytes};
|
||||
|
||||
use crate::states::SupplyState;
|
||||
|
||||
@@ -19,9 +19,6 @@ pub struct PriceToAmount {
|
||||
state: State,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug, Deref, DerefMut, Serialize, Deserialize, Encode, Decode)]
|
||||
struct State(BTreeMap<Dollars, Sats>);
|
||||
|
||||
impl PriceToAmount {
|
||||
pub fn forced_import(path: &Path, name: &str) -> Self {
|
||||
Self::import(path, name).unwrap_or_else(|_| Self {
|
||||
@@ -35,10 +32,7 @@ impl PriceToAmount {
|
||||
let path = Self::path_(path, name);
|
||||
fs::create_dir_all(&path)?;
|
||||
|
||||
let config = config::standard();
|
||||
let file = File::open(Self::path_state_(&path))?;
|
||||
let mut reader = BufReader::new(file);
|
||||
let state = decode_from_std_read(&mut reader, config)?;
|
||||
let state = State::deserialize(&fs::read(&path)?)?;
|
||||
|
||||
Ok(Self {
|
||||
height: Height::try_from(Self::path_height_(&path).as_path()).ok(),
|
||||
@@ -86,13 +80,7 @@ impl PriceToAmount {
|
||||
pub fn flush(&mut self, height: Height) -> Result<()> {
|
||||
self.height = Some(height);
|
||||
height.write(&self.path_height())?;
|
||||
|
||||
let file = File::create(self.path_state()).inspect_err(|_| {
|
||||
dbg!(self.path_state());
|
||||
})?;
|
||||
let mut writer = BufWriter::new(file);
|
||||
encode_into_std_write(&self.state, &mut writer, config::standard())?;
|
||||
|
||||
fs::write(self.path_state(), self.state.serialize())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -118,3 +106,47 @@ impl PriceToAmount {
|
||||
path.join("height")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug, Deref, DerefMut, Serialize, Deserialize)]
|
||||
struct State(BTreeMap<Dollars, Sats>);
|
||||
|
||||
impl State {
|
||||
fn serialize(&self) -> Vec<u8> {
|
||||
let len = self.len();
|
||||
|
||||
let mut buffer = Vec::with_capacity(8 + len * 16);
|
||||
|
||||
buffer.extend_from_slice(len.as_bytes());
|
||||
|
||||
self.iter().for_each(|(key, value)| {
|
||||
buffer.extend_from_slice(key.as_bytes());
|
||||
buffer.extend_from_slice(value.as_bytes());
|
||||
});
|
||||
|
||||
buffer
|
||||
}
|
||||
|
||||
fn deserialize(data: &[u8]) -> Result<Self> {
|
||||
let mut cursor = Cursor::new(data);
|
||||
let mut buffer = [0u8; 8];
|
||||
|
||||
cursor
|
||||
.read_exact(&mut buffer)
|
||||
.map_err(|_| Error::Str("Failed to read entry count"))?;
|
||||
let entry_count = usize::read_from_bytes(&buffer)?;
|
||||
|
||||
let mut map = BTreeMap::new();
|
||||
|
||||
for _ in 0..entry_count {
|
||||
cursor.read_exact(&mut buffer)?;
|
||||
let key = Dollars::read_from_bytes(&buffer)?;
|
||||
|
||||
cursor.read_exact(&mut buffer)?;
|
||||
let value = Sats::read_from_bytes(&buffer)?;
|
||||
|
||||
map.insert(key, value);
|
||||
}
|
||||
|
||||
Ok(Self(map))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ homepage.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
bincode = { workspace = true }
|
||||
bitcoin = { workspace = true }
|
||||
bitcoincore-rpc = { workspace = true }
|
||||
byteview = { workspace = true }
|
||||
|
||||
@@ -15,8 +15,6 @@ pub enum Error {
|
||||
Fjall(fjall::Error),
|
||||
SystemTimeError(time::SystemTimeError),
|
||||
ZeroCopyError,
|
||||
BincodeEncodeError(bincode::error::EncodeError),
|
||||
BincodeDecodeError(bincode::error::DecodeError),
|
||||
|
||||
WrongEndian,
|
||||
DifferentVersion { found: Version, expected: Version },
|
||||
@@ -81,18 +79,6 @@ impl From<serde_json::Error> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bincode::error::DecodeError> for Error {
|
||||
fn from(error: bincode::error::DecodeError) -> Self {
|
||||
Self::BincodeDecodeError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bincode::error::EncodeError> for Error {
|
||||
fn from(error: bincode::error::EncodeError) -> Self {
|
||||
Self::BincodeEncodeError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
@@ -101,8 +87,6 @@ impl fmt::Display for Error {
|
||||
Error::SerdeJson(error) => Debug::fmt(&error, f),
|
||||
Error::Jiff(error) => Debug::fmt(&error, f),
|
||||
Error::Fjall(error) => Debug::fmt(&error, f),
|
||||
Error::BincodeDecodeError(error) => Debug::fmt(&error, f),
|
||||
Error::BincodeEncodeError(error) => Debug::fmt(&error, f),
|
||||
Error::ZeroCopyError => write!(f, "ZeroCopy error"),
|
||||
Error::UnexpectedData => write!(f, "Unexpected data"),
|
||||
|
||||
|
||||
@@ -4,13 +4,11 @@ use std::{
|
||||
ops::{Add, AddAssign, Div, Mul},
|
||||
};
|
||||
|
||||
use bincode::{Decode, Encode};
|
||||
use byteview::ByteView;
|
||||
use derive_deref::Deref;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{CheckedSub, copy_first_8bytes};
|
||||
use crate::CheckedSub;
|
||||
|
||||
use super::{Bitcoin, Cents, Close, High, Sats, StoredF32, StoredF64};
|
||||
|
||||
@@ -26,8 +24,6 @@ use super::{Bitcoin, Cents, Close, High, Sats, StoredF32, StoredF64};
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
)]
|
||||
pub struct Dollars(f64);
|
||||
|
||||
@@ -362,22 +358,3 @@ impl Ord for Dollars {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for Dollars {
|
||||
fn from(value: ByteView) -> Self {
|
||||
let bytes = copy_first_8bytes(&value).unwrap();
|
||||
Self::from(f64::from_be_bytes(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dollars> for ByteView {
|
||||
fn from(value: Dollars) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Dollars> for ByteView {
|
||||
fn from(value: &Dollars) -> Self {
|
||||
Self::new(&value.to_be_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use std::ops::Add;
|
||||
|
||||
use byteview::ByteView;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, IntoBytes};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{CheckedSub, Printable, TypeIndex};
|
||||
@@ -76,19 +74,3 @@ impl Printable for P2AAddressIndex {
|
||||
&["aaddr", "p2aaddr", "p2aaddressindex"]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for P2AAddressIndex {
|
||||
fn from(value: ByteView) -> Self {
|
||||
Self::read_from_bytes(&value).unwrap()
|
||||
}
|
||||
}
|
||||
impl From<P2AAddressIndex> for ByteView {
|
||||
fn from(value: P2AAddressIndex) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&P2AAddressIndex> for ByteView {
|
||||
fn from(value: &P2AAddressIndex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use std::ops::Add;
|
||||
|
||||
use byteview::ByteView;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, IntoBytes};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{CheckedSub, Printable, TypeIndex};
|
||||
@@ -77,19 +75,3 @@ impl Printable for P2PK33AddressIndex {
|
||||
&["pk33addr", "p2pk33addr", "p2pk33addressindex"]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for P2PK33AddressIndex {
|
||||
fn from(value: ByteView) -> Self {
|
||||
Self::read_from_bytes(&value).unwrap()
|
||||
}
|
||||
}
|
||||
impl From<P2PK33AddressIndex> for ByteView {
|
||||
fn from(value: P2PK33AddressIndex) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&P2PK33AddressIndex> for ByteView {
|
||||
fn from(value: &P2PK33AddressIndex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use std::ops::Add;
|
||||
|
||||
use byteview::ByteView;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, IntoBytes};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{CheckedSub, Printable, TypeIndex};
|
||||
@@ -76,19 +74,3 @@ impl Printable for P2PK65AddressIndex {
|
||||
&["pk65addr", "p2pk65addr", "p2pk65addressindex"]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for P2PK65AddressIndex {
|
||||
fn from(value: ByteView) -> Self {
|
||||
Self::read_from_bytes(&value).unwrap()
|
||||
}
|
||||
}
|
||||
impl From<P2PK65AddressIndex> for ByteView {
|
||||
fn from(value: P2PK65AddressIndex) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&P2PK65AddressIndex> for ByteView {
|
||||
fn from(value: &P2PK65AddressIndex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use std::ops::Add;
|
||||
|
||||
use byteview::ByteView;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, IntoBytes};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{CheckedSub, Printable, TypeIndex};
|
||||
@@ -77,19 +75,3 @@ impl Printable for P2PKHAddressIndex {
|
||||
&["pkhaddr", "p2pkhaddr", "p2pkhaddressindex"]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for P2PKHAddressIndex {
|
||||
fn from(value: ByteView) -> Self {
|
||||
Self::read_from_bytes(&value).unwrap()
|
||||
}
|
||||
}
|
||||
impl From<P2PKHAddressIndex> for ByteView {
|
||||
fn from(value: P2PKHAddressIndex) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&P2PKHAddressIndex> for ByteView {
|
||||
fn from(value: &P2PKHAddressIndex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use std::ops::Add;
|
||||
|
||||
use byteview::ByteView;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, IntoBytes};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{CheckedSub, Printable, TypeIndex};
|
||||
@@ -77,19 +75,3 @@ impl Printable for P2SHAddressIndex {
|
||||
&["shaddr", "p2shaddr", "p2shaddressindex"]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for P2SHAddressIndex {
|
||||
fn from(value: ByteView) -> Self {
|
||||
Self::read_from_bytes(&value).unwrap()
|
||||
}
|
||||
}
|
||||
impl From<P2SHAddressIndex> for ByteView {
|
||||
fn from(value: P2SHAddressIndex) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&P2SHAddressIndex> for ByteView {
|
||||
fn from(value: &P2SHAddressIndex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use std::ops::Add;
|
||||
|
||||
use byteview::ByteView;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, IntoBytes};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{CheckedSub, Printable, TypeIndex};
|
||||
@@ -77,19 +75,3 @@ impl Printable for P2TRAddressIndex {
|
||||
&["traddr", "p2traddr", "p2traddressindex"]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for P2TRAddressIndex {
|
||||
fn from(value: ByteView) -> Self {
|
||||
Self::read_from_bytes(&value).unwrap()
|
||||
}
|
||||
}
|
||||
impl From<P2TRAddressIndex> for ByteView {
|
||||
fn from(value: P2TRAddressIndex) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&P2TRAddressIndex> for ByteView {
|
||||
fn from(value: &P2TRAddressIndex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use std::ops::Add;
|
||||
|
||||
use byteview::ByteView;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, IntoBytes};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{CheckedSub, Printable, TypeIndex};
|
||||
@@ -77,19 +75,3 @@ impl Printable for P2WPKHAddressIndex {
|
||||
&["wpkhaddr", "p2wpkhaddr", "p2wpkhaddressindex"]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for P2WPKHAddressIndex {
|
||||
fn from(value: ByteView) -> Self {
|
||||
Self::read_from_bytes(&value).unwrap()
|
||||
}
|
||||
}
|
||||
impl From<P2WPKHAddressIndex> for ByteView {
|
||||
fn from(value: P2WPKHAddressIndex) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&P2WPKHAddressIndex> for ByteView {
|
||||
fn from(value: &P2WPKHAddressIndex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use std::ops::Add;
|
||||
|
||||
use byteview::ByteView;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use serde::Serialize;
|
||||
use zerocopy::{FromBytes, IntoBytes};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{CheckedSub, Printable, TypeIndex};
|
||||
@@ -77,19 +75,3 @@ impl Printable for P2WSHAddressIndex {
|
||||
&["wshaddr", "p2wshaddr", "p2wshaddressindex"]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for P2WSHAddressIndex {
|
||||
fn from(value: ByteView) -> Self {
|
||||
Self::read_from_bytes(&value).unwrap()
|
||||
}
|
||||
}
|
||||
impl From<P2WSHAddressIndex> for ByteView {
|
||||
fn from(value: P2WSHAddressIndex) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
impl From<&P2WSHAddressIndex> for ByteView {
|
||||
fn from(value: &P2WSHAddressIndex) -> Self {
|
||||
Self::new(value.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,12 @@ use std::{
|
||||
ops::{Add, AddAssign, Div, Mul, SubAssign},
|
||||
};
|
||||
|
||||
use bincode::{Decode, Encode};
|
||||
use bitcoin::Amount;
|
||||
use byteview::ByteView;
|
||||
use derive_deref::Deref;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
|
||||
|
||||
use crate::{CheckedSub, StoredF64, copy_first_8bytes};
|
||||
use crate::{CheckedSub, StoredF64};
|
||||
|
||||
use super::{Bitcoin, Cents, Dollars, Height};
|
||||
|
||||
@@ -21,6 +20,7 @@ use super::{Bitcoin, Cents, Dollars, Height};
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Deref,
|
||||
Default,
|
||||
FromBytes,
|
||||
Immutable,
|
||||
@@ -28,8 +28,6 @@ use super::{Bitcoin, Cents, Dollars, Height};
|
||||
KnownLayout,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
)]
|
||||
pub struct Sats(u64);
|
||||
|
||||
@@ -243,25 +241,6 @@ impl From<Sats> for u128 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ByteView> for Sats {
|
||||
fn from(value: ByteView) -> Self {
|
||||
let bytes = copy_first_8bytes(&value).unwrap();
|
||||
Self::from(u64::from_be_bytes(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Sats> for ByteView {
|
||||
fn from(value: &Sats) -> Self {
|
||||
Self::new(&value.0.to_be_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Sats> for ByteView {
|
||||
fn from(value: Sats) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Sats> for usize {
|
||||
type Output = Sats;
|
||||
fn mul(self, rhs: Sats) -> Self::Output {
|
||||
|
||||
@@ -30,6 +30,7 @@ impl From<ByteView> for TypeIndexWithOutputindex {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TypeIndexWithOutputindex> for ByteView {
|
||||
fn from(value: TypeIndexWithOutputindex) -> Self {
|
||||
ByteView::from(&value)
|
||||
|
||||
@@ -14,10 +14,12 @@ fn main() -> color_eyre::Result<()> {
|
||||
|
||||
brk_logger::init(Some(Path::new(".log")));
|
||||
|
||||
// let bitcoin_dir = brk_core::default_bitcoin_path();
|
||||
let bitcoin_dir = Path::new("/Volumes/WD_BLACK1/bitcoin");
|
||||
let bitcoin_dir = brk_core::default_bitcoin_path();
|
||||
// let bitcoin_dir = Path::new("/Volumes/WD_BLACK1/bitcoin");
|
||||
let outputs_dir = Path::new("./_outputs");
|
||||
fs::create_dir_all(outputs_dir)?;
|
||||
// let outputs_dir = brk_core::default_brk_path().join("outputs");
|
||||
let outputs_dir = Path::new("/Volumes/WD_BLACK1/brk");
|
||||
// let outputs_dir = Path::new("/Volumes/WD_BLACK1/brk");
|
||||
|
||||
let rpc = Box::leak(Box::new(bitcoincore_rpc::Client::new(
|
||||
"http://localhost:8332",
|
||||
|
||||
@@ -14,9 +14,8 @@ brk_indexer = { workspace = true }
|
||||
brk_vecs = { workspace = true }
|
||||
color-eyre = { workspace = true }
|
||||
derive_deref = { workspace = true }
|
||||
rmcp = { workspace = true }
|
||||
schemars = { workspace = true }
|
||||
schemars = "1.0.4"
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
serde_with = "3.14.0"
|
||||
tabled = { workspace = true }
|
||||
tabled = "0.20.0"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use color_eyre::eyre::eyre;
|
||||
use rmcp::schemars::JsonSchema;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
use rmcp::schemars::{self, JsonSchema};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
|
||||
@@ -11,4 +11,7 @@ repository.workspace = true
|
||||
axum = { workspace = true }
|
||||
brk_interface = { workspace = true }
|
||||
log = { workspace = true }
|
||||
rmcp = { workspace = true }
|
||||
brk_rmcp = { version = "0.3.0", features = [
|
||||
"transport-worker",
|
||||
"transport-streamable-http-server",
|
||||
] }
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
// #![doc = "```"]
|
||||
|
||||
use brk_interface::{IdParam, Interface, PaginatedIndexParam, PaginationParam, Params};
|
||||
use log::info;
|
||||
use rmcp::{
|
||||
use brk_rmcp::{
|
||||
ErrorData as McpError, RoleServer, ServerHandler,
|
||||
handler::server::{router::tool::ToolRouter, tool::Parameters},
|
||||
model::*,
|
||||
service::RequestContext,
|
||||
tool, tool_handler, tool_router,
|
||||
};
|
||||
use log::info;
|
||||
|
||||
pub mod route;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use axum::Router;
|
||||
use brk_interface::Interface;
|
||||
use rmcp::transport::{
|
||||
use brk_rmcp::transport::{
|
||||
StreamableHttpServerConfig,
|
||||
streamable_http_server::{StreamableHttpService, session::local::LocalSessionManager},
|
||||
};
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::{Dollars, Height, Result, Sats, Version};
|
||||
use brk_store::{AnyStore, Store};
|
||||
use brk_core::Result;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let p = Path::new("./examples/_fjall");
|
||||
|
||||
let keyspace = brk_store::open_keyspace(p)?;
|
||||
|
||||
let mut store: Store<Dollars, Sats> =
|
||||
brk_store::Store::import(&keyspace, p, "n", Version::ZERO, None)?;
|
||||
// let mut store: Store<usize, usize> =
|
||||
// brk_store::Store::import(&keyspace, p, "n", Version::ZERO, None)?;
|
||||
|
||||
store.insert_if_needed(Dollars::from(10.0), Sats::FIFTY_BTC, Height::ZERO);
|
||||
// store.insert_if_needed(Sats::new(10), Sats::FIFTY_BTC, Height::ZERO);
|
||||
|
||||
store.commit(Height::ZERO)?;
|
||||
// store.commit(Height::ZERO)?;
|
||||
|
||||
store.persist()?;
|
||||
// store.persist()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use super::{Region, Regions};
|
||||
pub struct Layout {
|
||||
start_to_index: BTreeMap<u64, usize>,
|
||||
start_to_hole: BTreeMap<u64, u64>,
|
||||
start_to_reserved: BTreeMap<u64, u64>,
|
||||
}
|
||||
|
||||
impl From<&Regions> for Layout {
|
||||
@@ -43,6 +44,7 @@ impl From<&Regions> for Layout {
|
||||
Self {
|
||||
start_to_index,
|
||||
start_to_hole,
|
||||
start_to_reserved: BTreeMap::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,28 +58,73 @@ impl Layout {
|
||||
&self.start_to_hole
|
||||
}
|
||||
|
||||
pub fn get_last_region(&self) -> Option<(u64, usize)> {
|
||||
self.start_to_index
|
||||
.last_key_value()
|
||||
.map(|(start, index)| (*start, *index))
|
||||
pub fn len(&self, regions: &Regions) -> u64 {
|
||||
let mut len = 0;
|
||||
let mut start = 0;
|
||||
if let Some((start_reserved, reserved)) = self.get_last_reserved() {
|
||||
start = start_reserved;
|
||||
len = start + reserved;
|
||||
}
|
||||
if let Some((hole_start, gap)) = self.get_last_hole()
|
||||
&& hole_start > start
|
||||
{
|
||||
start = hole_start;
|
||||
len = start + gap;
|
||||
}
|
||||
if let Some((region_start, region_index)) = self.get_last_region()
|
||||
&& region_start > start
|
||||
{
|
||||
len = region_start
|
||||
+ regions
|
||||
.get_region_from_index(region_index)
|
||||
.unwrap()
|
||||
.read()
|
||||
.reserved();
|
||||
}
|
||||
len
|
||||
}
|
||||
|
||||
pub fn get_last_region_index(&self) -> Option<usize> {
|
||||
self.get_last_region().map(|(_, index)| index)
|
||||
}
|
||||
|
||||
pub fn is_last_region(&self, index: usize) -> bool {
|
||||
let last = self.get_last_region();
|
||||
let is_last = last.is_some_and(|(_, other_index)| index == other_index);
|
||||
if is_last {
|
||||
assert!(self.start_to_hole.range(last.unwrap().0..).next().is_none());
|
||||
pub fn get_last_region(&self) -> Option<(u64, usize)> {
|
||||
self.start_to_index
|
||||
.last_key_value()
|
||||
.map(|(start, index)| (*start, *index))
|
||||
}
|
||||
|
||||
fn get_last_hole(&self) -> Option<(u64, u64)> {
|
||||
self.start_to_hole
|
||||
.last_key_value()
|
||||
.map(|(start, gap)| (*start, *gap))
|
||||
}
|
||||
|
||||
fn get_last_reserved(&self) -> Option<(u64, u64)> {
|
||||
self.start_to_reserved
|
||||
.last_key_value()
|
||||
.map(|(start, reserved)| (*start, *reserved))
|
||||
}
|
||||
|
||||
pub fn is_last_anything(&self, index: usize) -> bool {
|
||||
if let Some((last_start, last_index)) = self.get_last_region()
|
||||
&& last_index == index
|
||||
&& self
|
||||
.get_last_hole()
|
||||
.is_none_or(|(hole_start, _)| last_start > hole_start)
|
||||
&& self
|
||||
.get_last_reserved()
|
||||
.is_none_or(|(reserved_start, _)| last_start > reserved_start)
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
is_last
|
||||
}
|
||||
|
||||
pub fn insert_region(&mut self, start: u64, index: usize) {
|
||||
assert!(self.start_to_index.insert(start, index).is_none())
|
||||
// TODO: Other checks related to holes ?
|
||||
// TODO: Other checks related to holes and reserved ?
|
||||
}
|
||||
|
||||
pub fn move_region(&mut self, new_start: u64, index: usize, region: &Region) -> Result<()> {
|
||||
@@ -87,14 +134,15 @@ impl Layout {
|
||||
}
|
||||
|
||||
pub fn remove_region(&mut self, index: usize, region: &Region) -> Result<()> {
|
||||
// info!("Remove region {index}");
|
||||
|
||||
let start = region.start();
|
||||
let mut reserved = region.reserved();
|
||||
|
||||
if self
|
||||
.start_to_index
|
||||
.remove(&start)
|
||||
.is_none_or(|index_| index != index_)
|
||||
{
|
||||
let removed = self.start_to_index.remove(&start);
|
||||
|
||||
if removed.is_none_or(|index_| index != index_) {
|
||||
dbg!((index, removed));
|
||||
return Err(Error::Str(
|
||||
"Something went wrong, indexes of removed region should be the same",
|
||||
));
|
||||
@@ -105,19 +153,7 @@ impl Layout {
|
||||
.remove(&(start + reserved))
|
||||
.unwrap_or_default();
|
||||
|
||||
if self
|
||||
.start_to_index
|
||||
.keys()
|
||||
.last()
|
||||
.is_none_or(|®ion_start| {
|
||||
self.start_to_hole
|
||||
.keys()
|
||||
.last()
|
||||
.is_some_and(|&hole_start| hole_start > region_start)
|
||||
})
|
||||
{
|
||||
self.start_to_hole.pop_last();
|
||||
} else if let Some((&hole_start, gap)) = self.start_to_hole.range_mut(..start).next_back()
|
||||
if let Some((&hole_start, gap)) = self.start_to_hole.range_mut(..start).next_back()
|
||||
&& hole_start + *gap == start
|
||||
{
|
||||
*gap += reserved;
|
||||
@@ -142,7 +178,7 @@ impl Layout {
|
||||
.map(|(_, s)| *s)
|
||||
}
|
||||
|
||||
pub fn remove_or_compress_hole_to_right(&mut self, start: u64, compress_by: u64) {
|
||||
pub fn remove_or_compress_hole(&mut self, start: u64, compress_by: u64) {
|
||||
if let Some(gap) = self.start_to_hole.remove(&start)
|
||||
&& gap != compress_by
|
||||
{
|
||||
@@ -154,4 +190,10 @@ impl Layout {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reserve(&mut self, start: u64, reserved: u64) {
|
||||
if self.start_to_reserved.insert(start, reserved).is_some() {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ impl File {
|
||||
let mut layout = self.layout.write();
|
||||
|
||||
let start = if let Some(start) = layout.find_smallest_adequate_hole(PAGE_SIZE) {
|
||||
layout.remove_or_compress_hole_to_right(start, PAGE_SIZE);
|
||||
layout.remove_or_compress_hole(start, PAGE_SIZE);
|
||||
start
|
||||
} else {
|
||||
let start = layout
|
||||
@@ -204,8 +204,6 @@ impl File {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// let layouat_lock = self.layout.read();
|
||||
|
||||
assert!(new_len > reserved);
|
||||
let mut new_reserved = reserved;
|
||||
while new_len > new_reserved {
|
||||
@@ -217,22 +215,21 @@ impl File {
|
||||
let mut layout = self.layout.write();
|
||||
|
||||
// If is last continue writing
|
||||
if layout.is_last_region(region_index) {
|
||||
if layout.is_last_anything(region_index) {
|
||||
// println!(
|
||||
// "{region_index} Append to file at {}",
|
||||
// start + at.unwrap_or(len)
|
||||
// );
|
||||
|
||||
self.set_min_len(start + new_reserved)?;
|
||||
|
||||
if at.is_none() {
|
||||
self.write(start + len, data);
|
||||
}
|
||||
let mut region = region_lock.write();
|
||||
region.set_reserved(new_reserved);
|
||||
if let Some(at) = at {
|
||||
self.write(start + at, data);
|
||||
}
|
||||
drop(region);
|
||||
drop(layout);
|
||||
|
||||
self.write(start + len, data);
|
||||
|
||||
let mut region = region_lock.write();
|
||||
region.set_len(new_len);
|
||||
regions.write_to_mmap(®ion, region_index);
|
||||
|
||||
@@ -247,19 +244,18 @@ impl File {
|
||||
{
|
||||
// println!("Expand {region_index} to hole");
|
||||
|
||||
layout.remove_or_compress_hole_to_right(hole_start, added_reserve);
|
||||
drop(layout);
|
||||
|
||||
if at.is_none() {
|
||||
self.write(start + len, data);
|
||||
}
|
||||
layout.remove_or_compress_hole(hole_start, added_reserve);
|
||||
let mut region = region_lock.write();
|
||||
region.set_reserved(new_reserved);
|
||||
if let Some(at) = at {
|
||||
self.write(start + at, data);
|
||||
}
|
||||
drop(region);
|
||||
drop(layout);
|
||||
|
||||
self.write(start + len, data);
|
||||
|
||||
let mut region = region_lock.write();
|
||||
region.set_len(new_len);
|
||||
regions.write_to_mmap(®ion, region_index);
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -267,8 +263,8 @@ impl File {
|
||||
if let Some(hole_start) = layout.find_smallest_adequate_hole(new_reserved) {
|
||||
// println!("Move {region_index} to hole at {hole_start}");
|
||||
|
||||
layout.remove_or_compress_hole_to_right(hole_start, new_reserved);
|
||||
// drop(layout);
|
||||
layout.remove_or_compress_hole(hole_start, new_reserved);
|
||||
drop(layout);
|
||||
|
||||
self.write(
|
||||
hole_start,
|
||||
@@ -276,39 +272,29 @@ impl File {
|
||||
);
|
||||
self.write(hole_start + len, data);
|
||||
|
||||
// let mut layout = self.layout.write();
|
||||
let mut region = region_lock.write();
|
||||
let mut layout = self.layout.write();
|
||||
layout.move_region(hole_start, region_index, ®ion)?;
|
||||
drop(layout);
|
||||
|
||||
region.set_start(hole_start);
|
||||
region.set_reserved(new_reserved);
|
||||
region.set_len(new_len);
|
||||
|
||||
drop(layout);
|
||||
|
||||
regions.write_to_mmap(®ion, region_index);
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let new_start = layout.len(®ions);
|
||||
// Write at the end
|
||||
// let mut region_lock = region.write();
|
||||
let (last_region_start, last_region_index) = layout.get_last_region().unwrap();
|
||||
let new_start = last_region_start
|
||||
+ regions
|
||||
.get_region_from_index(last_region_index)
|
||||
.unwrap()
|
||||
.read()
|
||||
.reserved();
|
||||
// println!(
|
||||
// "Move {region_index} to the end, from {start}..{} to {new_start}..{}",
|
||||
// start + reserved,
|
||||
// new_start + new_reserved
|
||||
// );
|
||||
|
||||
self.set_min_len(new_start + new_reserved)?;
|
||||
|
||||
let mut region = region_lock.write();
|
||||
layout.move_region(new_start, region_index, ®ion)?;
|
||||
layout.reserve(new_start, new_reserved);
|
||||
drop(layout);
|
||||
|
||||
self.write(
|
||||
new_start,
|
||||
@@ -316,14 +302,14 @@ impl File {
|
||||
);
|
||||
self.write(new_start + len, data);
|
||||
|
||||
// dbg!(new_start, region_index, ®ion_lock, new_reserved, new_len);
|
||||
let mut region = region_lock.write();
|
||||
let mut layout = self.layout.write();
|
||||
layout.move_region(new_start, region_index, ®ion)?;
|
||||
drop(layout);
|
||||
|
||||
region.set_start(new_start);
|
||||
region.set_reserved(new_reserved);
|
||||
region.set_len(new_len);
|
||||
|
||||
drop(layout);
|
||||
|
||||
regions.write_to_mmap(®ion, region_index);
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -34,8 +34,7 @@ impl Regions {
|
||||
let id_to_index_path = path.join("id_to_index");
|
||||
|
||||
let id_to_index: HashMap<String, usize> =
|
||||
deserialize_hashmap_binary(&fs::read(&id_to_index_path).unwrap_or_default())
|
||||
.unwrap_or_default();
|
||||
Self::deserialize(&fs::read(&id_to_index_path).unwrap_or_default()).unwrap_or_default();
|
||||
|
||||
let index_to_region_file = OpenOptions::new()
|
||||
.read(true)
|
||||
@@ -123,10 +122,7 @@ impl Regions {
|
||||
}
|
||||
|
||||
fn flush_id_to_index(&mut self) -> Result<()> {
|
||||
fs::write(
|
||||
&self.id_to_index_path,
|
||||
serialize_hashmap_binary(&self.id_to_index),
|
||||
)?;
|
||||
fs::write(&self.id_to_index_path, Self::serialize(&self.id_to_index))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -231,52 +227,49 @@ impl Regions {
|
||||
pub fn flush(&self) -> Result<()> {
|
||||
self.index_to_region_mmap.flush().map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_hashmap_binary(map: &HashMap<String, usize>) -> Vec<u8> {
|
||||
let mut buffer = Vec::new();
|
||||
fn serialize(map: &HashMap<String, usize>) -> Vec<u8> {
|
||||
let mut buffer = Vec::new();
|
||||
|
||||
buffer.extend_from_slice(&map.len().to_ne_bytes());
|
||||
buffer.extend_from_slice(&map.len().to_ne_bytes());
|
||||
|
||||
for (key, value) in map {
|
||||
buffer.extend_from_slice(&key.len().to_ne_bytes());
|
||||
buffer.extend_from_slice(key.as_bytes());
|
||||
buffer.extend_from_slice(&value.to_ne_bytes());
|
||||
for (key, value) in map {
|
||||
buffer.extend_from_slice(key.len().as_bytes());
|
||||
buffer.extend_from_slice(key.as_bytes());
|
||||
buffer.extend_from_slice(value.as_bytes());
|
||||
}
|
||||
|
||||
buffer
|
||||
}
|
||||
|
||||
buffer
|
||||
}
|
||||
|
||||
fn deserialize_hashmap_binary(data: &[u8]) -> Result<HashMap<String, usize>> {
|
||||
let mut cursor = Cursor::new(data);
|
||||
let mut buffer = [0u8; 8];
|
||||
|
||||
cursor
|
||||
.read_exact(&mut buffer)
|
||||
.map_err(|_| Error::Str("Failed to read entry count"))?;
|
||||
let entry_count = usize::from_ne_bytes(buffer);
|
||||
|
||||
let mut map = HashMap::with_capacity(entry_count);
|
||||
|
||||
for _ in 0..entry_count {
|
||||
cursor
|
||||
.read_exact(&mut buffer)
|
||||
.map_err(|_| Error::Str("Failed to read key length"))?;
|
||||
let key_len = usize::from_ne_bytes(buffer);
|
||||
|
||||
let mut key_bytes = vec![0u8; key_len];
|
||||
cursor
|
||||
.read_exact(&mut key_bytes)
|
||||
.map_err(|_| Error::Str("Failed to read key"))?;
|
||||
let key = String::from_utf8(key_bytes).map_err(|_| Error::Str("Invalid UTF-8 in key"))?;
|
||||
fn deserialize(data: &[u8]) -> Result<HashMap<String, usize>> {
|
||||
let mut cursor = Cursor::new(data);
|
||||
let mut buffer = [0u8; 8];
|
||||
|
||||
cursor
|
||||
.read_exact(&mut buffer)
|
||||
.map_err(|_| Error::Str("Failed to read value"))?;
|
||||
let value = usize::from_ne_bytes(buffer);
|
||||
.map_err(|_| Error::Str("Failed to read entry count"))?;
|
||||
let entry_count = usize::read_from_bytes(&buffer)?;
|
||||
|
||||
map.insert(key, value);
|
||||
let mut map = HashMap::with_capacity(entry_count);
|
||||
|
||||
for _ in 0..entry_count {
|
||||
cursor
|
||||
.read_exact(&mut buffer)
|
||||
.map_err(|_| Error::Str("Failed to read key length"))?;
|
||||
let key_len = usize::read_from_bytes(&buffer)?;
|
||||
|
||||
let mut key_bytes = vec![0u8; key_len];
|
||||
cursor.read_exact(&mut key_bytes)?;
|
||||
let key =
|
||||
String::from_utf8(key_bytes).map_err(|_| Error::Str("Invalid UTF-8 in key"))?;
|
||||
|
||||
cursor.read_exact(&mut buffer)?;
|
||||
let value = usize::read_from_bytes(&buffer)?;
|
||||
|
||||
map.insert(key, value);
|
||||
}
|
||||
|
||||
Ok(map)
|
||||
}
|
||||
|
||||
Ok(map)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user