20260718 重构 RPKI Explorer 查询界面
This commit is contained in:
@@ -50,6 +50,68 @@ pub enum ObjectLookup {
|
||||
Sha256(String),
|
||||
}
|
||||
|
||||
/// Optional predicates applied while streaming report objects. `reason` and
|
||||
/// `query` must be pre-lowercased by the caller; they are matched as
|
||||
/// case-insensitive substrings. The other fields are exact matches.
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
pub struct ObjectFilter {
|
||||
pub object_type: Option<String>,
|
||||
pub result: Option<String>,
|
||||
pub rejected: Option<bool>,
|
||||
pub reason: Option<String>,
|
||||
pub query: Option<String>,
|
||||
pub repo_id: Option<String>,
|
||||
pub pp_id: Option<String>,
|
||||
pub issues_only: bool,
|
||||
}
|
||||
|
||||
impl ObjectFilter {
|
||||
pub fn matches(&self, object: &ObjectInstanceRecord) -> bool {
|
||||
if self.issues_only && !(object.rejected || object.result == "error") {
|
||||
return false;
|
||||
}
|
||||
if let Some(rejected) = self.rejected
|
||||
&& object.rejected != rejected
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if let Some(result) = self.result.as_deref()
|
||||
&& !object.result.eq_ignore_ascii_case(result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if let Some(object_type) = self.object_type.as_deref()
|
||||
&& !object.object_type.eq_ignore_ascii_case(object_type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if let Some(repo_id) = self.repo_id.as_deref()
|
||||
&& object.repo_id != repo_id
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if let Some(pp_id) = self.pp_id.as_deref()
|
||||
&& object.pp_id != pp_id
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if let Some(reason) = self.reason.as_deref() {
|
||||
let Some(reject_reason) = object.reject_reason.as_deref() else {
|
||||
return false;
|
||||
};
|
||||
if !reject_reason.to_lowercase().contains(reason) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if let Some(query) = self.query.as_deref()
|
||||
&& !object.uri.to_lowercase().contains(query)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ObjectResolutionMeta {
|
||||
@@ -81,13 +143,37 @@ pub fn list_report_objects(
|
||||
scope: ObjectScope,
|
||||
limit: usize,
|
||||
cursor: Option<&str>,
|
||||
) -> QueryDbResult<QueryPage<ObjectInstanceRecord>> {
|
||||
list_report_objects_filtered(
|
||||
report_path,
|
||||
run_id,
|
||||
scope,
|
||||
&ObjectFilter::default(),
|
||||
limit,
|
||||
cursor,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn list_report_objects_filtered(
|
||||
report_path: &Path,
|
||||
run_id: &str,
|
||||
scope: ObjectScope,
|
||||
filter: &ObjectFilter,
|
||||
limit: usize,
|
||||
cursor: Option<&str>,
|
||||
) -> QueryDbResult<QueryPage<ObjectInstanceRecord>> {
|
||||
let (start_pp_index, start_object_index) = parse_object_cursor(cursor)?;
|
||||
let file = File::open(report_path)?;
|
||||
let reader = BufReader::new(file);
|
||||
let mut deserializer = serde_json::Deserializer::from_reader(reader);
|
||||
let mut state =
|
||||
ObjectScanState::new_list(run_id, scope, limit, start_pp_index, start_object_index);
|
||||
let mut state = ObjectScanState::new_list(
|
||||
run_id,
|
||||
scope,
|
||||
filter.clone(),
|
||||
limit,
|
||||
start_pp_index,
|
||||
start_object_index,
|
||||
);
|
||||
ObjectScanSeed { state: &mut state }
|
||||
.deserialize(&mut deserializer)
|
||||
.map_err(QueryDbError::from)?;
|
||||
@@ -530,6 +616,7 @@ struct ObjectScanState<'a> {
|
||||
run_id: &'a str,
|
||||
scope: ObjectScope,
|
||||
mode: ObjectScanMode,
|
||||
filter: ObjectFilter,
|
||||
limit: usize,
|
||||
start_pp_index: u64,
|
||||
start_object_index: u64,
|
||||
@@ -544,6 +631,7 @@ impl<'a> ObjectScanState<'a> {
|
||||
fn new_list(
|
||||
run_id: &'a str,
|
||||
scope: ObjectScope,
|
||||
filter: ObjectFilter,
|
||||
limit: usize,
|
||||
start_pp_index: u64,
|
||||
start_object_index: u64,
|
||||
@@ -552,6 +640,7 @@ impl<'a> ObjectScanState<'a> {
|
||||
run_id,
|
||||
scope,
|
||||
mode: ObjectScanMode::List,
|
||||
filter,
|
||||
limit,
|
||||
start_pp_index,
|
||||
start_object_index,
|
||||
@@ -568,6 +657,7 @@ impl<'a> ObjectScanState<'a> {
|
||||
run_id,
|
||||
scope,
|
||||
mode: ObjectScanMode::Lookup(lookup),
|
||||
filter: ObjectFilter::default(),
|
||||
limit: 1,
|
||||
start_pp_index: 0,
|
||||
start_object_index: 0,
|
||||
@@ -682,7 +772,8 @@ fn process_raw_publication_point(
|
||||
let after_cursor = pp_index > state.start_pp_index
|
||||
|| (pp_index == state.start_pp_index
|
||||
&& object_index >= state.start_object_index);
|
||||
if after_cursor && state.data.len() < state.limit {
|
||||
if after_cursor && state.data.len() < state.limit && state.filter.matches(&record)
|
||||
{
|
||||
state.data.push(record);
|
||||
if state.data.len() == state.limit {
|
||||
state.next_cursor = Some(object_cursor(pp_index, object_index + 1));
|
||||
|
||||
Reference in New Issue
Block a user