feat: unp4k supper search support

This commit is contained in:
xkeyC 2025-12-11 00:54:30 +08:00
parent 83c0fa6a26
commit 3fd020b8b0
9 changed files with 58 additions and 71 deletions

View File

@ -63,13 +63,8 @@ Future<String> dcbRecordToXmlByIndex({required BigInt index}) =>
RustLib.instance.api.crateApiUnp4KApiDcbRecordToXmlByIndex(index: index);
/// DCB
Future<List<DcbSearchResult>> dcbSearchAll({
required String query,
required BigInt maxResults,
}) => RustLib.instance.api.crateApiUnp4KApiDcbSearchAll(
query: query,
maxResults: maxResults,
);
Future<List<DcbSearchResult>> dcbSearchAll({required String query}) =>
RustLib.instance.api.crateApiUnp4KApiDcbSearchAll(query: query);
/// DCB
/// merge: true = XMLfalse = XML

View File

@ -116,7 +116,6 @@ abstract class RustLibApi extends BaseApi {
Future<List<DcbSearchResult>> crateApiUnp4KApiDcbSearchAll({
required String query,
required BigInt maxResults,
});
Future<List<String>> crateApiHttpApiDnsLookupIps({required String host});
@ -693,35 +692,26 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
@override
Future<List<DcbSearchResult>> crateApiUnp4KApiDcbSearchAll({
required String query,
required BigInt maxResults,
}) {
return handler.executeNormal(
NormalTask(
callFfi: (port_) {
var arg0 = cst_encode_String(query);
var arg1 = cst_encode_usize(maxResults);
return wire.wire__crate__api__unp4k_api__dcb_search_all(
port_,
arg0,
arg1,
);
return wire.wire__crate__api__unp4k_api__dcb_search_all(port_, arg0);
},
codec: DcoCodec(
decodeSuccessData: dco_decode_list_dcb_search_result,
decodeErrorData: dco_decode_AnyhowException,
),
constMeta: kCrateApiUnp4KApiDcbSearchAllConstMeta,
argValues: [query, maxResults],
argValues: [query],
apiImpl: this,
),
);
}
TaskConstMeta get kCrateApiUnp4KApiDcbSearchAllConstMeta =>
const TaskConstMeta(
debugName: "dcb_search_all",
argNames: ["query", "maxResults"],
);
const TaskConstMeta(debugName: "dcb_search_all", argNames: ["query"]);
@override
Future<List<String>> crateApiHttpApiDnsLookupIps({required String host}) {

View File

@ -1450,13 +1450,8 @@ class RustLibWire implements BaseWire {
void wire__crate__api__unp4k_api__dcb_search_all(
int port_,
ffi.Pointer<wire_cst_list_prim_u_8_strict> query,
int max_results,
) {
return _wire__crate__api__unp4k_api__dcb_search_all(
port_,
query,
max_results,
);
return _wire__crate__api__unp4k_api__dcb_search_all(port_, query);
}
late final _wire__crate__api__unp4k_api__dcb_search_allPtr =
@ -1465,7 +1460,6 @@ class RustLibWire implements BaseWire {
ffi.Void Function(
ffi.Int64,
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
ffi.UintPtr,
)
>
>(
@ -1474,7 +1468,7 @@ class RustLibWire implements BaseWire {
late final _wire__crate__api__unp4k_api__dcb_search_all =
_wire__crate__api__unp4k_api__dcb_search_allPtr
.asFunction<
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>, int)
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)
>();
void wire__crate__api__http_api__dns_lookup_ips(

View File

@ -261,7 +261,7 @@ class DcbViewerModel extends _$DcbViewerModel {
state = state.copyWith(isSearching: true, fullTextSearchQuery: query, viewMode: DcbViewMode.searchResults);
try {
final apiResults = await unp4k_api.dcbSearchAll(query: query, maxResults: BigInt.from(1000000));
final apiResults = await unp4k_api.dcbSearchAll(query: query);
//
final results = apiResults.map((r) {

View File

@ -41,7 +41,7 @@ final class DcbViewerModelProvider
}
}
String _$dcbViewerModelHash() => r'94c3542282f64917efadbe14a0ee4967220bec77';
String _$dcbViewerModelHash() => r'f0af2a7b4451f746288e2c9565a418af80f58835';
abstract class _$DcbViewerModel extends $Notifier<DcbViewerState> {
DcbViewerState build();

1
rust/Cargo.lock generated
View File

@ -4916,6 +4916,7 @@ dependencies = [
"once_cell",
"ort",
"parking_lot",
"rayon",
"reqwest",
"scopeguard",
"serde",

View File

@ -34,6 +34,7 @@ serde = { version = "1.0.228", features = ["derive"] }
unp4k_rs = { git = "https://github.com/StarCitizenToolBox/unp4k_rs", rev = "29430002d6f3a8d87feabac26c03ae0311c81263" }
#unp4k_rs = { path = "../../unp4k_rs" }
uuid = { version = "1.19.0", features = ["v4"] }
rayon = "1.10"
parking_lot = "0.12.5"
crossbeam-channel = "0.5.15"
librqbit = { git = "https://github.com/StarCitizenToolBox/rqbit", rev = "f8c0b0927904e1d8b0e28e708bd69fd8069d413a" }

View File

@ -1,5 +1,6 @@
use anyhow::{anyhow, Result};
use flutter_rust_bridge::frb;
use rayon::prelude::*;
use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
@ -329,7 +330,7 @@ pub struct DcbSearchMatch {
}
/// 全文搜索 DCB 记录
pub async fn dcb_search_all(query: String, max_results: usize) -> Result<Vec<DcbSearchResult>> {
pub async fn dcb_search_all(query: String) -> Result<Vec<DcbSearchResult>> {
tokio::task::spawn_blocking(move || {
let reader = GLOBAL_DCB_READER.lock().unwrap();
let df = reader
@ -337,48 +338,58 @@ pub async fn dcb_search_all(query: String, max_results: usize) -> Result<Vec<Dcb
.ok_or_else(|| anyhow!("DCB reader not initialized"))?;
let query_lower = query.to_lowercase();
let mut results = Vec::new();
for (path, &index) in df.path_to_record() {
if results.len() >= max_results {
break;
}
// 收集所有记录路径和索引
let records: Vec<(String, usize)> = df
.path_to_record()
.iter()
.map(|(path, &index)| (path.clone(), index))
.collect();
// 先检查路径是否匹配
let path_matches = path.to_lowercase().contains(&query_lower);
// 使用 rayon 并发搜索
let mut results: Vec<DcbSearchResult> = records
.par_iter()
.filter_map(|(path, index)| {
// 先检查路径是否匹配
let path_matches = path.to_lowercase().contains(&query_lower);
// 尝试获取 XML 并搜索内容
if let Ok(xml) = df.record_to_xml_by_index(index, true) {
let mut matches = Vec::new();
// 尝试获取 XML 并搜索内容
if let Ok(xml) = df.record_to_xml_by_index(*index, true) {
let mut matches = Vec::new();
for (line_num, line) in xml.lines().enumerate() {
if line.to_lowercase().contains(&query_lower) {
let line_content = if line.len() > 200 {
format!("{}...", &line[..200])
} else {
line.to_string()
};
matches.push(DcbSearchMatch {
line_number: line_num + 1,
line_content,
});
for (line_num, line) in xml.lines().enumerate() {
if line.to_lowercase().contains(&query_lower) {
let line_content = if line.len() > 200 {
format!("{}...", &line[..200])
} else {
line.to_string()
};
matches.push(DcbSearchMatch {
line_number: line_num + 1,
line_content,
});
// 每条记录最多保留 5 个匹配
if matches.len() >= 5 {
break;
// 每条记录最多保留 5 个匹配
if matches.len() >= 5 {
break;
}
}
}
}
if path_matches || !matches.is_empty() {
results.push(DcbSearchResult {
path: path.clone(),
index,
matches,
});
if path_matches || !matches.is_empty() {
return Some(DcbSearchResult {
path: path.clone(),
index: *index,
matches,
});
}
}
}
}
None
})
.collect();
// 按路径排序以保持结果稳定性
results.sort_by(|a, b| a.path.cmp(&b.path));
Ok(results)
})

View File

@ -332,7 +332,6 @@ fn wire__crate__api__unp4k_api__dcb_record_to_xml_by_index_impl(
fn wire__crate__api__unp4k_api__dcb_search_all_impl(
port_: flutter_rust_bridge::for_generated::MessagePort,
query: impl CstDecode<String>,
max_results: impl CstDecode<usize>,
) {
FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::<flutter_rust_bridge::for_generated::DcoCodec, _, _, _>(
flutter_rust_bridge::for_generated::TaskInfo {
@ -342,13 +341,10 @@ fn wire__crate__api__unp4k_api__dcb_search_all_impl(
},
move || {
let api_query = query.cst_decode();
let api_max_results = max_results.cst_decode();
move |context| async move {
transform_result_dco::<_, _, flutter_rust_bridge::for_generated::anyhow::Error>(
(move || async move {
let output_ok =
crate::api::unp4k_api::dcb_search_all(api_query, api_max_results)
.await?;
let output_ok = crate::api::unp4k_api::dcb_search_all(api_query).await?;
Ok(output_ok)
})()
.await,
@ -4649,9 +4645,8 @@ mod io {
pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__unp4k_api__dcb_search_all(
port_: i64,
query: *mut wire_cst_list_prim_u_8_strict,
max_results: usize,
) {
wire__crate__api__unp4k_api__dcb_search_all_impl(port_, query, max_results)
wire__crate__api__unp4k_api__dcb_search_all_impl(port_, query)
}
#[unsafe(no_mangle)]