wip: regex condition parsing

This commit is contained in:
Greg Heartsfield 2022-10-14 14:51:04 -05:00
parent b3fe03279b
commit e7f67c8e36
4 changed files with 41 additions and 44 deletions

14
Cargo.lock generated
View File

@ -1042,11 +1042,11 @@ dependencies = [
"r2d2", "r2d2",
"r2d2_sqlite", "r2d2_sqlite",
"rand 0.8.5", "rand 0.8.5",
"regex",
"rusqlite", "rusqlite",
"secp256k1", "secp256k1",
"serde", "serde",
"serde_json", "serde_json",
"serde_urlencoded",
"thiserror", "thiserror",
"tokio", "tokio",
"tokio-tungstenite", "tokio-tungstenite",
@ -1767,18 +1767,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
"itoa",
"ryu",
"serde",
]
[[package]] [[package]]
name = "sha-1" name = "sha-1"
version = "0.10.0" version = "0.10.0"

View File

@ -32,7 +32,7 @@ http = { version = "0.2" }
parse_duration = "2" parse_duration = "2"
rand = "0.8" rand = "0.8"
const_format = "0.2.28" const_format = "0.2.28"
serde_urlencoded = "0.7" regex = "1"
[dev-dependencies] [dev-dependencies]
anyhow = "1" anyhow = "1"

View File

@ -1,11 +1,12 @@
//! Event parsing and validation //! Event parsing and validation
//use crate::error::Error::*; use crate::error::Error;
//use crate::error::Result; use crate::error::Result;
//use crate::utils::unix_time; //use crate::utils::unix_time;
//use bitcoin_hashes::{sha256, Hash}; //use bitcoin_hashes::{sha256, Hash};
//use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::Regex;
//use secp256k1::{schnorr, Secp256k1, VerifyOnly, XOnlyPublicKey}; //use secp256k1::{schnorr, Secp256k1, VerifyOnly, XOnlyPublicKey};
use serde::{Deserializer, Deserialize, Serialize}; use serde::{Deserialize, Serialize};
//use serde_json::value::Value; //use serde_json::value::Value;
//use serde_json::Number; //use serde_json::Number;
//use std::collections::HashMap; //use std::collections::HashMap;
@ -58,35 +59,11 @@ pub enum Value {
Number(u64), Number(u64),
} }
#[derive(Serialize, PartialEq, Eq, Debug, Clone)] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
pub struct ConditionQuery { pub struct ConditionQuery {
pub(crate) conditions: Vec<Condition>, pub(crate) conditions: Vec<Condition>,
} }
impl <'de> Deserialize<'de> for ConditionQuery {
fn deserialize<D>(d: D) -> Result<ConditionQuery, D::Error>
where
D: Deserializer<'de>,
{
// recv'd is an array of pairs.
let _recvd: Value = d.deserialize_seq
let cond_list = recvd.as_object().ok_or_else(|| {
serde::de::Error::invalid_type(
Unexpected::Other("reqfilter is not an object"),
&"a json object",
)
})?;
// all valid conditions will be put into this vec
let conditions : Vec<Condition> = vec![];
// loop through the parsed value, and identify if they are
// known attributes. unknown attributes will trigger failure,
// since we can't respect those restrictions.
Ok(ConditionQuery{conditions})
}
}
/// Parsed delegation statement /// Parsed delegation statement
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
pub struct Delegation { pub struct Delegation {
@ -95,6 +72,7 @@ pub struct Delegation {
pub(crate) signature: String, pub(crate) signature: String,
} }
/// Parsed delegation condition /// Parsed delegation condition
/// see https://github.com/nostr-protocol/nips/pull/28#pullrequestreview-1084903800 /// see https://github.com/nostr-protocol/nips/pull/28#pullrequestreview-1084903800
/// An example complex condition would be: kind=1,2,3&created_at<1665265999 /// An example complex condition would be: kind=1,2,3&created_at<1665265999
@ -105,6 +83,36 @@ pub struct Condition {
pub(crate) values: Vec<Value>, pub(crate) values: Vec<Value>,
} }
fn str_to_condition(cs: &str) -> Option<Condition> {
// a condition is a string (alphanum+underscore), an operator (<>=!), and values (num+comma)
lazy_static! {
static ref RE: Regex = Regex::new("([[:word:]])([<>=!]+)([,[[:digit:]]]+))").unwrap();
}
// match against the regex
let caps = RE.captures(cs)?;
let _field =caps.get(0)?;
Some(Condition {field: Field::Kind, operator: Operator::LessThan, values: vec![]})
}
/// Parse a condition query from a string slice
impl TryFrom<&str> for ConditionQuery {
type Error = Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
// split the string with '&'
let conds = value.split('&');
// parse each individual condition
for c in conds.into_iter() {
str_to_condition(c).ok_or(Error::DelegationParseError)?;
}
Ok(ConditionQuery{conditions: vec![]})
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -114,6 +122,5 @@ mod tests {
fn parse_empty() { fn parse_empty() {
// given an empty condition query, produce an empty vector // given an empty condition query, produce an empty vector
assert_eq!(Delegation::from(""), vec![]); assert_eq!(Delegation::from(""), vec![]);
assert_eq!(serde_urlencoded::from_str::<Vec<(String, String)>>(""), vec![]);
} }
} }

View File

@ -50,6 +50,8 @@ pub enum Error {
HyperError(hyper::Error), HyperError(hyper::Error),
#[error("Hex encoding error")] #[error("Hex encoding error")]
HexError(hex::FromHexError), HexError(hex::FromHexError),
#[error("Delegation parse error")]
DelegationParseError,
#[error("Unknown/Undocumented")] #[error("Unknown/Undocumented")]
UnknownError, UnknownError,
} }