modified: .gitignore
modified: app.py new file: command_storage/.gitignore
This commit is contained in:
60
app.py
60
app.py
@@ -8,18 +8,22 @@ from flask import Flask, render_template, jsonify, send_from_directory, request
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# In-memory storage for commands (thread-safe)
|
||||
command_storage = {}
|
||||
# File-based storage for commands (works across multiple workers)
|
||||
STORAGE_DIR = Path(__file__).parent / 'command_storage'
|
||||
STORAGE_DIR.mkdir(exist_ok=True)
|
||||
storage_lock = Lock()
|
||||
|
||||
def cleanup_expired_commands():
|
||||
"""Remove expired commands from storage"""
|
||||
with storage_lock:
|
||||
now = datetime.now(timezone.utc)
|
||||
expired_keys = [key for key, value in command_storage.items()
|
||||
if datetime.fromisoformat(value['expires_at']) < now]
|
||||
for key in expired_keys:
|
||||
del command_storage[key]
|
||||
"""Remove expired command files"""
|
||||
now = datetime.now(timezone.utc)
|
||||
for file_path in STORAGE_DIR.glob('*.json'):
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
data = json.load(f)
|
||||
if datetime.fromisoformat(data['expires_at']) < now:
|
||||
file_path.unlink()
|
||||
except:
|
||||
pass # Ignore corrupted files
|
||||
|
||||
# Load projects from version.json
|
||||
def load_projects():
|
||||
@@ -272,13 +276,18 @@ def store_command():
|
||||
created_at = datetime.now(timezone.utc)
|
||||
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:
|
||||
command_storage[command_uuid] = {
|
||||
'command': command,
|
||||
'created_at': created_at.isoformat(),
|
||||
'expires_at': expires_at.isoformat()
|
||||
}
|
||||
with open(storage_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(command_data, f)
|
||||
|
||||
# Generate URL - use HTTPS if behind proxy
|
||||
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)"""
|
||||
cleanup_expired_commands()
|
||||
|
||||
# Keep lock for entire operation to prevent race conditions
|
||||
with storage_lock:
|
||||
command_data = command_storage.get(command_uuid)
|
||||
|
||||
if not command_data:
|
||||
return jsonify({'error': 'Command not found or expired'}), 404
|
||||
storage_file = STORAGE_DIR / f'{command_uuid}.json'
|
||||
|
||||
if not storage_file.exists():
|
||||
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
|
||||
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 a copy to avoid modification outside lock
|
||||
return jsonify(dict(command_data)), 200
|
||||
return jsonify(command_data), 200
|
||||
except Exception as e:
|
||||
return jsonify({'error': 'Failed to read command'}), 500
|
||||
|
||||
# Serve /versions as JSON
|
||||
@app.route('/versions')
|
||||
|
||||
Reference in New Issue
Block a user