commit 753df47443d5a9aa2a28b2b20d395f559af27054
parent 26a0ce2b322393175a7bed045a943fc003b464fb
Author: Greg Heartsfield <scsibug@imap.cc>
Date: Sat, 12 Feb 2022 09:29:38 -0600
refactor: create utils/hexrange utility modules
Diffstat:
6 files changed, 181 insertions(+), 172 deletions(-)
diff --git a/src/db.rs b/src/db.rs
@@ -3,8 +3,11 @@ use crate::config::SETTINGS;
use crate::error::Error;
use crate::error::Result;
use crate::event::Event;
+use crate::hexrange::hex_range;
+use crate::hexrange::HexSearch;
use crate::nip05;
use crate::subscription::Subscription;
+use crate::utils::is_hex;
use governor::clock::Clock;
use governor::{Quota, RateLimiter};
use hex;
@@ -560,86 +563,6 @@ pub struct QueryResult {
pub event: String,
}
-/// Check if a string contains only hex characters.
-fn is_hex(s: &str) -> bool {
- s.chars().all(|x| char::is_ascii_hexdigit(&x))
-}
-
-/// Check if a string contains only f chars
-fn is_all_fs(s: &str) -> bool {
- s.chars().all(|x| x == 'f' || x == 'F')
-}
-
-/// Types of hexadecimal queries.
-#[derive(PartialEq, Debug, Clone)]
-enum HexSearch {
- // when no range is needed, exact 32-byte
- Exact(Vec<u8>),
- // lower (inclusive) and upper range (exclusive)
- Range(Vec<u8>, Vec<u8>),
- // lower bound only, upper bound is MAX inclusive
- LowerOnly(Vec<u8>),
-}
-
-/// Find the next hex sequence greater than the argument.
-fn hex_range(s: &str) -> Option<HexSearch> {
- // handle special cases
- if !is_hex(s) || s.len() > 64 {
- return None;
- }
- if s.len() == 64 {
- return Some(HexSearch::Exact(hex::decode(s).ok()?));
- }
- // if s is odd, add a zero
- let mut hash_base = s.to_owned();
- let mut odd = hash_base.len() % 2 != 0;
- if odd {
- // extend the string to make it even
- hash_base.push('0');
- }
- let base = hex::decode(hash_base).ok()?;
- // check for all ff's
- if is_all_fs(s) {
- // there is no higher bound, we only want to search for blobs greater than this.
- return Some(HexSearch::LowerOnly(base));
- }
-
- // return a range
- let mut upper = base.clone();
- let mut byte_len = upper.len();
-
- // for odd strings, we made them longer, but we want to increment the upper char (+16).
- // we know we can do this without overflowing because we explicitly set the bottom half to 0's.
- while byte_len > 0 {
- byte_len -= 1;
- // check if byte can be incremented, or if we need to carry.
- let b = upper[byte_len];
- if b == u8::MAX {
- // reset and carry
- upper[byte_len] = 0;
- } else if odd {
- // check if first char in this byte is NOT 'f'
- if b < 240 {
- upper[byte_len] = b + 16; // bump up the first character in this byte
- // increment done, stop iterating through the vec
- break;
- } else {
- // if it is 'f', reset the byte to 0 and do a carry
- // reset and carry
- upper[byte_len] = 0;
- }
- // done with odd logic, so don't repeat this
- odd = false;
- } else {
- // bump up the first character in this byte
- upper[byte_len] = b + 1;
- // increment done, stop iterating
- break;
- }
- }
- Some(HexSearch::Range(base, upper))
-}
-
/// Produce a arbitrary list of '?' parameters.
fn repeat_vars(count: usize) -> String {
if count == 0 {
@@ -683,7 +606,6 @@ fn query_from_sub(sub: &Subscription) -> (String, Vec<Box<dyn ToSql>>) {
params.push(Box::new(upper));
}
Some(HexSearch::LowerOnly(lower)) => {
- // info!("{:?} => lower; {:?} ", auth, hex::encode(lower));
auth_searches.push("author>?".to_owned());
params.push(Box::new(lower));
}
@@ -836,84 +758,3 @@ pub async fn db_query(
ok
});
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn hex_range_exact() -> Result<()> {
- let hex = "abcdef00abcdef00abcdef00abcdef00abcdef00abcdef00abcdef00abcdef00";
- let r = hex_range(hex);
- assert_eq!(
- r,
- Some(HexSearch::Exact(hex::decode(hex).expect("invalid hex")))
- );
- Ok(())
- }
- #[test]
- fn hex_full_range() -> Result<()> {
- //let hex = "abcdef00abcdef00abcdef00abcdef00abcdef00abcdef00abcdef00abcdef00";
- let hex = "aaaa";
- let hex_upper = "aaab";
- let r = hex_range(hex);
- assert_eq!(
- r,
- Some(HexSearch::Range(
- hex::decode(hex).expect("invalid hex"),
- hex::decode(hex_upper).expect("invalid hex")
- ))
- );
- Ok(())
- }
-
- #[test]
- fn hex_full_range_odd() -> Result<()> {
- let r = hex_range("abc");
- assert_eq!(
- r,
- Some(HexSearch::Range(
- hex::decode("abc0").expect("invalid hex"),
- hex::decode("abd0").expect("invalid hex")
- ))
- );
- Ok(())
- }
-
- #[test]
- fn hex_full_range_odd_end_f() -> Result<()> {
- let r = hex_range("abf");
- assert_eq!(
- r,
- Some(HexSearch::Range(
- hex::decode("abf0").expect("invalid hex"),
- hex::decode("ac00").expect("invalid hex")
- ))
- );
- Ok(())
- }
-
- #[test]
- fn hex_no_upper() -> Result<()> {
- let r = hex_range("ffff");
- assert_eq!(
- r,
- Some(HexSearch::LowerOnly(
- hex::decode("ffff").expect("invalid hex")
- ))
- );
- Ok(())
- }
-
- #[test]
- fn hex_no_upper_odd() -> Result<()> {
- let r = hex_range("fff");
- assert_eq!(
- r,
- Some(HexSearch::LowerOnly(
- hex::decode("fff0").expect("invalid hex")
- ))
- );
- Ok(())
- }
-}
diff --git a/src/event.rs b/src/event.rs
@@ -3,6 +3,7 @@ use crate::config;
use crate::error::Error::*;
use crate::error::Result;
use crate::nip05;
+use crate::utils::unix_time;
use bitcoin_hashes::{sha256, Hash};
use lazy_static::lazy_static;
use log::*;
@@ -13,7 +14,6 @@ use serde_json::Number;
use std::collections::HashMap;
use std::collections::HashSet;
use std::str::FromStr;
-use std::time::SystemTime;
lazy_static! {
/// Secp256k1 verification instance.
@@ -72,14 +72,6 @@ impl From<EventCmd> for Result<Event> {
}
}
-/// Seconds since 1970.
-pub fn unix_time() -> u64 {
- SystemTime::now()
- .duration_since(SystemTime::UNIX_EPOCH)
- .map(|x| x.as_secs())
- .unwrap_or(0)
-}
-
impl Event {
pub fn is_kind_metadata(&self) -> bool {
self.kind == 0
diff --git a/src/hexrange.rs b/src/hexrange.rs
@@ -0,0 +1,158 @@
+//! Utilities for searching hexadecimal
+use crate::utils::is_hex;
+use hex;
+
+/// Types of hexadecimal queries.
+#[derive(PartialEq, Debug, Clone)]
+pub enum HexSearch {
+ // when no range is needed, exact 32-byte
+ Exact(Vec<u8>),
+ // lower (inclusive) and upper range (exclusive)
+ Range(Vec<u8>, Vec<u8>),
+ // lower bound only, upper bound is MAX inclusive
+ LowerOnly(Vec<u8>),
+}
+
+/// Check if a string contains only f chars
+fn is_all_fs(s: &str) -> bool {
+ s.chars().all(|x| x == 'f' || x == 'F')
+}
+
+/// Find the next hex sequence greater than the argument.
+pub fn hex_range(s: &str) -> Option<HexSearch> {
+ // handle special cases
+ if !is_hex(s) || s.len() > 64 {
+ return None;
+ }
+ if s.len() == 64 {
+ return Some(HexSearch::Exact(hex::decode(s).ok()?));
+ }
+ // if s is odd, add a zero
+ let mut hash_base = s.to_owned();
+ let mut odd = hash_base.len() % 2 != 0;
+ if odd {
+ // extend the string to make it even
+ hash_base.push('0');
+ }
+ let base = hex::decode(hash_base).ok()?;
+ // check for all ff's
+ if is_all_fs(s) {
+ // there is no higher bound, we only want to search for blobs greater than this.
+ return Some(HexSearch::LowerOnly(base));
+ }
+
+ // return a range
+ let mut upper = base.clone();
+ let mut byte_len = upper.len();
+
+ // for odd strings, we made them longer, but we want to increment the upper char (+16).
+ // we know we can do this without overflowing because we explicitly set the bottom half to 0's.
+ while byte_len > 0 {
+ byte_len -= 1;
+ // check if byte can be incremented, or if we need to carry.
+ let b = upper[byte_len];
+ if b == u8::MAX {
+ // reset and carry
+ upper[byte_len] = 0;
+ } else if odd {
+ // check if first char in this byte is NOT 'f'
+ if b < 240 {
+ upper[byte_len] = b + 16; // bump up the first character in this byte
+ // increment done, stop iterating through the vec
+ break;
+ } else {
+ // if it is 'f', reset the byte to 0 and do a carry
+ // reset and carry
+ upper[byte_len] = 0;
+ }
+ // done with odd logic, so don't repeat this
+ odd = false;
+ } else {
+ // bump up the first character in this byte
+ upper[byte_len] = b + 1;
+ // increment done, stop iterating
+ break;
+ }
+ }
+ Some(HexSearch::Range(base, upper))
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn hex_range_exact() -> Result<()> {
+ let hex = "abcdef00abcdef00abcdef00abcdef00abcdef00abcdef00abcdef00abcdef00";
+ let r = hex_range(hex);
+ assert_eq!(
+ r,
+ Some(HexSearch::Exact(hex::decode(hex).expect("invalid hex")))
+ );
+ Ok(())
+ }
+ #[test]
+ fn hex_full_range() -> Result<()> {
+ let hex = "aaaa";
+ let hex_upper = "aaab";
+ let r = hex_range(hex);
+ assert_eq!(
+ r,
+ Some(HexSearch::Range(
+ hex::decode(hex).expect("invalid hex"),
+ hex::decode(hex_upper).expect("invalid hex")
+ ))
+ );
+ Ok(())
+ }
+
+ #[test]
+ fn hex_full_range_odd() -> Result<()> {
+ let r = hex_range("abc");
+ assert_eq!(
+ r,
+ Some(HexSearch::Range(
+ hex::decode("abc0").expect("invalid hex"),
+ hex::decode("abd0").expect("invalid hex")
+ ))
+ );
+ Ok(())
+ }
+
+ #[test]
+ fn hex_full_range_odd_end_f() -> Result<()> {
+ let r = hex_range("abf");
+ assert_eq!(
+ r,
+ Some(HexSearch::Range(
+ hex::decode("abf0").expect("invalid hex"),
+ hex::decode("ac00").expect("invalid hex")
+ ))
+ );
+ Ok(())
+ }
+
+ #[test]
+ fn hex_no_upper() -> Result<()> {
+ let r = hex_range("ffff");
+ assert_eq!(
+ r,
+ Some(HexSearch::LowerOnly(
+ hex::decode("ffff").expect("invalid hex")
+ ))
+ );
+ Ok(())
+ }
+
+ #[test]
+ fn hex_no_upper_odd() -> Result<()> {
+ let r = hex_range("fff");
+ assert_eq!(
+ r,
+ Some(HexSearch::LowerOnly(
+ hex::decode("fff0").expect("invalid hex")
+ ))
+ );
+ Ok(())
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
@@ -4,7 +4,9 @@ pub mod conn;
pub mod db;
pub mod error;
pub mod event;
+pub mod hexrange;
pub mod info;
pub mod nip05;
pub mod protostream;
pub mod subscription;
+pub mod utils;
diff --git a/src/nip05.rs b/src/nip05.rs
@@ -7,7 +7,8 @@
use crate::config::SETTINGS;
use crate::db;
use crate::error::{Error, Result};
-use crate::event::{unix_time, Event};
+use crate::event::Event;
+use crate::utils::unix_time;
use hyper::body::HttpBody;
use hyper::client::connect::HttpConnector;
use hyper::Client;
diff --git a/src/utils.rs b/src/utils.rs
@@ -0,0 +1,15 @@
+//! Common utility functions
+use std::time::SystemTime;
+
+/// Seconds since 1970.
+pub fn unix_time() -> u64 {
+ SystemTime::now()
+ .duration_since(SystemTime::UNIX_EPOCH)
+ .map(|x| x.as_secs())
+ .unwrap_or(0)
+}
+
+/// Check if a string contains only hex characters.
+pub fn is_hex(s: &str) -> bool {
+ s.chars().all(|x| char::is_ascii_hexdigit(&x))
+}