rework on player restriction , exposing rest apis

This commit is contained in:
Ayush Saini 2023-06-19 21:58:35 +05:30
parent af7fb5a586
commit bf4c01c291
10 changed files with 883 additions and 361 deletions

View file

@ -11,8 +11,8 @@ import _thread
import random import random
from tools import playlist from tools import playlist
from tools import logger from tools import logger
Commands = ['recents','info','createteam', 'showid', 'hideid', 'lm', 'gp', 'party', 'quit', 'kickvote', 'maxplayers', 'playlist', 'ban', 'kick', 'remove', 'end', 'quit', 'mute', 'unmute', 'slowmo', 'nv', 'dv', 'pause', Commands = ['recents', 'info', 'createteam', 'showid', 'hideid', 'lm', 'gp', 'party', 'quit', 'kickvote', 'maxplayers', 'playlist', 'ban', 'kick', 'remove', 'end', 'quit', 'mute', 'unmute', 'slowmo', 'nv', 'dv', 'pause',
'cameramode', 'createrole', 'addrole', 'removerole', 'addcommand', 'addcmd', 'removecommand', 'getroles', 'removecmd', 'changetag', 'customtag', 'customeffect','removeeffect','removetag' 'add', 'spectators', 'lobbytime'] 'cameramode', 'createrole', 'addrole', 'removerole', 'addcommand', 'addcmd', 'removecommand', 'getroles', 'removecmd', 'changetag', 'customtag', 'customeffect', 'removeeffect', 'removetag' 'add', 'spectators', 'lobbytime']
CommandAliases = ['max', 'rm', 'next', 'restart', 'mutechat', 'unmutechat', 'sm', CommandAliases = ['max', 'rm', 'next', 'restart', 'mutechat', 'unmutechat', 'sm',
'slow', 'night', 'day', 'pausegame', 'camera_mode', 'rotate_camera', 'effect'] 'slow', 'night', 'day', 'pausegame', 'camera_mode', 'rotate_camera', 'effect']
@ -136,7 +136,7 @@ def create_team(arguments):
ba.internal.chatmessage("enter team name") ba.internal.chatmessage("enter team name")
else: else:
from ba._team import SessionTeam from ba._team import SessionTeam
_ba.get_foreground_host_session().sessionteams.append(SessionTeam(team_id=len(_ba.get_foreground_host_session().sessionteams) +1, name=str(arguments[0]), color=(random.uniform(0, 1.2), random.uniform( _ba.get_foreground_host_session().sessionteams.append(SessionTeam(team_id=len(_ba.get_foreground_host_session().sessionteams) + 1, name=str(arguments[0]), color=(random.uniform(0, 1.2), random.uniform(
0, 1.2), random.uniform(0, 1.2)))) 0, 1.2), random.uniform(0, 1.2))))
from ba._lobby import Lobby from ba._lobby import Lobby
_ba.get_foreground_host_session().lobby = Lobby() _ba.get_foreground_host_session().lobby = Lobby()
@ -157,9 +157,12 @@ def get_player_info(arguments, client_id):
if account['client_id'] == int(arguments[0]): if account['client_id'] == int(arguments[0]):
send(pdata.get_detailed_info(account["pbid"]), client_id) send(pdata.get_detailed_info(account["pbid"]), client_id)
def get_recents(client_id): def get_recents(client_id):
for players in serverdata.recents: for players in serverdata.recents:
send(f"{players['client_id']} {players['deviceId']} {players['pbid']}", client_id) send(
f"{players['client_id']} {players['deviceId']} {players['pbid']}", client_id)
def changepartysize(arguments): def changepartysize(arguments):
if len(arguments) == 0: if len(arguments) == 0:
@ -184,7 +187,7 @@ def kick(arguments):
cl_id = int(arguments[0]) cl_id = int(arguments[0])
for ros in ba.internal.get_game_roster(): for ros in ba.internal.get_game_roster():
if ros["client_id"] == cl_id: if ros["client_id"] == cl_id:
logger.log("kicked "+ ros["display_string"]) logger.log("kicked " + ros["display_string"])
ba.internal.disconnect_client(int(arguments[0])) ba.internal.disconnect_client(int(arguments[0]))
return return
@ -201,11 +204,11 @@ def kikvote(arguments, clientid):
cl_id = int(arguments[1]) cl_id = int(arguments[1])
for ros in ba.internal.get_game_roster(): for ros in ba.internal.get_game_roster():
if ros["client_id"] == cl_id: if ros["client_id"] == cl_id:
if ros["account_id"] in serverdata.clients: pdata.enable_kick_vote(ros["account_id"])
serverdata.clients[ros["account_id"] logger.log(
]["canStartKickVote"] = True f'kick vote enabled for {ros["account_id"]} {ros["display_string"]}')
send( send(
"Upon server restart, Kick-vote will be enabled for this person", clientid) "Upon server restart, Kick-vote will be enabled for this person", clientid)
return return
except: except:
return return
@ -220,9 +223,10 @@ def kikvote(arguments, clientid):
if ros["client_id"] == cl_id: if ros["client_id"] == cl_id:
_ba.disable_kickvote(ros["account_id"]) _ba.disable_kickvote(ros["account_id"])
send("Kick-vote disabled for this person", clientid) send("Kick-vote disabled for this person", clientid)
if ros["account_id"] in serverdata.clients: logger.log(
serverdata.clients[ros["account_id"] f'kick vote disabled for {ros["account_id"]} {ros["display_string"]}')
]["canStartKickVote"] = False pdata.disable_kick_vote(
ros["account_id"], 2, "by chat command")
return return
except: except:
return return
@ -272,17 +276,19 @@ def end(arguments):
def ban(arguments): def ban(arguments):
try: try:
cl_id = int(arguments[0]) cl_id = int(arguments[0])
ac_id = "" duration = int(arguments[1]) if len(arguments) >= 2 else 0.5
for ros in ba.internal.get_game_roster(): for ros in ba.internal.get_game_roster():
if ros["client_id"] == cl_id: if ros["client_id"] == cl_id:
ac_id = ros['account_id'] pdata.ban_player(ros['account_id'], duration,
pdata.ban_player(ros['account_id']) "by chat command")
logger.log("banned "+ros["display_string"]) logger.log(f'banned {ros["display_string"]} by chat command')
if ac_id in serverdata.clients:
serverdata.clients[ac_id]["isBan"] = True for account in serverdata.recents: # backup case if player left the server
for account in serverdata.recents: # backup case if player left the server
if account['client_id'] == int(arguments[0]): if account['client_id'] == int(arguments[0]):
pdata.ban_player(account["pbid"]) pdata.ban_player(
account["pbid"], duration, "by chat command")
logger.log(
f'banned {ros["display_string"]} by chat command, recents')
kick(arguments) kick(arguments)
except: except:
pass pass
@ -298,17 +304,18 @@ def mute(arguments):
serverdata.muted = True serverdata.muted = True
try: try:
cl_id = int(arguments[0]) cl_id = int(arguments[0])
ac_id = "" duration = int(arguments[1]) if len(arguments) >= 2 else 0.5
for ros in ba.internal.get_game_roster(): for ros in ba.internal.get_game_roster():
if ros["client_id"] == cl_id: if ros["client_id"] == cl_id:
pdata.mute(ros['account_id']) pdata.mute(ros['account_id'])
ac_id = ros['account_id'] ac_id = ros['account_id']
logger.log("muted "+ros["display_string"]) logger.log(f'muted {ros["display_string"]}')
if ac_id in serverdata.clients: pdata.mute(ac_id, duration, "muted by chat command")
serverdata.clients[ac_id]["isMuted"] = True return
for account in serverdata.recents: # backup case if player left the server for account in serverdata.recents: # backup case if player left the server
if account['client_id'] == int(arguments[0]): if account['client_id'] == int(arguments[0]):
pdata.mute(account["pbid"]) pdata.mute(account["pbid"], duration,
"muted by chat command, from recents")
except: except:
pass pass
return return
@ -319,14 +326,16 @@ def un_mute(arguments):
serverdata.muted = False serverdata.muted = False
try: try:
cl_id = int(arguments[0]) cl_id = int(arguments[0])
ac_id = ""
for ros in ba.internal.get_game_roster(): for ros in ba.internal.get_game_roster():
if ros["client_id"] == cl_id: if ros["client_id"] == cl_id:
pdata.unmute(ros['account_id']) pdata.unmute(ros['account_id'])
ac_id = ros['account_id'] logger.log(f'unmuted {ros["display_string"]} by chat command')
if ac_id in serverdata.clients: return
serverdata.clients[ac_id]["isMuted"] = False for account in serverdata.recents: # backup case if player left the server
return if account['client_id'] == int(arguments[0]):
pdata.unmute(account["pbid"])
logger.log(
f'unmuted {ros["display_string"]} by chat command, recents')
except: except:
pass pass
@ -485,24 +494,27 @@ def set_custom_tag(arguments):
except: except:
return return
def remove_custom_tag(arguments): def remove_custom_tag(arguments):
try: try:
session = ba.internal.get_foreground_host_session() session = ba.internal.get_foreground_host_session()
for i in session.sessionplayers: for i in session.sessionplayers:
if i.inputdevice.client_id == int(arguments[0]): if i.inputdevice.client_id == int(arguments[0]):
pdata.remove_tag( i.get_v1_account_id()) pdata.remove_tag(i.get_v1_account_id())
except: except:
return return
def remove_custom_effect(arguments): def remove_custom_effect(arguments):
try: try:
session = ba.internal.get_foreground_host_session() session = ba.internal.get_foreground_host_session()
for i in session.sessionplayers: for i in session.sessionplayers:
if i.inputdevice.client_id == int(arguments[0]): if i.inputdevice.client_id == int(arguments[0]):
pdata.remove_effect( i.get_v1_account_id()) pdata.remove_effect(i.get_v1_account_id())
except: except:
return return
def set_custom_effect(arguments): def set_custom_effect(arguments):
try: try:
session = ba.internal.get_foreground_host_session() session = ba.internal.get_foreground_host_session()

