feat: wigle config and status endpoints
This commit is contained in:
parent
eaf49841f0
commit
064378870b
2 changed files with 150 additions and 1 deletions
|
|
@ -3,7 +3,7 @@ import subprocess
|
|||
from flask import Flask, request, jsonify
|
||||
from . import config, db, forwarder
|
||||
from .auth import get_device_serial, get_api_token, require_auth
|
||||
from .routes import landmarks, gnss, status, frames
|
||||
from .routes import landmarks, gnss, status, frames, wigle
|
||||
|
||||
|
||||
def create_app():
|
||||
|
|
@ -19,6 +19,7 @@ def create_app():
|
|||
app.register_blueprint(gnss.bp)
|
||||
app.register_blueprint(status.bp)
|
||||
app.register_blueprint(frames.bp)
|
||||
app.register_blueprint(wigle.bp)
|
||||
|
||||
# ── PAIRING ENDPOINT ─────────────────────────────────────────────────────
|
||||
@app.route('/pair')
|
||||
|
|
|
|||
148
adacam_api/routes/wigle.py
Normal file
148
adacam_api/routes/wigle.py
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
"""WiGLE wardriving status and config endpoints."""
|
||||
import os
|
||||
import sqlite3
|
||||
import subprocess
|
||||
import time
|
||||
from flask import Blueprint, jsonify, request
|
||||
from ..auth import require_auth
|
||||
|
||||
bp = Blueprint('wigle', __name__, url_prefix='/api/1/wigle')
|
||||
|
||||
WIGLE_DB = '/data/adacam/wigle.db'
|
||||
|
||||
|
||||
def _get_db():
|
||||
"""Get SQLite connection to wigle.db, create tables if needed."""
|
||||
os.makedirs(os.path.dirname(WIGLE_DB), exist_ok=True)
|
||||
conn = sqlite3.connect(WIGLE_DB)
|
||||
conn.execute('''CREATE TABLE IF NOT EXISTS wigle_records (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT, bssid TEXT NOT NULL, ssid TEXT,
|
||||
auth_mode TEXT, first_seen TEXT, channel INTEGER, rssi INTEGER,
|
||||
lat REAL, lon REAL, alt REAL, accuracy REAL, uploaded INTEGER DEFAULT 0, created_at INTEGER)''')
|
||||
conn.execute('''CREATE TABLE IF NOT EXISTS wigle_config (key TEXT PRIMARY KEY, value TEXT)''')
|
||||
return conn
|
||||
|
||||
|
||||
def _get_config(conn):
|
||||
cur = conn.execute('SELECT key, value FROM wigle_config')
|
||||
return dict(cur.fetchall())
|
||||
|
||||
|
||||
def _mask_api_name(api_name: str) -> str:
|
||||
"""Mask API name showing only first 4 chars."""
|
||||
if not api_name or len(api_name) < 4:
|
||||
return '●●●●●●●●' if api_name else ''
|
||||
return api_name[:4] + '●●●●●●●●'
|
||||
|
||||
|
||||
@bp.route('/status')
|
||||
def wigle_status():
|
||||
"""Get WiGLE service status (unauthenticated)."""
|
||||
try:
|
||||
conn = _get_db()
|
||||
cfg = _get_config(conn)
|
||||
|
||||
total = conn.execute('SELECT COUNT(*) FROM wigle_records').fetchone()[0]
|
||||
pending = conn.execute('SELECT COUNT(*) FROM wigle_records WHERE uploaded=0').fetchone()[0]
|
||||
|
||||
last_scan = cfg.get('last_scan')
|
||||
last_upload = cfg.get('last_upload')
|
||||
|
||||
conn.close()
|
||||
|
||||
return jsonify({
|
||||
'enabled': cfg.get('enabled', '0') == '1',
|
||||
'api_name': _mask_api_name(cfg.get('api_name', '')),
|
||||
'total_networks': total,
|
||||
'pending_upload': pending,
|
||||
'last_scan': int(last_scan) if last_scan else None,
|
||||
'last_upload': int(last_upload) if last_upload else None
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e), 'enabled': False, 'total_networks': 0, 'pending_upload': 0})
|
||||
|
||||
|
||||
@bp.route('/stats')
|
||||
def wigle_stats():
|
||||
"""Get WiGLE statistics (unauthenticated)."""
|
||||
try:
|
||||
conn = _get_db()
|
||||
|
||||
total = conn.execute('SELECT COUNT(*) FROM wigle_records').fetchone()[0]
|
||||
uploaded = conn.execute('SELECT COUNT(*) FROM wigle_records WHERE uploaded=1').fetchone()[0]
|
||||
pending = conn.execute('SELECT COUNT(*) FROM wigle_records WHERE uploaded=0').fetchone()[0]
|
||||
|
||||
# Scans today (records created in last 24h)
|
||||
day_ago = int(time.time()) - 86400
|
||||
scans_today = conn.execute(
|
||||
'SELECT COUNT(DISTINCT first_seen) FROM wigle_records WHERE created_at > ?',
|
||||
(day_ago,)
|
||||
).fetchone()[0]
|
||||
|
||||
conn.close()
|
||||
|
||||
return jsonify({
|
||||
'total_networks': total,
|
||||
'uploaded_networks': uploaded,
|
||||
'pending_upload': pending,
|
||||
'scans_today': scans_today
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e), 'total_networks': 0, 'uploaded_networks': 0, 'pending_upload': 0, 'scans_today': 0})
|
||||
|
||||
|
||||
@bp.route('/config', methods=['POST'])
|
||||
@require_auth
|
||||
def wigle_config():
|
||||
"""Set WiGLE configuration (authenticated)."""
|
||||
data = request.get_json() or {}
|
||||
|
||||
try:
|
||||
conn = _get_db()
|
||||
|
||||
# Update enabled status
|
||||
if 'enabled' in data:
|
||||
conn.execute(
|
||||
'INSERT OR REPLACE INTO wigle_config (key, value) VALUES (?, ?)',
|
||||
('enabled', '1' if data['enabled'] else '0')
|
||||
)
|
||||
|
||||
# Update API credentials
|
||||
if 'api_name' in data:
|
||||
conn.execute(
|
||||
'INSERT OR REPLACE INTO wigle_config (key, value) VALUES (?, ?)',
|
||||
('api_name', data['api_name'])
|
||||
)
|
||||
|
||||
if 'api_token' in data:
|
||||
conn.execute(
|
||||
'INSERT OR REPLACE INTO wigle_config (key, value) VALUES (?, ?)',
|
||||
('api_token', data['api_token'])
|
||||
)
|
||||
|
||||
# Optional: scan/upload intervals
|
||||
if 'scan_interval_seconds' in data:
|
||||
conn.execute(
|
||||
'INSERT OR REPLACE INTO wigle_config (key, value) VALUES (?, ?)',
|
||||
('scan_interval_seconds', str(data['scan_interval_seconds']))
|
||||
)
|
||||
|
||||
if 'upload_interval_seconds' in data:
|
||||
conn.execute(
|
||||
'INSERT OR REPLACE INTO wigle_config (key, value) VALUES (?, ?)',
|
||||
('upload_interval_seconds', str(data['upload_interval_seconds']))
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
# Restart the wigle service to pick up config changes
|
||||
try:
|
||||
subprocess.run(['systemctl', 'restart', 'adacam-wigle'], timeout=10)
|
||||
except Exception:
|
||||
pass # Service may not exist yet
|
||||
|
||||
return jsonify({'ok': True, 'message': 'WiGLE configuration updated'})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
Loading…
Add table
Add a link
Reference in a new issue