85 lines
2.4 KiB
Rust
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)
|
|
);
|
|
}
|
|
}
|