Merge pull request #29 from ThomasRubini/server_doc
This commit is contained in:
		
						commit
						e3f779abeb
					
				| @ -5,6 +5,14 @@ import os | ||||
| from truthseeker import discord_bot | ||||
| 
 | ||||
| class TruthSeekerApp(flask.Flask): | ||||
|     """ | ||||
|     Main class of the app | ||||
|     A single instance 'APP' of this class will be created and shared across the files | ||||
|     The class itself is a child class of flask.Flask and has property representing other services | ||||
| 
 | ||||
|     :attr SocketIO socketio_app: the SocketIO service | ||||
|     :attr DiscordBot discord_bot: the Discord Bot service | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self): | ||||
|         super().__init__("truthseeker") | ||||
| @ -26,7 +34,10 @@ class TruthSeekerApp(flask.Flask): | ||||
|     def run_app(self): | ||||
|         self.socketio_app.run(self) | ||||
| 
 | ||||
|     def set_app_secret(self): | ||||
|     def set_app_secret(self) -> None: | ||||
|         """ | ||||
|         Set the secret used by flask | ||||
|         """ | ||||
|         if os.path.isfile("instance/secret.txt"): | ||||
|             f = open("instance/secret.txt", "r") | ||||
|             self.config["SECRET_KEY"] = f.read() | ||||
| @ -41,7 +52,10 @@ class TruthSeekerApp(flask.Flask): | ||||
|             f.close() | ||||
|             print("Generated secret and wrote to secret.txt !") | ||||
| 
 | ||||
|     def get_discord_bot_token(self): | ||||
|     def get_discord_bot_token(self) -> str: | ||||
|         """ | ||||
|         Get the token used by the discord bot | ||||
|         """ | ||||
|         if os.path.isfile("instance/discord_bot_token.txt"): | ||||
|             f = open("instance/discord_bot_token.txt", "r") | ||||
|             token = f.read() | ||||
|  | ||||
| @ -3,10 +3,14 @@ import threading | ||||
| import truthseeker | ||||
| import asyncio | ||||
| 
 | ||||
| async def empty_coro(): | ||||
|     return | ||||
| 
 | ||||
| class DiscordBot: | ||||
|     """ | ||||
|     Wrapper around a discord bot, providing utility methods to interact with it | ||||
| 
 | ||||
|     :attr Client bot: the underlying discord bot from discord.py | ||||
|     :attr TextChannel __channel__: the channel used by the bot to send messages | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self): | ||||
|         self.bot = discord.Client(intents=discord.Intents.default()) | ||||
|         self.__channel__ = None | ||||
| @ -19,7 +23,10 @@ class DiscordBot: | ||||
|             self.__setup__channel__() | ||||
|             self.update_games_presence() | ||||
| 
 | ||||
|     def __setup__channel__(self): | ||||
|     def __setup__channel__(self) -> None: | ||||
|         """ | ||||
|         Setup the channel that the bot will send message in | ||||
|         """ | ||||
|         if len(self.bot.guilds) == 1: | ||||
|             self.__channel__ = discord.utils.get(self.bot.guilds[0].channels, name="bot") | ||||
|         else: | ||||
| @ -31,6 +38,9 @@ class DiscordBot: | ||||
|         return thr | ||||
| 
 | ||||
|     def API(func): | ||||
|         """ | ||||
|         Decorator used to wrap APIs methods, to handle thread context change, and ready check | ||||
|         """ | ||||
|         def decorator(self, *args, **kwargs): | ||||
|             if self.bot and self.bot.is_ready(): | ||||
|                 self.event_loop.create_task(func(self, *args, **kwargs)) | ||||
| @ -39,7 +49,10 @@ class DiscordBot: | ||||
|         return decorator | ||||
| 
 | ||||
|     @API | ||||
|     async def update_games_presence(self): | ||||
|     async def update_games_presence(self) -> None: | ||||
|         """ | ||||
|         Update the bot's status using the app's current context | ||||
|         """ | ||||
|         games_n = len(truthseeker.APP.games_list) | ||||
|         activity_name = f"Handling {games_n} game{'' if games_n==1 else 's'} !" | ||||
|         activity = discord.Activity(name=activity_name, type=discord.ActivityType.watching) | ||||
| @ -47,7 +60,10 @@ class DiscordBot: | ||||
| 
 | ||||
|     @API | ||||
|     async def send_message(self, text): | ||||
|         """ | ||||
|         Send a message to the channel used by the bot | ||||
|         """ | ||||
|         if self.__channel__: | ||||
|             await self.__channel__.send(text) | ||||
|         else: | ||||
|             print("channel member not defined, not sending discord message") | ||||
|             print("channel not defined, not sending discord message") | ||||
|  | ||||
| @ -3,20 +3,15 @@ import random | ||||
| from truthseeker.logic.data_persistance.data_access import * | ||||
| from datetime import datetime, timedelta | ||||
| from truthseeker import APP | ||||
| 
 | ||||
