modified: .gitignore

modified:   app.py
	new file:   command_storage/.gitignore
This commit is contained in:
SimolZimol
2026-01-07 04:24:59 +01:00
parent 6d38651305
commit 404b2ac77f
3 changed files with 42 additions and 24 deletions

3
.gitignore vendored
View File

@@ -3,6 +3,9 @@ __pycache__/
*.py[cod] *.py[cod]
*$py.class *$py.class
# Command storage (temporary files)
command_storage/*.json
# Virtual environments # Virtual environments
.venv/ .venv/
venv/ venv/

60
app.py
View File

@@ -8,18 +8,22 @@ from flask import Flask, render_template, jsonify, send_from_directory, request
app = Flask(__name__) app = Flask(__name__)
# In-memory storage for commands (thread-safe) # File-based storage for commands (works across multiple workers)
command_storage = {} STORAGE_DIR = Path(__file__).parent / 'command_storage'
STORAGE_DIR.mkdir(exist_ok=True)
storage_lock = Lock() storage_lock = Lock()
def cleanup_expired_commands(): def cleanup_expired_commands():
"""Remove expired commands from storage""" """Remove expired command files"""
with storage_lock: now = datetime.now(timezone.utc)
now = datetime.now(timezone.utc) for file_path in STORAGE_DIR.glob('*.json'):
expired_keys = [key for key, value in command_storage.items() try:
if datetime.fromisoformat(value['expires_at']) < now] with open(file_path, 'r') as f:
for key in expired_keys: data = json.load(f)
del command_storage[key] if datetime.fromisoformat(data['expires_at']) < now:
file_path.unlink()
except:
pass # Ignore corrupted files
# Load projects from version.json # Load projects from version.json
def load_projects(): def load_projects():
@@ -272,13 +276,18 @@ def store_command():
created_at = datetime.now(timezone.utc) created_at = datetime.now(timezone.utc)
expires_at = created_at + timedelta(minutes=30) expires_at = created_at + timedelta(minutes=30)
# Store command # Prepare data
command_data = {
'command': command,
'created_at': created_at.isoformat(),
'expires_at': expires_at.isoformat()
}
# Store to file
storage_file = STORAGE_DIR / f'{command_uuid}.json'
with storage_lock: with storage_lock:
command_storage[command_uuid] = { with open(storage_file, 'w', encoding='utf-8') as f:
'command': command, json.dump(command_data, f)
'created_at': created_at.isoformat(),
'expires_at': expires_at.isoformat()
}
# Generate URL - use HTTPS if behind proxy # Generate URL - use HTTPS if behind proxy
scheme = request.headers.get('X-Forwarded-Proto', 'https' if request.is_secure else 'http') scheme = request.headers.get('X-Forwarded-Proto', 'https' if request.is_secure else 'http')
@@ -300,20 +309,23 @@ def retrieve_command(command_uuid):
"""Retrieve stored command by UUID (JSON response for plugin)""" """Retrieve stored command by UUID (JSON response for plugin)"""
cleanup_expired_commands() cleanup_expired_commands()
# Keep lock for entire operation to prevent race conditions storage_file = STORAGE_DIR / f'{command_uuid}.json'
with storage_lock:
command_data = command_storage.get(command_uuid) if not storage_file.exists():
return jsonify({'error': 'Command not found or expired'}), 404
if not command_data:
return jsonify({'error': 'Command not found or expired'}), 404 try:
with open(storage_file, 'r', encoding='utf-8') as f:
command_data = json.load(f)
# Check if expired # Check if expired
if datetime.fromisoformat(command_data['expires_at']) < datetime.now(timezone.utc): if datetime.fromisoformat(command_data['expires_at']) < datetime.now(timezone.utc):
del command_storage[command_uuid] storage_file.unlink()
return jsonify({'error': 'Command expired'}), 410 return jsonify({'error': 'Command expired'}), 410
# Return a copy to avoid modification outside lock return jsonify(command_data), 200
return jsonify(dict(command_data)), 200 except Exception as e:
return jsonify({'error': 'Failed to read command'}), 500
# Serve /versions as JSON # Serve /versions as JSON
@app.route('/versions') @app.route('/versions')

3
command_storage/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
# This directory stores temporary command data
# Files are automatically deleted after 30 minutes
*.json