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.

121 lines
4.5KB

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