mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-22 12:23:04 -07:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 903e69ff77 | |||
| c4167ddaad | |||
| 50bfdb0d68 | |||
| a6cb09ff1c | |||
| e4c9f23476 | |||
| 44e5415d43 | |||
| 1c653693ed | |||
| 39c470ad7a |
Generated
+31
-30
@@ -443,7 +443,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk"
|
||||
version = "0.0.67"
|
||||
version = "0.0.71"
|
||||
dependencies = [
|
||||
"brk_bundler",
|
||||
"brk_cli",
|
||||
@@ -464,7 +464,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_bundler"
|
||||
version = "0.0.67"
|
||||
version = "0.0.71"
|
||||
dependencies = [
|
||||
"brk_rolldown",
|
||||
"log",
|
||||
@@ -475,7 +475,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_cli"
|
||||
version = "0.0.67"
|
||||
version = "0.0.71"
|
||||
dependencies = [
|
||||
"bitcoincore-rpc",
|
||||
"brk_computer",
|
||||
@@ -498,7 +498,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_computer"
|
||||
version = "0.0.67"
|
||||
version = "0.0.71"
|
||||
dependencies = [
|
||||
"bitcoin",
|
||||
"bitcoincore-rpc",
|
||||
@@ -519,7 +519,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_core"
|
||||
version = "0.0.67"
|
||||
version = "0.0.71"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitcoin",
|
||||
@@ -540,7 +540,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_exit"
|
||||
version = "0.0.67"
|
||||
version = "0.0.71"
|
||||
dependencies = [
|
||||
"brk_logger",
|
||||
"ctrlc",
|
||||
@@ -549,7 +549,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_fetcher"
|
||||
version = "0.0.67"
|
||||
version = "0.0.71"
|
||||
dependencies = [
|
||||
"brk_core",
|
||||
"brk_logger",
|
||||
@@ -561,7 +561,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_indexer"
|
||||
version = "0.0.67"
|
||||
version = "0.0.71"
|
||||
dependencies = [
|
||||
"bitcoin",
|
||||
"bitcoincore-rpc",
|
||||
@@ -579,7 +579,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_interface"
|
||||
version = "0.0.67"
|
||||
version = "0.0.71"
|
||||
dependencies = [
|
||||
"brk_computer",
|
||||
"brk_core",
|
||||
@@ -588,7 +588,7 @@ dependencies = [
|
||||
"brk_vec",
|
||||
"color-eyre",
|
||||
"derive_deref",
|
||||
"schemars 1.0.0",
|
||||
"schemars 1.0.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
@@ -597,7 +597,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_logger"
|
||||
version = "0.0.67"
|
||||
version = "0.0.71"
|
||||
dependencies = [
|
||||
"color-eyre",
|
||||
"env_logger",
|
||||
@@ -607,7 +607,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_mcp"
|
||||
version = "0.0.67"
|
||||
version = "0.0.71"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"brk_interface",
|
||||
@@ -618,7 +618,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_parser"
|
||||
version = "0.0.67"
|
||||
version = "0.0.71"
|
||||
dependencies = [
|
||||
"bitcoin",
|
||||
"bitcoincore-rpc",
|
||||
@@ -633,9 +633,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_rmcp"
|
||||
version = "0.1.7"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ecf167efab04b87a8850e12196228388733aa43adaeafd5b4d6f9e29d850263"
|
||||
checksum = "26db177d2933b727fe5f53b52d5ebead13d57f94ed8637717117a8bb1a3f1bae"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"brk_rmcp-macros",
|
||||
@@ -648,7 +648,7 @@ dependencies = [
|
||||
"paste",
|
||||
"pin-project-lite",
|
||||
"rand 0.9.1",
|
||||
"schemars 1.0.0",
|
||||
"schemars 1.0.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sse-stream",
|
||||
@@ -663,10 +663,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_rmcp-macros"
|
||||
version = "0.1.7"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7e3a4b2b6bdb0508a756e9296321b6ce33234070060ad68f68c8372b7b53fc6"
|
||||
checksum = "4557e65ffea1466260a6ab13e3ba54bcee69c39576e4bfb8b81e50b375924540"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_json",
|
||||
@@ -980,7 +981,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_server"
|
||||
version = "0.0.67"
|
||||
version = "0.0.71"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"bitcoincore-rpc",
|
||||
@@ -1010,7 +1011,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_state"
|
||||
version = "0.0.67"
|
||||
version = "0.0.71"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"brk_core",
|
||||
@@ -1022,7 +1023,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_store"
|
||||
version = "0.0.67"
|
||||
version = "0.0.71"
|
||||
dependencies = [
|
||||
"brk_core",
|
||||
"byteview",
|
||||
@@ -1043,7 +1044,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brk_vec"
|
||||
version = "0.0.67"
|
||||
version = "0.0.71"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"brk_core",
|
||||
@@ -2849,9 +2850,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxc_resolver"
|
||||
version = "11.2.0"
|
||||
version = "11.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce097520c87cb9aae8b43b39b333a6709342db75b88e76b5c6bcadf0cccf16ea"
|
||||
checksum = "3e9fbd425311540ada87997dbec6e9a2e0bab00b7e82db8e6ef79a0d0a9cfce1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"indexmap 2.9.0",
|
||||
@@ -3012,9 +3013,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "papaya"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6827e3fc394523c21d4464d02c0bb1c19966ea4a58a9844ad6d746214179d2bc"
|
||||
checksum = "af228bb1296c9b044ee75e2a2325409c2d899bcfcc6150e5e41f148e0a87dd20"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"seize",
|
||||
@@ -3561,9 +3562,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "febc07c7e70b5db4f023485653c754d76e1bbe8d9dbfa20193ce13da9f9633f4"
|
||||
checksum = "fe8c9d1c68d67dd9f97ecbc6f932b60eb289c5dbddd8aa1405484a8fd2fcd984"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"ref-cast",
|
||||
@@ -3574,9 +3575,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1eeedaab7b1e1d09b5b4661121f4d27f9e7487089b0117833ccd7a882ee1ecc"
|
||||
checksum = "6ca9fcb757952f8e8629b9ab066fc62da523c46c2b247b1708a3be06dd82530b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
+19
-18
@@ -4,7 +4,7 @@ members = ["crates/*"]
|
||||
package.description = "The Bitcoin Research Kit is a suite of tools designed to extract, compute and display data stored on a Bitcoin Core node"
|
||||
package.license = "MIT"
|
||||
package.edition = "2024"
|
||||
package.version = "0.0.67"
|
||||
package.version = "0.0.71"
|
||||
package.homepage = "https://bitcoinresearchkit.org"
|
||||
package.repository = "https://github.com/bitcoinresearchkit/brk"
|
||||
|
||||
@@ -22,22 +22,23 @@ axum = "0.8.4"
|
||||
bincode = { version = "2.0.1", features = ["serde"] }
|
||||
bitcoin = { version = "0.32.6", features = ["serde"] }
|
||||
bitcoincore-rpc = "0.19.0"
|
||||
brk_bundler = { version = "0.0.67", path = "crates/brk_bundler" }
|
||||
brk_cli = { version = "0.0.67", path = "crates/brk_cli" }
|
||||
brk_computer = { version = "0.0.67", path = "crates/brk_computer" }
|
||||
brk_core = { version = "0.0.67", path = "crates/brk_core" }
|
||||
brk_exit = { version = "0.0.67", path = "crates/brk_exit" }
|
||||
brk_fetcher = { version = "0.0.67", path = "crates/brk_fetcher" }
|
||||
brk_indexer = { version = "0.0.67", path = "crates/brk_indexer" }
|
||||
brk_interface = { version = "0.0.67", path = "crates/brk_interface" }
|
||||
brk_logger = { version = "0.0.67", path = "crates/brk_logger" }
|
||||
brk_mcp = { version = "0.0.67", path = "crates/brk_mcp" }
|
||||
brk_parser = { version = "0.0.67", path = "crates/brk_parser" }
|
||||
brk_rmcp = { version = "0.1.7", features = ["transport-streamable-http-server", "transport-worker"]}
|
||||
brk_server = { version = "0.0.67", path = "crates/brk_server" }
|
||||
brk_state = { version = "0.0.67", path = "crates/brk_state" }
|
||||
brk_store = { version = "0.0.67", path = "crates/brk_store" }
|
||||
brk_vec = { version = "0.0.67", path = "crates/brk_vec" }
|
||||
brk_bundler = { version = "0.0.71", path = "crates/brk_bundler" }
|
||||
brk_cli = { version = "0.0.71", path = "crates/brk_cli" }
|
||||
brk_computer = { version = "0.0.71", path = "crates/brk_computer" }
|
||||
brk_core = { version = "0.0.71", path = "crates/brk_core" }
|
||||
brk_exit = { version = "0.0.71", path = "crates/brk_exit" }
|
||||
brk_fetcher = { version = "0.0.71", path = "crates/brk_fetcher" }
|
||||
brk_indexer = { version = "0.0.71", path = "crates/brk_indexer" }
|
||||
brk_interface = { version = "0.0.71", path = "crates/brk_interface" }
|
||||
brk_logger = { version = "0.0.71", path = "crates/brk_logger" }
|
||||
brk_mcp = { version = "0.0.71", path = "crates/brk_mcp" }
|
||||
brk_parser = { version = "0.0.71", path = "crates/brk_parser" }
|
||||
brk_rmcp = { version = "0.1.8", features = ["transport-streamable-http-server", "transport-worker"]}
|
||||
# brk_rmcp = { path = "../rust-sdk/crates/rmcp", features = ["transport-streamable-http-server", "transport-worker"]}
|
||||
brk_server = { version = "0.0.71", path = "crates/brk_server" }
|
||||
brk_state = { version = "0.0.71", path = "crates/brk_state" }
|
||||
brk_store = { version = "0.0.71", path = "crates/brk_store" }
|
||||
brk_vec = { version = "0.0.71", path = "crates/brk_vec" }
|
||||
byteview = "=0.6.1"
|
||||
clap = { version = "4.5.40", features = ["string"] }
|
||||
clap_derive = "4.5.40"
|
||||
@@ -48,7 +49,7 @@ jiff = "0.2.15"
|
||||
log = { version = "0.4.27" }
|
||||
minreq = { version = "2.13.4", features = ["https", "serde_json"] }
|
||||
rayon = "1.10.0"
|
||||
schemars = "1.0.0"
|
||||
schemars = "1.0.1"
|
||||
serde = { version = "1.0.219" }
|
||||
serde_bytes = "0.11.17"
|
||||
serde_derive = "1.0.219"
|
||||
|
||||
@@ -42,7 +42,7 @@ The toolkit can be used in various ways to accommodate as many needs as possible
|
||||
It has a wide range of functionalities including charts, tables and simulations which you can visit for free and without the need for an account. \
|
||||
Also available at: [kibo.money](https://kibo.money) // [satonomics.xyz](https://satonomics.xyz)
|
||||
- **[API](https://github.com/bitcoinresearchkit/brk/tree/main/crates/brk_server#brk-server)** \
|
||||
Researchers and developers are free to use BRK's public API with  dataset variants at their disposal. \
|
||||
Researchers and developers are free to use BRK's public API with  dataset variants at their disposal. \
|
||||
Just like the website, it's entirely free, with no authentication or rate-limiting.
|
||||
- **[AI](https://github.com/bitcoinresearchkit/brk/blob/main/crates/brk_mcp/README.md#brk-mcp)** \
|
||||
LLMs have to possibility to connect to BRK's backend through a [MCP](https://modelcontextprotocol.io/introduction). \
|
||||
|
||||
@@ -16,6 +16,7 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::services::Services;
|
||||
|
||||
#[derive(Parser, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
|
||||
#[command(version, about)]
|
||||
pub struct Config {
|
||||
/// Bitcoin main directory path, defaults: ~/.bitcoin, ~/Library/Application\ Support/Bitcoin, saved
|
||||
#[serde(default, deserialize_with = "default_on_error")]
|
||||
@@ -87,7 +88,7 @@ pub struct Config {
|
||||
#[arg(long, value_name = "SECONDS")]
|
||||
delay: Option<u64>,
|
||||
|
||||
/// Activate the Model Context Protocol (MCP) endpoint to give LLMs access to BRK (experimental), default: false, saved
|
||||
/// Activate the Model Context Protocol (MCP) endpoint to give LLMs access to BRK (experimental), default: true, saved
|
||||
#[serde(default, deserialize_with = "default_on_error")]
|
||||
#[arg(long, value_name = "BOOL")]
|
||||
mcp: Option<bool>,
|
||||
@@ -366,7 +367,7 @@ impl Config {
|
||||
}
|
||||
|
||||
pub fn mcp(&self) -> bool {
|
||||
self.mcp.is_some_and(|b| b)
|
||||
self.mcp.is_none_or(|b| b)
|
||||
}
|
||||
|
||||
pub fn watch(&self) -> bool {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::{path::Path, thread};
|
||||
use std::path::Path;
|
||||
|
||||
use brk_core::Version;
|
||||
use brk_exit::Exit;
|
||||
@@ -44,31 +44,22 @@ impl Vecs {
|
||||
computation: Computation,
|
||||
format: Format,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let (indexes, fetched) = thread::scope(|s| {
|
||||
let indexes_handle = s.spawn(|| {
|
||||
indexes::Vecs::forced_import(
|
||||
path,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexer,
|
||||
computation,
|
||||
format,
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
let indexes = indexes::Vecs::forced_import(
|
||||
path,
|
||||
version + VERSION + Version::ZERO,
|
||||
indexer,
|
||||
computation,
|
||||
format,
|
||||
)?;
|
||||
|
||||
let fetch_handle = s.spawn(|| {
|
||||
fetch.then(|| {
|
||||
fetched::Vecs::forced_import(
|
||||
path,
|
||||
version + VERSION + Version::ZERO,
|
||||
computation,
|
||||
format,
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
});
|
||||
|
||||
(indexes_handle.join().unwrap(), fetch_handle.join().unwrap())
|
||||
let fetched = fetch.then(|| {
|
||||
fetched::Vecs::forced_import(
|
||||
path,
|
||||
version + VERSION + Version::ZERO,
|
||||
computation,
|
||||
format,
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
Ok(Self {
|
||||
|
||||
@@ -11,7 +11,7 @@ use color_eyre::eyre::{ContextCompat, eyre};
|
||||
use log::info;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{Close, Date, Dollars, Fetcher, High, Low, Open, fetchers::retry};
|
||||
use crate::{Close, Date, Dollars, Fetcher, High, Low, Open, retry};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Binance {
|
||||
@@ -5,9 +5,10 @@ use color_eyre::eyre::{ContextCompat, eyre};
|
||||
use log::info;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{Close, Dollars, High, Low, Open, fetchers::retry};
|
||||
use crate::{Close, Dollars, High, Low, Open, retry};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub struct BRK {
|
||||
height_to_ohlc: BTreeMap<Height, Vec<OHLCCents>>,
|
||||
dateindex_to_ohlc: BTreeMap<DateIndex, Vec<OHLCCents>>,
|
||||
@@ -47,7 +48,7 @@ impl BRK {
|
||||
retry(
|
||||
|_| {
|
||||
let url = format!(
|
||||
"{API_URL}/query?index=height&values=ohlc&from={}&to={}",
|
||||
"{API_URL}/height-to-ohlc?from={}&to={}",
|
||||
height,
|
||||
height + CHUNK_SIZE
|
||||
);
|
||||
@@ -96,7 +97,7 @@ impl BRK {
|
||||
retry(
|
||||
|_| {
|
||||
let url = format!(
|
||||
"{API_URL}/query?index=dateindex&values=ohlc&from={}&to={}",
|
||||
"{API_URL}/dateindex-to-ohlc?from={}&to={}",
|
||||
dateindex,
|
||||
dateindex + CHUNK_SIZE
|
||||
);
|
||||
@@ -1,9 +0,0 @@
|
||||
mod binance;
|
||||
mod brk;
|
||||
mod kraken;
|
||||
mod retry;
|
||||
|
||||
pub use binance::*;
|
||||
pub use brk::*;
|
||||
pub use kraken::*;
|
||||
use retry::*;
|
||||
@@ -5,7 +5,7 @@ use color_eyre::eyre::ContextCompat;
|
||||
use log::info;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{Fetcher, fetchers::retry};
|
||||
use crate::{Fetcher, retry};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Kraken {
|
||||
@@ -7,12 +7,18 @@ use std::{collections::BTreeMap, path::Path, thread::sleep, time::Duration};
|
||||
|
||||
use brk_core::{Close, Date, Dollars, Height, High, Low, OHLCCents, Open, Timestamp};
|
||||
use color_eyre::eyre::Error;
|
||||
|
||||
mod fetchers;
|
||||
|
||||
pub use fetchers::*;
|
||||
use log::info;
|
||||
|
||||
mod binance;
|
||||
mod brk;
|
||||
mod kraken;
|
||||
mod retry;
|
||||
|
||||
pub use binance::*;
|
||||
pub use brk::*;
|
||||
pub use kraken::*;
|
||||
use retry::*;
|
||||
|
||||
const TRIES: usize = 12 * 60;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
||||
@@ -12,29 +12,53 @@ use serde::{Deserialize, de::Error};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, JsonSchema)]
|
||||
pub enum Index {
|
||||
#[schemars(description = "Date/day index")]
|
||||
DateIndex,
|
||||
#[schemars(description = "Decade index")]
|
||||
DecadeIndex,
|
||||
#[schemars(description = "Difficulty epoch index (equivalent to ~2 weeks)")]
|
||||
DifficultyEpoch,
|
||||
#[schemars(description = "Empty output index")]
|
||||
EmptyOutputIndex,
|
||||
#[schemars(description = "Halving epoch index (equivalent to ~4 years)")]
|
||||
HalvingEpoch,
|
||||
#[schemars(description = "Height/block index")]
|
||||
Height,
|
||||
#[schemars(description = "Transaction input index (based on total)")]
|
||||
InputIndex,
|
||||
#[schemars(description = "Month index")]
|
||||
MonthIndex,
|
||||
#[schemars(description = "Op return index")]
|
||||
OpReturnIndex,
|
||||
#[schemars(description = "Transaction output index (based on total)")]
|
||||
OutputIndex,
|
||||
#[schemars(description = "Index of P2A address")]
|
||||
P2AAddressIndex,
|
||||
#[schemars(description = "Index of P2MS output")]
|
||||
P2MSOutputIndex,
|
||||
#[schemars(description = "Index of P2PK (33 bytes) address")]
|
||||
P2PK33AddressIndex,
|
||||
#[schemars(description = "Index of P2PK (65 bytes) address")]
|
||||
P2PK65AddressIndex,
|
||||
#[schemars(description = "Index of P2PKH address")]
|
||||
P2PKHAddressIndex,
|
||||
#[schemars(description = "Index of P2SH address")]
|
||||
P2SHAddressIndex,
|
||||
#[schemars(description = "Index of P2TR address")]
|
||||
P2TRAddressIndex,
|
||||
#[schemars(description = "Index of P2WPKH address")]
|
||||
P2WPKHAddressIndex,
|
||||
#[schemars(description = "Index of P2WSH address")]
|
||||
P2WSHAddressIndex,
|
||||
#[schemars(description = "Quarter index")]
|
||||
QuarterIndex,
|
||||
#[schemars(description = "Transaction index")]
|
||||
TxIndex,
|
||||
#[schemars(description = "Unknown output index")]
|
||||
UnknownOutputIndex,
|
||||
#[schemars(description = "Week index")]
|
||||
WeekIndex,
|
||||
#[schemars(description = "Year index")]
|
||||
YearIndex,
|
||||
}
|
||||
|
||||
|
||||
@@ -12,11 +12,11 @@ use crate::{
|
||||
#[derive(Debug, Deserialize, JsonSchema)]
|
||||
pub struct Params {
|
||||
#[serde(alias = "i")]
|
||||
#[schemars(description = "Index of the values requested")]
|
||||
#[schemars(description = "Index of requested vecs")]
|
||||
pub index: Index,
|
||||
|
||||
#[serde(alias = "v")]
|
||||
#[schemars(description = "Ids of the requested vecs")]
|
||||
#[schemars(description = "Ids of requested vecs")]
|
||||
pub ids: MaybeIds,
|
||||
|
||||
#[serde(flatten)]
|
||||
@@ -45,18 +45,24 @@ impl From<((Index, String), ParamsOpt)> for Params {
|
||||
pub struct ParamsOpt {
|
||||
#[serde(default, alias = "f", deserialize_with = "de_unquote_i64")]
|
||||
/// Inclusive starting index, if negative will be from the end
|
||||
#[schemars(description = "Inclusive starting index, if negative will be from the end")]
|
||||
from: Option<i64>,
|
||||
|
||||
#[serde(default, alias = "t", deserialize_with = "de_unquote_i64")]
|
||||
/// Exclusive ending index, if negative will be from the end, overrides 'count'
|
||||
#[schemars(
|
||||
description = "Exclusive ending index, if negative will be from the end, overrides 'count'"
|
||||
)]
|
||||
to: Option<i64>,
|
||||
|
||||
#[serde(default, alias = "c", deserialize_with = "de_unquote_usize")]
|
||||
/// Number of values
|
||||
/// Number of values requested
|
||||
#[schemars(description = "Number of values requested")]
|
||||
count: Option<usize>,
|
||||
|
||||
/// Format of the output
|
||||
#[serde(default)]
|
||||
/// Format of the output
|
||||
#[schemars(description = "Format of the output")]
|
||||
format: Option<Format>,
|
||||
}
|
||||
|
||||
|
||||
+18
-23
@@ -6,12 +6,10 @@
|
||||
use brk_interface::{IdParam, Interface, PaginatedIndexParam, PaginationParam, Params};
|
||||
use brk_rmcp::{
|
||||
Error as McpError, RoleServer, ServerHandler,
|
||||
model::{
|
||||
CallToolResult, Content, Implementation, InitializeRequestParam, InitializeResult,
|
||||
ProtocolVersion, ServerCapabilities, ServerInfo,
|
||||
},
|
||||
handler::server::{router::tool::ToolRouter, tool::Parameters},
|
||||
model::*,
|
||||
service::RequestContext,
|
||||
tool,
|
||||
tool, tool_handler, tool_router,
|
||||
};
|
||||
use log::info;
|
||||
|
||||
@@ -20,14 +18,18 @@ pub mod route;
|
||||
#[derive(Clone)]
|
||||
pub struct MCP {
|
||||
interface: &'static Interface<'static>,
|
||||
tool_router: ToolRouter<MCP>,
|
||||
}
|
||||
|
||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
#[tool(tool_box)]
|
||||
#[tool_router]
|
||||
impl MCP {
|
||||
pub fn new(interface: &'static Interface<'static>) -> Self {
|
||||
Self { interface }
|
||||
Self {
|
||||
interface,
|
||||
tool_router: Self::tool_router(),
|
||||
}
|
||||
}
|
||||
|
||||
#[tool(description = "
|
||||
@@ -54,8 +56,8 @@ Get the count of all existing vec ids.
|
||||
Get the count of all existing vecs.
|
||||
Equals to the sum of supported Indexes of each vec id.
|
||||
")]
|
||||
async fn get_variant_count(&self) -> Result<CallToolResult, McpError> {
|
||||
info!("mcp: get_variant_count");
|
||||
async fn get_vec_count(&self) -> Result<CallToolResult, McpError> {
|
||||
info!("mcp: get_vec_count");
|
||||
Ok(CallToolResult::success(vec![
|
||||
Content::json(self.interface.get_vec_count()).unwrap(),
|
||||
]))
|
||||
@@ -88,7 +90,7 @@ If the `page` param is omitted, it will default to the first page.
|
||||
")]
|
||||
async fn get_vecids(
|
||||
&self,
|
||||
#[tool(aggr)] pagination: PaginationParam,
|
||||
Parameters(pagination): Parameters<PaginationParam>,
|
||||
) -> Result<CallToolResult, McpError> {
|
||||
info!("mcp: get_vecids");
|
||||
Ok(CallToolResult::success(vec![
|
||||
@@ -103,7 +105,7 @@ If the `page` param is omitted, it will default to the first page.
|
||||
")]
|
||||
async fn get_index_to_vecids(
|
||||
&self,
|
||||
#[tool(aggr)] paginated_index: PaginatedIndexParam,
|
||||
Parameters(paginated_index): Parameters<PaginatedIndexParam>,
|
||||
) -> Result<CallToolResult, McpError> {
|
||||
info!("mcp: get_index_to_vecids");
|
||||
Ok(CallToolResult::success(vec![
|
||||
@@ -117,7 +119,7 @@ The list will be empty if the vec id isn't correct.
|
||||
")]
|
||||
async fn get_vecid_to_indexes(
|
||||
&self,
|
||||
#[tool(aggr)] param: IdParam,
|
||||
Parameters(param): Parameters<IdParam>,
|
||||
) -> Result<CallToolResult, McpError> {
|
||||
info!("mcp: get_vecid_to_indexes");
|
||||
Ok(CallToolResult::success(vec![
|
||||
@@ -127,14 +129,12 @@ The list will be empty if the vec id isn't correct.
|
||||
|
||||
#[tool(description = "
|
||||
Get one or multiple vecs depending on given parameters.
|
||||
If you'd like to request multiple vec ids, simply separate them with a ','.
|
||||
To get the last value set `-1` to the `from` parameter.
|
||||
The response's format will depend on the given parameters, it will be:
|
||||
- A value: If requested only one vec and the given range returns one value (for example: `from=-1`)
|
||||
- A list: If requested only one vec and the given range returns multiple values (for example: `from=-1000&count=100` or `from=-444&to=-333`)
|
||||
- A matrix: When multiple vecs are requested, even if they each return one value.
|
||||
")]
|
||||
fn get_vecs(&self, #[tool(aggr)] params: Params) -> Result<CallToolResult, McpError> {
|
||||
fn get_vecs(&self, Parameters(params): Parameters<Params>) -> Result<CallToolResult, McpError> {
|
||||
info!("mcp: get_vecs");
|
||||
Ok(CallToolResult::success(vec![
|
||||
Content::json(self.interface.search_and_format(params).unwrap()).unwrap(),
|
||||
@@ -142,7 +142,7 @@ The response's format will depend on the given parameters, it will be:
|
||||
}
|
||||
|
||||
#[tool(description = "
|
||||
Get the running version of the Bitcoin Research Kit
|
||||
Get the running version of the Bitcoin Research Kit.
|
||||
")]
|
||||
async fn get_version(&self) -> Result<CallToolResult, McpError> {
|
||||
info!("mcp: get_version");
|
||||
@@ -152,7 +152,7 @@ Get the running version of the Bitcoin Research Kit
|
||||
}
|
||||
}
|
||||
|
||||
#[tool(tool_box)]
|
||||
#[tool_handler]
|
||||
impl ServerHandler for MCP {
|
||||
fn get_info(&self) -> ServerInfo {
|
||||
ServerInfo {
|
||||
@@ -181,13 +181,8 @@ An 'Index' (or indexes) is the timeframe of a dataset.
|
||||
async fn initialize(
|
||||
&self,
|
||||
_request: InitializeRequestParam,
|
||||
context: RequestContext<RoleServer>,
|
||||
_context: RequestContext<RoleServer>,
|
||||
) -> Result<InitializeResult, McpError> {
|
||||
if let Some(http_request_part) = context.extensions.get::<axum::http::request::Parts>() {
|
||||
let initialize_headers = &http_request_part.headers;
|
||||
let initialize_uri = &http_request_part.uri;
|
||||
tracing::info!(?initialize_headers, %initialize_uri, "initialize from http server");
|
||||
}
|
||||
Ok(self.get_info())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,10 @@ impl Header {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn modified(&self) -> bool {
|
||||
self.modified
|
||||
}
|
||||
|
||||
pub fn vec_version(&self) -> Version {
|
||||
self.inner.load().vec_version
|
||||
}
|
||||
@@ -69,11 +73,9 @@ impl Header {
|
||||
self.inner.load().height
|
||||
}
|
||||
|
||||
pub fn write_if_needed(&mut self, file: &mut File) -> io::Result<()> {
|
||||
if self.modified {
|
||||
self.inner.load().write(file)?;
|
||||
self.modified = false;
|
||||
}
|
||||
pub fn write(&mut self, file: &mut File) -> io::Result<()> {
|
||||
self.inner.load().write(file)?;
|
||||
self.modified = false;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +95,9 @@ where
|
||||
|
||||
// ---
|
||||
|
||||
fn open_file(&self) -> io::Result<File> {
|
||||
Self::open_file_(&self.path())
|
||||
}
|
||||
fn open_file_(path: &Path) -> io::Result<File> {
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
@@ -106,13 +109,9 @@ where
|
||||
Ok(file)
|
||||
}
|
||||
|
||||
fn file(&self) -> &File;
|
||||
fn mut_file(&mut self) -> &mut File;
|
||||
|
||||
fn file_set_len(&mut self, len: u64) -> Result<()> {
|
||||
let file = self.mut_file();
|
||||
fn file_set_len(&mut self, file: &mut File, len: u64) -> Result<()> {
|
||||
Self::file_set_len_(file, len)?;
|
||||
self.update_mmap()
|
||||
self.update_mmap(file)
|
||||
}
|
||||
fn file_set_len_(file: &mut File, len: u64) -> Result<()> {
|
||||
file.set_len(len)?;
|
||||
@@ -120,32 +119,31 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn file_write_all(&mut self, buf: &[u8]) -> Result<()> {
|
||||
let file = self.mut_file();
|
||||
fn file_write_all(&mut self, file: &mut File, buf: &[u8]) -> Result<()> {
|
||||
file.write_all(buf)?;
|
||||
self.update_mmap()
|
||||
self.update_mmap(file)
|
||||
}
|
||||
|
||||
fn file_truncate_and_write_all(&mut self, len: u64, buf: &[u8]) -> Result<()> {
|
||||
let file = self.mut_file();
|
||||
fn file_truncate_and_write_all(&mut self, file: &mut File, len: u64, buf: &[u8]) -> Result<()> {
|
||||
Self::file_set_len_(file, len)?;
|
||||
file.write_all(buf)?;
|
||||
self.update_mmap()
|
||||
self.update_mmap(file)
|
||||
}
|
||||
|
||||
fn reset(&mut self) -> Result<()>;
|
||||
|
||||
#[inline]
|
||||
fn reset_(&mut self) -> Result<()> {
|
||||
self.file_truncate_and_write_all(HEADER_OFFSET as u64, &[])
|
||||
let mut file = self.open_file()?;
|
||||
self.file_truncate_and_write_all(&mut file, HEADER_OFFSET as u64, &[])
|
||||
}
|
||||
|
||||
fn new_mmap(file: &File) -> Result<Arc<Mmap>> {
|
||||
Ok(Arc::new(unsafe { Mmap::map(file)? }))
|
||||
}
|
||||
|
||||
fn update_mmap(&mut self) -> Result<()> {
|
||||
let mmap = Self::new_mmap(self.file())?;
|
||||
fn update_mmap(&mut self, file: &File) -> Result<()> {
|
||||
let mmap = Self::new_mmap(file)?;
|
||||
self.mmap().store(mmap);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
mem,
|
||||
fs, mem,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
@@ -189,14 +188,6 @@ where
|
||||
self.inner.parent()
|
||||
}
|
||||
|
||||
fn file(&self) -> &File {
|
||||
self.inner.file()
|
||||
}
|
||||
|
||||
fn mut_file(&mut self) -> &mut File {
|
||||
self.inner.mut_file()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn stored_len(&self) -> usize {
|
||||
Self::stored_len__(&self.pages_meta.load())
|
||||
@@ -221,7 +212,7 @@ where
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<()> {
|
||||
self.inner.write_header_if_needed()?;
|
||||
let file_opt = self.inner.write_header_if_needed()?;
|
||||
|
||||
let pushed_len = self.pushed_len();
|
||||
|
||||
@@ -295,11 +286,13 @@ where
|
||||
|
||||
pages_meta.write()?;
|
||||
|
||||
let mut file = file_opt.unwrap_or(self.open_file()?);
|
||||
|
||||
if let Some(truncate_at) = truncate_at {
|
||||
self.file_set_len(truncate_at)?;
|
||||
self.file_set_len(&mut file, truncate_at)?;
|
||||
}
|
||||
|
||||
self.file_write_all(&buf)?;
|
||||
self.file_write_all(&mut file, &buf)?;
|
||||
|
||||
self.pages_meta.store(Arc::new(pages_meta));
|
||||
|
||||
@@ -354,7 +347,9 @@ where
|
||||
|
||||
self.pages_meta.store(Arc::new(pages_meta));
|
||||
|
||||
self.file_truncate_and_write_all(len, &buf)?;
|
||||
let mut file = self.open_file()?;
|
||||
|
||||
self.file_truncate_and_write_all(&mut file, len, &buf)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ pub struct RawVec<I, T> {
|
||||
header: Header,
|
||||
parent: PathBuf,
|
||||
name: String,
|
||||
file: Option<File>,
|
||||
// Consider Arc<ArcSwap<Option<Mmap>>> for dataraces when reorg ?
|
||||
mmap: Arc<ArcSwap<Mmap>>,
|
||||
pushed: Vec<T>,
|
||||
@@ -55,18 +54,16 @@ where
|
||||
|
||||
pub fn import(parent: &Path, name: &str, version: Version) -> Result<Self> {
|
||||
let path = Self::path_(parent, name);
|
||||
let (file, mmap, header) = match Self::open_file_(&path) {
|
||||
let (mmap, header) = match Self::open_file_(&path) {
|
||||
Ok(mut file) => {
|
||||
if file.metadata()?.len() == 0 {
|
||||
let header = Header::create_and_write(&mut file, version, Format::Raw)?;
|
||||
let mmap = Self::new_mmap(&file)?;
|
||||
(file, mmap, header)
|
||||
(mmap, header)
|
||||
} else {
|
||||
let mmap = Self::new_mmap(&file)?;
|
||||
// dbg!(&mmap[..]);
|
||||
let header = Header::import_and_verify(&mmap, version, Format::Raw)?;
|
||||
// dbg!((&header, name, I::to_string()));
|
||||
(file, mmap, header)
|
||||
(mmap, header)
|
||||
}
|
||||
}
|
||||
Err(e) => match e.kind() {
|
||||
@@ -75,7 +72,7 @@ where
|
||||
let mut file = Self::open_file_(&path)?;
|
||||
let header = Header::create_and_write(&mut file, version, Format::Raw)?;
|
||||
let mmap = Self::new_mmap(&file)?;
|
||||
(file, mmap, header)
|
||||
(mmap, header)
|
||||
}
|
||||
_ => return Err(e.into()),
|
||||
},
|
||||
@@ -86,7 +83,6 @@ where
|
||||
Ok(Self {
|
||||
mmap,
|
||||
header,
|
||||
file: Some(file),
|
||||
name: name.to_string(),
|
||||
parent: parent.to_owned(),
|
||||
pushed: vec![],
|
||||
@@ -111,8 +107,14 @@ where
|
||||
iter
|
||||
}
|
||||
|
||||
pub fn write_header_if_needed(&mut self) -> io::Result<()> {
|
||||
self.header.write_if_needed(self.file.as_mut().unwrap())
|
||||
pub fn write_header_if_needed(&mut self) -> io::Result<Option<File>> {
|
||||
if self.header.modified() {
|
||||
let mut file = self.open_file()?;
|
||||
self.header.write(&mut file)?;
|
||||
Ok(Some(file))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,16 +145,6 @@ where
|
||||
&self.mmap
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn file(&self) -> &File {
|
||||
self.file.as_ref().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn mut_file(&mut self) -> &mut File {
|
||||
self.file.as_mut().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn stored_len(&self) -> usize {
|
||||
self.stored_len_(&self.mmap.load())
|
||||
@@ -177,7 +169,7 @@ where
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<()> {
|
||||
self.write_header_if_needed()?;
|
||||
let file_opt = self.write_header_if_needed()?;
|
||||
|
||||
let pushed_len = self.pushed_len();
|
||||
|
||||
@@ -200,7 +192,9 @@ where
|
||||
bytes
|
||||
};
|
||||
|
||||
self.file_write_all(&bytes)?;
|
||||
let mut file = file_opt.unwrap_or(self.open_file()?);
|
||||
|
||||
self.file_write_all(&mut file, &bytes)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -219,7 +213,8 @@ where
|
||||
|
||||
let len = index * Self::SIZE_OF_T + HEADER_OFFSET;
|
||||
|
||||
self.file_set_len(len as u64)?;
|
||||
let mut file = self.open_file()?;
|
||||
self.file_set_len(&mut file, len as u64)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -266,7 +261,6 @@ impl<I, T> Clone for RawVec<I, T> {
|
||||
header: self.header.clone(),
|
||||
parent: self.parent.clone(),
|
||||
name: self.name.clone(),
|
||||
file: None,
|
||||
mmap: self.mmap.clone(),
|
||||
pushed: vec![],
|
||||
phantom: PhantomData,
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
use std::{
|
||||
fs::File,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use arc_swap::ArcSwap;
|
||||
use brk_core::{Result, Value, Version};
|
||||
@@ -91,22 +88,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn file(&self) -> &File {
|
||||
match self {
|
||||
StoredVec::Raw(v) => v.file(),
|
||||
StoredVec::Compressed(v) => v.file(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn mut_file(&mut self) -> &mut File {
|
||||
match self {
|
||||
StoredVec::Raw(v) => v.mut_file(),
|
||||
StoredVec::Compressed(v) => v.mut_file(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn stored_len(&self) -> usize {
|
||||
match self {
|
||||
|
||||
Reference in New Issue
Block a user