def send_file(self, file_name, window): """ Send the data in a single file to the Discord Bot Server. This is done in a few steps. # TODO: Optimize amount of times the file is looped over # TODO: Split this into multiple shorter functions 1. Retrieve basic information for this CombatLog that is required for sending it, including the date it was created and the player name. 2. Check the requirement that the server for this character is known. This is only the case if the character name is unique for this system across all servers. If the server cannot reliably be determined, the CombatLog data cannot be sent. 3. Check the files.db database in the temporary data directory if this file is in it. If it is not, this is the first time this file is processed. If it is, this file has already been processed at least once. 4. Parse the file, determining individual matches and the times they started at. 5. Retrieve data from the character database (managed by the MainWindow.characters_frame in the :characters: attribute. 6. If Discord sharing is enabled for the character, make sure the Discord Bot Server knows about it by sending the command for registering a character to the server. Note that this may cause duplicate registration requests among multiple files, but the Discord Bot Server will ignore them if the character is already registered. 7. Loop over the matches to send. 7.1. Retrieve match-specific required information such as the player ID format and the results. 7.2. Check if the match is a tutorial match. If it is, the character was the only participant and sending it would only clutter the database. 7.3. Check if the non-personal match data has already been sent for this file and if not send it to the server. # TODO: Extend this part for sending the map type 7.4. Check if personal data sharing is enabled for this character and it has not already been sent. Then send the personal match data to the server. 8. Update the files.db database with whether the sharing of data was successful. Only if *all* matches were successfully synchronized will the state be set to True. If the state is False, a new attempt will be made at some later point. 9. Save the database to file to prevent loss of data if the user exits the process unexpectedly. :param file_name: Absolute path to the CombatLog to sync :param window: MainWindow instance of this GSF Parser """ date = Parser.parse_filename(file_name) lines = Parser.read_file(file_name) player_name = Parser.get_player_name(lines) server = window.characters_frame.characters.get_server_for_character(player_name) basename = os.path.basename(file_name) # Actually send the file data to the server if date is None or server is None: return print("[DiscordClient] Synchronizing file: {}".format(basename)) if basename not in self.db: self.db[basename] = {"match": False, "char": False} match_s, char_s = self.db[basename]["match"], self.db[basename]["char"] player_id_list = Parser.get_player_id_list(lines) file_cube, matches, spawns = Parser.split_combatlog(lines, player_id_list) character = window.characters_frame.characters[(server, player_name)] character_enabled = character["Discord"] if character_enabled is True: server, name, faction = character["Server"], character["Name"], character["Faction"] self.send_character(server, faction, name) print("[DiscordClient] Character sharing {} for {} on {}".format( "enabled" if character_enabled else "disabled", player_name, server)) for index, (start, end) in enumerate(zip(matches[::2], matches[1::2])): match = file_cube[index] id_fmt = Parser.get_id_format(match[0]) start, end = map(lambda time: datetime.combine(date.date(), time.time()), (start, end)) results = Parser.parse_match(match, player_id_list) abls, dmg_d, dmg_t, _, _, _, _, _, enemies, _, _, ships, _ = results if Parser.is_tutorial(match): continue if self.db[basename]["match"] is False: match_s = self.send_match_start(server, date, start, id_fmt) and match_s match_s = self.send_match_end(server, date, start, id_fmt, end) and match_s else: print("[DiscordClient] Ignored {}".format(basename)) data = FileHandler.get_data_dictionary() spawn_dict = None for spawn in spawns[index]: result = FileHandler.get_spawn_dictionary(data, basename, start, spawn) if isinstance(result, dict): spawn_dict = result if isinstance(spawn_dict, dict): if "map" in spawn_dict and isinstance(spawn_dict["map"], tuple) and None not in spawn_dict["map"]: self.send_match_map(server, date, start, id_fmt, spawn_dict["map"]) if "score" in spawn_dict and isinstance(spawn_dict["score"], float): self.send_match_score(server, date, start, id_fmt, character["Faction"], spawn_dict["score"]) if character_enabled is True: if self.db[basename]["char"] is False: # Parse the file with results and send the results ship = ship_tiers[max(ships, key=ships.__getitem__)] if len(ships) != 0 else "Unknown" deaths = len(match) - 1 char_s = self.send_result( server, date, start, id_fmt, player_name, len(enemies), dmg_d, dmg_t, deaths, ship) print("[DiscordClient] {} to send character result for ({}, {})".format( "Succeeded" if char_s is True else "Failed", server, player_name)) else: print("[DiscordClient] Not sending character result because already sent.") else: print("[DiscordClient] Not sending character result because not enabled.") self.db[basename] = {"match": match_s, "char": char_s} self.save_database()