RXSM update server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

125 lines
4.6KB

  1. # Created 2019-09-10 by NGnius
  2. from flask import Flask, Blueprint, jsonify, request, send_file, render_template
  3. import sqlite3 as dblib
  4. from hashlib import sha512
  5. from os import getcwd
  6. from threading import get_ident
  7. from time import time
  8. from datetime import datetime
  9. database_path = 'rxsm-update.db'
  10. database_connections = dict()
  11. app = Flask('rxsm-update-server')
  12. def get_or_create_connection():
  13. global database_connections, database_path
  14. thread_id = get_ident()
  15. if thread_id not in database_connections:
  16. database_connections[thread_id] = dblib.connect(database_path)
  17. return database_connections[thread_id]
  18. def close_connection():
  19. thread_id = get_ident()
  20. if thread_id in database_connections:
  21. database_connections[thread_id].close()
  22. del(database_connections[thread_id])
  23. @app.route('/', methods=['GET'])
  24. def index():
  25. return render_template('index.html')
  26. @app.route('/release', methods=['POST'])
  27. def create_or_modify_release():
  28. try:
  29. req_json = request.get_json(force=True)
  30. token = req_json['token']
  31. version = req_json['version']
  32. platform = req_json['platform']
  33. url = req_json['url']
  34. except:
  35. return jsonify({'status':400, 'reason':'Invalid request; missing parameter or invalid JSON'}), 400
  36. with open('.token', 'r') as f:
  37. master_token = f.read()
  38. if sha512(token.encode()).hexdigest() != master_token:
  39. return jsonify({'status':403, 'reason':'Permission denied; invalid token'}), 403
  40. db_connection = get_or_create_connection()
  41. cursor = db_connection.cursor()
  42. cursor.execute('SELECT version FROM releases WHERE version=? AND platform=?', (version, platform))
  43. result = cursor.fetchone()
  44. operation = ''
  45. if result is None:
  46. cursor.execute('INSERT INTO releases (version, platform, url, created_date) VALUES (?,?,?,?)', (version, platform, url, int(time())))
  47. operation = 'create'
  48. else:
  49. cursor.execute('UPDATE releases SET url=?, created_date=? WHERE version=? and platform=?', (url, int(time()), version, platform))
  50. operation = 'update'
  51. db_connection.commit()
  52. close_connection()
  53. return jsonify({'status':200, 'reason':'Version %s %sd successfully' % (version, operation)}), 200
  54. @app.route('/db', methods=['GET'])
  55. @app.route('/database', methods=['GET'])
  56. def download_database():
  57. return send_file(database_path, cache_timeout=1, as_attachment=True, attachment_filename='rxsm.sqlite')
  58. @app.route('/update', methods=['POST'])
  59. @app.route('/check-for-update', methods=['POST'])
  60. def check_for_update():
  61. start = time()
  62. db_connection = get_or_create_connection()
  63. cursor = db_connection.cursor()
  64. collect_anonymous_stats = str(request.headers.get('DNT')).strip() != '1'
  65. # hit counter
  66. if collect_anonymous_stats:
  67. today = datetime.today().date().isoformat()
  68. cursor.execute('SELECT count FROM hits WHERE date=?', (today,))
  69. result = cursor.fetchone()
  70. if result is not None:
  71. cursor.execute('UPDATE hits SET count=count+1 WHERE date=?', (today,))
  72. else:
  73. cursor.execute('INSERT INTO hits (date, count) VALUES (?,?)', (today, 1))
  74. db_connection.commit()
  75. # update lookup
  76. try:
  77. req_json = request.get_json(force=True)
  78. current_version = req_json['version']
  79. platform = req_json['platform']
  80. except:
  81. close_connection()
  82. return jsonify({'status':400, 'reason':'Invalid request; missing parameter or invalid JSON'}), 400
  83. cursor.execute('SELECT version, url FROM releases WHERE platform=? ORDER BY created_date DESC', (platform,))
  84. result = cursor.fetchone()
  85. close_connection()
  86. if result is None:
  87. return jsonify({'status':404, 'reason':'Platform not found (%ss)' % (time()-start), 'url':'', 'out-of-date':False}), 404
  88. elif result[0] != current_version:
  89. return jsonify({'status':200, 'reason':'Ok (%ss)' % (time()-start), 'url':result[1], 'out-of-date':True}), 200
  90. else:
  91. return jsonify({'status':200, 'reason':'Ok (%ss)' % (time()-start), 'url':result[1], 'out-of-date':False}), 200
  92. # always try to create db table(s)
  93. conn = get_or_create_connection()
  94. cursor = conn.cursor()
  95. cursor.execute(\
  96. '''CREATE TABLE IF NOT EXISTS releases (
  97. id INTEGER PRIMARY KEY,
  98. version TEXT NOT NULL,
  99. url TEXT NOT NULL,
  100. platform TEXT NOT NULL,
  101. created_date INTEGER NOT NULL
  102. )''' )
  103. cursor.execute(\
  104. '''CREATE TABLE IF NOT EXISTS hits (
  105. date TEXT UNIQUE NOT NULL,
  106. count INTEGER NOT NULL
  107. )''' )
  108. conn.commit()
  109. if __name__ == '__main__':
  110. print('Working directory: ' + getcwd())
  111. app.run(host='0.0.0.0', port=9080, threaded=True)