# Created 2019-09-10 by NGnius from flask import Flask, Blueprint, jsonify, request, send_file, render_template import sqlite3 as dblib from hashlib import sha512 from os import getcwd from threading import get_ident from time import time from datetime import datetime database_path = 'rxsm-update.db' database_connections = dict() app = Flask('rxsm-update-server') def get_or_create_connection(): global database_connections, database_path thread_id = get_ident() if thread_id not in database_connections: database_connections[thread_id] = dblib.connect(database_path) return database_connections[thread_id] def close_connection(): thread_id = get_ident() if thread_id in database_connections: database_connections[thread_id].close() del(database_connections[thread_id]) @app.route('/', methods=['GET']) def index(): return render_template('index.html') @app.route('/release', methods=['POST']) def create_or_modify_release(): try: req_json = request.get_json(force=True) token = req_json['token'] version = req_json['version'] platform = req_json['platform'] url = req_json['url'] except: return jsonify({'status':400, 'reason':'Invalid request; missing parameter or invalid JSON'}), 400 with open('.token', 'r') as f: master_token = f.read() if sha512(token.encode()).hexdigest() != master_token: return jsonify({'status':403, 'reason':'Permission denied; invalid token'}), 403 db_connection = get_or_create_connection() cursor = db_connection.cursor() cursor.execute('SELECT version FROM releases WHERE version=? AND platform=?', (version, platform)) result = cursor.fetchone() operation = '' if result is None: cursor.execute('INSERT INTO releases (version, platform, url, created_date) VALUES (?,?,?,?)', (version, platform, url, int(time()))) operation = 'create' else: cursor.execute('UPDATE releases SET url=?, created_date=? WHERE version=? and platform=?', (url, int(time()), version, platform)) operation = 'update' db_connection.commit() close_connection() return jsonify({'status':200, 'reason':'Version %s %sd successfully' % (version, operation)}), 200 @app.route('/db', methods=['GET']) @app.route('/database', methods=['GET']) def download_database(): return send_file(database_path, cache_timeout=1, as_attachment=True, attachment_filename='rxsm.sqlite') @app.route('/update', methods=['POST']) @app.route('/check-for-update', methods=['POST']) def check_for_update(): start = time() db_connection = get_or_create_connection() cursor = db_connection.cursor() collect_anonymous_stats = str(request.headers.get('DNT')).strip() != '1' # hit counter if collect_anonymous_stats: today = datetime.today().date().isoformat() cursor.execute('SELECT count FROM hits WHERE date=?', (today,)) result = cursor.fetchone() if result is not None: cursor.execute('UPDATE hits SET count=count+1 WHERE date=?', (today,)) else: cursor.execute('INSERT INTO hits (date, count) VALUES (?,?)', (today, 1)) db_connection.commit() # update lookup try: req_json = request.get_json(force=True) current_version = req_json['version'] platform = req_json['platform'] except: close_connection() return jsonify({'status':400, 'reason':'Invalid request; missing parameter or invalid JSON'}), 400 cursor.execute('SELECT version, url FROM releases WHERE platform=? ORDER BY created_date DESC', (platform,)) result = cursor.fetchone() close_connection() if result is None: return jsonify({'status':404, 'reason':'Platform not found (%ss)' % (time()-start), 'url':'', 'out-of-date':False}), 404 elif result[0] != current_version: return jsonify({'status':200, 'reason':'Ok (%ss)' % (time()-start), 'url':result[1], 'out-of-date':True}), 200 else: return jsonify({'status':200, 'reason':'Ok (%ss)' % (time()-start), 'url':result[1], 'out-of-date':False}), 200 # always try to create db table(s) conn = get_or_create_connection() cursor = conn.cursor() cursor.execute(\ '''CREATE TABLE IF NOT EXISTS releases ( id INTEGER PRIMARY KEY, version TEXT NOT NULL, url TEXT NOT NULL, platform TEXT NOT NULL, created_date INTEGER NOT NULL )''' ) cursor.execute(\ '''CREATE TABLE IF NOT EXISTS hits ( date TEXT UNIQUE NOT NULL, count INTEGER NOT NULL )''' ) conn.commit() if __name__ == '__main__': print('Working directory: ' + getcwd()) app.run(host='0.0.0.0', port=9080, threaded=True)