WebHost: working web-gen

This commit is contained in:
Fabian Dill 2021-09-18 01:02:26 +02:00
parent 11245462f0
commit 38b5ee7314
3 changed files with 106 additions and 99 deletions

View File

@ -24,7 +24,7 @@ import pickle
import functools import functools
import io import io
import collections import collections
import importlib
from yaml import load, dump, safe_load from yaml import load, dump, safe_load
try: try:
@ -365,16 +365,25 @@ safe_builtins = {
class RestrictedUnpickler(pickle.Unpickler): class RestrictedUnpickler(pickle.Unpickler):
def __init__(self, *args, **kwargs):
super(RestrictedUnpickler, self).__init__(*args, **kwargs)
self.options_module = importlib.import_module("Options")
self.net_utils_module = importlib.import_module("NetUtils")
def find_class(self, module, name): def find_class(self, module, name):
if module == "builtins" and name in safe_builtins: if module == "builtins" and name in safe_builtins:
return getattr(builtins, name) return getattr(builtins, name)
# used by MultiServer -> savegame/multidata
if module == "NetUtils" and name in {"NetworkItem", "ClientStatus", "Hint"}: if module == "NetUtils" and name in {"NetworkItem", "ClientStatus", "Hint"}:
import NetUtils return getattr(self.net_utils_module, name)
return getattr(NetUtils, name) # Options are unpickled by WebHost -> Generate
if module.endswith("Options"):
if module == "Options": if module == "Options":
import Options mod = self.options_module
obj = getattr(Options, name) else:
if issubclass(obj, Options.Option): mod = importlib.import_module(module)
obj = getattr(mod, name)
if issubclass(obj, self.options_module.Option):
return obj return obj
# Forbid everything else. # Forbid everything else.
raise pickle.UnpicklingError("global '%s.%s' is forbidden" % raise pickle.UnpicklingError("global '%s.%s' is forbidden" %

View File

@ -2,6 +2,7 @@ import os
import tempfile import tempfile
import random import random
import json import json
import zipfile
from collections import Counter from collections import Counter
from flask import request, flash, redirect, url_for, session, render_template from flask import request, flash, redirect, url_for, session, render_template
@ -15,6 +16,7 @@ import pickle
from .models import * from .models import *
from WebHostLib import app from WebHostLib import app
from .check import get_yaml_data, roll_options from .check import get_yaml_data, roll_options
from .upload import upload_zip_to_db
@app.route('/generate', methods=['GET', 'POST']) @app.route('/generate', methods=['GET', 'POST'])
@ -69,7 +71,7 @@ def gen_game(gen_options, race=False, owner=None, sid=None):
if race: if race:
random.seed() # reset to time-based random source random.seed() # reset to time-based random source
seedname = "M" + (f"{random.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits)) seedname = "W" + (f"{random.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits))
erargs = parse_arguments(['--multi', str(playercount)]) erargs = parse_arguments(['--multi', str(playercount)])
erargs.seed = seed erargs.seed = seed
@ -84,7 +86,10 @@ def gen_game(gen_options, race=False, owner=None, sid=None):
for player, (playerfile, settings) in enumerate(gen_options.items(), 1): for player, (playerfile, settings) in enumerate(gen_options.items(), 1):
for k, v in settings.items(): for k, v in settings.items():
if v is not None: if v is not None:
if hasattr(erargs, k):
getattr(erargs, k)[player] = v getattr(erargs, k)[player] = v
else:
setattr(erargs, k, {player: v})
if not erargs.name[player]: if not erargs.name[player]:
erargs.name[player] = os.path.splitext(os.path.split(playerfile)[-1])[0] erargs.name[player] = os.path.splitext(os.path.split(playerfile)[-1])[0]
@ -92,7 +97,7 @@ def gen_game(gen_options, race=False, owner=None, sid=None):
ERmain(erargs, seed) ERmain(erargs, seed)
return upload_to_db(target.name, owner, sid, race) return upload_to_db(target.name, sid, owner, race)
except BaseException as e: except BaseException as e:
if sid: if sid:
with db_session: with db_session:
@ -122,37 +127,19 @@ def wait_seed(seed: UUID):
return render_template("waitSeed.html", seed_id=seed_id) return render_template("waitSeed.html", seed_id=seed_id)
def upload_to_db(folder, owner, sid, race:bool): def upload_to_db(folder, sid, owner, race):
slots = set()
spoiler = ""
multidata = None
for file in os.listdir(folder): for file in os.listdir(folder):
file = os.path.join(folder, file) file = os.path.join(folder, file)
if file.endswith(".apbp"): if file.endswith(".zip"):
player_text = file.split("_P", 1)[1]
player_name = player_text.split("_", 1)[1].split(".", 1)[0]
player_id = int(player_text.split(".", 1)[0].split("_", 1)[0])
slots.add(Slot(data=open(file, "rb").read(),
player_id=player_id, player_name = player_name, game = "A Link to the Past"))
elif file.endswith(".txt"):
spoiler = open(file, "rt", encoding="utf-8-sig").read()
elif file.endswith(".archipelago"):
multidata = open(file, "rb").read()
if multidata:
with db_session: with db_session:
if sid: with zipfile.ZipFile(file) as zfile:
seed = Seed(multidata=multidata, spoiler=spoiler, slots=slots, owner=owner, res = upload_zip_to_db(zfile, owner, {"race": race}, sid)
id=sid, meta=json.dumps({"race": race, "tags": ["generated"]})) if type(res) == "str":
else: raise Exception(res)
seed = Seed(multidata=multidata, spoiler=spoiler, slots=slots, owner=owner, elif res:
meta=json.dumps({"race": race, "tags": ["generated"]})) seed = res
for patch in slots: gen = Generation.get(id=seed.id)
patch.seed = seed
if sid:
gen = Generation.get(id=sid)
if gen is not None: if gen is not None:
gen.delete() gen.delete()
return seed.id return seed.id
else: raise Exception("Generation zipfile not found.")
raise Exception("Multidata required (.archipelago), but not found.")

View File

@ -3,6 +3,7 @@ import lzma
import json import json
import base64 import base64
import MultiServer import MultiServer
import uuid
from flask import request, flash, redirect, url_for, session, render_template from flask import request, flash, redirect, url_for, session, render_template
from pony.orm import flush, select from pony.orm import flush, select
@ -17,29 +18,17 @@ accepted_zip_contents = {"patches": ".apbp",
banned_zip_contents = (".sfc",) banned_zip_contents = (".sfc",)
@app.route('/uploads', methods=['GET', 'POST']) def upload_zip_to_db(zfile: zipfile.ZipFile, owner=None, meta={"race": False}, sid=None):
def uploads(): if not owner:
if request.method == 'POST': owner = session["_id"]
# check if the post request has the file part infolist = zfile.infolist()
if 'file' not in request.files:
flash('No file part')
else:
file = request.files['file']
# if user does not select file, browser also
# submit an empty part without filename
if file.filename == '':
flash('No selected file')
elif file and allowed_file(file.filename):
if file.filename.endswith(".zip"):
slots = set() slots = set()
spoiler = "" spoiler = ""
multidata = None multidata = None
with zipfile.ZipFile(file, 'r') as zfile:
infolist = zfile.infolist()
for file in infolist: for file in infolist:
if file.filename.endswith(banned_zip_contents): if file.filename.endswith(banned_zip_contents):
return "Uploaded data contained a rom file, which is likely to contain copyrighted material. Your file was deleted." return "Uploaded data contained a rom file, which is likely to contain copyrighted material. " \
"Your file was deleted."
elif file.filename.endswith(".apbp"): elif file.filename.endswith(".apbp"):
data = zfile.open(file, "r").read() data = zfile.open(file, "r").read()
yaml_data = parse_yaml(lzma.decompress(data).decode("utf-8-sig")) yaml_data = parse_yaml(lzma.decompress(data).decode("utf-8-sig"))
@ -58,7 +47,7 @@ def uploads():
game="Minecraft")) game="Minecraft"))
elif file.filename.endswith(".zip"): elif file.filename.endswith(".zip"):
# Factorio mods needs a specific name or they do not function # Factorio mods need a specific name or they do not function
_, seed_name, slot_id, slot_name = file.filename.rsplit("_", 1)[0].split("-") _, seed_name, slot_id, slot_name = file.filename.rsplit("_", 1)[0].split("-")
slots.add(Slot(data=zfile.open(file, "r").read(), player_name=slot_name, slots.add(Slot(data=zfile.open(file, "r").read(), player_name=slot_name,
player_id=int(slot_id[1:]), game="Factorio")) player_id=int(slot_id[1:]), game="Factorio"))
@ -81,14 +70,36 @@ def uploads():
multidata = zfile.open(file).read() multidata = zfile.open(file).read()
if multidata: if multidata:
flush() # commit slots flush() # commit slots
seed = Seed(multidata=multidata, spoiler=spoiler, slots=slots, owner=session["_id"]) seed = Seed(multidata=multidata, spoiler=spoiler, slots=slots, owner=owner, meta=json.dumps(meta),
id=sid if sid else uuid.uuid4())
flush() # create seed flush() # create seed
for slot in slots: for slot in slots:
slot.seed = seed slot.seed = seed
return seed
return redirect(url_for("viewSeed", seed=seed.id))
else: else:
flash("No multidata was found in the zip file, which is required.") flash("No multidata was found in the zip file, which is required.")
@app.route('/uploads', methods=['GET', 'POST'])
def uploads():
if request.method == 'POST':
# check if the post request has the file part
if 'file' not in request.files:
flash('No file part')
else:
file = request.files['file']
# if user does not select file, browser also
# submit an empty part without filename
if file.filename == '':
flash('No selected file')
elif file and allowed_file(file.filename):
if file.filename.endswith(".zip"):
with zipfile.ZipFile(file, 'r') as zfile:
res = upload_zip_to_db(zfile)
if type(res) == str:
return res
elif res:
return redirect(url_for("viewSeed", seed=res.id))
else: else:
try: try:
multidata = file.read() multidata = file.read()