Initial commit

This commit is contained in:
2025-12-17 16:47:48 +00:00
commit 13813f3363
4964 changed files with 1079753 additions and 0 deletions

160
masterserver.py Executable file
View File

@@ -0,0 +1,160 @@
#!/usr/bin/env python
"""
Aya Masterserver
A basic masterserver implementing authorization. Feel free to modify as needed.
Requires flask and waitress (`pip install flask waitress`)
./masterserver.py --port 53600 --key <your_authorization_key> (optional)
"""
import json
import time
import uuid
import argparse
import logging
from flask import Flask, request, jsonify
from datetime import datetime
from waitress import serve
class AyaMasterserver:
def __init__(self, port=53600, authorization_key=None):
self.app = Flask(__name__)
self.port = port
self.authorization_key = authorization_key
self.servers = {}
self.setup_routes()
# Configure custom logging format
logging.basicConfig(
level=logging.INFO,
format='[Aya Masterserver] %(message)s'
)
self.logger = logging.getLogger(__name__)
def check_auth(self):
if not self.authorization_key:
return True
auth_header = request.headers.get('Authorization')
return auth_header == self.authorization_key
def setup_routes(self):
@self.app.route('/broadcast', methods=['POST'])
def broadcast_server():
if not self.check_auth():
return jsonify({'error': 'Unauthorized'}), 401
if not request.is_json:
return jsonify({'error': 'Content-Type must be application/json'}), 400
data = request.get_json()
required_fields = ['server_host', 'server_name', 'server_port', 'server_ip', 'players', 'max_players']
for field in required_fields:
if field not in data:
return jsonify({'error': f'Missing required field: {field}'}), 400
try:
server_port = int(data['server_port'])
players = int(data['players'])
max_players = int(data['max_players'])
except (ValueError, TypeError):
return jsonify({'error': 'server_port, players, and max_players must be integers'}), 400
request_ip = request.remote_addr
if request.headers.get('X-Forwarded-For'):
request_ip = request.headers.get('X-Forwarded-For').split(',')[0].strip()
server_id = str(uuid.uuid4())
server_info = {
'server_id': server_id,
'server_host': data['server_host'],
'server_name': str(data['server_name']),
'server_port': server_port,
'server_ip': request_ip,
'players': players,
'max_players': max_players,
'last_ping': time.time()
}
self.servers[server_id] = server_info
self.logger.info(f"New server broadcasting: {server_id} - {data['server_name']}")
return jsonify({'status': 'success', 'server_id': server_id}), 200
@self.app.route('/ping', methods=['GET', 'POST'])
def ping_server():
if not self.check_auth():
return jsonify({'error': 'Unauthorized'}), 401
request_ip = request.remote_addr
if request.headers.get('X-Forwarded-For'):
request_ip = request.headers.get('X-Forwarded-For').split(',')[0].strip()
server_id = request.args.get('id')
if not server_id:
return jsonify({'error': 'Missing required field: id'}), 400
# Check if the server exists
server_info = self.servers.get(server_id)
if not server_info:
return jsonify({'error': 'Server not found'}), 404
# Verify the IP matches the client_ip for the server
if server_info['server_ip'] != request_ip:
return jsonify({'error': 'IP address mismatch for ping - please ping from the IP you broadcasted from'}), 403
self.servers[server_id]['last_ping'] = time.time()
return jsonify({'status': 'success'}), 200
@self.app.route('/', methods=['GET'])
def get_servers():
if not self.check_auth():
return jsonify({'error': 'Unauthorized'}), 401
# Clean up expired servers (older than 5 minutes)
current_time = time.time()
expired = [sid for sid, info in self.servers.items()
if current_time - info['last_ping'] > 300]
for server_id in expired:
del self.servers[server_id]
self.logger.info(f"Removed expired server: {server_id}")
return jsonify({
'servers': list(self.servers.values()),
'timestamp': datetime.now().isoformat()
}), 200
@self.app.route('/health', methods=['GET'])
def health_check():
if not self.check_auth():
return jsonify({'error': 'Unauthorized'}), 401
return jsonify({
'status': 'healthy',
'timestamp': datetime.now().isoformat(),
'server_count': len(self.servers)
}), 200
def run(self):
self.logger.info(f"Starting Aya Masterserver on port {self.port}...")
self.logger.info("Authorization required" if self.authorization_key else "No authorization required")
serve(self.app, host='0.0.0.0', port=self.port, threads=4)
print("[Aya Masterserver] Shutting down...")
def main():
parser = argparse.ArgumentParser(description='Aya Masterserver')
parser.add_argument('--port', type=int, default=53600, help='Port (default: 53600)')
parser.add_argument('--key', type=str, default=None, help='Authorization key (default: none)')
args = parser.parse_args()
masterserver = AyaMasterserver(port=args.port, authorization_key=args.key)
try:
masterserver.run()
except Exception as e:
print(f"[Aya Masterserver] Error: {e}")
if __name__ == '__main__':
main()