diff --git a/ChaChaGameStats/GameStatsSupervisor.py b/ChaChaGameStats/GameStatsSupervisor.py index 4f0fd57..09567d7 100644 --- a/ChaChaGameStats/GameStatsSupervisor.py +++ b/ChaChaGameStats/GameStatsSupervisor.py @@ -19,6 +19,7 @@ from . import RconQuakes from . import RconUTEngineWebAdminUT2k4 from . import RconUTEngineWebAdminUT3 from . import RconUTEngineWebAdminUT99 +from . import RconUT99_ChaChaRESTStats from . import RconMinecraft from pickle import TRUE from concurrent.futures import ThreadPoolExecutor @@ -123,7 +124,7 @@ class GameStatsSupervisorFactory: self._RconFactory = RconBase.RconFactory() self.register_GameStatsSupervisorRconBuilder("ut2k4", RconUTEngineWebAdminUT2k4.RconUTEngineWebAdminUT2k4) self.register_GameStatsSupervisorRconBuilder("ut3", RconUTEngineWebAdminUT3.RconUTEngineWebAdminUT3) - self.register_GameStatsSupervisorRconBuilder("ut99", RconUTEngineWebAdminUT99.RconUTEngineWebAdminUT99) + self.register_GameStatsSupervisorRconBuilder("ut99", RconUTEngineWebAdminUT99.RconUT99_ChaChaRESTStats) self.register_GameStatsSupervisorRconBuilder("q2", RconQuakes.RconSourceEngineQuake2) self.register_GameStatsSupervisorRconBuilder("q3a", RconQuakes.RconSourceEngineQuake3A) self.register_GameStatsSupervisorRconBuilder("codmw3", RconCODs.RconSourceEngineCODMW3) diff --git a/ChaChaGameStats/RconUT99_ChaChaRESTStats.py b/ChaChaGameStats/RconUT99_ChaChaRESTStats.py new file mode 100644 index 0000000..d105f2a --- /dev/null +++ b/ChaChaGameStats/RconUT99_ChaChaRESTStats.py @@ -0,0 +1,93 @@ +""" +ChaChaGameStats (c) by clement chastanier + +ChaChaGameStats is licensed under a +Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License. + +You should have received a copy of the license along with this +work. If not, see . +""" + +import time +from pprint import pprint + +import requests + +from . import GameStatsInterface +from . import RconBase + + +#class ExceptionRconIncorrectPadding(RconBase.ExceptionRcon): +# pass + +class RconUT99_ChaChaRESTStats(RconBase.RconBase): + def __init__(self,GameName:str,ip:str,port:int,user:str,password:str,timeout:int): + print("INIT ???") + super().__init__(GameName,ip,port,user,password,timeout) + self.session = None + self.BaseUrl = "http://" + self.ip + ":" + str(self.port) + "/api/v1/" + self.GameServerStatusResult = None + self.timeout = timeout + + def connect(self): + self.session = requests.session() + super().connect() + + def disconnect(self): + try: + self.session.close() + except Exception as e: + print("WARNING: self.session.close() failed: %s" % e) + super().disconnect() + + def GetStatus(self) -> dict(): + PINGstarttime = time.time() + defaults_all=self.session.get(self.BaseUrl + "defaults_all",timeout=self.timeout) + PING = round( (time.time() - PINGstarttime)*1000) + current_all=self.session.get(self.BaseUrl + "current_all",timeout=self.timeout) + res=dict() + res["ping"]=PING + res["defaults_all"]=defaults_all.json() + res["current_all"]=current_all.json() + return res + + ## interface implementation + def GetGameServerStatusResult(self) -> GameStatsInterface.GameServerStatusResult_Main: + self.GameServerStatusResult = super().GetGameServerStatusResult() + if self.GameServerStatusResult.status != "DOWN": + try: + self.GameServerStatusResult.raw = self.GetStatus() + self.GameServerStatusResult.status = "UP" + except RconBase.ExceptionRconTimeout: + self.GameServerStatusResult.status = "DOWN" + self.GameServerStatusResult.ping = 999 + return self.GameServerStatusResult + except RconBase.ExceptionWrongRconPassword: + self.GameServerStatusResult.status = "REFUSED" + self.GameServerStatusResult.ping = 999 + return self.GameServerStatusResult + + self.GameServerStatusResult.name = self.GameServerStatusResult.raw["defaults_all"]["ServerName"] + self.GameServerStatusResult.map = self.GameServerStatusResult.raw["current_all"]["Level"] + self.GameServerStatusResult.gametype = self.GameServerStatusResult.raw["current_all"]["GameName"] + self.GameServerStatusResult.mods = ", ".join(self.GameServerStatusResult.raw["current_all"]["Mutators"]) + self.GameServerStatusResult.maxplayers = self.GameServerStatusResult.raw["defaults_all"]["MaxPlayers"] + self.GameServerStatusResult.ping = self.GameServerStatusResult.raw["ping"] + self.GameServerStatusResult.version = None + self.GameServerStatusResult.players = [] + numplayers = 0 + for player in self.GameServerStatusResult.raw["current_all"]["player_list"]: + if player["bIsSpectator"] or player["bIsABot"]: + continue + newplayer = GameStatsInterface.GameServerStatusResult_Players() + newplayer.name = player["PlayerName"] + newplayer.score = player["Score"] + newplayer.ping = player["Ping"] + newplayer.ip = player["IP"] + newplayer.port = None + newplayer.uid = None + newplayer.num = numplayers + self.GameServerStatusResult.players.append(newplayer) + numplayers+=1 + self.GameServerStatusResult.nplayer = numplayers + return self.GameServerStatusResult \ No newline at end of file diff --git a/ChaChaGameStats/RconUTEngineWebAdmin.py b/ChaChaGameStats/RconUTEngineWebAdmin.py index e91f98e..5ebb629 100644 --- a/ChaChaGameStats/RconUTEngineWebAdmin.py +++ b/ChaChaGameStats/RconUTEngineWebAdmin.py @@ -46,7 +46,6 @@ class RconUTEngineWebAdmin(RconBase.RconBase,metaclass=abc.ABCMeta): self.GameServerStatusResult = None self.timeout = timeout self.initConstant() - self.fetchData = {}; def initConstant(self): pass @@ -65,8 +64,7 @@ class RconUTEngineWebAdmin(RconBase.RconBase,metaclass=abc.ABCMeta): def _fetchPageRAW(self,page) -> str: try: - response = self.session.get(page,data=self.fetchData,timeout=self.timeout) - self.fetchData = {} + response = self.session.get(page,timeout=self.timeout) if response.status_code != 200: raise RconBase.ExceptionWrongRconPassword except requests.exceptions.RequestException as e: @@ -150,32 +148,47 @@ class RconUTEngineWebAdminMODCENTRAL(RconUTEngineWebAdmin,metaclass=abc.ABCMeta) tree = self._fetchPageETree(url) try: level1 = tree.findall(".//form[@action='"+element+"']")[0] - level2 = level1.findall(".//table")[0] - infoChart = level2.findall(".//tr") - for info_record in infoChart: - data = info_record.findall(".//td/select") - if data : - attributename = data[0].attrib["name"].split('.')[-1] #get last var name: BLABLA.keyname => keyname - data_value = data[0].findall(".//option[@selected]") + level2 = level1.findall(".//table") + # table based page + if level2: + level2 = level2[0] + infoChart = level2.findall(".//tr") + for info_record in infoChart: + data = info_record.findall(".//td/select") + if data : + attributename = data[0].attrib["name"].split('.')[-1] #get last var name: BLABLA.keyname => keyname + data_value = data[0].findall(".//option[@selected]") + if data_value: + if "value" in data_value[0].attrib: + ar_ServerRules[attributename] = data_value[0].attrib["value"] + else: + ar_ServerRules[attributename] = data_value[0].text + continue + data = info_record.findall(".//td/input") + if data and data[0].attrib["name"]!="Apply": + attributename = data[0].attrib["name"].split('.')[-1] #get last var name: BLABLA.keyname => keyname + if "value" in data[0].attrib: + ar_ServerRules[attributename] = data[0].attrib["value"] + else: + ar_ServerRules[attributename] = data[0].text + if data[0].attrib["type"] == "checkbox" : + if "checked" in data[0].attrib: + ar_ServerRules[attributename] = "true" + else: + ar_ServerRules[attributename] = "false" + continue + else: + #new pages UT99 469c .... :-/ + selects = level1.findall(".//select") + for _select in selects: + attributename = _select.attrib["name"].split('.')[-1] #get last var name: BLABLA.keyname => keyname + data_value = _select.findall(".//option[@selected]") if data_value: if "value" in data_value[0].attrib: ar_ServerRules[attributename] = data_value[0].attrib["value"] else: ar_ServerRules[attributename] = data_value[0].text - continue - data = info_record.findall(".//td/input") - if data and data[0].attrib["name"]!="Apply": - attributename = data[0].attrib["name"].split('.')[-1] #get last var name: BLABLA.keyname => keyname - if "value" in data[0].attrib: - ar_ServerRules[attributename] = data[0].attrib["value"] - else: - ar_ServerRules[attributename] = data[0].text - if data[0].attrib["type"] == "checkbox" : - if "checked" in data[0].attrib: - ar_ServerRules[attributename] = "true" - else: - ar_ServerRules[attributename] = "false" - continue + continue except Exception as e: raise RconBase.ExceptionRconResultParse(e) return ar_ServerRules \ No newline at end of file diff --git a/ChaChaGameStats/RconUTEngineWebAdminUT99.py b/ChaChaGameStats/RconUTEngineWebAdminUT99.py index f0ff261..2e6939d 100644 --- a/ChaChaGameStats/RconUTEngineWebAdminUT99.py +++ b/ChaChaGameStats/RconUTEngineWebAdminUT99.py @@ -171,8 +171,13 @@ class RconUTEngineWebAdminUT99(RconUTEngineWebAdmin.RconUTEngineWebAdminMODCENTR ar_PlayersStats = [] tree = self._fetchPageETree(self.currentplayersUrl) try: - level1 = tree.findall(".//form[@action='current_players']")[0] - level2 = level1.findall(".//table")[1] + level1 = tree.findall(".//form[@action='current_players']") + if len(level1) == 2: #ut469c + level1 = level1[1] + level2 = level1.findall(".//table")[0] + else: + level1 = level1[0] + level2 = level1.findall(".//table")[1] player_chart = level2.findall(".//tr") del player_chart[0] for player_record in player_chart: diff --git a/ChaChaGameStats/_version.py b/ChaChaGameStats/_version.py index 0d36b3b..925ed92 100644 --- a/ChaChaGameStats/_version.py +++ b/ChaChaGameStats/_version.py @@ -7,4 +7,4 @@ Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported You should have received a copy of the license along with this work. If not, see . """ -__version__ = "0.1.4" +__version__ = "0.1.8" diff --git a/sample.py b/sample.py index 76d6b6d..76b1cb9 100644 --- a/sample.py +++ b/sample.py @@ -39,6 +39,33 @@ if __name__ == "__main__": """ + ar_games.append( _GameStatsSupervisorFactory.create( name = "ut99-dm", + gametype = "ut99", + ip = "172.16.1.41", + + + Interface_QuakeStats = { "port":5000}, + + Interface_RconBase = { "port":5000, + "username":"chacha", + "password":"cfographut"} + ) + ) + """ + ar_games.append( _GameStatsSupervisorFactory.create( name = "ut99-ctf", + gametype = "ut99", + ip = "127.0.0.1", + #ip = "37.59.37.210", + + + #Interface_QuakeStats = { "port":5040}, + + Interface_RconBase = { "port":8080, + "username":"", + "password":""} + ) + ) + """ ar_games.append( _GameStatsSupervisorFactory.create( name = "ut99-niut", gametype = "ut99", ip = "172.16.1.40", @@ -62,7 +89,8 @@ if __name__ == "__main__": "username":"chacha", "password":"cfographut"} ) - ) + ) + ar_games.append( _GameStatsSupervisorFactory.create( name = "ut99-utp", gametype = "ut99", ip = "172.16.1.42", @@ -76,6 +104,7 @@ if __name__ == "__main__": ) ) + ar_games.append( _GameStatsSupervisorFactory.create( name = "codbo2-3", gametype = "codbo2", ip = "GAME-CODBO2", @@ -124,7 +153,7 @@ if __name__ == "__main__": print("") print("== Testing: " + game.GameName + "==") res = game.API_GetGameServerStatusResult() - print("res: " + str(res.__dict__)) + pprint("res: " + str(res.__dict__)) for player in res.players: print(player.__dict__) if "QuakeStats" in res.raw: