def broadcast_chat(self, value, global_message=True, sender=None, team=None, irc=False): """ Send a chat message to many users """ if irc: self.irc_say('* %s' % value) ServerProtocol.send_chat(self, value, global_message, sender, team)
def send_chat(self, value, global_message=True, sender=None, team=None, irc=False): if irc: self.irc_say('* %s' % value) ServerProtocol.send_chat(self, value, global_message, sender, team)
def master_disconnected(self, client=None): ServerProtocol.master_disconnected(self, client) if self.master and self.master_reconnect_call is None: if client: message = 'Master connection could not be established' else: message = 'Master connection lost' log.info('%s, reconnecting in 60 seconds...' % message) self.master_reconnect_call = reactor.callLater( 60, self.reconnect_master)
def master_disconnected(self, client = None): ServerProtocol.master_disconnected(self, client) if self.master and self.master_reconnect_call is None: if client: message = 'Master connection could not be established' else: message = 'Master connection lost' print '%s, reconnecting in 20 seconds...' % message self.master_reconnect_call = reactor.callLater(20, self.reconnect_master)
def update_world(self): last_time = self.last_time current_time = reactor.seconds() if last_time is not None: dt = current_time - last_time if dt > 1.0: print '(warning: high CPU usage detected - %s)' % dt self.last_time = current_time ServerProtocol.update_world(self) time_taken = reactor.seconds() - current_time if time_taken > 1.0: print 'World update iteration took %s, objects: %s' % (time_taken, self.world.objects)
def update_world(self): last_time = self.last_time current_time = reactor.seconds() if last_time is not None: dt = current_time - last_time if dt > 1.0: log.warn('high CPU usage detected - %s' % dt) self.last_time = current_time ServerProtocol.update_world(self) time_taken = reactor.seconds() - current_time if time_taken > 1.0: log.warn('World update iteration took %s, objects: %s' % (time_taken, self.world.objects))
def data_received(self, peer, packet): ip = peer.address.host current_time = reactor.seconds() try: ServerProtocol.data_received(self, peer, packet) except (NoDataLeft, InvalidData): import traceback traceback.print_exc() print 'IP %s was hardbanned for invalid data or possibly DDoS.' % ip self.hard_bans.add(ip) return dt = reactor.seconds() - current_time if dt > 1.0: print '(warning: processing %r from %s took %s)' % (packet.data, ip, dt)
def data_received(self, peer, packet): ip = peer.address.host current_time = reactor.seconds() try: ServerProtocol.data_received(self, peer, packet) except (NoDataLeft, InvalidData): import traceback traceback.print_exc() print 'IP %s was hardbanned for invalid data or possibly DDoS.' % ip self.hard_bans.add(ip) return dt = reactor.seconds() - current_time if dt > 1.0: print '(warning: processing %r from %s took %s)' % ( packet.data, ip, dt)
def data_received(self, peer: Peer, packet: Packet) -> None: ip = peer.address.host current_time = reactor.seconds() try: ServerProtocol.data_received(self, peer, packet) except (NoDataLeft, ValueError): import traceback traceback.print_exc() log.info( 'IP %s was hardbanned for invalid data or possibly DDoS.' % ip) self.hard_bans.add(ip) return dt = reactor.seconds() - current_time if dt > 1.0: log.warn('processing {!r} from {} took {}'.format( packet.data, ip, dt))
def __init__(self, interface: bytes, config_dict: Dict[str, Any]) -> None: # logfile path relative to config dir if not abs path log_filename = logfile.get() if log_filename.strip(): # catches empty filename if not os.path.isabs(log_filename): log_filename = os.path.join(config.config_dir, log_filename) ensure_dir_exists(log_filename) if logging_rotate_daily.get(): logging_file = DailyLogFile(log_filename, '.') else: logging_file = open(log_filename, 'a') globalLogPublisher.addObserver(textFileLogObserver(logging_file)) globalLogPublisher.addObserver(textFileLogObserver(sys.stderr)) log.info('piqueserver started on %s' % time.strftime('%c')) self.config = config_dict if random_rotation: self.map_rotator_type = random_choice_cycle else: self.map_rotator_type = itertools.cycle # pylint: disable=redefined-variable-type self.default_time_limit = default_time_limit.get() self.default_cap_limit = cap_limit.get() self.advance_on_win = int(advance_on_win.get()) self.win_count = itertools.count(1) self.bans = NetworkDict() # attempt to load a saved bans list try: with open(os.path.join(config.config_dir, bans_file.get()), 'r') as f: self.bans.read_list(json.load(f)) log.debug("loaded {count} bans", count=len(self.bans)) except FileNotFoundError: log.debug("skip loading bans: file unavailable", count=len(self.bans)) except IOError as e: log.error('Could not read bans.txt: {}'.format(e)) except ValueError as e: log.error('Could not parse bans.txt: {}'.format(e)) self.hard_bans = set() # possible DDoS'ers are added here self.player_memory = deque(maxlen=100) if len(self.name) > MAX_SERVER_NAME_SIZE: log.warn('(server name too long; it will be truncated to "%s")' % (self.name[:MAX_SERVER_NAME_SIZE])) self.respawn_time = respawn_time_option.get() self.respawn_waves = respawn_waves.get() if game_mode.get() == 'ctf': self.game_mode = CTF_MODE elif game_mode.get() == 'tc': self.game_mode = TC_MODE elif self.game_mode is None: raise NotImplementedError('invalid game mode: %s' % game_mode) self.game_mode_name = game_mode.get().split('.')[-1] self.team1_name = team1_name.get() self.team2_name = team2_name.get() self.team1_color = tuple(team1_color.get()) self.team2_color = tuple(team2_color.get()) self.friendly_fire = friendly_fire.get() self.friendly_fire_on_grief = friendly_fire_on_grief.get() self.friendly_fire_time = grief_friendly_fire_time.get() self.spade_teamkills_on_grief = spade_teamkills_on_grief.get() self.fall_damage = fall_damage.get() self.teamswitch_interval = teamswitch_interval.get() self.teamswitch_allowed = teamswitch_allowed.get() self.max_players = max_players.get() self.melee_damage = melee_damage.get() self.max_connections_per_ip = max_connections_per_ip.get() self.passwords = passwords.get() self.server_prefix = server_prefix.get() self.time_announcements = time_announcements.get() self.balanced_teams = balanced_teams.get() self.login_retries = login_retries.get() # voting configuration self.default_ban_time = default_ban_duration.get() self.speedhack_detect = speedhack_detect.get() if user_blocks_only.get(): self.user_blocks = set() self.set_god_build = set_god_build.get() self.debug_log = debug_log_enabled.get() if self.debug_log: # TODO: make this configurable pyspades.debug.open_debug_log( os.path.join(config.config_dir, 'debug.log')) if ssh_enabled.get(): from piqueserver.ssh import RemoteConsole self.remote_console = RemoteConsole(self) irc = irc_options.get() if irc.get('enabled', False): from piqueserver.irc import IRCRelay self.irc_relay = IRCRelay(self, irc) if status_server_enabled.get(): from piqueserver.statusserver import StatusServerFactory self.status_server = StatusServerFactory(self) if ban_publish.get(): from piqueserver.banpublish import PublishServer self.ban_publish = PublishServer(self, ban_publish_port.get()) if bans_urls.get(): from piqueserver import bansubscribe self.ban_manager = bansubscribe.BanManager(self) self.start_time = reactor.seconds() self.end_calls = [] # TODO: why is this here? create_console(self) for user_type, func_names in rights.get().items(): for func_name in func_names: commands.add_rights(user_type, func_name) port = self.port = port_option.get() ServerProtocol.__init__(self, port, interface) self.host.intercept = self.receive_callback try: self.set_map_rotation(self.config['rotation']) except MapNotFound as e: log.critical('Invalid map in map rotation (%s), exiting.' % e.map) raise SystemExit self.update_format() self.tip_frequency = tip_frequency.get() if self.tips is not None and self.tip_frequency > 0: reactor.callLater(self.tip_frequency * 60, self.send_tip) self.master = register_master_option.get() self.set_master() self.http_agent = web_client.Agent(reactor) ip_getter = ip_getter_option.get() if ip_getter: self.get_external_ip(ip_getter)
def got_master_connection(self, client): log.info('Master connection established.') ServerProtocol.got_master_connection(self, client)
def got_master_connection(self, client): print 'Master connection established.' ServerProtocol.got_master_connection(self, client)
def __init__(self, interface: bytes, config_dict: Dict[str, Any]) -> None: # logfile path relative to config dir if not abs path log_filename = logfile.get() if log_filename.strip(): # catches empty filename if not os.path.isabs(log_filename): log_filename = os.path.join(config.config_dir, log_filename) ensure_dir_exists(log_filename) if logging_rotate_daily.get(): logging_file = DailyLogFile(log_filename, '.') else: logging_file = open(log_filename, 'a') predicate = LogLevelFilterPredicate( LogLevel.levelWithName(loglevel.get())) observers = [ FilteringLogObserver(textFileLogObserver(sys.stderr), [predicate]), FilteringLogObserver(textFileLogObserver(logging_file), [predicate]) ] globalLogBeginner.beginLoggingTo(observers) log.info('piqueserver started on %s' % time.strftime('%c')) self.config = config_dict if random_rotation.get(): self.map_rotator_type = random_choice_cycle else: self.map_rotator_type = itertools.cycle self.default_time_limit = default_time_limit.get() self.default_cap_limit = cap_limit.get() self.advance_on_win = int(advance_on_win.get()) self.win_count = itertools.count(1) self.bans = NetworkDict() # attempt to load a saved bans list try: with open(os.path.join(config.config_dir, bans_file.get()), 'r') as f: self.bans.read_list(json.load(f)) log.debug("loaded {count} bans", count=len(self.bans)) except FileNotFoundError: log.debug("skip loading bans: file unavailable", count=len(self.bans)) except IOError as e: log.error('Could not read bans.txt: {}'.format(e)) except ValueError as e: log.error('Could not parse bans.txt: {}'.format(e)) self.hard_bans = set() # possible DDoS'ers are added here self.player_memory = deque(maxlen=100) if len(self.name) > MAX_SERVER_NAME_SIZE: log.warn('(server name too long; it will be truncated to "%s")' % (self.name[:MAX_SERVER_NAME_SIZE])) self.respawn_time = respawn_time_option.get() self.respawn_waves = respawn_waves.get() # since AoS only supports CTF and TC at a protocol level, we need to get # the base game mode if we are using a custom game mode. game_mode_name = game_mode.get() if game_mode_name == 'ctf': self.game_mode = CTF_MODE elif game_mode.get() == 'tc': self.game_mode = TC_MODE elif self.game_mode not in [CTF_MODE, TC_MODE]: raise ValueError( 'invalid game mode: custom game mode "{}" does not set ' 'protocol.game_mode to one of TC_MODE or CTF_MODE. Are ' 'you sure the thing you have specified is a game mode?'.format( game_mode_name)) self.game_mode_name = game_mode.get().split('.')[-1] self.team1_name = team1_name.get()[:9] self.team2_name = team2_name.get()[:9] self.team1_color = tuple(team1_color.get()) self.team2_color = tuple(team2_color.get()) self.friendly_fire = friendly_fire.get() self.friendly_fire_on_grief = friendly_fire_on_grief.get() self.friendly_fire_time = grief_friendly_fire_time.get() self.spade_teamkills_on_grief = spade_teamkills_on_grief.get() self.fall_damage = fall_damage.get() self.teamswitch_interval = teamswitch_interval.get() self.teamswitch_allowed = teamswitch_allowed.get() self.max_players = max_players.get() self.melee_damage = melee_damage.get() self.max_connections_per_ip = max_connections_per_ip.get() self.passwords = passwords.get() self.server_prefix = server_prefix.get() self.time_announcements = time_announcements.get() self.balanced_teams = balanced_teams.get() self.login_retries = login_retries.get() # voting configuration self.default_ban_time = default_ban_duration.get() self.speedhack_detect = speedhack_detect.get() self.rubberband_distance = rubberband_distance.get() if user_blocks_only.get(): self.user_blocks = set() self.set_god_build = set_god_build.get() self.debug_log = debug_log_enabled.get() if self.debug_log: # TODO: make this configurable pyspades.debug.open_debug_log( os.path.join(config.config_dir, 'debug.log')) if ssh_enabled.get(): from piqueserver.ssh import RemoteConsole self.remote_console = RemoteConsole(self) irc = irc_options.get() if irc.get('enabled', False): from piqueserver.irc import IRCRelay self.irc_relay = IRCRelay(self, irc) if status_server_enabled.get(): from piqueserver.statusserver import StatusServer self.status_server = StatusServer(self) ensureDeferred(self.status_server.listen()) if ban_publish.get(): from piqueserver.banpublish import PublishServer self.ban_publish = PublishServer(self, ban_publish_port.get()) if bans_urls.get(): from piqueserver import bansubscribe self.ban_manager = bansubscribe.BanManager(self) self.start_time = time.time() self.end_calls = [] # TODO: why is this here? create_console(self) for user_type, func_names in rights.get().items(): for func_name in func_names: commands.add_rights(user_type, func_name) self.port = port_option.get() ServerProtocol.__init__(self, self.port, interface) self.host.intercept = self.receive_callback try: self.set_map_rotation(self.config['rotation']) except MapNotFound as e: log.critical('Invalid map in map rotation (%s), exiting.' % e.map) raise SystemExit map_load_d = self.advance_rotation() # discard the result of the map advance for now map_load_d.addCallback(lambda x: self._post_init()) ip_getter = ip_getter_option.get() if ip_getter: ensureDeferred(as_deferred(self.get_external_ip(ip_getter))) self.new_release = None notify_new_releases = config.option("release_notifications", default=True) if notify_new_releases.get(): ensureDeferred(as_deferred(self.watch_for_releases())) self.vacuum_loop = LoopingCall(self.vacuum_bans) # Run the vacuum every 6 hours, and kick it off it right now self.vacuum_loop.start(60 * 60 * 6, True) reactor.addSystemEventTrigger('before', 'shutdown', lambda: ensureDeferred(self.shutdown()))
def __init__(self, interface, config): self.config = config if config.get('random_rotation', False): self.map_rotator_type = random_choice_cycle else: self.map_rotator_type = itertools.cycle self.default_time_limit = config.get('default_time_limit', 20.0) self.default_cap_limit = config.get('cap_limit', 10.0) self.advance_on_win = int(config.get('advance_on_win', False)) self.win_count = itertools.count(1) self.bans = NetworkDict() try: self.bans.read_list(json.load(open('bans.txt', 'rb'))) except IOError: pass self.hard_bans = set() # possible DDoS'ers are added here self.player_memory = deque(maxlen = 100) self.config = config if len(self.name) > MAX_SERVER_NAME_SIZE: print '(server name too long; it will be truncated to "%s")' % ( self.name[:MAX_SERVER_NAME_SIZE]) self.respawn_time = config.get('respawn_time', 8) self.respawn_waves = config.get('respawn_waves', False) game_mode = config.get('game_mode', 'ctf') if game_mode == 'ctf': self.game_mode = CTF_MODE elif game_mode == 'tc': self.game_mode = TC_MODE elif self.game_mode is None: raise NotImplementedError('invalid game mode: %s' % game_mode) self.game_mode_name = game_mode team1 = config.get('team1', {}) team2 = config.get('team2', {}) self.team1_name = team1.get('name', 'Blue') self.team2_name = team2.get('name', 'Green') self.team1_color = tuple(team1.get('color', (0, 0, 196))) self.team2_color = tuple(team2.get('color', (0, 196, 0))) self.friendly_fire = config.get('friendly_fire', True) self.friendly_fire_time = config.get('grief_friendly_fire_time', 2.0) self.spade_teamkills_on_grief = config.get('spade_teamkills_on_grief', False) self.fall_damage = config.get('fall_damage', True) self.teamswitch_interval = config.get('teamswitch_interval', 0) self.max_players = config.get('max_players', 20) self.melee_damage = config.get('melee_damage', 100) self.max_connections_per_ip = config.get('max_connections_per_ip', 0) self.passwords = config.get('passwords', {}) self.server_prefix = encode(config.get('server_prefix', '[*]')) self.time_announcements = config.get('time_announcements', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 30, 60, 120, 180, 240, 300, 600, 900, 1200, 1800, 2400, 3000]) self.balanced_teams = config.get('balanced_teams', None) self.login_retries = config.get('login_retries', 1) # voting configuration self.default_ban_time = config.get('default_ban_duration', 24*60) self.speedhack_detect = config.get('speedhack_detect', True) if config.get('user_blocks_only', False): self.user_blocks = set() self.set_god_build = config.get('set_god_build', False) self.debug_log = config.get('debug_log', False) if self.debug_log: pyspades.debug.open_debug_log() ssh = config.get('ssh', {}) if ssh.get('enabled', False): from ssh import RemoteConsole self.remote_console = RemoteConsole(self, ssh) irc = config.get('irc', {}) if irc.get('enabled', False): from irc import IRCRelay self.irc_relay = IRCRelay(self, irc) status = config.get('status_server', {}) if status.get('enabled', False): from statusserver import StatusServerFactory self.status_server = StatusServerFactory(self, status) publish = config.get('ban_publish', {}) if publish.get('enabled', False): from banpublish import PublishServer self.ban_publish = PublishServer(self, publish) ban_subscribe = config.get('ban_subscribe', {}) if ban_subscribe.get('enabled', True): import bansubscribe self.ban_manager = bansubscribe.BanManager(self, ban_subscribe) logfile = config.get('logfile', None) if logfile is not None and logfile.strip(): if config.get('rotate_daily', False): create_filename_path(logfile) logging_file = DailyLogFile(logfile, '.') else: logging_file = open_create(logfile, 'a') log.addObserver(log.FileLogObserver(logging_file).emit) log.msg('pyspades server started on %s' % time.strftime('%c')) log.startLogging(sys.stdout) # force twisted logging self.start_time = reactor.seconds() self.end_calls = [] self.console = create_console(self) for password in self.passwords.get('admin', []): if password == 'replaceme': print 'REMEMBER TO CHANGE THE DEFAULT ADMINISTRATOR PASSWORD!' elif not password: self.everyone_is_admin = True for user_type, func_names in config.get('rights', {}).iteritems(): for func_name in func_names: commands.add_rights(func_name, user_type) port = self.port = config.get('port', 32887) ServerProtocol.__init__(self, port, interface) self.host.receiveCallback = self.receive_callback ret = self.set_map_rotation(config['maps']) if not ret: print 'Invalid map in map rotation (%s), exiting.' % ret.map raise SystemExit self.update_format() self.tip_frequency = config.get('tip_frequency', 0) if self.tips is not None and self.tip_frequency > 0: reactor.callLater(self.tip_frequency * 60, self.send_tip) self.master = config.get('master', True) self.set_master() get_external_ip(config.get('network_interface', '')).addCallback( self.got_external_ip)
def send_chat(self, value, global_message = True, sender = None, team = None, irc = False): if irc: self.irc_say('* %s' % value) ServerProtocol.send_chat(self, value, global_message, sender, team)
def __init__(self, interface, config): self.config = config if config.get('random_rotation', False): self.map_rotator_type = random_choice_cycle else: self.map_rotator_type = itertools.cycle self.default_time_limit = config.get('default_time_limit', 20.0) self.default_cap_limit = config.get('cap_limit', 10.0) self.advance_on_win = int(config.get('advance_on_win', False)) self.win_count = itertools.count(1) self.bans = NetworkDict() try: self.bans.read_list(json.load(open('bans.txt', 'rb'))) except IOError: pass self.hard_bans = set() # possible DDoS'ers are added here self.player_memory = deque(maxlen=100) self.config = config if len(self.name) > MAX_SERVER_NAME_SIZE: print '(server name too long; it will be truncated to "%s")' % ( self.name[:MAX_SERVER_NAME_SIZE]) self.respawn_time = config.get('respawn_time', 8) self.respawn_waves = config.get('respawn_waves', False) game_mode = config.get('game_mode', 'ctf') if game_mode == 'ctf': self.game_mode = CTF_MODE elif game_mode == 'tc': self.game_mode = TC_MODE elif self.game_mode is None: raise NotImplementedError('invalid game mode: %s' % game_mode) self.game_mode_name = game_mode team1 = config.get('team1', {}) team2 = config.get('team2', {}) self.team1_name = team1.get('name', 'Blue') self.team2_name = team2.get('name', 'Green') self.team1_color = tuple(team1.get('color', (0, 0, 196))) self.team2_color = tuple(team2.get('color', (0, 196, 0))) self.friendly_fire = config.get('friendly_fire', True) self.friendly_fire_time = config.get('grief_friendly_fire_time', 2.0) self.spade_teamkills_on_grief = config.get('spade_teamkills_on_grief', False) self.fall_damage = config.get('fall_damage', True) self.teamswitch_interval = config.get('teamswitch_interval', 0) self.max_players = config.get('max_players', 20) self.melee_damage = config.get('melee_damage', 100) self.max_connections_per_ip = config.get('max_connections_per_ip', 0) self.passwords = config.get('passwords', {}) self.server_prefix = encode(config.get('server_prefix', '[*]')) self.time_announcements = config.get('time_announcements', [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 30, 60, 120, 180, 240, 300, 600, 900, 1200, 1800, 2400, 3000 ]) self.balanced_teams = config.get('balanced_teams', None) self.login_retries = config.get('login_retries', 1) # voting configuration self.default_ban_time = config.get('default_ban_duration', 24 * 60) self.speedhack_detect = config.get('speedhack_detect', True) if config.get('user_blocks_only', False): self.user_blocks = set() self.set_god_build = config.get('set_god_build', False) self.debug_log = config.get('debug_log', False) if self.debug_log: pyspades.debug.open_debug_log() ssh = config.get('ssh', {}) if ssh.get('enabled', False): from ssh import RemoteConsole self.remote_console = RemoteConsole(self, ssh) irc = config.get('irc', {}) if irc.get('enabled', False): from irc import IRCRelay self.irc_relay = IRCRelay(self, irc) status = config.get('status_server', {}) if status.get('enabled', False): from statusserver import StatusServerFactory self.status_server = StatusServerFactory(self, status) publish = config.get('ban_publish', {}) if publish.get('enabled', False): from banpublish import PublishServer self.ban_publish = PublishServer(self, publish) ban_subscribe = config.get('ban_subscribe', {}) if ban_subscribe.get('enabled', True): import bansubscribe self.ban_manager = bansubscribe.BanManager(self, ban_subscribe) logfile = config.get('logfile', None) if logfile is not None and logfile.strip(): if config.get('rotate_daily', False): create_filename_path(logfile) logging_file = DailyLogFile(logfile, '.') else: logging_file = open_create(logfile, 'a') log.addObserver(log.FileLogObserver(logging_file).emit) log.msg('pyspades server started on %s' % time.strftime('%c')) log.startLogging(sys.stdout) # force twisted logging self.start_time = reactor.seconds() self.end_calls = [] self.console = create_console(self) for password in self.passwords.get('admin', []): if password == 'replaceme': print 'REMEMBER TO CHANGE THE DEFAULT ADMINISTRATOR PASSWORD!' elif not password: self.everyone_is_admin = True for user_type, func_names in config.get('rights', {}).iteritems(): for func_name in func_names: commands.add_rights(func_name, user_type) port = self.port = config.get('port', 32887) ServerProtocol.__init__(self, port, interface) self.host.receiveCallback = self.receive_callback ret = self.set_map_rotation(config['maps']) if not ret: print 'Invalid map in map rotation (%s), exiting.' % ret.map raise SystemExit self.update_format() self.tip_frequency = config.get('tip_frequency', 0) if self.tips is not None and self.tip_frequency > 0: reactor.callLater(self.tip_frequency * 60, self.send_tip) self.master = config.get('master', True) self.set_master() get_external_ip(config.get('network_interface', '')).addCallback(self.got_external_ip)