View file

@ -6,19 +6,22 @@ from chatHandle.ChatCommands import Main
from tools import logger, servercheck from tools import logger, servercheck
from chatHandle.chatFilter import ChatFilter from chatHandle.chatFilter import ChatFilter
from features import votingmachine from features import votingmachine
import ba, _ba from playersData import pdata
import ba
import _ba
import ba.internal import ba.internal
import setting import setting
from datetime import datetime
settings = setting.get_settings_data() settings = setting.get_settings_data()
def filter_chat_message(msg, client_id): def filter_chat_message(msg, client_id):
now = datetime.now()
if client_id == -1: if client_id == -1:
if msg.startswith("/"): if msg.startswith("/"):
Main.Command(msg, client_id) Main.Command(msg, client_id)
return None return None
logger.log(f"Host msg: | {msg}" , "chat") logger.log(f"Host msg: | {msg}", "chat")
return msg return msg
acid = "" acid = ""
displaystring = "" displaystring = ""
@ -42,21 +45,23 @@ def filter_chat_message(msg, client_id):
if msg == None: if msg == None:
return return
if msg in ["end","dv","nv","sm"] and settings["allowVotes"]: if msg in ["end", "dv", "nv", "sm"] and settings["allowVotes"]:
votingmachine.vote(acid, client_id, msg) votingmachine.vote(acid, client_id, msg)
if acid in serverdata.clients and serverdata.clients[acid]["verified"]: if acid in serverdata.clients and serverdata.clients[acid]["verified"]:
if serverdata.muted: if serverdata.muted:
_ba.screenmessage("Server on mute", transient=True, clients=[client_id]) _ba.screenmessage("Server on mute",
transient=True, clients=[client_id])
return return
elif serverdata.clients[acid]["isMuted"]: elif acid in pdata.get_blacklist()["muted-ids"] and now < datetime.strptime(pdata.get_blacklist()["muted-ids"][acid]["till"], "%Y-%m-%d %H:%M:%S"):
_ba.screenmessage("You are on mute", transient=True, clients=[client_id]) _ba.screenmessage(
"You are on mute, maybe try after some time", transient=True, clients=[client_id])
return None return None
elif servercheck.get_account_age(serverdata.clients[acid]["accountAge"]) < settings['minAgeToChatInHours']: elif servercheck.get_account_age(serverdata.clients[acid]["accountAge"]) < settings['minAgeToChatInHours']:
_ba.screenmessage("New accounts not allowed to chat here", transient=True, clients=[client_id]) _ba.screenmessage("New accounts not allowed to chat here",
transient=True, clients=[client_id])
return None return None
else: else:
if msg.startswith(",") and settings["allowTeamChat"]: if msg.startswith(",") and settings["allowTeamChat"]:
@ -66,5 +71,6 @@ def filter_chat_message(msg, client_id):
return msg return msg
else: else:
_ba.screenmessage("Fetching your account info , Wait a minute", transient=True, clients=[client_id]) _ba.screenmessage("Fetching your account info , Wait a minute",
transient=True, clients=[client_id])
return None return None

View file

