Files
dht/dht-search/src/storage/keys.rs
T

85 lines
2.4 KiB
Rust

// 负责定义稳定的 RocksDB 键空间编码和版本边界
use crate::domain::InfoHash;
pub(crate) const DATABASE_SCHEMA_VERSION: u32 = 1;
pub(crate) const SCHEMA_VERSION_KEY: &[u8] = b"\x00schema-version";
const TORRENT_PREFIX: u8 = b't';
const CONTENT_PREFIX: u8 = b'c';
const PENDING_INDEX_PREFIX: u8 = b'p';
pub(crate) fn torrent_key(info_hash: InfoHash) -> [u8; 1 + InfoHash::BYTE_LEN] {
prefixed_info_hash(TORRENT_PREFIX, info_hash)
}
pub(crate) fn torrent_prefix() -> [u8; 1] {
[TORRENT_PREFIX]
}
pub(crate) fn pending_index_key(info_hash: InfoHash) -> [u8; 1 + InfoHash::BYTE_LEN] {
prefixed_info_hash(PENDING_INDEX_PREFIX, info_hash)
}
pub(crate) fn pending_index_prefix() -> [u8; 1] {
[PENDING_INDEX_PREFIX]
}
pub(crate) fn content_member_key(
content_key: &[u8; 32],
info_hash: InfoHash,
) -> [u8; 1 + 32 + InfoHash::BYTE_LEN] {
let mut key = [0_u8; 1 + 32 + InfoHash::BYTE_LEN];
key[0] = CONTENT_PREFIX;
key[1..33].copy_from_slice(content_key);
key[33..].copy_from_slice(info_hash.as_bytes());
key
}
pub(crate) fn content_members_prefix(content_key: &[u8; 32]) -> [u8; 1 + 32] {
let mut key = [0_u8; 1 + 32];
key[0] = CONTENT_PREFIX;
key[1..].copy_from_slice(content_key);
key
}
pub(crate) fn decode_content_member_info_hash(
key: &[u8],
content_key: &[u8; 32],
) -> Option<InfoHash> {
let expected_prefix = content_members_prefix(content_key);
if key.len() != 1 + 32 + InfoHash::BYTE_LEN || !key.starts_with(&expected_prefix) {
return None;
}
let bytes: [u8; InfoHash::BYTE_LEN] = key[33..].try_into().ok()?;
Some(InfoHash::from_bytes(bytes))
}
pub(crate) fn decode_pending_info_hash(key: &[u8]) -> Option<InfoHash> {
if key.len() != 1 + InfoHash::BYTE_LEN || key.first().copied() != Some(PENDING_INDEX_PREFIX) {
return None;
}
let bytes: [u8; InfoHash::BYTE_LEN] = key[1..].try_into().ok()?;
Some(InfoHash::from_bytes(bytes))
}
fn prefixed_info_hash(prefix: u8, info_hash: InfoHash) -> [u8; 1 + InfoHash::BYTE_LEN] {
let mut key = [0_u8; 1 + InfoHash::BYTE_LEN];
key[0] = prefix;
key[1..].copy_from_slice(info_hash.as_bytes());
key
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pending_key_round_trips_infohash() {
let hash = InfoHash::from_bytes([7; 20]);
assert_eq!(
decode_pending_info_hash(&pending_index_key(hash)),
Some(hash)
);
}
}