forked from ArchipelagoMW/Archipelago
- Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathWebHost.py
More file actions
Latest commit
139 lines (118 loc) · 5.39 KB
/
Copy pathWebHost.py
File metadata and controls
139 lines (118 loc) · 5.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
importargparse
importos
importmultiprocessing
importlogging
importtyping
importModuleUpdate
ModuleUpdate.requirements_files.add(os.path.join("WebHostLib", "requirements.txt"))
ModuleUpdate.update()
# in case app gets imported by something like gunicorn
importUtils
importsettings
fromUtilsimportget_file_safe_name
iftyping.TYPE_CHECKING:
fromflaskimportFlask
Utils.local_path.cached_path=os.path.dirname(__file__)
settings.no_gui=True
configpath=os.path.abspath("config.yaml")
ifnotos.path.exists(configpath):
# fall back to config.yaml in user_path if config does not exist in cwd to match settings.py
configpath=os.path.abspath(Utils.user_path('config.yaml'))
defget_app() ->"Flask":
fromWebHostLibimportregister, cache, appasraw_app
fromWebHostLib.modelsimportdb
app=raw_app
ifos.path.exists(configpath) andnotapp.config["TESTING"]:
importyaml
app.config.from_file(configpath, yaml.safe_load)
logging.info(f"Updated config from {configpath}")
# inside get_app() so it's usable in systems like gunicorn, which do not run WebHost.py, but import it.
parser=argparse.ArgumentParser(allow_abbrev=False)
parser.add_argument('--config_override', default=None,
help="Path to yaml config file that overrules config.yaml.")
args=parser.parse_known_args()[0]
ifargs.config_override:
importyaml
app.config.from_file(os.path.abspath(args.config_override), yaml.safe_load)
logging.info(f"Updated config from {args.config_override}")
ifnotapp.config["HOST_ADDRESS"]:
logging.info("Getting public IP, as HOST_ADDRESS is empty.")
app.config["HOST_ADDRESS"] =Utils.get_public_ipv4()
logging.info(f"HOST_ADDRESS was set to {app.config['HOST_ADDRESS']}")
register()
cache.init_app(app)
db.bind(**app.config["PONY"])
db.generate_mapping(create_tables=True)
returnapp
defcopy_tutorials_files_to_static() ->None:
importshutil
importzipfile
fromwerkzeug.utilsimportsecure_filename
zfile: zipfile.ZipInfo
fromworlds.AutoWorldimportAutoWorldRegister
worlds= {}
forgame, worldinAutoWorldRegister.world_types.items():
ifhasattr(world.web, 'tutorials') and (notworld.hiddenorgame=='Archipelago'):
worlds[game] =world
base_target_path=Utils.local_path("WebHostLib", "static", "generated", "docs")
shutil.rmtree(base_target_path, ignore_errors=True)
forgame, worldinworlds.items():
# copy files from world's docs folder to the generated folder
target_path=os.path.join(base_target_path, secure_filename(game))
os.makedirs(target_path, exist_ok=True)
ifworld.zip_path:
zipfile_path=world.zip_path
assertos.path.isfile(zipfile_path), f"{zipfile_path} is not a valid file(path)."
assertzipfile.is_zipfile(zipfile_path), f"{zipfile_path} is not a valid zipfile."
withzipfile.ZipFile(zipfile_path) aszf:
forzfileinzf.infolist():
ifnotzfile.is_dir() and"/docs/"inzfile.filename:
zfile.filename=os.path.basename(zfile.filename)
withopen(os.path.join(target_path, secure_filename(zfile.filename)), "wb") asf:
f.write(zf.read(zfile))
else:
source_path=Utils.local_path(os.path.dirname(world.__file__), "docs")
files=os.listdir(source_path)
forfileinfiles:
shutil.copyfile(Utils.local_path(source_path, file),
Utils.local_path(target_path, secure_filename(file)))
if__name__=="__main__":
multiprocessing.freeze_support()
multiprocessing.set_start_method('spawn')
logging.basicConfig(format='[%(asctime)s] %(message)s', level=logging.INFO)
fromWebHostLib.autolauncherimportautohost, autogen, stop
fromWebHostLib.optionsimportcreateascreate_options_files
try:
fromWebHostLib.lttpspritesimportupdate_sprites_lttp
update_sprites_lttp()
exceptExceptionase:
logging.exception(e)
logging.warning("Could not update LttP sprites.")
app=get_app()
fromworldsimportAutoWorldRegister
# Update to only valid WebHost worlds
invalid_worlds= {nameforname, worldinAutoWorldRegister.world_types.items()
ifnothasattr(world.web, "tutorials")}
ifinvalid_worlds:
logging.error(f"Following worlds not loaded as they are invalid for WebHost: {invalid_worlds}")
AutoWorldRegister.world_types= {k: vfork, vinAutoWorldRegister.world_types.items() ifknotininvalid_worlds}
create_options_files()
copy_tutorials_files_to_static()
ifapp.config["SELFLAUNCH"]:
autohost(app.config)
ifapp.config["SELFGEN"]:
autogen(app.config)
ifapp.config["SELFHOST"]: # using WSGI, you just want to run get_app()
ifapp.config["DEBUG"]:
app.run(debug=True, port=app.config["PORT"])
else:
fromwaitressimportserve
serve(app, port=app.config["PORT"], threads=app.config["WAITRESS_THREADS"])
else:
fromtimeimportsleep
try:
whileTrue:
sleep(1) # wait for process to be killed
except (SystemExit, KeyboardInterrupt):
pass
stop() # stop worker threads