| 
									
										
										
										
											2020-06-20 20:03:06 +02:00
										 |  |  | import os | 
					
						
							|  |  |  | import multiprocessing | 
					
						
							|  |  |  | import logging | 
					
						
							| 
									
										
										
										
											2022-05-03 22:14:03 +02:00
										 |  |  | import typing | 
					
						
							| 
									
										
										
										
											2020-06-20 20:03:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-06 15:11:17 +02:00
										 |  |  | import ModuleUpdate | 
					
						
							| 
									
										
										
										
											2022-03-14 21:30:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-06 15:30:20 +02:00
										 |  |  | ModuleUpdate.requirements_files.add(os.path.join("WebHostLib", "requirements.txt")) | 
					
						
							| 
									
										
										
										
											2021-06-06 15:11:17 +02:00
										 |  |  | ModuleUpdate.update() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-24 14:08:45 +02:00
										 |  |  | # in case app gets imported by something like gunicorn | 
					
						
							|  |  |  | import Utils | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:35 +02:00
										 |  |  | import settings | 
					
						
							| 
									
										
										
										
											2022-03-14 21:30:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-06 01:54:46 +02:00
										 |  |  | if typing.TYPE_CHECKING: | 
					
						
							|  |  |  |     from flask import Flask | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-31 00:10:18 +02:00
										 |  |  | Utils.local_path.cached_path = os.path.dirname(__file__) or "."  # py3.8 is not abs. remove "." when dropping 3.8 | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:35 +02:00
										 |  |  | settings.no_gui = True | 
					
						
							| 
									
										
										
										
											2021-05-13 00:28:53 +02:00
										 |  |  | configpath = os.path.abspath("config.yaml") | 
					
						
							| 
									
										
										
										
											2022-03-31 05:08:15 +02:00
										 |  |  | if not os.path.exists(configpath):  # fall back to config.yaml in home | 
					
						
							|  |  |  |     configpath = os.path.abspath(Utils.user_path('config.yaml')) | 
					
						
							| 
									
										
										
										
											2020-06-20 20:03:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-27 18:17:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-06 01:54:46 +02:00
										 |  |  | def get_app() -> "Flask": | 
					
						
							| 
									
										
										
										
											2023-09-20 16:05:56 +02:00
										 |  |  |     from WebHostLib import register, cache, app as raw_app | 
					
						
							|  |  |  |     from WebHostLib.models import db | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-10 17:42:22 +02:00
										 |  |  |     app = raw_app | 
					
						
							| 
									
										
										
										
											2022-12-14 20:01:06 +01:00
										 |  |  |     if os.path.exists(configpath) and not app.config["TESTING"]: | 
					
						
							| 
									
										
										
										
											2020-06-20 20:03:06 +02:00
										 |  |  |         import yaml | 
					
						
							| 
									
										
										
										
											2021-05-13 00:28:53 +02:00
										 |  |  |         app.config.from_file(configpath, yaml.safe_load) | 
					
						
							| 
									
										
										
										
											2020-06-20 20:03:06 +02:00
										 |  |  |         logging.info(f"Updated config from {configpath}") | 
					
						
							| 
									
										
										
										
											2023-03-09 21:31:00 +01:00
										 |  |  |     if not app.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']}") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-20 20:58:56 -04:00
										 |  |  |     register() | 
					
						
							| 
									
										
										
										
											2023-09-09 05:02:05 +02:00
										 |  |  |     cache.init_app(app) | 
					
						
							| 
									
										
										
										
											2020-06-20 20:03:06 +02:00
										 |  |  |     db.bind(**app.config["PONY"]) | 
					
						
							|  |  |  |     db.generate_mapping(create_tables=True) | 
					
						
							| 
									
										
										
										
											2020-07-10 17:42:22 +02:00
										 |  |  |     return app | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-03 22:14:03 +02:00
										 |  |  | def create_ordered_tutorials_file() -> typing.List[typing.Dict[str, typing.Any]]: | 
					
						
							| 
									
										
										
										
											2022-03-14 21:30:18 +01:00
										 |  |  |     import json | 
					
						
							| 
									
										
										
										
											2022-05-11 13:05:53 -05:00
										 |  |  |     import shutil | 
					
						
							| 
									
										
										
										
											2022-08-15 23:52:03 +02:00
										 |  |  |     import zipfile | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     zfile: zipfile.ZipInfo | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 00:27:37 +02:00
										 |  |  |     from worlds.AutoWorld import AutoWorldRegister | 
					
						
							| 
									
										
										
										
											2022-05-11 13:05:53 -05:00
										 |  |  |     worlds = {} | 
					
						
							|  |  |  |     data = [] | 
					
						
							|  |  |  |     for game, world in AutoWorldRegister.world_types.items(): | 
					
						
							| 
									
										
										
										
											2022-06-10 18:49:12 -05:00
										 |  |  |         if hasattr(world.web, 'tutorials') and (not world.hidden or game == 'Archipelago'): | 
					
						
							| 
									
										
										
										
											2022-05-11 13:05:53 -05:00
										 |  |  |             worlds[game] = world | 
					
						
							| 
									
										
										
										
											2022-08-15 23:52:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     base_target_path = Utils.local_path("WebHostLib", "static", "generated", "docs") | 
					
						
							| 
									
										
										
										
											2022-05-11 13:05:53 -05:00
										 |  |  |     for game, world in worlds.items(): | 
					
						
							|  |  |  |         # copy files from world's docs folder to the generated folder | 
					
						
							| 
									
										
										
										
											2022-08-15 23:52:03 +02:00
										 |  |  |         target_path = os.path.join(base_target_path, game) | 
					
						
							|  |  |  |         os.makedirs(target_path, exist_ok=True) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-18 00:27:37 +02:00
										 |  |  |         if world.zip_path: | 
					
						
							|  |  |  |             zipfile_path = world.zip_path | 
					
						
							| 
									
										
										
										
											2022-08-15 23:52:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             assert os.path.isfile(zipfile_path), f"{zipfile_path} is not a valid file(path)." | 
					
						
							|  |  |  |             assert zipfile.is_zipfile(zipfile_path), f"{zipfile_path} is not a valid zipfile." | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             with zipfile.ZipFile(zipfile_path) as zf: | 
					
						
							|  |  |  |                 for zfile in zf.infolist(): | 
					
						
							|  |  |  |                     if not zfile.is_dir() and "/docs/" in zfile.filename: | 
					
						
							| 
									
										
										
										
											2023-07-05 14:36:46 -07:00
										 |  |  |                         zfile.filename = os.path.basename(zfile.filename) | 
					
						
							| 
									
										
										
										
											2022-08-15 23:52:03 +02:00
										 |  |  |                         zf.extract(zfile, target_path) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             source_path = Utils.local_path(os.path.dirname(world.__file__), "docs") | 
					
						
							|  |  |  |             files = os.listdir(source_path) | 
					
						
							|  |  |  |             for file in files: | 
					
						
							|  |  |  |                 shutil.copyfile(Utils.local_path(source_path, file), Utils.local_path(target_path, file)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-11 13:05:53 -05:00
										 |  |  |         # build a json tutorial dict per game | 
					
						
							|  |  |  |         game_data = {'gameTitle': game, 'tutorials': []} | 
					
						
							|  |  |  |         for tutorial in world.web.tutorials: | 
					
						
							|  |  |  |             # build dict for the json file | 
					
						
							|  |  |  |             current_tutorial = { | 
					
						
							|  |  |  |                 'name': tutorial.tutorial_name, | 
					
						
							|  |  |  |                 'description': tutorial.description, | 
					
						
							|  |  |  |                 'files': [{ | 
					
						
							|  |  |  |                     'language': tutorial.language, | 
					
						
							|  |  |  |                     'filename': game + '/' + tutorial.file_name, | 
					
						
							|  |  |  |                     'link': f'{game}/{tutorial.link}', | 
					
						
							| 
									
										
										
										
											2022-05-26 20:39:08 -04:00
										 |  |  |                     'authors': tutorial.authors | 
					
						
							| 
									
										
										
										
											2022-05-11 13:05:53 -05:00
										 |  |  |                 }] | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # check if the name of the current guide exists already | 
					
						
							|  |  |  |             for guide in game_data['tutorials']: | 
					
						
							|  |  |  |                 if guide and tutorial.tutorial_name == guide['name']: | 
					
						
							|  |  |  |                     guide['files'].append(current_tutorial['files'][0]) | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 game_data['tutorials'].append(current_tutorial) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         data.append(game_data) | 
					
						
							|  |  |  |     with open(Utils.local_path("WebHostLib", "static", "generated", "tutorials.json"), 'w', encoding='utf-8-sig') as json_target: | 
					
						
							|  |  |  |         generic_data = {} | 
					
						
							|  |  |  |         for games in data: | 
					
						
							|  |  |  |             if 'Archipelago' in games['gameTitle']: | 
					
						
							|  |  |  |                 generic_data = data.pop(data.index(games)) | 
					
						
							| 
									
										
										
										
											2022-08-26 14:44:09 +00:00
										 |  |  |         sorted_data = [generic_data] + Utils.title_sorted(data, key=lambda entry: entry["gameTitle"]) | 
					
						
							| 
									
										
										
										
											2022-05-11 13:05:53 -05:00
										 |  |  |         json.dump(sorted_data, json_target, indent=2, ensure_ascii=False) | 
					
						
							|  |  |  |     return sorted_data | 
					
						
							| 
									
										
										
										
											2022-03-14 21:30:18 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-10 17:42:22 +02:00
										 |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     multiprocessing.freeze_support() | 
					
						
							|  |  |  |     multiprocessing.set_start_method('spawn') | 
					
						
							|  |  |  |     logging.basicConfig(format='[%(asctime)s] %(message)s', level=logging.INFO) | 
					
						
							| 
									
										
										
										
											2023-09-20 16:05:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     from WebHostLib.lttpsprites import update_sprites_lttp | 
					
						
							| 
									
										
										
										
											2024-05-19 20:40:36 +02:00
										 |  |  |     from WebHostLib.autolauncher import autohost, autogen, stop | 
					
						
							| 
									
										
										
										
											2023-09-20 16:05:56 +02:00
										 |  |  |     from WebHostLib.options import create as create_options_files | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-07 00:42:02 +02:00
										 |  |  |     try: | 
					
						
							|  |  |  |         update_sprites_lttp() | 
					
						
							|  |  |  |     except Exception as e: | 
					
						
							|  |  |  |         logging.exception(e) | 
					
						
							|  |  |  |         logging.warning("Could not update LttP sprites.") | 
					
						
							| 
									
										
										
										
											2020-07-10 17:42:22 +02:00
										 |  |  |     app = get_app() | 
					
						
							| 
									
										
										
										
											2021-07-22 18:21:31 +02:00
										 |  |  |     create_options_files() | 
					
						
							| 
									
										
										
										
											2022-03-14 21:30:18 +01:00
										 |  |  |     create_ordered_tutorials_file() | 
					
						
							| 
									
										
										
										
											2020-07-10 17:42:22 +02:00
										 |  |  |     if app.config["SELFLAUNCH"]: | 
					
						
							| 
									
										
										
										
											2020-06-28 09:28:13 +02:00
										 |  |  |         autohost(app.config) | 
					
						
							| 
									
										
										
										
											2021-12-13 05:48:33 +01:00
										 |  |  |     if app.config["SELFGEN"]: | 
					
						
							|  |  |  |         autogen(app.config) | 
					
						
							| 
									
										
										
										
											2020-07-10 17:42:22 +02:00
										 |  |  |     if app.config["SELFHOST"]:  # using WSGI, you just want to run get_app() | 
					
						
							|  |  |  |         if app.config["DEBUG"]: | 
					
						
							|  |  |  |             app.run(debug=True, port=app.config["PORT"]) | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2023-09-20 16:05:56 +02:00
										 |  |  |             from waitress import serve | 
					
						
							| 
									
										
										
										
											2020-07-10 17:42:22 +02:00
										 |  |  |             serve(app, port=app.config["PORT"], threads=app.config["WAITRESS_THREADS"]) | 
					
						
							| 
									
										
										
										
											2024-05-19 20:40:36 +02:00
										 |  |  |     else: | 
					
						
							|  |  |  |         from time import sleep | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             while True: | 
					
						
							|  |  |  |                 sleep(1)  # wait for process to be killed | 
					
						
							|  |  |  |         except (SystemExit, KeyboardInterrupt): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |     stop()  # stop worker threads |