@ -4,6 +4,8 @@
# (see https://ballistica.net/wiki/meta-tag-system) # (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations from __future__ import annotations
import shutil
import copy
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import time import time
@ -17,13 +19,13 @@ import _ba
import ba.internal import ba.internal
import json import json
import datetime import datetime
from tools.ServerUpdate import contributeData , checkSpammer from tools.ServerUpdate import checkSpammer
import setting import setting
from datetime import datetime, timedelta
if TYPE_CHECKING: if TYPE_CHECKING:
pass pass
setti=setting.get_settings_data() settings = setting.get_settings_data()
PLAYERS_DATA_PATH = os.path.join( PLAYERS_DATA_PATH = os.path.join(
_ba.env()["python_directory_user"], "playersData" + os.sep _ba.env()["python_directory_user"], "playersData" + os.sep
@ -54,7 +56,7 @@ def get_info(account_id: str) -> dict | None:
dict | None dict | None
information of client information of client
""" """
profiles=get_profiles() profiles = get_profiles()
if account_id in profiles: if account_id in profiles:
return profiles[account_id] return profiles[account_id]
return None return None
@ -68,54 +70,69 @@ def get_profiles() -> dict:
dict dict
profiles of the players profiles of the players
""" """
if CacheData.profiles=={}: if CacheData.profiles == {}:
try: try:
if os.stat(PLAYERS_DATA_PATH+"profiles.json").st_size > 1000000: if os.stat(PLAYERS_DATA_PATH+"profiles.json").st_size > 1000000:
newpath = PLAYERS_DATA_PATH + "profiles.json"+str(datetime.datetime.now()) newpath = f'{PLAYERS_DATA_PATH}profiles-{str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))}.json'
shutil.copyfile(PLAYERS_DATA_PATH + "profiles.json", newpath) shutil.copyfile(PLAYERS_DATA_PATH + "profiles.json", newpath)
if setti["contributeData"]: profiles = {"pb-sdf": {}}
contributeData(newpath)
profiles = {"pb-sdf":{}}
print("resetting profiles") print("resetting profiles")
else: else:
f=open(PLAYERS_DATA_PATH + "profiles.json","r") f = open(PLAYERS_DATA_PATH + "profiles.json", "r")
profiles = json.load(f) profiles = json.load(f)
f.close() f.close()
print("loading old proiles.json") print("loading old proiles.json")
CacheData.profiles=profiles CacheData.profiles = profiles
except Exception as e: except Exception as e:
f=open(PLAYERS_DATA_PATH + "profiles.json.backup","r") f = open(PLAYERS_DATA_PATH + "profiles.json.backup", "r")
profiles = json.load(f) profiles = json.load(f)
print(e) print(e)
print("exception happened , falling back to profiles.json.backup") print("exception happened , falling back to profiles.json.backup")
CacheData.profiles=profiles CacheData.profiles = profiles
f.close() f.close()
return profiles return profiles
else: else:
return CacheData.profiles return CacheData.profiles
def get_profiles_archive_index():
return [x for x in os.listdir(PLAYERS_DATA_PATH) if x.startswith("profiles")]
def get_old_profiles(filename):
try:
f = open(PLAYERS_DATA_PATH + filename, "r")
profiles = json.load(f)
return profiles
except:
return {}
def get_blacklist() -> dict: def get_blacklist() -> dict:
if CacheData.blacklist == {}: if CacheData.blacklist == {}:
try: try:
f = open(PLAYERS_DATA_PATH + "blacklist.json","r") f = open(PLAYERS_DATA_PATH + "blacklist.json", "r")
CacheData.blacklist = json.load(f) CacheData.blacklist = json.load(f)
except: except:
print('error opening blacklist json') print('error opening blacklist json')
return { return {
"ban":{ "ban": {
"ids":[], "ids": {},
"ips":[], "ips": {},
"deviceids":[] "deviceids": {}
}, },
"muted-ids":[] "muted-ids": {},
} "kick-vote-disabled": {}
}
return CacheData.blacklist return CacheData.blacklist
def update_blacklist(): def update_blacklist():
with open(PLAYERS_DATA_PATH + "blacklist.json","w") as f: with open(PLAYERS_DATA_PATH + "blacklist.json", "w") as f:
json.dump(CacheData.blacklist,f,indent=4) json.dump(CacheData.blacklist, f, indent=4)
def commit_profiles(data={}) -> None: def commit_profiles(data={}) -> None:
"""Commits the given profiles in the database. """Commits the given profiles in the database.
@ -127,6 +144,7 @@ def commit_profiles(data={}) -> None:
# with OpenJson(PLAYERS_DATA_PATH + "profiles.json") as profiles_file: # with OpenJson(PLAYERS_DATA_PATH + "profiles.json") as profiles_file:
# profiles_file.dump(CacheData.profiles, indent=4) # profiles_file.dump(CacheData.profiles, indent=4)
def get_detailed_info(pbid): def get_detailed_info(pbid):
main_account = get_info(pbid) main_account = get_info(pbid)
if main_account == None: if main_account == None:
@ -164,19 +182,16 @@ def add_profile(
""" """
profiles = get_profiles() profiles = get_profiles()
profiles[account_id] = { profiles[account_id] = {
"display_string": display_string, "display_string": display_string,
"profiles": [], "profiles": [],
"name": current_name, "name": current_name,
"isBan": False, "accountAge": account_age,
"isMuted": False, "registerOn": time.time(),
"accountAge": account_age, "spamCount": 0,
"registerOn": time.time(), "lastSpam": time.time(),
"canStartKickVote": True, "totaltimeplayer": 0,
"spamCount": 0, }
"lastSpam": time.time(), CacheData.profiles = profiles
"totaltimeplayer": 0,
}
CacheData.profiles=profiles
serverdata.clients[account_id] = profiles[account_id] serverdata.clients[account_id] = profiles[account_id]
serverdata.clients[account_id]["warnCount"] = 0 serverdata.clients[account_id]["warnCount"] = 0
@ -190,14 +205,15 @@ def add_profile(
cid = ros['client_id'] cid = ros['client_id']
ip = _ba.get_client_ip(cid) ip = _ba.get_client_ip(cid)
serverdata.clients[account_id]["lastIP"] = ip serverdata.clients[account_id]["lastIP"] = ip
serverdata.recents.append({"client_id":cid,"deviceId":display_string,"pbid": account_id}) serverdata.recents.append(
{"client_id": cid, "deviceId": display_string, "pbid": account_id})
serverdata.recents = serverdata.recents[-20:] serverdata.recents = serverdata.recents[-20:]
device_id = _ba.get_client_public_device_uuid(cid) device_id = _ba.get_client_public_device_uuid(cid)
if(device_id==None): if (device_id == None):
device_id = _ba.get_client_device_uuid(cid) device_id = _ba.get_client_device_uuid(cid)
checkSpammer({'id':account_id,'display':display_string,'ip':ip,'device':device_id}) checkSpammer({'id': account_id, 'display': display_string,
if device_id in get_blacklist()["ban"]["deviceids"]: 'ip': ip, 'device': device_id})
serverdata.clients[account_id]["isBan"]=True if device_id in get_blacklist()["ban"]["deviceids"] or account_id in get_blacklist()["ban"]["ids"]:
ba.internal.disconnect_client(cid) ba.internal.disconnect_client(cid)
serverdata.clients[account_id]["deviceUUID"] = device_id serverdata.clients[account_id]["deviceUUID"] = device_id
@ -215,7 +231,7 @@ def update_display_string(account_id: str, display_string: str) -> None:
profiles = get_profiles() profiles = get_profiles()
if account_id in profiles: if account_id in profiles:
profiles[account_id]["display_string"] = display_string profiles[account_id]["display_string"] = display_string
CacheData.profiles=profiles CacheData.profiles = profiles
commit_profiles() commit_profiles()
@ -255,11 +271,11 @@ def update_profile(
if name is not None: if name is not None:
profiles[account_id]["name"] = name profiles[account_id]["name"] = name
CacheData.profiles=profiles CacheData.profiles = profiles
commit_profiles() commit_profiles()
def ban_player(account_id: str) -> None: def ban_player(account_id: str, duration_in_days: float, reason: str) -> None:
"""Bans the player. """Bans the player.
Parameters Parameters
@ -267,27 +283,51 @@ def ban_player(account_id: str) -> None:
account_id : str account_id : str
account id of the player to be banned account id of the player to be banned
""" """
profiles = get_profiles() current_profiles = get_profiles()
if account_id in profiles: ip = ""
profiles[account_id]["isBan"] = True device_id = ""
CacheData.profiles=profiles if account_id in current_profiles:
# _thread.start_new_thread(commit_profiles, (profiles,)) ip = current_profiles[account_id]["lastIP"]
cid = -1 device_id = current_profiles[account_id]["deviceUUID"]
for ros in ba.internal.get_game_roster():
if ros['account_id'] == account_id:
cid = ros['client_id']
ip = _ba.get_client_ip(cid)
device_id = _ba.get_client_public_device_uuid(cid) ban_time = datetime.now() + timedelta(days=duration_in_days)
if(device_id==None):
device_id = _ba.get_client_device_uuid(cid)
CacheData.blacklist["ban"]["ips"].append(ip)
CacheData.blacklist["ban"]["ids"].append(account_id) CacheData.blacklist["ban"]["ips"][ip] = {"till": ban_time.strftime(
CacheData.blacklist["ban"]["deviceids"].append(device_id) "%Y-%m-%d %H:%M:%S"), "reason": f'linked with account {account_id}'}
_thread.start_new_thread(update_blacklist,()) CacheData.blacklist["ban"]["ids"][account_id] = {
"till": ban_time.strftime("%Y-%m-%d %H:%M:%S"), "reason": reason}
CacheData.blacklist["ban"]["deviceids"][device_id] = {"till": ban_time.strftime(
"%Y-%m-%d %H:%M:%S"), "reason": f'linked with account {account_id}'}
_thread.start_new_thread(update_blacklist, ())
def mute(account_id: str) -> None:
def unban_player(account_id):
current_profiles = get_profiles()
ip = ""
device_id = ""
if account_id in current_profiles:
ip = current_profiles[account_id]["lastIP"]
device_id = current_profiles[account_id]["deviceUUID"]
CacheData.blacklist["ban"]["ips"].pop(ip, None)
CacheData.blacklist["ban"]["deviceids"].pop(device_id, None)
CacheData.blacklist["ban"]["ids"].pop(account_id, None)
_thread.start_new_thread(update_blacklist, ())
def disable_kick_vote(account_id, duration, reason):
ban_time = datetime.now() + timedelta(days=duration)
CacheData.blacklist["kick-vote-disabled"][account_id] = {"till": ban_time.strftime(
"%Y-%m-%d %H:%M:%S"), "reason": reason}
_thread.start_new_thread(update_blacklist, ())
def enable_kick_vote(account_id):
CacheData.blacklist["kick-vote-disabled"].pop(account_id, None)
_thread.start_new_thread(update_blacklist, ())
def mute(account_id: str, duration_in_days: float, reason: str) -> None:
"""Mutes the player. """Mutes the player.
Parameters Parameters
@ -295,11 +335,11 @@ def mute(account_id: str) -> None:
account_id : str account_id : str
acccount id of the player to be muted acccount id of the player to be muted
""" """
profiles = get_profiles() ban_time = datetime.now() + timedelta(days=duration_in_days)
if account_id in profiles:
profiles[account_id]["isMuted"] = True
CacheData.profiles=profiles
CacheData.blacklist["muted-ids"][account_id] = {"till": ban_time.strftime(
"%Y-%m-%d %H:%M:%S"), "reason": reason}
_thread.start_new_thread(update_blacklist, ())
def unmute(account_id: str) -> None: def unmute(account_id: str) -> None:
@ -310,11 +350,8 @@ def unmute(account_id: str) -> None:
account_id : str account_id : str
acccount id of the player to be unmuted acccount id of the player to be unmuted
""" """
profiles = get_profiles() CacheData.blacklist["muted-ids"].pop(account_id, None)
if account_id in profiles: _thread.start_new_thread(update_blacklist, ())
profiles[account_id]["isMuted"] = False
CacheData.profiles=profiles
_thread.start_new_thread(commit_profiles, (profiles,))
def update_spam(account_id: str, spam_count: int, last_spam: float) -> None: def update_spam(account_id: str, spam_count: int, last_spam: float) -> None:
@ -333,7 +370,7 @@ def update_spam(account_id: str, spam_count: int, last_spam: float) -> None:
if account_id in profiles: if account_id in profiles:
profiles[account_id]["spamCount"] = spam_count profiles[account_id]["spamCount"] = spam_count
profiles[account_id]["lastSpam"] = last_spam profiles[account_id]["lastSpam"] = last_spam
CacheData.profiles=profiles CacheData.profiles = profiles
commit_profiles(profiles) commit_profiles(profiles)
@ -549,15 +586,19 @@ def get_custom() -> dict:
""" """
if CacheData.custom == {}: if CacheData.custom == {}:
try: try:
f=open(PLAYERS_DATA_PATH + "custom.json","r") f = open(PLAYERS_DATA_PATH + "custom.json", "r")
custom = json.load(f) custom = json.load(f)
f.close() f.close()
CacheData.custom=custom CacheData.custom = custom
except: except:
f=open(PLAYERS_DATA_PATH + "custom.json.backup","r") f = open(PLAYERS_DATA_PATH + "custom.json.backup", "r")
custom = json.load(f) custom = json.load(f)
f.close() f.close()
CacheData.custom=custom CacheData.custom = custom
for account_id in custom["customeffects"]:
custom["customeffects"][account_id] = [custom["customeffects"][account_id]] if type(
custom["customeffects"][account_id]) is str else custom["customeffects"][account_id]
return CacheData.custom return CacheData.custom
@ -573,7 +614,8 @@ def set_effect(effect: str, account_id: str) -> None:
""" """
custom = get_custom() custom = get_custom()
if account_id in custom["customeffects"]: if account_id in custom["customeffects"]:
effects = [custom["customeffects"][account_id]] if type(custom["customeffects"][account_id]) is str else custom["customeffects"][account_id] effects = [custom["customeffects"][account_id]] if type(
custom["customeffects"][account_id]) is str else custom["customeffects"][account_id]
effects.append(effect) effects.append(effect)
custom["customeffects"][account_id] = effects custom["customeffects"][account_id] = effects
else: else:
@ -598,6 +640,22 @@ def set_tag(tag: str, account_id: str) -> None:
commit_c() commit_c()
def get_roles():
return CacheData.roles
def update_roles(roles):
CacheData.roles = roles
def get_custom_perks():
return CacheData.custom
def update_custom_perks(custom):
CacheData.custom = custom
def remove_effect(account_id: str) -> None: def remove_effect(account_id: str) -> None:
"""Removes the effect from player. """Removes the effect from player.
@ -609,7 +667,6 @@ def remove_effect(account_id: str) -> None:
custom = get_custom() custom = get_custom()
custom["customeffects"].pop(account_id) custom["customeffects"].pop(account_id)
CacheData.custom = custom CacheData.custom = custom
commit_c()
def remove_tag(account_id: str) -> None: def remove_tag(account_id: str) -> None:
@ -623,7 +680,6 @@ def remove_tag(account_id: str) -> None:
custom = get_custom() custom = get_custom()
custom["customtag"].pop(account_id) custom["customtag"].pop(account_id)
CacheData.custom = custom CacheData.custom = custom
commit_c()
def commit_c(): def commit_c():
@ -654,28 +710,31 @@ def load_white_list() -> None:
for account_id in data: for account_id in data:
CacheData.whitelist.append(account_id) CacheData.whitelist.append(account_id)
def load_cache(): def load_cache():
""" to be called on server boot""" """ to be called on server boot"""
get_profiles() get_profiles()
get_custom() get_custom()
get_roles() get_roles()
import shutil
import copy
def dump_cache(): def dump_cache():
if CacheData.profiles!={}: if CacheData.profiles != {}:
shutil.copyfile(PLAYERS_DATA_PATH + "profiles.json",PLAYERS_DATA_PATH + "profiles.json.backup") shutil.copyfile(PLAYERS_DATA_PATH + "profiles.json",
profiles= copy.deepcopy(CacheData.profiles) PLAYERS_DATA_PATH + "profiles.json.backup")
with open(PLAYERS_DATA_PATH + "profiles.json","w") as f: profiles = copy.deepcopy(CacheData.profiles)
json.dump(profiles,f,indent=4) with open(PLAYERS_DATA_PATH + "profiles.json", "w") as f:
if CacheData.roles!={}: json.dump(profiles, f, indent=4)
shutil.copyfile(PLAYERS_DATA_PATH + "roles.json",PLAYERS_DATA_PATH + "roles.json.backup") if CacheData.roles != {}:
roles= copy.deepcopy(CacheData.roles) shutil.copyfile(PLAYERS_DATA_PATH + "roles.json",
PLAYERS_DATA_PATH + "roles.json.backup")
roles = copy.deepcopy(CacheData.roles)
with open(PLAYERS_DATA_PATH + "roles.json", "w") as f: with open(PLAYERS_DATA_PATH + "roles.json", "w") as f:
json.dump(roles, f, indent=4) json.dump(roles, f, indent=4)
if CacheData.custom!={}: if CacheData.custom != {}:
shutil.copyfile(PLAYERS_DATA_PATH + "custom.json",PLAYERS_DATA_PATH + "custom.json.backup") shutil.copyfile(PLAYERS_DATA_PATH + "custom.json",
custom= copy.deepcopy(CacheData.custom) PLAYERS_DATA_PATH + "custom.json.backup")
custom = copy.deepcopy(CacheData.custom)
with open(PLAYERS_DATA_PATH + "custom.json", "w") as f: with open(PLAYERS_DATA_PATH + "custom.json", "w") as f:
json.dump(custom, f, indent=4) json.dump(custom, f, indent=4)
time.sleep(60) time.sleep(60)

View file

@ -2,119 +2,43 @@
# coding: utf-8 # coding: utf-8
# ba_meta require api 7 # ba_meta require api 7
from typing import Optional, Any, Dict, List, Type, Sequence # from gunicorn.app.base import BaseApplication
from ba._gameactivity import GameActivity # from gunicorn.workers import ggevent as gevent_worker
import ba,_ba
import ba.internal from flask import Flask, request, jsonify
import json from functools import wraps
import os import os
import _thread import _thread
# from stats import mystats # import uvicorn
from . import bombsquad_service
os.environ['FLASK_APP'] = 'bombsquadflaskapi.py' os.environ['FLASK_APP'] = 'bombsquadflaskapi.py'
os.environ['FLASK_ENV'] = 'development' os.environ['FLASK_ENV'] = 'development'
from stats import mystats
stats={} app = Flask(__name__)
leaderboard={}
top200={}
class BsDataThread(object):
def __init__(self):
self.Timer = ba.Timer( 8,ba.Call(self.refreshStats),timetype = ba.TimeType.REAL,repeat = True)
self.Timerr = ba.Timer( 10,ba.Call(self.startThread),timetype = ba.TimeType.REAL,repeat = True)
def startThread(self):
_thread.start_new_thread(self.refreshLeaderboard,())
def refreshLeaderboard(self):
global leaderboard
global top200
_t200={}
lboard=mystats.get_all_stats()
leaderboard=lboard
try:
entries = [(a['scores'], a['kills'], a['deaths'], a['games'], a['name'], a['aid'],a['last_seen']) for a in lboard.values()]
except:
print("stats reset is required , please clear out stats.json records , or download fresh stats.json from github")
import _ba
_ba.quit()
entries.sort(key=lambda x: x[1] or 0, reverse=True)
rank=0
for entry in entries:
rank+=1
if rank >201:
break
_t200[entry[5]]={"rank":rank,"scores":int(entry[0]),"games":int(entry[3]),"kills":int(entry[1]),"deaths":int(entry[2]),"name_html":entry[4],"last_seen":entry[6]}
top200=_t200
def refreshStats(self):
liveplayers={}
nextMap=''
currentMap=''
global stats
for i in ba.internal.get_game_roster():
try:
liveplayers[i['account_id']]={'name':i['players'][0]['name_full'],'client_id':i['client_id'],'device_id':i['display_string']}
except:
liveplayers[i['account_id']]={'name':"<in-lobby>",'clientid':i['client_id'],'device_id':i['display_string']}
try:
nextMap=ba.internal.get_foreground_host_session().get_next_game_description().evaluate()
current_game_spec=ba.internal.get_foreground_host_session()._current_game_spec
gametype: Type[GameActivity] =current_game_spec['resolved_type']
currentMap=gametype.get_settings_display_string(current_game_spec).evaluate()
except:
pass
minigame={'current':currentMap,'next':nextMap}
# system={'cpu':"p.cpu_percent()",'ram':p.virtual_memory().percent}
system={'cpu':"null",'ram':'null'}
stats['system']=system
stats['roster']=liveplayers
stats['chats']=ba.internal.get_chat_messages()
stats['playlist']=minigame
stats['teamInfo']=self.getTeamInfo()
#print(self.getTeamInfo());
def getTeamInfo(self):
data={}
session=ba.internal.get_foreground_host_session()
data['sessionType']=type(session).__name__
teams=session.sessionteams
for team in teams:
data[team.id]={'name':team.name.evaluate(),
'color':list(team.color),
'score':team.customdata['score'],
'players':[]
}
for player in team.players:
teamplayer={'name':player.getname(),
'device_id':player.inputdevice.get_v1_account_name(True),
'inGame':player.in_game,
'character':player.character,
'account_id':player.get_v1_account_id()
}
data[team.id]['players'].append(teamplayer)
return data
BsDataThread()
import flask
from flask import request, jsonify
app = flask.Flask(__name__)
app.config["DEBUG"] = False app.config["DEBUG"] = False
SECRET_KEY = "my_secret_key"
@app.after_request
def add_cors_headers(response):
# Allow requests from any origin
response.headers['Access-Control-Allow-Origin'] = '*'
# Allow specific headers
response.headers['Access-Control-Allow-Headers'] = 'Content-Type,Authorization,Secret-Key'
# Allow specific HTTP methods
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE'
return response
def check_admin(func):
@wraps(func)
def wrapper(*args, **kwargs):
if "Secret-Key" not in request.headers or request.headers["Secret-Key"] != SECRET_KEY:
return jsonify({"message": "Invalid secret key provided."}), 401
return func(*args, **kwargs)
return wrapper
@app.route('/', methods=['GET']) @app.route('/', methods=['GET'])
@ -122,26 +46,219 @@ def home():
return '''Nothing here :)''' return '''Nothing here :)'''
# A route to return all of the available entries in our catalog. @app.route('/api/live-stats', methods=['GET'])
@app.route('/getStats', methods=['GET']) def get_live_stats():
def api_all(): return jsonify(bombsquad_service.get_stats()), 200
return json.dumps(stats)
@app.route('/getLeaderboard',methods=['GET'])
def get_l():
return json.dumps(leaderboard)
@app.route('/getTop200',methods=['GET']) @app.route('/api/top-200', methods=['GET'])
def get_top200(): def get_top200():
return json.dumps(top200) return jsonify(bombsquad_service.get_top_200()), 200
class InitalRun: # ============ Admin only =========
def __init__(self):
print("start flask")
flask_run = _thread.start_new_thread(app.run, ("0.0.0.0",5000,False )) @app.route('/api/login', methods=['POST'])
@check_admin
def login():
return jsonify({"message": "Successful"}), 200
@app.route('/api/current-leaderboard', methods=['GET'])
@check_admin
def get_complete_leaderboard():
return jsonify(bombsquad_service.get_complete_leaderboard()), 200
@app.route('/api/server-settings', methods=['GET'])
@check_admin
def get_server_settings():
return jsonify(bombsquad_service.get_server_settings()), 200
@app.route('/api/roles', methods=['GET'])
@check_admin
def get_roles():
return jsonify(bombsquad_service.get_roles()), 200
@app.route('/api/roles', methods=['POST'])
@check_admin
def update_roles():
try:
data = request.get_json()
bombsquad_service.update_roles(data)
response = {
'message': 'Roles updated successfully'}
return jsonify(response), 201
except Exception as e:
return jsonify({'message': 'Error processing request', 'error': str(e)}), 400
@app.route('/api/perks', methods=['GET'])
@check_admin
def get_perks():
return jsonify(bombsquad_service.get_perks()), 200
@app.route('/api/perks', methods=['POST'])
@check_admin
def update_perks():
try:
data = request.get_json()
bombsquad_service.update_perks(data)
response = {
'message': 'Custom perks updated successfully'}
return jsonify(response), 201
except Exception as e:
return jsonify({'message': 'Error processing request', 'error': str(e)}), 400
@app.route('/api/server-settings', methods=['POST'])
@check_admin
def update_server_settings():
try:
data = request.get_json()
bombsquad_service.update_server_settings(data)
response = {
'message': 'Settings updated successfully, server may need restart'}
return jsonify(response), 201
except Exception as e:
return jsonify({'message': 'Error processing request', 'error': str(e)}), 400
@app.route('/api/db-list', methods=['GET'])
@check_admin
def fetch_dB_list():
key = request.args.get('type')
if key is None:
return "type required", 400
if key == "logs":
return jsonify(bombsquad_service.get_logs_db_list()), 200
elif key == "players":
return jsonify(bombsquad_service.get_profiles_db_list()), 200
else:
return jsonify({"message": "Invalid db type"}), 400
@app.route('/api/search-logs', methods=['GET'])
@check_admin
def search_logs():
key = request.args.get('key')
db = request.args.get('db')
if key is None or db is None:
return jsonify({"message": "key and db required"}), 400
return jsonify(bombsquad_service.get_matching_logs(key, db)), 200
@app.route('/api/search-player', methods=['GET'])
@check_admin
def search_players():
key = request.args.get('key')
db = request.args.get('db')
if key is None or db is None:
return jsonify({"message": "key and db required"}), 400
return jsonify(bombsquad_service.search_player_profile(key, db)), 200
@app.route('/api/get-player-info', methods=['GET'])
@check_admin
def get_player():
account_id = request.args.get('account-id')
if account_id is None:
return jsonify({"message": "account-id required"}), 400
return jsonify(bombsquad_service.get_player_details(account_id)), 200
@app.route('/api/update-player', methods=['POST'])
@check_admin
def update_player():
account_id = request.args.get('account-id')
action = request.args.get('action')
duration = int(request.args.get('duration'))
if account_id is None or action is None:
return "account-id and action required", 400
if action == "ban":
bombsquad_service.ban_player(account_id, duration)
elif action == "unban":
bombsquad_service.unban_player(account_id)
elif action == "mute":
bombsquad_service.mute_player(account_id, duration)
elif action == "unmute":
bombsquad_service.unmute_player(account_id)
elif action == "disable-kick-vote":
bombsquad_service.disable_kick_vote(account_id, duration)
elif action == "enable-kick-vote":
bombsquad_service.enable_kick_vote(account_id)
else:
return jsonify({"message": "Invalid Action"}), 400
return jsonify({"message": f"{action} done"}), 201
@app.route('/api/config', methods=['GET'])
@check_admin
def get_config():
return jsonify(bombsquad_service.get_server_config()), 200
@app.route('/api/action', methods=['POST'])
@check_admin
def do_action():
action = request.args.get('action')
value = request.args.get('value')
bombsquad_service.do_action(action, value)
return jsonify({"message": f'{action} done'}), 200
@app.route('/api/config', methods=['POST'])
@check_admin
def update_server_config():
try:
data = request.get_json()
bombsquad_service.update_server_config(data)
response = {
'message': 'config updated successfully, server will restart'}
return jsonify(response), 201
except Exception as e:
return jsonify({'message': 'Error processing request', 'error': str(e)}), 400
# from flask_asgi import FlaskASGI
# asgi_app = FlaskASGI(app)
# class FlaskApplication(BaseApplication):
# def __init__(self, app, options=None):
# self.options = options or {}
# self.application = app
# super(FlaskApplication, self).__init__()
# def load_config(self):
# config = {key: value for key, value in self.options.items(
# ) if key in self.cfg.settings and value is not None}
# for key, value in config.items():
# self.cfg.set(key.lower(), value)
# def load(self):
# return self.application
# def start_uvicorn():
# uvicorn.run("main:app", host='0.0.0.0', port=5000,
# reload=False, log_level="debug", workers=3, use_colors=True, no_signal=True)
# flask_run = _thread.start_new_thread(app.run, ("0.0.0.0", 5000, False))
def enable(): def enable():
InitalRun() flask_run = _thread.start_new_thread(app.run, ("0.0.0.0", 5000, False))
# SAMPLE OUTPUT # uvicorn_thread = threading.Thread(target=start_uvicorn)
# {'system': {'cpu': 80, 'ram': 34}, 'roster': {}, 'chats': [], 'playlist': {'current': 'Meteor Shower @ Rampage', 'next': 'Assault @ Step Right Up'}, 'teamInfo': {'sessionType': 'DualTeamSession', 0: {'name': 'Blue', 'color': (0.1, 0.25, 1.0), 'score': 1, 'players': [{'name': 'Jolly', 'device_id': '\ue030PC295588', 'inGame': True, 'character': 'xmas', 'account_id': 'pb-IF4TVWwZUQ=='}]}, 1: {'name': 'Red', 'color': (1.0, 0.25, 0.2), 'score': 0, 'players': []}}} # uvicorn_thread.start()
# options = {
# 'bind': '0.0.0.0:8000',
# 'workers': 4,
# 'worker_class': 'gevent'
# }
# flask_app = FlaskApplication(app, options)
# gevent_worker.GeventWorker(app.wsgi_app).init_process()
# flask_app.run()

View file

@ -0,0 +1,257 @@
import ba
import _ba
import ba.internal
from stats import mystats
from typing import Optional, Any, Dict, List, Type, Sequence
from ba._gameactivity import GameActivity
from playersData import pdata
from serverData import serverdata
from tools import servercheck, logger
import setting
from datetime import datetime
import _thread
import os
import yaml
stats = {}
leaderboard = {}
top200 = {}
serverinfo = {}
class BsDataThread(object):
def __init__(self):
global stats
stats["name"] = _ba.app.server._config.party_name
stats["discord"] = "https://discord.gg/ucyaesh"
stats["vapidKey"] = "sjfbsdjfdsf"
self.refresh_stats_cache_timer = ba.Timer(8, ba.Call(self.refreshStats),
timetype=ba.TimeType.REAL, repeat=True)
self.refresh_leaderboard_cache_timer = ba.Timer(10, ba.Call(
self.refreshLeaderboard), timetype=ba.TimeType.REAL, repeat=True)
def startThread(self):
_thread.start_new_thread(self.refreshLeaderboard, ())
def refreshLeaderboard(self):
global leaderboard
global top200
lboard = mystats.get_cached_stats()
leaderboard = lboard
sorted_data = sorted(lboard.values(), key=lambda x: x["rank"])
top_200_players = sorted_data[:200]
top200 = {player["aid"]: player for player in top_200_players}
def refreshStats(self):
global stats
global serverinfo
liveplayers = {}
nextMap = ''
currentMap = ''
for i in ba.internal.get_game_roster():
try:
liveplayers[i['account_id']] = {
'name': i['players'][0]['name_full'], 'client_id': i['client_id'], 'device_id': i['display_string']}
except:
liveplayers[i['account_id']] = {
'name': "<in-lobby>", 'client_id': i['client_id'], 'device_id': i['display_string']}
try:
nextMap = ba.internal.get_foreground_host_session(
).get_next_game_description().evaluate()
current_game_spec = ba.internal.get_foreground_host_session()._current_game_spec
gametype: Type[GameActivity] = current_game_spec['resolved_type']
currentMap = gametype.get_settings_display_string(
current_game_spec).evaluate()
except:
pass
current_games = {'current': currentMap, 'next': nextMap}
# system={'cpu':"p.cpu_percent()",'ram':p.virtual_memory().percent}
system = {'cpu': "null", 'ram': 'null'}
stats['system'] = system
stats['roster'] = liveplayers
stats['chats'] = ba.internal.get_chat_messages()
stats['playlist'] = current_games
stats['teamInfo'] = self.getTeamInfo()
stats["sessionType"] = type(
ba.internal.get_foreground_host_session()).__name__
# print(self.getTeamInfo());
def getTeamInfo(self):
data = {}
session = ba.internal.get_foreground_host_session()
if session:
teams = session.sessionteams
for team in teams:
data[str(team.id)] = {'name': team.name if isinstance(team.name, str) else team.name.evaluate(),
'color': list(team.color),
'score': team.customdata['score'],
'players': []
}
for player in team.players:
teamplayer = {'name': player.getname(),
'device_id': player.inputdevice.get_v1_account_name(True),
'inGame': player.in_game,
'character': player.character,
'account_id': player.get_v1_account_id()
}
data[str(team.id)]['players'].append(teamplayer)
return data
BsDataThread()
def get_stats():
return stats
def get_complete_leaderboard():
return leaderboard
def get_top_200():
return top200
def get_server_settings():
return setting.get_settings_data()
def update_server_settings(settings):
logger.log(f'updating server settings, request from web')
setting.commit(settings)
def get_roles():
return pdata.get_roles()
def get_perks():
# TODO wire with spaz_effects to fetch list of effects.
return {"perks": pdata.get_custom_perks(), "availableEffects": ["spark", "glow", "fairydust"]}
def update_perks(custom):
logger.log(f'updating custom perks, request from web')
pdata.update_custom_perks(custom)
def update_roles(roles):
logger.log("updated roles from web")
return pdata.update_roles(roles)
def get_profiles_db_list():
return pdata.get_profiles_archive_index()
def get_logs_db_list():
return serverdata.get_stats_index()
def get_matching_logs(key: str, filename: str):
logs = serverdata.read_logs(filename)
matching_lines = [line.strip() for line in logs.split('\n') if key in line]
return matching_lines
def search_player_profile(search_key: str, db: str):
selectedDB = {}
if db == "profiles.json":
selectedDB = pdata.get_profiles()
elif db in pdata.get_profiles_archive_index():
selectedDB = pdata.get_old_profiles(db)
matching_objects = {}
for key in selectedDB.keys():
if (search_key == key or
any(search_key.lower() in s.lower() for s in selectedDB[key].get("display_string", [])) or
search_key.lower() in selectedDB[key].get("name", "").lower()):
matching_objects[key] = selectedDB[key]
return matching_objects
def get_player_details(account_id: str):
current_time = datetime.now()
current_profiles = pdata.get_profiles()
ip = ""
device_id = ""
if account_id in current_profiles:
ip = current_profiles[account_id]["lastIP"]
device_id = current_profiles[account_id]["deviceUUID"]
extra_info = pdata.get_detailed_info(account_id)
isBanned = False
isMuted = False
isKickVoteDisabled = False
haveBanReason = servercheck.check_ban(ip, device_id, account_id, False)
if haveBanReason:
isBanned = True
extra_info += " , Banned for > " + haveBanReason
if account_id in pdata.get_blacklist()["muted-ids"] and current_time < datetime.strptime(pdata.get_blacklist()["muted-ids"][account_id]["till"], "%Y-%m-%d %H:%M:%S"):
isMuted = True
extra_info += f', Muted for > { pdata.get_blacklist()["muted-ids"][account_id]["reason"] } , till > {pdata.get_blacklist()["muted-ids"][account_id]["till"]} ,'
if account_id in pdata.get_blacklist()["kick-vote-disabled"] and current_time < datetime.strptime(pdata.get_blacklist()["kick-vote-disabled"][account_id]["till"], "%Y-%m-%d %H:%M:%S"):
isKickVoteDisabled = True
extra_info += f', Kick vote disabled for > { pdata.get_blacklist()["kick-vote-disabled"][account_id]["reason"] } , till > {pdata.get_blacklist()["kick-vote-disabled"][account_id]["till"]} '
return {"extra": extra_info, "isBan": isBanned, "isMuted": isMuted, "isKickVoteDisabled": isKickVoteDisabled}
def unban_player(account_id):
logger.log(f'unbanning {account_id} , request from web')
pdata.unban_player(account_id)
def unmute_player(account_id):
logger.log(f'unmuting {account_id} , request from web')
pdata.unmute(account_id)
def enable_kick_vote(account_id):
logger.log(f'enabling kick vote for {account_id} , request from web')
pdata.enable_kick_vote(account_id)
# TODO take duration input
def ban_player(account_id, duration):
logger.log(f'banning {account_id} , request from web')
pdata.ban_player(account_id, duration, "manually from website")
def mute_player(account_id, duration):
logger.log(f'muting {account_id} , request from web')
pdata.mute(account_id, duration, "manually from website")
def disable_kick_vote(account_id, duration):
logger.log(f'disable {account_id} , request from web')
pdata.disable_kick_vote(account_id, duration, "manually from website")
def get_server_config():
return _ba.app.server._config.__dict__
def update_server_config(config):
current_dir = os.getcwd()
file_path = os.path.join(current_dir, '..', 'config.yaml')
with open(file_path, "w") as f:
f.write(yaml.dump(config))
def do_action(action, value):
if action == "message":
_ba.pushcall(ba.Call(_ba.chatmessage, value), from_other_thread=True)
elif action == "quit":
_ba.pushcall(ba.Call(_ba.quit), from_other_thread=True)

View file

@ -1,8 +1,37 @@
# Released under the MIT License. See LICENSE for details. # Released under the MIT License. See LICENSE for details.
clients={} import fcntl
cachedclients=[] import _ba
muted=False import os
coopmode=False clients = {}
ips={} cachedclients = []
recents=[] muted = False
coopmode = False
ips = {}
recents = []
SERVER_DATA_PATH = os.path.join(
_ba.env()["python_directory_user"], "serverData" + os.sep
)
def get_stats_index():
return [x for x in os.listdir(SERVER_DATA_PATH) if "log" in x]
def read_logs(filename):
file_path = SERVER_DATA_PATH+filename
if not os.path.exists(file_path):
return ""
file = open(file_path, "r")
fcntl.flock(file.fileno(), fcntl.LOCK_SH)
contents = ""
try:
contents = file.read()
finally:
fcntl.flock(file.fileno(), fcntl.LOCK_UN)
file.close()
return contents

View file

@ -30,6 +30,10 @@ def get_settings_data() -> dict:
with open(SETTINGS_PATH, mode="r", encoding="utf-8") as data: with open(SETTINGS_PATH, mode="r", encoding="utf-8") as data:
return json.load(data) return json.load(data)
def refresh_cache() -> None:
get_settings_data.cache_clear()
# lets cache it again
get_settings_data()
def commit(data: dict) -> None: def commit(data: dict) -> None:
"""Commits the data in setting file. """Commits the data in setting file.
@ -41,3 +45,5 @@ def commit(data: dict) -> None:
""" """
with open(SETTINGS_PATH, mode="w", encoding="utf-8") as setting_file: with open(SETTINGS_PATH, mode="w", encoding="utf-8") as setting_file:
json.dump(data, setting_file, indent=4) json.dump(data, setting_file, indent=4)
# settings updated ok now update the cache
refresh_cache()

View file

@ -6,29 +6,17 @@ import os
import shutil import shutil
import threading import threading
import datetime import datetime
import custom_hooks
import urllib.request import urllib.request
from ba._activitytypes import * from ba._activitytypes import *
from ba import _activitytypes as ba_actypes
from ba._lobby import JoinInfo
from typing import Any, Dict, Optional
from ba._team import EmptyTeam # pylint: disable=W0611
from ba._player import EmptyPlayer # pylint: disable=W0611
from ba._music import setmusic, MusicType
from ba._activity import Activity
damage_data = {} damage_data = {}
# Don't touch the above line
"""
mystats module for BombSquad version 1.5.29
Provides functionality for dumping player stats to disk between rounds.
"""
ranks = [] ranks = []
top3Name = [] top3Name = []
# False-positive from pylint due to our class-generics-filter.
# variables
our_settings = setting.get_settings_data() our_settings = setting.get_settings_data()
# where our stats file and pretty html output will go
base_path = os.path.join(_ba.env()['python_directory_user'], "stats" + os.sep) base_path = os.path.join(_ba.env()['python_directory_user'], "stats" + os.sep)
statsfile = base_path + 'stats.json' statsfile = base_path + 'stats.json'
cached_stats = {} cached_stats = {}
@ -47,16 +35,14 @@ statsDefault = {
"last_seen": "2022-04-26 17:01:13.715014" "last_seen": "2022-04-26 17:01:13.715014"
} }
} }
# <th><b>Total Damage</b></th> #removed this line as it isn't crt data
# useful functions
seasonStartDate = None seasonStartDate = None
def get_all_stats(): def get_all_stats():
global seasonStartDate global seasonStartDate
if os.path.exists(statsfile): if os.path.exists(statsfile):
renameFile = False
with open(statsfile, 'r', encoding='utf8') as f: with open(statsfile, 'r', encoding='utf8') as f:
try: try:
jsonData = json.loads(f.read()) jsonData = json.loads(f.read())
@ -83,7 +69,7 @@ def get_all_stats():
def backupStatsFile(): def backupStatsFile():
shutil.copy(statsfile, statsfile.replace( shutil.copy(statsfile, statsfile.replace(
".json", "") + str(seasonStartDate) + ".json") ".json", "") + str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) + ".json")
def dump_stats(s: dict): def dump_stats(s: dict):
@ -107,23 +93,27 @@ def get_stats_by_id(account_id: str):
else: else:
return None return None
def get_cached_stats(): def get_cached_stats():
return cached_stats return cached_stats
def get_sorted_stats(stats):
entries = [(a['scores'], a['kills'], a['deaths'], a['games'],
a['name'], a['aid']) for a in stats.values()]
# this gives us a list of kills/names sorted high-to-low
entries.sort(key=lambda x: x[1] or 0, reverse=True)
return entries
def refreshStats(): def refreshStats():
global cached_stats global cached_stats
# lastly, write a pretty html version. # lastly, write a pretty html version.
# our stats url could point at something like this... # our stats url could point at something like this...
pStats = get_all_stats() pStats = get_all_stats()
cached_stats = pStats cached_stats = pStats
entries = get_sorted_stats(pStats)
entries = [(a['scores'], a['kills'], a['deaths'], a['games'],
a['name'], a['aid']) for a in pStats.values()]
# this gives us a list of kills/names sorted high-to-low
entries.sort(key=lambda x: x[1] or 0, reverse=True)
rank = 0 rank = 0
toppers = {}
toppersIDs = [] toppersIDs = []
_ranks = [] _ranks = []
for entry in entries: for entry in entries:

View file

@ -17,7 +17,7 @@ import shutil
import threading import threading
import setting import setting
import _ba import _ba
import fcntl
if TYPE_CHECKING: if TYPE_CHECKING:
pass pass
@ -33,6 +33,7 @@ if SETTINGS["discordbot"]["enable"]:
WEBHOOK_URL = SETTINGS["discordWebHook"]["webhookURL"] WEBHOOK_URL = SETTINGS["discordWebHook"]["webhookURL"]
@dataclass @dataclass
class RecentLogs: class RecentLogs:
"""Saves the recent logs.""" """Saves the recent logs."""
@ -54,7 +55,7 @@ def log(msg: str, mtype: str = "sys") -> None:
message = msg.replace("||", "|") message = msg.replace("||", "|")
discord_bot.push_log("***" + mtype + ":***" + message) discord_bot.push_log("***" + mtype + ":***" + message)
current_time = datetime.datetime.now() current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
msg = f"{current_time} + : {msg} \n" msg = f"{current_time} + : {msg} \n"
if SETTINGS["discordWebHook"]["enable"]: if SETTINGS["discordWebHook"]["enable"]:
@ -102,14 +103,38 @@ class dumplogs(threading.Thread):
elif self.type == "cmndlog": elif self.type == "cmndlog":
log_path = SERVER_DATA_PATH + "cmndusage.log" log_path = SERVER_DATA_PATH + "cmndusage.log"
else: else:
log_path = SERVER_DATA_PATH + "logs.log" log_path = SERVER_DATA_PATH + "systemlogs.log"
if os.path.exists(log_path): if os.path.exists(log_path):
if os.stat(log_path).st_size > 1000000: if os.stat(log_path).st_size > 1000000:
shutil.copy(log_path, log_path+str(datetime.datetime.now())) self.copy_file(
os.remove(log_path) log_path, log_path+str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
with open(log_path, mode="a+", encoding="utf-8") as file:
for msg in self.msg: self.write_file(log_path, self.msg)
def write_file(self, file_path, data):
file = open(file_path, "a+", encoding="utf-8")
fcntl.flock(file.fileno(), fcntl.LOCK_EX)
try:
for msg in data:
file.write(msg) file.write(msg)
finally:
fcntl.flock(file.fileno(), fcntl.LOCK_UN)
file.close()
def copy_file(self, file_path, dest_path):
lock_file = open(file_path, "r")
fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
try:
shutil.copy(file_path, dest_path)
except Exception as e:
print("Error occurred while copying file:", str(e))
finally:
fcntl.flock(lock_file.fileno(), fcntl.LOCK_UN)
lock_file.close()
os.remove(lock_file)
def send_webhook_message(): def send_webhook_message():
global webhook_queue global webhook_queue

View file

@ -7,7 +7,7 @@ import _ba
import ba.internal import ba.internal
import urllib.request import urllib.request
import json import json
import datetime from datetime import datetime
import time import time
import ba import ba
from ba._general import Call from ba._general import Call
@ -23,11 +23,13 @@ blacklist = pdata.get_blacklist()
settings = setting.get_settings_data() settings = setting.get_settings_data()
ipjoin = {} ipjoin = {}
class checkserver(object): class checkserver(object):
def start(self): def start(self):
self.players = [] self.players = []
self.t1 = ba.Timer(1, ba.Call(self.check), repeat=True, timetype=ba.TimeType.REAL) self.t1 = ba.Timer(1, ba.Call(self.check),
repeat=True, timetype=ba.TimeType.REAL)
def check(self): def check(self):
newPlayers = [] newPlayers = []
@ -36,33 +38,33 @@ class checkserver(object):
for ros in ba.internal.get_game_roster(): for ros in ba.internal.get_game_roster():
ip = _ba.get_client_ip(ros["client_id"]) ip = _ba.get_client_ip(ros["client_id"])
device_id = _ba.get_client_public_device_uuid(ros["client_id"]) device_id = _ba.get_client_public_device_uuid(ros["client_id"])
# if not ros["account_id"]: if (device_id == None):
# logger.log(f'Player disconnected, None account Id || {ros["display_string"] } IP {ip} {device_id}' , device_id = _ba.get_client_device_uuid(ros["client_id"])
# "playerjoin")
# ba.internal.disconnect_client(ros["client_id"], 0)
if device_id not in deviceClientMap: if device_id not in deviceClientMap:
deviceClientMap[device_id] = [ros["client_id"]] deviceClientMap[device_id] = [ros["client_id"]]
else: else:
deviceClientMap[device_id].append(ros["client_id"]) deviceClientMap[device_id].append(ros["client_id"])
if len(deviceClientMap[device_id]) >= settings['maxAccountPerIP']: if len(deviceClientMap[device_id]) >= settings['maxAccountPerIP']:
_ba.chatmessage(f"Only {settings['maxAccountPerIP']} player per IP allowed, disconnecting this device.", clients=[ros["client_id"]]) _ba.chatmessage(f"Only {settings['maxAccountPerIP']} player per IP allowed, disconnecting this device.", clients=[
ros["client_id"]])
ba.internal.disconnect_client(ros["client_id"]) ba.internal.disconnect_client(ros["client_id"])
logger.log(f'Player disconnected, reached max players per device || {ros["account_id"]}' , logger.log(f'Player disconnected, reached max players per device || {ros["account_id"]}',
"playerjoin") "playerjoin")
continue continue
if ip not in ipClientMap: if ip not in ipClientMap:
ipClientMap[ip] = [ros["client_id"]] ipClientMap[ip] = [ros["client_id"]]
else: else:
ipClientMap[ip].append(ros["client_id"]) ipClientMap[ip].append(ros["client_id"])
if len(ipClientMap[ip]) >= settings['maxAccountPerIP']: if len(ipClientMap[ip]) >= settings['maxAccountPerIP']:
_ba.chatmessage(f"Only {settings['maxAccountPerIP']} player per IP allowed, disconnecting this device.", clients=[ros["client_id"]]) _ba.chatmessage(f"Only {settings['maxAccountPerIP']} player per IP allowed, disconnecting this device.", clients=[
ros["client_id"]])
ba.internal.disconnect_client(ros["client_id"]) ba.internal.disconnect_client(ros["client_id"])
logger.log(f'Player disconnected, reached max players per IP address || {ros["account_id"]}' , logger.log(f'Player disconnected, reached max players per IP address || {ros["account_id"]}',
"playerjoin") "playerjoin")
continue continue
newPlayers.append(ros['account_id']) newPlayers.append(ros['account_id'])
if ros['account_id'] not in self.players and ros[ if ros['account_id'] not in self.players and ros[
'client_id'] != -1: 'client_id'] != -1:
# new player joined lobby # new player joined lobby
d_str = ros['display_string'] d_str = ros['display_string']
@ -92,7 +94,8 @@ class checkserver(object):
_ba.screenmessage("Not in whitelist,contact admin", _ba.screenmessage("Not in whitelist,contact admin",
color=(1, 0, 0), transient=True, color=(1, 0, 0), transient=True,
clients=[ros['client_id']]) clients=[ros['client_id']])
logger.log(f'{d_str} || { ros["account_id"]} | kicked > not in whitelist') logger.log(
f'{d_str} || { ros["account_id"]} | kicked > not in whitelist')
ba.internal.disconnect_client(ros['client_id']) ba.internal.disconnect_client(ros['client_id'])
return return
@ -101,14 +104,15 @@ class checkserver(object):
if ros['account_id'] in serverdata.clients: if ros['account_id'] in serverdata.clients:
on_player_join_server(ros['account_id'], on_player_join_server(ros['account_id'],
serverdata.clients[ serverdata.clients[
ros['account_id']], ip) ros['account_id']], ip, device_id)
else: else:
LoadProfile(ros['account_id'], ip).start() # from local cache, then call on_player_join_server # from local cache, then call on_player_join_server
LoadProfile(ros['account_id'], ip, device_id).start()
self.players = newPlayers self.players = newPlayers
def on_player_join_server(pbid, player_data, ip): def on_player_join_server(pbid, player_data, ip, device_id):
global ipjoin global ipjoin
now = time.time() now = time.time()
# player_data=pdata.get_info(pbid) # player_data=pdata.get_info(pbid)
@ -124,7 +128,7 @@ def on_player_join_server(pbid, player_data, ip):
if now - lastjoin < 15: if now - lastjoin < 15:
joincount += 1 joincount += 1
if joincount > 2: if joincount > 2:
_ba.screenmessage("Joining too fast , slow down dude", _ba.screenmessage("Joining too fast , slow down dude", # its not possible now tho, network layer will catch it before reaching here
color=(1, 0, 1), transient=True, color=(1, 0, 1), transient=True,
clients=[clid]) clients=[clid])
logger.log(f'{pbid} || kicked for joining too fast') logger.log(f'{pbid} || kicked for joining too fast')
@ -137,52 +141,53 @@ def on_player_join_server(pbid, player_data, ip):
ipjoin[ip]["count"] = joincount ipjoin[ip]["count"] = joincount
ipjoin[ip]["lastJoin"] = now ipjoin[ip]["lastJoin"] = now
else: else:
ipjoin[ip] = {"lastJoin":now,"count":0} ipjoin[ip] = {"lastJoin": now, "count": 0}
if pbid in serverdata.clients: if pbid in serverdata.clients:
serverdata.clients[pbid]["lastJoin"] = now serverdata.clients[pbid]["lastJoin"] = now
if player_data != None: # player data not in serevrdata or in local.json cache if player_data != None: # player data is in serevrdata or in local.json cache
serverdata.recents.append({"client_id":clid,"deviceId":device_string,"pbid":pbid}) serverdata.recents.append(
{"client_id": clid, "deviceId": device_string, "pbid": pbid})
serverdata.recents = serverdata.recents[-20:] serverdata.recents = serverdata.recents[-20:]
if player_data["isBan"] or get_account_age(player_data["accountAge"]) < \ if check_ban(ip, device_id, pbid):
settings["minAgeToJoinInHours"]: _ba.chatmessage(
'sad ,your account is flagged contact server owner for unban', clients=[clid])
ba.internal.disconnect_client(clid)
return
if get_account_age(player_data["accountAge"]) < \
settings["minAgeToJoinInHours"]:
for ros in ba.internal.get_game_roster(): for ros in ba.internal.get_game_roster():
if ros['account_id'] == pbid: if ros['account_id'] == pbid:
if not player_data["isBan"]:
_ba.screenmessage(
"New Accounts not allowed here , come back later",
color=(1, 0, 0), transient=True,
clients=[ros['client_id']])
logger.log(pbid + " | kicked > reason:Banned account")
_ba.screenmessage( _ba.screenmessage(
"Contact server owner, your account not allowed here", "New Accounts not allowed here , come back later",
color=(1, 0, 0), transient=True, color=(1, 0, 0), transient=True,
clients=[ros['client_id']]) clients=[ros['client_id']])
logger.log(pbid + " | kicked > reason:Banned account")
ba.internal.disconnect_client(ros['client_id']) ba.internal.disconnect_client(ros['client_id'])
return return
else: else:
current_time = datetime.now()
if pbid not in serverdata.clients: if pbid not in serverdata.clients:
if check_ban(clid,pbid): # ahh , lets reset if plyer joining after some long time
return
serverdata.clients[pbid] = player_data serverdata.clients[pbid] = player_data
serverdata.clients[pbid]["warnCount"] = 0 serverdata.clients[pbid]["warnCount"] = 0
serverdata.clients[pbid]["lastWarned"] = time.time() serverdata.clients[pbid]["lastWarned"] = time.time()
serverdata.clients[pbid]["verified"] = False serverdata.clients[pbid]["verified"] = False
serverdata.clients[pbid]["rejoincount"] = 1 serverdata.clients[pbid]["rejoincount"] = 1
serverdata.clients[pbid]["lastJoin"] = time.time() serverdata.clients[pbid]["lastJoin"] = time.time()
if not player_data["canStartKickVote"]: if pbid in blacklist["kick-vote-disabled"] and current_time < datetime.strptime(blacklist["kick-vote-disabled"][pbid]["till"], "%Y-%m-%d %H:%M:%S"):
_ba.disable_kickvote(pbid) _ba.disable_kickvote(pbid)
serverdata.clients[pbid]["lastIP"] = ip serverdata.clients[pbid]["lastIP"] = ip
device_id = _ba.get_client_public_device_uuid(clid) device_id = _ba.get_client_public_device_uuid(clid)
if(device_id==None): if (device_id == None):
device_id = _ba.get_client_device_uuid(clid) device_id = _ba.get_client_device_uuid(clid)
serverdata.clients[pbid]["deviceUUID"] = device_id serverdata.clients[pbid]["deviceUUID"] = device_id
verify_account(pbid, player_data) # checked for spoofed ids verify_account(pbid, player_data) # checked for spoofed ids
logger.log(pbid+" ip: "+serverdata.clients[pbid]["lastIP"]+", Device id: "+device_id) logger.log(
f'{pbid} ip: {serverdata.clients[pbid]["lastIP"]} , Device id: {device_id}')
_ba.screenmessage(settings["regularWelcomeMsg"] + " " + device_string, _ba.screenmessage(settings["regularWelcomeMsg"] + " " + device_string,
color=(0.60, 0.8, 0.6), transient=True, color=(0.60, 0.8, 0.6), transient=True,
clients=[clid]) clients=[clid])
@ -201,19 +206,33 @@ def on_player_join_server(pbid, player_data, ip):
# pdata.add_profile(pbid,d_string,d_string) # pdata.add_profile(pbid,d_string,d_string)
def check_ban(clid, pbid):
ip = _ba.get_client_ip(clid)
device_id = _ba.get_client_public_device_uuid(clid) def check_ban(ip, device_id, pbid, log=True):
if(device_id==None): current_time = datetime.now()
device_id = _ba.get_client_device_uuid(clid)
if (ip in blacklist["ban"]['ips'] or device_id in blacklist['ban']['deviceids'] or pbid in blacklist["ban"]["ids"]): if ip in blacklist["ban"]['ips'] and current_time < datetime.strptime(blacklist["ban"]["ips"][ip]["till"], "%Y-%m-%d %H:%M:%S"):
_ba.chatmessage('sad ,your account is flagged contact server owner for unban',clients=[clid]) msg = f' reason: matched IP | {blacklist["ban"]["ips"][ip]["reason"]} , Till : {blacklist["ban"]["ips"][ip]["till"]}'
logger.log(pbid + " | kicked > reason: Banned account") if log:
ba.internal.disconnect_client(clid) logger.log(f'{pbid} | kicked > {msg}')
return True return True
return msg
elif device_id in blacklist["ban"]["deviceids"] and current_time < datetime.strptime(blacklist["ban"]["deviceids"][device_id]["till"], "%Y-%m-%d %H:%M:%S"):
msg = f'reason: matched deviceId | {blacklist["ban"]["deviceids"][device_id]["reason"]}, Till : {blacklist["ban"]["deviceids"][device_id]["till"]}'
if log:
logger.log(
f'{pbid} | kicked > {msg}')
return True
return msg
elif pbid in blacklist["ban"]["ids"] and current_time < datetime.strptime(blacklist["ban"]["ids"][pbid]["till"], "%Y-%m-%d %H:%M:%S"):
msg = f'reason: matched ID | {blacklist["ban"]["ids"][pbid]["reason"]} , Till : {blacklist["ban"]["ids"][pbid]["till"]}'
if log:
logger.log(
f'{pbid} | kicked > {msg}')
return True
return msg
return False return False
def verify_account(pb_id, p_data): def verify_account(pb_id, p_data):
d_string = "" d_string = ""
for ros in ba.internal.get_game_roster(): for ros in ba.internal.get_game_roster():
@ -260,8 +279,8 @@ def get_account_creation_date(pb_id):
else: else:
creation_time = account_creation["created"] creation_time = account_creation["created"]
creation_time = map(str, creation_time) creation_time = map(str, creation_time)
creation_time = datetime.datetime.strptime("/".join(creation_time), creation_time = datetime.strptime("/".join(creation_time),
"%Y/%m/%d/%H/%M/%S") "%Y/%m/%d/%H/%M/%S")
# Convert to IST # Convert to IST
creation_time += datetime.timedelta(hours=5, minutes=30) creation_time += datetime.timedelta(hours=5, minutes=30)
return str(creation_time) return str(creation_time)
@ -285,14 +304,15 @@ def get_device_accounts(pb_id):
# ============ file I/O ============= # ============ file I/O =============
class LoadProfile(threading.Thread): class LoadProfile(threading.Thread):
def __init__(self, pb_id, ip): def __init__(self, pb_id, ip, device_id):
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.pbid = pb_id self.pbid = pb_id
self.ip = ip self.ip = ip
self.device_id = device_id
def run(self): def run(self):
player_data = pdata.get_info(self.pbid) player_data = pdata.get_info(self.pbid)
_ba.pushcall(Call(on_player_join_server, self.pbid, player_data, self.ip), _ba.pushcall(Call(on_player_join_server, self.pbid, player_data, self.ip, self.device_id),
from_other_thread=True) from_other_thread=True)
@ -316,7 +336,8 @@ def my_acc_age(pb_id):
def save_age(age, pb_id, display_string): def save_age(age, pb_id, display_string):
_ba.pushcall(Call(pdata.add_profile,pb_id, display_string,display_string, age), from_other_thread=True) _ba.pushcall(Call(pdata.add_profile, pb_id, display_string,
display_string, age), from_other_thread=True)
time.sleep(2) time.sleep(2)
thread2 = FetchThread( thread2 = FetchThread(
target=get_device_accounts, target=get_device_accounts,
@ -352,8 +373,8 @@ def kick_by_pb_id(pb_id, msg):
def get_account_age(ct): def get_account_age(ct):
creation_time = datetime.datetime.strptime(ct, "%Y-%m-%d %H:%M:%S") creation_time = datetime.strptime(ct, "%Y-%m-%d %H:%M:%S")
now = datetime.datetime.now() now = datetime.now()
delta = now - creation_time delta = now - creation_time
delta_hours = delta.total_seconds() / (60 * 60) delta_hours = delta.total_seconds() / (60 * 60)
return delta_hours return delta_hours
@ -364,18 +385,18 @@ def reportSpam(id):
profiles = pdata.get_profiles() profiles = pdata.get_profiles()
if id in profiles: if id in profiles:
count = profiles[id]["spamCount"] count = profiles[id]["spamCount"]
if now - profiles[id]["lastSpam"] < 2 * 24 * 60 * 60: if now - profiles[id]["lastSpam"] < 2 * 24 * 60 * 60:
count += 1 count += 1
if count > 3: if count > 3:
logger.log(id+" auto banned for spamming") logger.log(id+" auto banned for spamming")
profiles[id]["isBan"] = True # by default ban for 1 day , change here if you want
pdata.ban_player(id, 1, "auto ban exceed warn count")
else: else:
count = 0 count = 0
profiles[id]["spamCount"] = count profiles[id]["spamCount"] = count
profiles[id]["lastSpam"] = now profiles[id]["lastSpam"] = now
pdata.commit_profiles(profiles)
def on_join_request(ip): def on_join_request(ip):
now = time.time() now = time.time()
@ -383,11 +404,11 @@ def on_join_request(ip):
lastRequest = serverdata.ips[ip]["lastRequest"] lastRequest = serverdata.ips[ip]["lastRequest"]
count = serverdata.ips[ip]["count"] count = serverdata.ips[ip]["count"]
if now - lastRequest < 5: if now - lastRequest < 5:
count +=1 count += 1
if count > 40: if count > 40:
_ba.ban_ip(ip) _ba.ban_ip(ip)
else: else:
count = 0 count = 0
serverdata.ips[ip] = {"lastRequest":time.time(),"count":count} serverdata.ips[ip] = {"lastRequest": time.time(), "count": count}
else: else:
serverdata.ips[ip]={"lastRequest":time.time(),"count":0} serverdata.ips[ip] = {"lastRequest": time.time(), "count": 0}