| 
 | ||||
| # Map of all actively running games | ||||
| # games_list["game.game_id"]-> game info linked to that id | ||||
| from typing import Union, Optional | ||||
| 
 | ||||
| def random_string(length: int) ->str: | ||||
|     """ | ||||
|     This function create a random string as long as the lint passed as  | ||||
|     parameter | ||||
|      | ||||
|     : param length: the lenght of the random string | ||||
|     : type length : int | ||||
|     : return      : a random string | ||||
|     : return type : string | ||||
|     :param length: the length of the random string to create | ||||
|     :return: a random string | ||||
|     """ | ||||
|     return "".join(random.choice(string.ascii_letters) for _ in range(length)) | ||||
| 
 | ||||
| @ -24,13 +19,13 @@ class Member: | ||||
|     """ | ||||
|     stores information related to the member of a given game | ||||
| 
 | ||||
|     Member.username : The username of this member | ||||
|     Member.socker : The reference to the socket to talk to this member | ||||
| 
 | ||||
|     :attr str username: The username of this member | ||||
|     :attr TODO progress: TODO | ||||
|     :attr TODO results: TODO | ||||
|     """ | ||||
|      | ||||
|     def __init__(self, username): | ||||
|         self.username = username | ||||
|         self.socket = None | ||||
|         self.progress = 0 | ||||
|         self.results = None | ||||
| 
 | ||||
| @ -44,10 +39,14 @@ class Game: | ||||
|     """ | ||||
|     The game info class stores all information linked to a active game | ||||
| 
 | ||||
|     Game.game_id : str, the game identifier of the game | ||||
|     Game.owner : Member, the game identifier of the game | ||||
|     Game.members : Member[], the members of the game | ||||
|     :attr str game_id: str, the game identifier of the game | ||||
|     :attr owner  Member: the player start created the game. It is also stored in self.members | ||||
|     :attr Member[] members: the members of the game | ||||
|     :attr bool has_started: TODO | ||||
|     :attr TODO gamedata: TODO | ||||
|     :attr TODO reaction_table: TODO | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self): | ||||
|         self.game_id = None | ||||
|         self.owner = None | ||||
| @ -56,12 +55,21 @@ class Game: | ||||
|         self.gamedata = {} | ||||
|         self.reaction_table = {} | ||||
| 
 | ||||
|     def set_owner(self, username): | ||||
|     def set_owner(self, username: str) -> Member: | ||||
|         """ | ||||
|         Set the owner of the game | ||||
| 
 | ||||
|         :param username: the username of the owner. | ||||
|         :return: the Member object created by this method | ||||
|         """ | ||||
|         self.owner = Member(username) | ||||
|         self.members.append(self.owner) | ||||
|         return self.owner | ||||
|      | ||||
|     def generateGameResults(self): | ||||
|     def generateGameResults(self) -> None: | ||||
|         """ | ||||
|         TODO + TODO RET TYPE | ||||
|         """ | ||||
|         data = {} | ||||
|         npcs = data["npcs"] = {} | ||||
|         for npc_id in self.gamedata["npcs"]: | ||||
| @ -75,29 +83,50 @@ class Game: | ||||
|             player_results[member.username] = member.results | ||||
|         return data | ||||
| 
 | ||||
|     def generate_data(self): | ||||
|     def generate_data(self) -> None: | ||||
|         """ | ||||
|         TODO | ||||
|         """ | ||||
|         #TODO Get language from player | ||||
|         self.gamedata, self.reaction_table = generateGameData("FR") | ||||
| 
 | ||||
|     def get_member(self, username): | ||||
|     def get_member(self, username: str) -> Union[Member, None]: | ||||
|         """ | ||||
|         Get a Member object from a username | ||||
| 
 | ||||
|         :param username: the username of the member to search for | ||||
|         :return the member corresponding to the username, or None if none if found: | ||||
|         """ | ||||
|         for member in self.members: | ||||
|             if member.username == username: | ||||
|                 return member | ||||
|          | ||||
|     def add_member(self, username): | ||||
|     def add_member(self, username: str) -> Union[Member, None]: | ||||
|         """ | ||||
|         Add a Member to the game | ||||
| 
 | ||||
