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))
+}