2 コミット 929307b23e ... b4d0fc75a8

作者 SHA1 メッセージ 日付
  Vecna b4d0fc75a8 Ignore days with no published extra-info 3 週間 前
  Vecna ae1b90ce6f Store 0 connection counts if cc does not appear in bridge-ips 3 週間 前
3 ファイル変更122 行追加22 行削除
  1. 57 22
      src/analysis.rs
  2. 9 0
      src/lib.rs
  3. 56 0
      src/tests/extra_infos.rs

+ 57 - 22
src/analysis.rs

@@ -69,12 +69,43 @@ pub fn blocked_in(
             // Assume bridges never become unblocked
             blocked_in.insert(country.to_string());
         } else {
-            // Get today's values
-            let new_map_binding = BTreeMap::<BridgeInfoType, u32>::new();
-            // TODO: Evaluate on yesterday if we don't have data for today?
+            // Get today's values, or yesterday's if no bridge-ips for today
             let today_info = match info.info_by_day.get(&today) {
-                Some(v) => v,
-                None => &new_map_binding,
+                Some(v) => {
+                    if v.contains_key(&BridgeInfoType::BridgeIps) {
+                        v
+                    } else {
+                        // Evaluate on yesterday if we don't have data for today
+                        match info.info_by_day.get(&(today - 1)) {
+                            Some(v2) => {
+                                if v2.contains_key(&BridgeInfoType::BridgeIps) {
+                                    v2
+                                } else {
+                                    // If we don't have data today or yesterday,
+                                    // assume the bridge is down, not blocked.
+                                    continue;
+                                }
+                            }
+                            // If we don't have data today or yesterday,
+                            // assume the bridge is down, not blocked.
+                            None => continue,
+                        }
+                    }
+                }
+                None => match info.info_by_day.get(&(today - 1)) {
+                    Some(v) => {
+                        if v.contains_key(&BridgeInfoType::BridgeIps) {
+                            v
+                        } else {
+                            // If we don't have data today or yesterday,
+                            // assume the bridge is down, not blocked.
+                            continue;
+                        }
+                    }
+                    // If we don't have data today or yesterday,
+                    // assume the bridge is down, not blocked.
+                    None => continue,
+                },
             };
             let bridge_ips_today = match today_info.get(&BridgeInfoType::BridgeIps) {
                 Some(&v) => v,
@@ -92,9 +123,9 @@ pub fn blocked_in(
             let num_days = min(age, max_historical_days);
 
             // Get time series for last num_days
-            let mut bridge_ips = vec![0; num_days as usize];
-            let mut negative_reports = vec![0; num_days as usize];
-            let mut positive_reports = vec![0; num_days as usize];
+            let mut bridge_ips = vec![];
+            let mut negative_reports = vec![];
+            let mut positive_reports = vec![];
 
             for i in 0..num_days {
                 let date = today - num_days + i - 1;
@@ -103,20 +134,24 @@ pub fn blocked_in(
                     Some(v) => v,
                     None => &new_map_binding,
                 };
-                bridge_ips[i as usize] = match day_info.get(&BridgeInfoType::BridgeIps) {
-                    Some(&v) => v,
-                    None => 0,
-                };
-                negative_reports[i as usize] = match day_info.get(&BridgeInfoType::NegativeReports)
-                {
-                    Some(&v) => v,
-                    None => 0,
-                };
-                positive_reports[i as usize] = match day_info.get(&BridgeInfoType::PositiveReports)
-                {
-                    Some(&v) => v,
-                    None => 0,
-                };
+
+                // If the bridge did not publish bridge-ips, ignore this day
+                if day_info.contains_key(&BridgeInfoType::BridgeIps) {
+                    let bip = *day_info.get(&BridgeInfoType::BridgeIps).unwrap();
+                    let nr = match day_info.get(&BridgeInfoType::NegativeReports) {
+                        Some(&v) => v,
+                        None => 0,
+                    };
+                    let pr = match day_info.get(&BridgeInfoType::PositiveReports) {
+                        Some(&v) => v,
+                        None => 0,
+                    };
+
+                    // If we have bridge-ips for today, add all 3 values to our time series
+                    bridge_ips.push(bip);
+                    negative_reports.push(nr);
+                    positive_reports.push(pr);
+                }
             }
 
             // Evaluate using appropriate stage based on age of the bridge

+ 9 - 0
src/lib.rs

@@ -339,6 +339,15 @@ pub fn add_extra_info_to_db(db: &Db, extra_info: ExtraInfo) {
                 .insert(country.to_string(), bridge_country_info);
         }
     }
+
+    // Store 0 if we have no connections from a country today, but we
+    // have seen connections from the country in the past.
+    for (country, info) in &mut bridge_info.info_by_country {
+        if !extra_info.bridge_ips.contains_key(country) {
+            info.add_info(BridgeInfoType::BridgeIps, extra_info.date, 0);
+        }
+    }
+
     // Commit changes to database
     db.insert(fingerprint, bincode::serialize(&bridge_info).unwrap())
         .unwrap();

+ 56 - 0
src/tests/extra_infos.rs

@@ -136,4 +136,60 @@ router-digest F30B38390C375E1EE74BFED844177804442569E0"#;
     assert!(db.contains_key(bridge_to_test).unwrap());
     let _bridge_info: BridgeInfo =
         bincode::deserialize(&db.get(bridge_to_test).unwrap().unwrap()).unwrap();
+
+    // Add another day's data, with no Russia data this time
+    let extra_info_str_2 = r#"@type bridge-extra-info 1.3
+extra-info ElephantBridgeDE2 72E12B89136B45BBC81D1EF0AC7DDDBB91B148DB
+bridge-stats-end 2024-04-06 06:51:44 (86400 s)
+bridge-ips us=32,??=8,au=8,br=8,by=8,cn=8,de=8,eg=8,eu=8,gb=8,ge=8,hr=8,ie=8,ir=8,kp=8,lt=8,mt=8,nl=8,pl=8,ro=8,sg=8,tn=8,tr=8,vn=8"#;
+
+    let extra_info_set_2 = ExtraInfo::parse_file(&extra_info_str_2);
+
+    // Add our extra-info to the server's records
+    {
+        use hyper::{Body, Client, Method, Request};
+        let client = Client::new();
+        let req = Request::builder()
+            .method(Method::POST)
+            .uri("http://localhost:8004/add".parse::<hyper::Uri>().unwrap())
+            .body(Body::from(
+                serde_json::to_string(&extra_info_set_2).unwrap(),
+            ))
+            .unwrap();
+        client.request(req).await.unwrap();
+    }
+
+    // Update extra-infos (add new record)
+    update_extra_infos(&db, "http://localhost:8004/")
+        .await
+        .unwrap();
+
+    let bridge_info: BridgeInfo =
+        bincode::deserialize(&db.get(bridge_to_test).unwrap().unwrap()).unwrap();
+
+    // We should not have any data on Canada
+    assert!(!bridge_info.info_by_country.contains_key("ca"));
+
+    // We should have data on Russia
+    let russia_info = bridge_info.info_by_country.get("ru").unwrap();
+    assert_eq!(
+        *russia_info
+            .info_by_day
+            .get(&2460406)
+            .unwrap()
+            .get(&BridgeInfoType::BridgeIps)
+            .unwrap(),
+        40
+    );
+    // Because we have historical data on Russia, but it wasn't listed
+    // today, we should see 0
+    assert_eq!(
+        *russia_info
+            .info_by_day
+            .get(&2460407)
+            .unwrap()
+            .get(&BridgeInfoType::BridgeIps)
+            .unwrap(),
+        0
+    );
 }