|         :param username: the username of the member to add | ||||
|         :return: the Member created, or None if a Member with this username already exists in the game | ||||
|         """ | ||||
|         if self.get_member(username): | ||||
|             return None | ||||
|         member = Member(username) | ||||
|         self.members.append(member) | ||||
|         return member | ||||
| 
 | ||||
|     def get_npc_reaction(self,npc_id,reaction): | ||||
|     def get_npc_reaction(self, npc_id, reaction) -> None: | ||||
|         """ | ||||
|         TODO + TODO TYPES | ||||
|         """ | ||||
|         if npc_id not in self.reaction_table.keys(): | ||||
|             return 0 | ||||
|         reaction_id = self.reaction_table[npc_id][int(reaction)] | ||||
|         return read_image(f"./truthseeker/static/images/npc/{npc_id}/{reaction_id}.png") | ||||
|      | ||||
|     def getPlayerResults(self,responses: dict): | ||||
|     def getPlayerResults(self, responses: dict) -> None: | ||||
|         """ | ||||
|         TODO + TODO RETTYPE | ||||
|         """ | ||||
|         results = {} | ||||
|         try: | ||||
|             for npc_id in responses: | ||||
| @ -108,7 +137,12 @@ class Game: | ||||
|             return False | ||||
| 
 | ||||
| 
 | ||||
|     def has_finished(self): | ||||
|     def has_finished(self) -> bool: | ||||
|         """ | ||||
|         Checks if the game has finished by checking if every Member has submitted answers | ||||
|          | ||||
|         :return: True if the game has finished, else False | ||||
|         """ | ||||
|         for member in self.members: | ||||
|             if member.results == None : return False | ||||
|         return True | ||||
| @ -119,13 +153,12 @@ class Game: | ||||
|     def __repr__(self) -> str: | ||||
|         return self.__str__() | ||||
| 
 | ||||
| def create_game(owner): | ||||
| def create_game(owner: str) -> Game: | ||||
|     """ | ||||
|     This function creates a new game by creating a Game object and stores  | ||||
|     it into the games_list dictionnary | ||||
| 
 | ||||
|     : return      : a new Game | ||||
|     : return type : Game | ||||
|     :return: a new Game | ||||
|     """ | ||||
|     game = Game() | ||||
|     game.owner = owner | ||||
| @ -134,32 +167,26 @@ def create_game(owner): | ||||
|     APP.games_list[game.game_id] = game | ||||
|     return game | ||||
| 
 | ||||
| def get_game(game_id): | ||||
|     if game_id in APP.games_list: | ||||
|         return APP.games_list[game_id] | ||||
|     else: | ||||
|         return None | ||||
| def get_game(game_id: str) -> Union[Game, None]: | ||||
|     """ | ||||
|     Get a game from its ID | ||||
| 
 | ||||
| def get_game_info(game_id): | ||||
|     """    if not flask.session: | ||||
|         return {"error": 1, "msg": "No session"} | ||||
|     game = game_logic.get_game(flask.session["game_id"]) | ||||
|     if game == None: | ||||
|         return {"error": 1, "msg": "this game doesn't exist"} | ||||
|     This function retrieve a the Game object linked to the game_id | ||||
|     passed as parametter | ||||
| 
 | ||||
|     : param game_id : the lenght of the random string | ||||
|     : type game_id  : str | ||||
|     : return        : The Game Object linked to the game_id | ||||
|     : return type   : Game | ||||
|     :param game_id: the id of the game to search | ||||
|     :return: the Game object or None if not found | ||||
|     """ | ||||
|     if game_id in APP.games_list: | ||||
|         return APP.games_list[game_id] | ||||
|     else: | ||||
|         return None | ||||
| 
 | ||||
| def check_username(username): | ||||
| def check_username(username: str) -> bool: | ||||
|     """ | ||||
|     Check if a username is valid using a set of rules | ||||
| 
 | ||||
|     :param username: the username to check | ||||
|     :return: True or False depending on if the rules are respected | ||||
|     """ | ||||
|      | ||||
|     if not username: | ||||
|         return False | ||||
|     if not username.isalnum(): | ||||
| @ -178,10 +205,10 @@ def generateNpcText(npc: tables.Npc, lang: str) -> dict: | ||||
|     data["QA_1"] = getTextFromLid(lang, getNpcRandomAnswer(npc,1).TEXT_LID) | ||||
|     return data | ||||
| 
 | ||||
| def generateNpcReactions(npc : tables.Npc) ->list: | ||||
| def generateNpcReactions(npc: tables.Npc) ->list: | ||||
|     return getNpcRandomTraitId(npc) | ||||
| 
 | ||||
| def generatePlaceData(npcs :list, places: list, lang : str) -> dict: | ||||
| def generatePlaceData(npcs: list, places: list, lang: str) -> dict: | ||||
|     data = {} | ||||
|     random.shuffle(npcs) | ||||
|     for place in places: | ||||
| @ -230,4 +257,4 @@ def getTraitIdFromString(trait): | ||||
|     return getTraitFromText(trait) | ||||
| 
 | ||||
| def get_npc_image(npc_id): | ||||
|     return read_image(f"./truthseeker/static/images/npc/{npc_id}/0.png") | ||||
|     return read_image(f"./truthseeker/static/images/npc/{npc_id}/0.png") | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user