diff --git a/analysis/geoip.py b/analysis/geoip.py index 076b42b..ca9e832 100644 --- a/analysis/geoip.py +++ b/analysis/geoip.py @@ -12,6 +12,7 @@ import bisect import gzip import logging import shutil +import tempfile from pathlib import Path from typing import Optional @@ -107,11 +108,24 @@ def _load_mmdb() -> None: try: import maxminddb - _mmdb_city = maxminddb.open_database(city_path) + + # maxminddb C extension cannot handle non-ASCII Windows paths. + # Workaround: copy MMDB files to a temp dir with ASCII-only path. + _tmp_dir = Path(tempfile.gettempdir()) / 'tianxuan_geoip' + _tmp_dir.mkdir(parents=True, exist_ok=True) + + _tmp_city = _tmp_dir / 'GeoLite2-City.mmdb' + if not _tmp_city.exists() or _tmp_city.stat().st_size != city_path.stat().st_size: + logger.info('[GEOIP] copying MMDB to ASCII-safe temp dir …') + shutil.copy2(city_path, _tmp_city) + _mmdb_city = maxminddb.open_database(str(_tmp_city)) logger.info('[GEOIP] loaded GeoLite2-City.mmdb (MMDB format)') if asn_path.exists(): - _mmdb_asn = maxminddb.open_database(asn_path) + _tmp_asn = _tmp_dir / 'GeoLite2-ASN.mmdb' + if not _tmp_asn.exists() or _tmp_asn.stat().st_size != asn_path.stat().st_size: + shutil.copy2(asn_path, _tmp_asn) + _mmdb_asn = maxminddb.open_database(str(_tmp_asn)) logger.info('[GEOIP] loaded GeoLite2-ASN.mmdb (ISP/ORG)') except Exception as e: logger.warning('[GEOIP] failed to open MMDB: %s', e) diff --git a/simple_analysis/views.py b/simple_analysis/views.py index ee1018d..72a4782 100644 --- a/simple_analysis/views.py +++ b/simple_analysis/views.py @@ -792,11 +792,12 @@ def _cluster_network(entry: dict, df: pl.DataFrame, meta: dict, logger.info('Network clustering: %d unique IPs from %d records', n_nodes, len(df)) # ── 2. GeoIP 解析所有 IP ─────────────────────────────────────────── + # MMDB优先(高精度),upload时的geo_cache兜底(低精度文本回退) node_geo = {} # ip → {lat, lon, city, country, isp, org} for ip in unique_ips: - info = geo_cache.get(ip) + info = geoip_lookup(ip) # 优先用当前加载的MMDB数据库 if not info: - info = geoip_lookup(ip) + info = geo_cache.get(ip) # 回退到上传时的缓存 if info: node_geo[ip] = info