Prepare API for gunicorn
It is now possible to run the API with gunicorn using gunicorn -w 4 -b 0.0.0.0:8001 'bcnsGDSAPI:create_app()'. Also did other small changes.
This commit is contained in:
parent
631dc761c6
commit
77b0bcb94a
52
bcnsGDSAPI/__init__.py
Normal file
52
bcnsGDSAPI/__init__.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
from flask import request, jsonify, Flask
|
||||||
|
import json
|
||||||
|
from datetime import date
|
||||||
|
import tomllib
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
class MyJSONEncoder(json.JSONEncoder):
|
||||||
|
def default(self, o):
|
||||||
|
if isinstance(o, date):
|
||||||
|
return o.isoformat()
|
||||||
|
|
||||||
|
return super().default(o)
|
||||||
|
|
||||||
|
|
||||||
|
def create_app(test_config=None):
|
||||||
|
app = Flask(__name__, instance_relative_config=True)
|
||||||
|
app.config['JSON_AS_ASCII'] = False
|
||||||
|
|
||||||
|
if test_config is None:
|
||||||
|
app.config.from_file('bcnsgdsapi-config.toml',
|
||||||
|
load=tomllib.load, text=False)
|
||||||
|
else:
|
||||||
|
app.config.from_mapping(test_config)
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.makedirs(app.instance_path)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
import bcnsGDSAPI.modules.db_connect
|
||||||
|
bcnsGDSAPI.modules.db_connect.init(app.config)
|
||||||
|
from bcnsGDSAPI.modules.gamelist import gamelist
|
||||||
|
from bcnsGDSAPI.modules.game import game
|
||||||
|
app.register_blueprint(gamelist)
|
||||||
|
app.register_blueprint(game)
|
||||||
|
|
||||||
|
# Just a simple homepage, nothing fancy
|
||||||
|
@app.route('/', methods=['GET'])
|
||||||
|
def home():
|
||||||
|
if 'id' not in request.args:
|
||||||
|
return "<h1>BCNS Game Distribution System</h1><p>API-endpoint</p>"
|
||||||
|
else:
|
||||||
|
return jsonify("I see you're a man of culture as well")
|
||||||
|
|
||||||
|
return app
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = create_app()
|
||||||
|
app.run(host="0.0.0.0", port=8001, debug=True)
|
||||||
@ -1,37 +1,19 @@
|
|||||||
import argparse
|
main = {}
|
||||||
import configparser
|
database = {}
|
||||||
import os
|
|
||||||
import inspect
|
|
||||||
|
|
||||||
|
|
||||||
def init():
|
def init(config=None):
|
||||||
global config
|
global main
|
||||||
|
global database
|
||||||
|
main = config["MAIN"]
|
||||||
|
database = config["DATABASE"]
|
||||||
|
|
||||||
# Decide what config-file to use
|
return True
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument('-e', '--environment', choices=['dev', 'prod', 'test'],
|
|
||||||
default='prod',
|
|
||||||
help='choose what environment type to run.'
|
|
||||||
' Defaults to prod')
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if args.environment == 'dev':
|
|
||||||
print("Using devapi.conf")
|
|
||||||
configfile = '/../devapi.conf'
|
|
||||||
elif args.environment == 'test':
|
|
||||||
print("Using testapi.conf")
|
|
||||||
configfile = '/../testapi.conf'
|
|
||||||
else:
|
|
||||||
print("Using api.conf")
|
|
||||||
configfile = '/../api.conf'
|
|
||||||
|
|
||||||
config = configparser.RawConfigParser()
|
|
||||||
config.read(os.path.dirname(
|
|
||||||
os.path.abspath(inspect.getfile(
|
|
||||||
inspect.currentframe()))) + configfile)
|
|
||||||
|
|
||||||
def contentpath():
|
def contentpath():
|
||||||
return(config.get('Database','contentpath'))
|
return database["contentpath"]
|
||||||
|
|
||||||
|
|
||||||
def nfosuffix():
|
def nfosuffix():
|
||||||
return(config.get('Database','nfo_suffix'))
|
return database["nfo_suffix"]
|
||||||
|
|||||||
@ -4,7 +4,6 @@ from io import BytesIO
|
|||||||
import zipfile
|
import zipfile
|
||||||
import pathlib
|
import pathlib
|
||||||
|
|
||||||
global gamelist
|
|
||||||
gamelist = []
|
gamelist = []
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
from __main__ import app
|
from flask import jsonify, request, send_from_directory, send_file, Blueprint
|
||||||
from flask import jsonify, request, send_from_directory, send_file
|
|
||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
import modules.db_connect
|
import bcnsGDSAPI.modules.db_connect
|
||||||
from modules.functions import reduceartcv2, make_archive
|
from bcnsGDSAPI.modules.functions import reduceartcv2, make_archive
|
||||||
import os
|
import os
|
||||||
|
|
||||||
contentpath = modules.db_connect.contentpath()
|
contentpath = bcnsGDSAPI.modules.db_connect.contentpath()
|
||||||
|
game = Blueprint('game', __name__, template_folder='templates')
|
||||||
|
|
||||||
|
|
||||||
# Fetch and present all information from one _index.nfo-file
|
# Fetch and present all information from one _index.nfo-file
|
||||||
@app.route('/game', methods=['POST'])
|
@game.route('/game', methods=['POST'])
|
||||||
def game(
|
def showgame(
|
||||||
predefinednfo=False,
|
predefinednfo=False,
|
||||||
return_dict=False,
|
return_dict=False,
|
||||||
skip_artwork=False,
|
skip_artwork=False,
|
||||||
@ -59,8 +59,8 @@ def game(
|
|||||||
|
|
||||||
|
|
||||||
# Fetch all artwork from a given _index.nfo-file
|
# Fetch all artwork from a given _index.nfo-file
|
||||||
@app.route('/game/artwork/size/<size>', methods=['POST'])
|
@game.route('/game/artwork/size/<size>', methods=['POST'])
|
||||||
@app.route('/game/artwork', methods=['POST'])
|
@game.route('/game/artwork', methods=['POST'])
|
||||||
def artwork(size='max'):
|
def artwork(size='max'):
|
||||||
f = open(request.json['nfo'], 'r')
|
f = open(request.json['nfo'], 'r')
|
||||||
nfo = json.load(f)
|
nfo = json.load(f)
|
||||||
@ -89,7 +89,7 @@ def artwork(size='max'):
|
|||||||
# Serve a file. Takes the following object parameters:
|
# Serve a file. Takes the following object parameters:
|
||||||
# nfopath base64-encoded full path to specific game nfo-file
|
# nfopath base64-encoded full path to specific game nfo-file
|
||||||
# filepath base64-encoded path to file starting from game dir
|
# filepath base64-encoded path to file starting from game dir
|
||||||
@app.route('/getfile', methods=["GET"])
|
@game.route('/getfile', methods=["GET"])
|
||||||
def getfile():
|
def getfile():
|
||||||
nfopath = os.path.dirname(
|
nfopath = os.path.dirname(
|
||||||
base64.b64decode(request.json['nfopath']).decode())
|
base64.b64decode(request.json['nfopath']).decode())
|
||||||
@ -98,7 +98,7 @@ def getfile():
|
|||||||
|
|
||||||
|
|
||||||
# Game folder as ZIP-file (kinda slow)
|
# Game folder as ZIP-file (kinda slow)
|
||||||
@app.route('/getzipfile', methods=["GET"])
|
@game.route('/getzipfile', methods=["GET"])
|
||||||
def getzipfile():
|
def getzipfile():
|
||||||
nfopath = base64.b64decode(request.json).decode()
|
nfopath = base64.b64decode(request.json).decode()
|
||||||
nfo = json.load(open(nfopath, 'r'))
|
nfo = json.load(open(nfopath, 'r'))
|
||||||
|
|||||||
@ -1,20 +1,20 @@
|
|||||||
from __main__ import app
|
from flask import jsonify, make_response, Blueprint
|
||||||
from flask import jsonify, make_response
|
import bcnsGDSAPI.modules.db_connect
|
||||||
import modules.db_connect
|
from bcnsGDSAPI.modules.functions import get_gamelist, set_gamelist
|
||||||
from modules.functions import get_gamelist, set_gamelist
|
import bcnsGDSAPI.modules.game
|
||||||
import modules.game
|
from bcnsGDSAPI.modules.gamelist_functions import (
|
||||||
from modules.gamelist_functions import (
|
|
||||||
get_threaded_thumbnails,
|
get_threaded_thumbnails,
|
||||||
update_threaded_thumbnails)
|
update_threaded_thumbnails)
|
||||||
import glob
|
import glob
|
||||||
|
|
||||||
contentpath = modules.db_connect.contentpath()
|
contentpath = bcnsGDSAPI.modules.db_connect.contentpath()
|
||||||
nfosuffix = modules.db_connect.nfosuffix()
|
nfosuffix = bcnsGDSAPI.modules.db_connect.nfosuffix()
|
||||||
|
gamelist = Blueprint('gamelist', __name__, template_folder='templates')
|
||||||
|
|
||||||
|
|
||||||
# Collects all _index.nfo-files present and crunches them into a list of
|
# Collects all _index.nfo-files present and crunches them into a list of
|
||||||
# games.
|
# games.
|
||||||
@app.route('/gamelist', methods=['GET'])
|
@gamelist.route('/gamelist', methods=['GET'])
|
||||||
def show_gamelist():
|
def show_gamelist():
|
||||||
if get_gamelist():
|
if get_gamelist():
|
||||||
return jsonify(get_gamelist())
|
return jsonify(get_gamelist())
|
||||||
@ -23,7 +23,7 @@ def show_gamelist():
|
|||||||
|
|
||||||
|
|
||||||
# Updates the gamelist by searching for new nfo's
|
# Updates the gamelist by searching for new nfo's
|
||||||
@app.route('/gamelist/update', methods=['GET'])
|
@gamelist.route('/gamelist/update', methods=['GET'])
|
||||||
def update_gamelist():
|
def update_gamelist():
|
||||||
nfolist = list(dict.fromkeys(glob.glob(
|
nfolist = list(dict.fromkeys(glob.glob(
|
||||||
str(contentpath)+'/**/**/*'+nfosuffix, recursive=True)))
|
str(contentpath)+'/**/**/*'+nfosuffix, recursive=True)))
|
||||||
@ -31,7 +31,7 @@ def update_gamelist():
|
|||||||
glist = []
|
glist = []
|
||||||
for nfo in nfolist:
|
for nfo in nfolist:
|
||||||
try:
|
try:
|
||||||
game = modules.game.game(nfo, True, True, True)
|
game = bcnsGDSAPI.modules.game.showgame(nfo, True, True, True)
|
||||||
glist.append(game)
|
glist.append(game)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(nfo, e)
|
print(nfo, e)
|
||||||
@ -41,7 +41,7 @@ def update_gamelist():
|
|||||||
|
|
||||||
|
|
||||||
# Fetch displayimage for all nfo-files
|
# Fetch displayimage for all nfo-files
|
||||||
@app.route('/gamelist/displayimage')
|
@gamelist.route('/gamelist/displayimage')
|
||||||
def get_displayimages(update=False):
|
def get_displayimages(update=False):
|
||||||
thumbnails = get_threaded_thumbnails()
|
thumbnails = get_threaded_thumbnails()
|
||||||
if (len(thumbnails) == 0) or update:
|
if (len(thumbnails) == 0) or update:
|
||||||
@ -50,7 +50,7 @@ def get_displayimages(update=False):
|
|||||||
|
|
||||||
|
|
||||||
# Update displayimages
|
# Update displayimages
|
||||||
@app.route('/gamelist/displayimage/update')
|
@gamelist.route('/gamelist/displayimage/update')
|
||||||
def update_displayimages():
|
def update_displayimages():
|
||||||
update_threaded_thumbnails()
|
update_threaded_thumbnails()
|
||||||
return make_response("<h1>Success</h1>", 200)
|
return make_response("<h1>Success</h1>", 200)
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
import modules.db_connect
|
import bcnsGDSAPI.modules.db_connect
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
from modules.functions import reduceartcv2
|
from bcnsGDSAPI.modules.functions import reduceartcv2
|
||||||
import threading
|
import threading
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
import time
|
import time
|
||||||
|
|
||||||
contentpath = modules.db_connect.contentpath()
|
contentpath = bcnsGDSAPI.modules.db_connect.contentpath()
|
||||||
nfosuffix = modules.db_connect.nfosuffix()
|
nfosuffix = bcnsGDSAPI.modules.db_connect.nfosuffix()
|
||||||
|
|
||||||
global nfofiles
|
global nfofiles
|
||||||
nfofiles = []
|
nfofiles = []
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
from datetime import date
|
from datetime import date
|
||||||
from flask import render_template, Flask, request
|
from flask import render_template, Flask, request
|
||||||
from json import JSONEncoder
|
from json import JSONEncoder
|
||||||
from bcnsGDSSite.modules.gamelist import gamelist
|
|
||||||
from bcnsGDSSite.modules.game import game
|
|
||||||
import bcnsGDSSite.modules.init
|
import bcnsGDSSite.modules.init
|
||||||
import os
|
import os
|
||||||
import inspect
|
import inspect
|
||||||
@ -21,9 +19,6 @@ class MyJSONEncoder(JSONEncoder):
|
|||||||
|
|
||||||
def create_app(test_config=None):
|
def create_app(test_config=None):
|
||||||
app = Flask(__name__, instance_relative_config=True)
|
app = Flask(__name__, instance_relative_config=True)
|
||||||
app.register_blueprint(gamelist)
|
|
||||||
app.register_blueprint(game)
|
|
||||||
print(app.url_map)
|
|
||||||
app.config.from_mapping(
|
app.config.from_mapping(
|
||||||
SECRET_KEY='dev',
|
SECRET_KEY='dev',
|
||||||
DATABASE=os.path.join(app.instance_path, 'bcns_gds.sqlite'),
|
DATABASE=os.path.join(app.instance_path, 'bcns_gds.sqlite'),
|
||||||
@ -44,14 +39,13 @@ def create_app(test_config=None):
|
|||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
bcnsGDSSite.modules.init.init(app.config)
|
||||||
|
|
||||||
# import bcnsGDSSite.modules.gamelist # noqa: E402
|
from bcnsGDSSite.modules.gamelist import gamelist
|
||||||
bcnsGDSSite.modules.init.set_apihost("http://" +
|
from bcnsGDSSite.modules.game import game
|
||||||
app.config['API']['host'] +
|
app.register_blueprint(gamelist)
|
||||||
':' + app.config['API']['port'])
|
app.register_blueprint(game)
|
||||||
|
|
||||||
bcnsGDSSite.modules.init.set_applanguage(
|
|
||||||
app.config['MAIN']['app_language'])
|
|
||||||
languages = bcnsGDSSite.modules.init.get_languages()
|
languages = bcnsGDSSite.modules.init.get_languages()
|
||||||
if not languages:
|
if not languages:
|
||||||
languages_path = os.path.dirname(
|
languages_path = os.path.dirname(
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import base64
|
|||||||
from flask import render_template, request, Response, Blueprint
|
from flask import render_template, request, Response, Blueprint
|
||||||
import bcnsGDSSite.modules.init
|
import bcnsGDSSite.modules.init
|
||||||
|
|
||||||
host_endpoint = bcnsGDSSite.modules.init.get_apihost()
|
apihost = bcnsGDSSite.modules.init.apihost()
|
||||||
languages = bcnsGDSSite.modules.init.get_languages()
|
languages = bcnsGDSSite.modules.init.get_languages()
|
||||||
app_language = bcnsGDSSite.modules.init.app_language
|
app_language = bcnsGDSSite.modules.init.app_language
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ def showgame(lang_code):
|
|||||||
gamepath = request.args.get("gamepath")
|
gamepath = request.args.get("gamepath")
|
||||||
|
|
||||||
game = json.loads((requests.post(
|
game = json.loads((requests.post(
|
||||||
host_endpoint + '/game', json=gamepath).content).decode())
|
apihost + '/game', json=gamepath).content).decode())
|
||||||
|
|
||||||
game['game']['plot'] = game['game']['plot'].split('\\n')
|
game['game']['plot'] = game['game']['plot'].split('\\n')
|
||||||
if 'linuxinstructions' in game['game']:
|
if 'linuxinstructions' in game['game']:
|
||||||
@ -54,7 +54,7 @@ def download(lang_code):
|
|||||||
gametitle = request.args.get("gametitle")
|
gametitle = request.args.get("gametitle")
|
||||||
targettype = request.args.get("targettype")
|
targettype = request.args.get("targettype")
|
||||||
if "zip" in targettype:
|
if "zip" in targettype:
|
||||||
gamezip = requests.get(host_endpoint + '/getzipfile', json=gamepath)
|
gamezip = requests.get(apihost + '/getzipfile', json=gamepath)
|
||||||
return Response(gamezip, mimetype="application/zip",
|
return Response(gamezip, mimetype="application/zip",
|
||||||
headers={
|
headers={
|
||||||
"Content-Disposition":
|
"Content-Disposition":
|
||||||
@ -77,7 +77,7 @@ def getfile(lang_code):
|
|||||||
filepath_enc = base64.b64encode(filepath.encode('utf-8')).decode()
|
filepath_enc = base64.b64encode(filepath.encode('utf-8')).decode()
|
||||||
jsonbody = {'nfopath': gamepath, 'filepath': filepath_enc}
|
jsonbody = {'nfopath': gamepath, 'filepath': filepath_enc}
|
||||||
print(gamepath, filepath)
|
print(gamepath, filepath)
|
||||||
file = requests.get(host_endpoint + '/getfile', json=jsonbody)
|
file = requests.get(apihost + '/getfile', json=jsonbody)
|
||||||
return Response(file, mimetype="application/pdf",
|
return Response(file, mimetype="application/pdf",
|
||||||
headers={
|
headers={
|
||||||
"Content-Disposition":
|
"Content-Disposition":
|
||||||
|
|||||||
@ -4,7 +4,7 @@ from flask import render_template, redirect, url_for, request, Blueprint
|
|||||||
import bcnsGDSSite.modules.init
|
import bcnsGDSSite.modules.init
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
host_endpoint = bcnsGDSSite.modules.init.get_apihost()
|
apihost = bcnsGDSSite.modules.init.apihost()
|
||||||
languages = bcnsGDSSite.modules.init.get_languages()
|
languages = bcnsGDSSite.modules.init.get_languages()
|
||||||
app_language = bcnsGDSSite.modules.init.app_language
|
app_language = bcnsGDSSite.modules.init.app_language
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ def showgamelist(lang_code):
|
|||||||
glist = None
|
glist = None
|
||||||
try:
|
try:
|
||||||
glist = json.loads((requests.get(
|
glist = json.loads((requests.get(
|
||||||
host_endpoint + '/gamelist').content).decode())
|
apihost + '/gamelist').content).decode())
|
||||||
|
|
||||||
# Sorting list alphabetically
|
# Sorting list alphabetically
|
||||||
glist = sorted(glist, key=lambda d: d['game']['title'])
|
glist = sorted(glist, key=lambda d: d['game']['title'])
|
||||||
@ -48,7 +48,7 @@ def showgamelist(lang_code):
|
|||||||
if thumbnails == "get":
|
if thumbnails == "get":
|
||||||
try:
|
try:
|
||||||
thumbnailslist = json.loads((requests.get(
|
thumbnailslist = json.loads((requests.get(
|
||||||
host_endpoint + '/gamelist/displayimage').content).decode())
|
apihost + '/gamelist/displayimage').content).decode())
|
||||||
|
|
||||||
except request.exceptions.ConnectionError as e:
|
except request.exceptions.ConnectionError as e:
|
||||||
print(e)
|
print(e)
|
||||||
@ -70,6 +70,6 @@ def showgamelist(lang_code):
|
|||||||
def gamelist_update(lang_code):
|
def gamelist_update(lang_code):
|
||||||
lang_code = lang(lang_code)
|
lang_code = lang(lang_code)
|
||||||
response = requests.get(
|
response = requests.get(
|
||||||
host_endpoint + '/gamelist/update')
|
apihost + '/gamelist/update')
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
return redirect(url_for('gamelist', lang_code=lang_code))
|
return redirect(url_for('gamelist.showgamelist', lang_code=lang_code))
|
||||||
|
|||||||
@ -1,14 +1,23 @@
|
|||||||
import os
|
|
||||||
import inspect
|
|
||||||
|
|
||||||
global languages
|
|
||||||
languages = {}
|
languages = {}
|
||||||
|
|
||||||
global apihost
|
|
||||||
apihost = "http://media.odecif.net:5501"
|
|
||||||
|
|
||||||
global app_language
|
|
||||||
app_language = ""
|
app_language = ""
|
||||||
|
main = {}
|
||||||
|
api = {}
|
||||||
|
|
||||||
|
|
||||||
|
def init(config=None):
|
||||||
|
global main
|
||||||
|
global api
|
||||||
|
main = config["MAIN"]
|
||||||
|
api = config["API"]
|
||||||
|
|
||||||
|
|
||||||
|
def apihost():
|
||||||
|
return (
|
||||||
|
api["protocol"] + "://" +
|
||||||
|
api["host"] + ":" +
|
||||||
|
api["port"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def set_languages(languages_dict):
|
def set_languages(languages_dict):
|
||||||
global languages
|
global languages
|
||||||
@ -36,7 +45,3 @@ def set_applanguage(new_applanguage):
|
|||||||
global app_language
|
global app_language
|
||||||
app_language = new_applanguage
|
app_language = new_applanguage
|
||||||
return app_language
|
return app_language
|
||||||
|
|
||||||
def init():
|
|
||||||
global apihost
|
|
||||||
apihost = ""
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user