fire_scope/
process.rs

1use crate::common::OutputFormat;
2use crate::error::AppError;
3use crate::output::write_ip_lists_to_files;
4use ipnet::IpNet;
5use std::collections::{BTreeSet, HashMap};
6use std::sync::Arc;
7use tokio::task::JoinHandle;
8use crate::common::debug_log;
9
10/// 全RIRテキストから該当国コードのIP一覧を集約し、そのまま書き出し
11pub async fn process_all_country_codes(
12    country_codes: &[String],
13    rir_texts: &[String],
14    output_format: OutputFormat,
15) -> Result<(), AppError> {
16    // 1回だけ全RIRテキストをパースして国コード→(IPv4,IPv6)のマップを作る(CPU重)
17    let rir_texts_owned = rir_texts.to_owned();
18    let country_map = tokio::task::spawn_blocking(move || {
19        crate::parse::parse_all_country_codes(&rir_texts_owned)
20    })
21    .await??;
22    let country_map_arc = Arc::new(country_map);
23
24    // 国コードごとに並列タスクを生成(事前パース結果を参照)
25    let mut tasks: Vec<JoinHandle<Result<(), AppError>>> = Vec::new();
26    for code in country_codes {
27        let code_cloned = code.clone();
28        let map_cloned = Arc::clone(&country_map_arc);
29        tasks.push(tokio::spawn(async move {
30            crate::process::process_country_code_from_map(&code_cloned, &map_cloned, output_format)
31                .await
32        }));
33    }
34
35    // すべてのタスクを待機
36    for handle in tasks {
37        handle.await??;
38    }
39    Ok(())
40}
41
42/// IPv4範囲をBTreeSetへ直接挿入
43/// 逐次集合化する
44// 旧実装の逐次パースヘルパは廃止(共通パーサへ統一)
45
46/// RIR テキストを1行ずつストリーミング解析し、重複排除しながら集合化
47/// 戻り値は **重複無し・昇順** の `BTreeSet`
48pub fn parse_and_collect_ips(
49    country_code: &str,
50    rir_texts: &[String],
51) -> Result<(BTreeSet<IpNet>, BTreeSet<IpNet>), AppError> {
52    // 実装統一: 共通の全体パーサを用い、対象国コードのみ抽出
53    let cc_upper = country_code.to_ascii_uppercase();
54    let map = crate::parse::parse_all_country_codes(rir_texts)?;
55    let (v4_vec, v6_vec) = map.get(&cc_upper).cloned().unwrap_or_default();
56    let v4_set: BTreeSet<IpNet> = v4_vec.into_iter().collect();
57    let v6_set: BTreeSet<IpNet> = v6_vec.into_iter().collect();
58    Ok((v4_set, v6_set))
59}
60
61pub async fn process_country_code_from_map(
62    country_code: &str,
63    country_map: &HashMap<String, (Vec<IpNet>, Vec<IpNet>)>,
64    output_format: OutputFormat,
65) -> Result<(), AppError> {
66    let upper = country_code.to_ascii_uppercase();
67    let (v4_vec, v6_vec) = match country_map.get(&upper) {
68        Some(tup) => tup,
69        None => {
70            debug_log(format!("No IPs found for country code: {}", upper));
71            return Ok(());
72        }
73    };
74
75    // CPU バウンドの aggregate を block_in_place で分離
76    let (ipv4_set, ipv6_set) = tokio::task::block_in_place(|| {
77        let v4_set = IpNet::aggregate(&v4_vec).into_iter().collect();
78        let v6_set = IpNet::aggregate(&v6_vec).into_iter().collect();
79        (v4_set, v6_set)
80    });
81
82    write_ip_lists_to_files(&upper, &ipv4_set, &ipv6_set, output_format).await
83}