Files
tianxuan/tianxuan/settings.py
T
TianXuan Developer 46013afa74 feat: add simple analysis module with global map visualization
- Add independent 'simple_analysis' Django app with full workflow:
  1. Upload/merge CSV files with auto column detection
  2. Filter by cnam + cnrs + isrs (optional)
  3. Clustering via HDBSCAN+haversine (geo) or /24 subnet (IP)
  4. Interactive Leaflet global map with cluster-colored data points
- Integrate into nav bar, settings, and URL routing without
  modifying existing analysis logic
- Cluster detail panel with IPs, top dst IPs, TLS/cipher profiles
- Chart.js bar/pie charts for cluster size distribution
- E2E Playwright tests for all workflow steps
- Support multiple CSV upload with diagonal_relaxed merge

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 22:39:16 +08:00

161 lines
5.0 KiB
Python

import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
os.makedirs(BASE_DIR / "logs", exist_ok=True)
# Application data directory (user data, outside project for clean updates)
_APP_DATA = Path(os.environ.get('APPDATA', str(Path.home() / '.tianxuan'))) / 'TianXuan'
_APP_DATA.mkdir(parents=True, exist_ok=True)
SECRET_KEY = "django-insecure-change-me-in-production"
DEBUG = True
import logging
import socket
logger = logging.getLogger(__name__)
hostname = socket.gethostname()
try:
local_ip = socket.gethostbyname(hostname)
except Exception:
logger.warning('hostname resolution failed for %s, using 127.0.0.1', hostname)
local_ip = "127.0.0.1"
ALLOWED_HOSTS = ["localhost", "127.0.0.1", hostname, local_ip, "*"]
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"analysis.apps.AnalysisConfig",
"simple_analysis.apps.SimpleAnalysisConfig",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "tianxuan.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "tianxuan.wsgi.application"
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": str(_APP_DATA / "db.sqlite3"),
'OPTIONS': {'timeout': 20},
}
}
CONN_MAX_AGE = 0
# Set SQLite journal mode to DELETE to avoid WAL files during compression
from django.db.backends.signals import connection_created
def _set_sqlite_journal(sender, connection, **kwargs):
if connection.vendor == "sqlite":
with connection.cursor() as cursor:
try:
cursor.execute("PRAGMA journal_mode=WAL;")
except Exception:
logger.warning('SQLite PRAGMA journal_mode=WAL failed')
try:
cursor.execute("PRAGMA synchronous=NORMAL;")
except Exception:
logger.warning('SQLite PRAGMA synchronous=NORMAL failed')
try:
cursor.execute("PRAGMA cache_size=-20000;")
except Exception:
logger.warning('SQLite PRAGMA cache_size failed')
try:
cursor.execute("PRAGMA temp_store=MEMORY;")
except Exception:
logger.warning('SQLite PRAGMA temp_store=MEMORY failed')
try:
cursor.execute("PRAGMA mmap_size=3000000000;")
except Exception:
logger.warning('SQLite PRAGMA mmap_size failed')
connection_created.connect(_set_sqlite_journal)
AUTH_PASSWORD_VALIDATORS = []
LANGUAGE_CODE = "zh-hans"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
DATA_UPLOAD_MAX_NUMBER_FIELDS = 10000000
DATA_UPLOAD_MAX_NUMBER_FILES = 10000
DATA_UPLOAD_MAX_MEMORY_SIZE = 256 * 1024 * 1024
FILE_UPLOAD_MAX_MEMORY_SIZE = 100 * 1024 * 1024
# Upload temp dir — use D: (3TB) to avoid filling C: (500GB OS drive)
FILE_UPLOAD_TEMP_DIR = r'D:\TianXuan\temp'
os.makedirs(FILE_UPLOAD_TEMP_DIR, exist_ok=True)
STATIC_URL = "static/"
STATICFILES_DIRS = [BASE_DIR / "static"]
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"verbose": {"format": "[{asctime}] {levelname} {name}: {message}", "style": "{"}
},
"handlers": {
"file": {
"class": "logging.handlers.RotatingFileHandler",
"filename": BASE_DIR / "logs" / "tianxuan.log",
"maxBytes": 10485760,
"backupCount": 5,
"formatter": "verbose",
"encoding": "utf-8",
},
"stderr": {"class": "logging.StreamHandler", "formatter": "verbose"},
},
"root": {"handlers": ["file", "stderr"], "level": "INFO"},
}
# Dynamically add the configured server host to ALLOWED_HOSTS.
# When the config host is 0.0.0.0 the wildcard "*" (already set above) covers
# all addresses; for a specific IP/DNS name we add it explicitly.
try:
from config import get_config
_cfg = get_config()
_ch = _cfg.server.host
if _ch and _ch not in ALLOWED_HOSTS and _ch != "0.0.0.0":
ALLOWED_HOSTS.append(_ch)
except Exception:
logger.warning('config import failed, ALLOWED_HOSTS unchanged')