def spot_server(my_thread): """ Create a telnet server with a port, address, a function to call with new connections and one to call with lost connections. """ telnet_server = TelnetServer(port=7300, address='', on_connect=on_connect, on_disconnect=on_disconnect, timeout=.05) logging.debug( "Listening for SPOT ({}) connections on port {}. CTRL-C to break.". format(my_thread, telnet_server.port)) while 1: if my_thread not in SERVER_RUN: logging.info("Restart spot_server thread by %s" % SERVER_RUN) return telnet_server.poll() kick_idle() process_clients()
def main(): # Create LOG dir if it doesn't exist if not os.path.exists(defaults['LOGDIR']): os.mkdir(defaults['LOGDIR']) server = TelnetServer(port=PORT) server.on_connect = my_on_connect server.on_disconnect = my_on_disconnect print(f"Starting server on port {server.port}. CTRL-C to interrupt.") while True: try: server.poll() # Send, Recv, and look for new connections kick_idle() # Check for idle clients process_client() # Check for client input except KeyboardInterrupt: server.stop() print("Server shutdown.") break
def test_telnet_server(): server = TelnetServer(port=7777, address='', on_connect=lambda x: CLIENTS.append(x), timeout=.05) client = socket.socket() client.connect(('127.0.0.1', 7777)) server.poll() # test that we have one connected client assert len(CLIENTS) == 1 CLIENTS[0].send("test") server.poll() data = client.recv(4) # test that we received the correct data if PYTHON_2: assert data == "test" else: assert data.decode("utf-8") == "test"
def test_telnet_server(): server = TelnetServer( port=7777, address='', on_connect=lambda x: CLIENTS.append(x), timeout=.05) client = socket.socket() client.connect(('127.0.0.1', 7777)) server.poll() # test that we have one connected client assert len(CLIENTS) == 1 CLIENTS[0].send("test") server.poll() data = client.recv(4) # test that we received the correct data if PYTHON_2: assert data == "test" else: assert data.decode("utf-8") == "test"
""" Example on_connect handler. """ client.send('You connected from %s\n' % client.addrport()) if CLIENTS: client.send('Also connected are:\n') for neighbor in CLIENTS: client.send('%s\n' % neighbor.addrport()) else: client.send('Sadly, you are alone.\n') CLIENTS.append(client) def my_on_disconnect(client): """ Example on_disconnect handler. """ CLIENTS.remove(client) if __name__ == "__main__": logging.basicConfig(level=logging.DEBUG) server = TelnetServer() server.on_connect=my_on_connect server.on_disconnect=my_on_disconnect logging.info("Starting server on port {}. CTRL-C to interrupt.".format(server.port)) while True: server.poll()
""" Create a signal handler so that ctrl-c doesn't just crash and burn. """ def signal_handler(signal, frame): # This is where we clean up the server. log('Cleaning up the world...') WORLD._cleanup() # The cleanup function runs a web of cleanup functions to secure all information before shutting down. SERVER.poll() log('Shutdown complete.') sys.exit(0) signal.signal(signal.SIGINT, signal_handler) """ Now, start our loop. """ while(WORLD.ALIVE == True): SERVER.poll() WORLD._loop() SERVER.poll() # Poll one last time. for key in WORLD.PLAYERS.keys(): # Disconnect all users. log('%s disconnected.' % (WORLD.PLAYERS[key].CLIENT.addrport()), '-') WORLD.PLAYERS[key].CLIENT.sock.close() if(WORLD.ALIVE == 'reboot'): # Reboot the server. log('Rebooting server...') SERVER = 0 # Release the server so the port isn't taken. os.execl(sys.argv[0],'') # Reboot the system. else: log('Shutdown complete.')
"Formatted list of commands.", 'end': "Terminates Telnet session.", 'exit': "Terminates Telnet session.", 'stop': "Stops the reception service, closing all connections.", } if __name__ == "__main__": logging.basicConfig(level=logging.DEBUG) telnet_server = TelnetServer(port=9090, address='', on_connect=on_connect, on_disconnect=on_disconnect, timeout=0.5) logging.info("Listening on " + str(telnet_server.address) + ":" + str(telnet_server.port)) read_vectors() read_groups() while RUN: telnet_server.poll() process() kick_idle() logging.info("Shutting down.")
if __name__ == '__main__': ## Simple chat server to demonstrate connection handling via the ## async and telnet modules. ## Create a telnet server with a port, address, ## a function to call with new connections ## and one to call with lost connections. telnet_server = TelnetServer( port=7777, address='', on_connect=on_connect, on_disconnect=on_disconnect, timeout=.05 # length of time to wait on user input during a pol() ) read_database("data.dat") print(">> Listening for connections on port %d. CTRL-C to break." % telnet_server.port) ## Server Loop while SERVER_RUN: telnet_server.poll() ## Send, Recv, and look for new connections kick_idle() ## Check for idle clients process_clients() ## Check for client input print(">> Server shutdown.")
Example on_connect handler. """ client.send('You connected from %s\n' % client.addrport()) if CLIENTS: client.send('Also connected are:\n') for neighbor in CLIENTS: client.send('%s\n' % neighbor.addrport()) else: client.send('Sadly, you are alone.\n') CLIENTS.append(client) def my_on_disconnect(client): """ Example on_disconnect handler. """ CLIENTS.remove(client) if __name__ == "__main__": logging.basicConfig(level=logging.DEBUG) server = TelnetServer() server.on_connect = my_on_connect server.on_disconnect = my_on_disconnect logging.info("Starting server on port {}. CTRL-C to interrupt.".format( server.port)) while True: server.poll()
# Main #------------------------------------------------------------------------------ if __name__ == '__main__': ## Simple chat server to demonstrate connection handling via the ## async and telnet modules. ## Create a telnet server with a port, address, ## a function to call with new connections ## and one to call with lost connections. telnet_server = TelnetServer( port=7777, address='', on_connect=on_connect, on_disconnect=on_disconnect, timeout = .05 ) print(">> Listening for connections on port %d. CTRL-C to break." % telnet_server.port) ## Server Loop while SERVER_RUN: telnet_server.poll() ## Send, Recv, and look for new connections kick_idle() ## Check for idle clients process_clients() ## Check for client input print(">> Server shutdown.")
def signal_handler(signal, frame): # This is where we clean up the server. log('Cleaning up the world...') WORLD._cleanup( ) # The cleanup function runs a web of cleanup functions to secure all information before shutting down. SERVER.poll() log('Shutdown complete.') sys.exit(0) signal.signal(signal.SIGINT, signal_handler) """ Now, start our loop. """ while (WORLD.ALIVE == True): SERVER.poll() WORLD._loop() SERVER.poll() # Poll one last time. for key in WORLD.PLAYERS.keys(): # Disconnect all users. log('%s disconnected.' % (WORLD.PLAYERS[key].CLIENT.addrport()), '-') WORLD.PLAYERS[key].CLIENT.sock.close() if (WORLD.ALIVE == 'reboot'): # Reboot the server. log('Rebooting server...') SERVER = 0 # Release the server so the port isn't taken. os.execl(sys.argv[0], '') # Reboot the system. else: log('Shutdown complete.')
class Server(daemon.Daemon): """ Server class that is initialized by the main.py script to act as the MUCK server. It performs all of the core functions of the MUCK server, which is mainly accepting connections and performing the login sequence before giving them access to the server and its world. """ is_running = False telnet_server = None logger = None connection_logger = None world = None interface = None work_factor = 10 db_connection = True welcome_message_data = "Unable to load welcome message!\n" exit_message_data = "Unable to load exit message!\n" pending_connection_list = [] established_connection_list = [] post_client_connect = signal("post_client_connect") pre_client_disconnect = signal("pre_client_disconnect") post_client_authenticated = signal("post_client_authenticated") database_status = signal("database_status") world_tick = signal("world_tick") scheduler = Scheduler() auth_low_argc = None auth_invalid_combination = None auth_connected = None auth_replace_Connection = None auth_connection_replaced = None auth_connect_suggestion = None game_client_disconnect = None def __init__(self, config=None, path=None, workdir=None): """ The server class is created and managed by the main.py script. When created, the server automatically initiates a Telnet server provided by Miniboa which immediately listens for incoming connections and will query them for login details upon connection. Keyword arguments: config -- An instance of game.Settings that is to be used when loading configuration data. path -- The data path that all permenant data should be written to. workdir -- The current working directory of the server. This should be an absolute path to application/. """ self.connection_logger = logging.getLogger("Connections") self.logger = logging.getLogger("Server") # Loading all of the configuration variables database_type = string.lower(config.get_index(index="DatabaseType", datatype=str)) database = config.get_index(index="DatabaseName", datatype=str) user = config.get_index(index="DatabaseUser", datatype=str) password = config.get_index(index="DatabasePassword", datatype=str) self.work_factor = config.get_index(index="WorkFactor", datatype=int) debug = config.get_index(index="Debug", datatype=bool) if database_type == "sqlite": database_location = path + config.get_index(index="TargetDatabase", datatype=str) else: database_location = config.get_index(index="TargetDatabase", datatype=str) # Load server messages self.auth_low_argc = config.get_index("AuthLowArgC", str) self.auth_invalid_combination = config.get_index("AuthInvalidCombination", str) self.auth_connected = config.get_index("AuthConnected", str) self.auth_replace_connection = config.get_index("AuthReplaceConnection", str) self.auth_connection_replaced = config.get_index("AuthConnectionReplaced", str) self.auth_connect_suggestion = config.get_index("AuthConnectSuggestion", str).replace("\\n", "\n") self.auth_replace_connection_global = config.get_index("AuthReplaceConnectionGlobal", str) self.game_client_disconnect = config.get_index("GameClientDisconnect", str) # Loading welcome/exit messages with open(workdir + "config/welcome_message.txt") as f: self.welcome_message_data = f.read() + "\n" with open(workdir + "config/exit_message.txt") as f: self.exit_message_data = f.read() + "\n" self.interface = interface.Interface(config=config, workdir=workdir, server=self, debug=debug) # Connect/Create our database is required database_exists = True if database_type == "sqlite": try: with open(database_location) as f: pass except IOError as e: self.logger.info( "This appears to be your first time running the ScalyMUCK server. We must initialise your database ..." ) database_exists = False database_engine = create_engine("sqlite:///%s" % (database_location), echo=False) else: url = database_type + "://" + user + ":" + password + "@" + database_location + "/" + database try: database_engine = create_engine(url, echo=False, pool_size=20, max_overflow=0) except OperationalError as e: self.logger.error(str(e)) self.logger.error("URL: " + url) self.is_running = False return self.world = world.World(engine=database_engine, server=self) game.models.Base.metadata.create_all(database_engine) # Check to see if our root user exists if database_type != "sqlite": root_user = self.world.find_player(name="RaptorJesus") if root_user is None: database_exists = False game.models.server = self game.models.world = self.world if database_exists is False: room = self.world.create_room("Portal Room Main") user = self.world.create_player( name="RaptorJesus", password="******", workfactor=self.work_factor, location=room, admin=True, sadmin=True, owner=True, ) room.set_owner(user) self.logger.info("The database has been successfully initialised.") self.interface.initialize( config=config, world=self.world, session=self.world.session, engine=database_engine, workdir=workdir, server=self, debug=debug, ) self.telnet_server = TelnetServer( port=config.get_index(index="ServerPort", datatype=int), address=config.get_index(index="ServerAddress", datatype=str), on_connect=self.on_client_connect, on_disconnect=self.on_client_disconnect, timeout=0.05, ) self.database_status.connect(self.callback_database_status) self.logger.info("ScalyMUCK successfully initialised.") self.is_running = True def callback_database_status(self, trigger, sender, status): self.db_connection = status if status is False: for connection in self.established_connection_list: connection.send("A critical database error has occurred. Please reconnect later.\n") connection.socket_send() connection.deactivate() connection.sock.close() for connection in self.pending_connection_list: connection.send("A critical database error has occurred. Please reconnect later.\n") connection.socket_send() connection.deactivate() connection.sock.close() self.established_connection_list = [] self.pending_connection_list = [] self.scheduler.start() # Actually apparently we don't need the scheduler it appears ... self.scheduler.add_interval_job(self.remote_db_ping, seconds=2) else: self.scheduler.stop() def remote_db_ping(self): player = self.world.session.query(game.models.Player).filter_by(id=1).first() self.database_status.send(sender=self, status=True) self.world.session.rollback() return def update(self): """ The update command is called by the main.py script file. The update command does as it says, it causes the server to go through and poll for data from any of the clients and processes this data differently based on whether or not that they had actually logged in. When this function finishes calling, a single world tick has passed. """ try: self.telnet_server.poll() except UnicodeDecodeError: return for connection in self.pending_connection_list: if connection.cmd_ready is True: data = "".join(filter(lambda x: ord(x) < 127 and ord(x) > 31, connection.get_command())) command_data = string.split(data, " ") # Try and perform the authentification process if len(command_data) < 3: connection.send("%s\n" % (self.auth_low_argc)) elif len(command_data) >= 3 and string.lower(command_data[0]) == "connect": name = string.lower(command_data[1]) password = command_data[2] target_player = self.world.find_player(name=name) if target_player is None: connection.send("%s\n" % self.auth_invalid_combination) else: player_hash = target_player.hash if player_hash == bcrypt.hashpw(password, player_hash) == player_hash: connection.id = target_player.id target_player.connection = connection # Check if our work factors differ work_factor = int(player_hash.split("$")[2]) if work_factor != self.work_factor: target_player.set_password(password) self.logger.info("%s had their hash updated." % (target_player.display_name)) self.connection_logger.info( "Client %s:%u signed in as user %s." % (connection.address, connection.port, target_player.display_name) ) self.post_client_authenticated.send(None, sender=target_player) for player in target_player.location.players: if player is not target_player: player.send(self.auth_connected % target_player.display_name) for player in self.established_connection_list: if player.id == connection.id: player.send("%s\n" % self.auth_replace_connection) player.socket_send() player.deactivate() player.sock.close() connection.send("%s\n" % self.auth_connection_replaced) self.world.find_room(id=target_player.location_id).broadcast( self.auth_replace_connection_global % target_player.display_name, target_player ) self.established_connection_list.remove(player) break self.pending_connection_list.remove(connection) self.established_connection_list.append(connection) else: connection.send("You have specified an invalid username/password combination.\n") elif len(command_data) >= 3 and string.lower(command_data[0]) != "connect": connection.send("%s\n" % (self.auth_connect_suggestion)) # connection.send('You must use the "connect" command:\n') # connection.send('connect <username> <password>\n') # With already connected clients, we'll now deploy the command interface. for index, connection in enumerate(self.established_connection_list): if connection.cmd_ready: input = "".join(filter(lambda x: ord(x) < 127 and ord(x) > 31, connection.get_command())) try: sending_player = self.world.find_player(id=connection.id) except game.exception.DatabaseError: connection.send("A critical error has occurred. Please reconnect later.\n") connection.socket_send() connection.deactivate() connection.sock.close() else: if sending_player is not None: sending_player.connection = connection self.interface.parse_command(sender=sending_player, input=input) self.world_tick.send(None) def shutdown(self): """ Shuts down the ScalyMUCK server. This command shuts down the ScalyMUCK server and gracefully disconnects all connected clients by sending a message before their disconnection which currently reads: "The server has been shutdown adruptly by the server owner." This message cannot be changed. """ self.is_running = False for connection in self.established_connection_list: connection.send("The server has been shutdown adruptly by the server owner.\n") connection.socket_send() def find_connection(self, id): """ Finds a player connection by their database ID. """ for player in self.established_connection_list: if player.id == id: return player def on_client_connect(self, client): """ This is merely a callback for Miniboa to refer to when receiving a client connection from somewhere. """ self.connection_logger.info("Received client connection from %s:%u" % (client.address, client.port)) if self.db_connection is False: client.send("A critical database error has occurred. Please reconnect later.\n") client.socket_send() client.deactivate() client.sock.close() return client.send(self.welcome_message_data) self.pending_connection_list.append(client) self.post_client_connect.send(sender=client) def on_client_disconnect(self, client): """ This is merely a callback for Miniboa to refer to when receiving a client disconnection. """ self.pre_client_disconnect.send(sender=client) self.connection_logger.info("Received client disconnection from %s:%u" % (client.address, client.port)) # Iterate over anyone who had connected but did not authenticate if client in self.pending_connection_list: self.pending_connection_list.remove(client) # Otherwise run over the list of people who had authenticated elif client in self.established_connection_list: player = self.world.find_player(id=client.id) room = self.world.find_room(id=player.location_id) room.broadcast(self.game_client_disconnect % player.display_name, player) self.established_connection_list.remove(client)
class Server(): ''' The game server object. Holds all other objects in the game. ''' def __init__(self): if len(sys.argv) >= 4: if len(sys.argv) == 4: self.name = str(sys.argv[3]) else: serverName = '' nameList = sys.argv[3:] for name in nameList: serverName += str(name) + ' ' serverName = serverName[:-1] self.name = serverName self.port = int(sys.argv[2]) if sys.argv[1] != 'localhost': self.address = int(sys.argv[1]) else: self.address = 'localhost' else: print "!! Command poorly formed. Should look like 'python MUDserver.py localhost 7734 test' or similar. !!" self.id_counter = 0 self.idle_timeout = CONFIG.IDLE_TIMEOUT self.log_file = None self.chat_log_file_byDate = None self.connected_clients = [] self.cc = self.connected_clients self.server_run = True self.engine_state = 'running' self.player_data = {} self.pd = self.player_data self.timers = [] self.move_timers = [] self.current_time = 0 self.startup_time = time.time() self.delta_time = 0 self.last_time = 0 self.god_list = [] # with open('../data/god_list', 'r') as f: # self.god_list = f.readlines() self.setupLog() self.setupClientRecords() self.TelnetServer = TelnetServer( #address should be a blank string for deployment across a network, as blank allows the server to use any network interface it finds. #localhost is for testing where server and clients both exist on one computer, without going across the network port=self.port, address=self.address, on_connect=self.on_connect, on_disconnect=self.on_disconnect, timeout = .05 ) self.Engine = Engine.Engine(self, self.server_run, self.god_list, self.cc, self.pd) self.Renderer = Renderer.Renderer(self) self.chatManager = ChatManager.chatManager(self) self.structureManager = Structures.StructureManager(self) self.structureManager.loadAreas() self.saveManager = SaveManager.SaveManager(self) def RUN(self): ''' main loop for the server ''' while self.server_run: self.TelnetServer.poll() ## Send, Recv, and look for new connections self.kickIdle() ## Check for idle clients self.current_time = time.time() self.delta_time = (self.current_time - self.startup_time) - self.last_time for timer in self.timers: timer.tick(self.delta_time) for timer in self.move_timers: timer.tick(self.delta_time) self.last_time = (self.current_time - self.startup_time) self.engine_state = self.Engine.processClients(self.server_run, self.god_list, self.cc, self.pd) ## Check for client input, saving any state changes generated by the engine to 'engineState' self.stateCheck() def setupLog(self): ''' creates server log files for writing in later ''' time_string = time.strftime('%H_%M_%S') date = time.strftime('%m_%d_%Y') dataPath = '../data/' logPath = dataPath + 'log/' server_path = logPath + self.name + '/' all_path = server_path +'all/' chat_path = server_path +'chat/' path = all_path + date + '/' chat_by_date = chat_path + 'byDate/' chat_by_channel = chat_path + 'byChannel/' chat_date = chat_by_date + date + '/' file_path = path + time_string chat_log_path = chat_date + time_string const_log_path = server_path + 'const' + '/' + date + "-" + time_string if not os.path.exists(dataPath): os.mkdir(dataPath) if not os.path.exists(logPath): os.mkdir(logPath) if not os.path.exists(server_path): os.mkdir(server_path) if not os.path.exists(all_path): os.mkdir(all_path) if not os.path.exists(chat_path): os.mkdir(chat_path) if not os.path.exists(path): os.mkdir(path) if not os.path.exists(chat_by_date): os.mkdir(chat_by_date) if not os.path.exists(chat_by_channel): os.mkdir(chat_by_channel) if not os.path.exists(chat_date): os.mkdir(chat_date) if not os.path.exists(file_path): f = open(file_path, 'a') f.close() if not os.path.exists(chat_log_path): f = open(chat_log_path, 'a') f.close() if not os.path.exists(server_path + 'const/'): os.mkdir(server_path + 'const/') if not os.path.exists(const_log_path): f = open(const_log_path, 'a') f.close() self.log_file = file_path self.chat_log_file_byDate = chat_log_path self.chat_log_file_byChannel = chat_by_channel self.const_log = const_log_path def setupClientRecords(self): ''' initializes the client records ''' path = '../data/client/' if not os.path.exists(path): os.mkdir(path) serverPath = '../data/client/' + str(self.name) + '/' if not os.path.exists(serverPath): os.mkdir(serverPath) def printLog(self, entry, log_file, printEntry = True): ''' prints a message to the console, and to a log file ''' time_stamp = time.strftime('%H:%M:%S') log_file = str(log_file) if printEntry == True: print entry with open(log_file, 'a') as f: f.write('[' + str(time_stamp) + '] ' + entry + '\n') def on_connect(self, client): """ on_connect function. Handles new connections. """ playerDataID = str(client.addrport()) self.printLog( "++ Opened connection to %s" % client.addrport(), self.log_file ) #need a printLog function #self.broadcast('%s connected.\n' % client.addrport() ) self.cc.append(client) clientID = self.id_counter self.id_counter += 1 clientInfo = ClientInfo.ClientInfo(owner=self, name='none', prompt='>>', client=client, ID=clientID, player_data_ID=playerDataID) self.pd[playerDataID] = clientInfo self.pd[playerDataID].loadFinish = False #holds information about if login is complete self.pd[playerDataID].authSuccess = False #holds information about the success of login attempts self.pd[playerDataID].numTries = 0 #the number of login attempts. # client.send("\n ____________" + (len(self.name) * "_") + "__\n") client.send_cc("\n ^I Welcome to ^!" + self.name + "^~^I! ^~\n\n") # client.send(" |____________" + (len(self.name) * "_") + "__|\n\n") client.send("Please tell us your name.\n%s" % str(self.pd[playerDataID].prompt)) def on_disconnect(self, client): """ on_disconnect function. Handles lost connections. """ playerDataID = str(client.addrport()) self.pd[playerDataID].saveToFile() self.printLog( "-- Lost connection to %s" %playerDataID, self.log_file ) self.cc.remove(client) del self.pd[playerDataID] # player = self.pd[playerDataID].avatar # if player is not None: #SysInit.clientDataSave(client, CLIENT_LIST, CLIENT_DATA, TIMERS) #player.currentRoom.players.remove(player) #alert(client, CLIENT_DATA, ("\n^g%s disappeared.^~\n" %player.name)) self.broadcast('%s leaves the conversation.\n' % playerDataID ) def kickIdle(self): #seems to be working, but probably needs more testing. Inconsistant behavior for clients on kick. """ Looks for idle clients and disconnects them by setting active to False. """ ## Who hasn't been typing? for client in self.cc: player = self.pd[str(client.addrport())] if client.idle() > self.idle_timeout and player.gameState != 'battle': self.printLog('>> Kicking (%s)%s from server. (idle)' %(player.ID, player.name), self.log_file ) #SysInit.clientDataSave(client, CLIENT_LIST, CLIENT_DATA, TIMERS) client.send_cc("You have been kicked for inactivity.\n") client.active = False def broadcast(self, msg): """ Send msg to every client. """ for client in self.cc: client.send_cc(msg + "\n") self.printLog(" " + msg, self.log_file) def stateCheck(self): ''' check to see if the server is running ''' if self.engine_state == 'shutdown': #print engineState # SysInit.dataSave(CLIENT_LIST, CLIENT_DATA, TIMERS) # RoomInit.saveAllRooms() # MobInit.saveMobs() # Objects.saveEq() self.printLog("<< Server shutdown.", self.log_file) self.server_run = False
class Server(object): """The Giles server itself. Tracks all players, games in progress, and so on. """ def __init__(self, name="Giles", source_url=None, admin_password=None, config_filename=None): if not source_url: print("Nice try setting source_url to nothing. Bailing.") sys.exit(1) self.name = name self.source_url = source_url self.config_filename = config_filename self.log = Log(name) self.players = [] self.spaces = [] self.should_run = True self.timestamp = None self.current_day = None self.update_timestamp() self.update_day() # Initialize the various workers. self.die_roller = DieRoller() self.configurator = Configurator() self.channel_manager = ChannelManager(self) self.game_master = GameMaster(self) self.chat = Chat(self) self.login = Login(self) # The admin manager needs the channel manager. self.admin_manager = AdminManager(self, admin_password) # No telnet server yet; that needs instantiate(). self.telnet = None # Set up the global channel for easy access. self.wall = self.channel_manager.channels[0] self.log.log("Server started up.") def instantiate(self, port=9435, timeout=.05): self.telnet = TelnetServer( port=port, address='', on_connect=self.connect_client, on_disconnect=self.disconnect_client, timeout=timeout) self.update_timestamp() def update_timestamp(self): old_timestamp = self.timestamp self.timestamp = time.strftime("%H:%M") return (old_timestamp != self.timestamp) def update_day(self): old_day = self.current_day self.current_day = time.strftime("%A, %B %d, %Y") return (old_day != self.current_day) def loop(self): cleanup_time = keepalive_time = gametick_time = time.time() cleanup_ticker = keepalive_ticker = gametick_ticker = 0 while self.should_run: self.telnet.poll() self.handle_players() # Handle time and the tickers. curr_time = time.time() cleanup_ticker += 1 if ((cleanup_time + CLEANUP_INTERVAL_SECONDS <= curr_time) or ((cleanup_ticker % CLEANUP_INTERVAL_TICKS) == 0)): self.cleanup() self.channel_manager.cleanup() self.game_master.cleanup() cleanup_time = curr_time cleanup_ticker = 0 keepalive_ticker += 1 if ((keepalive_time + KEEPALIVE_INTERVAL_SECONDS <= curr_time) or ((keepalive_ticker % KEEPALIVE_INTERVAL_TICKS) == 0)): self.keepalive() keepalive_time = curr_time keepalive_ticker = 0 gametick_ticker += 1 if ((gametick_time + GAMEINTERVAL_TICKS_SECONDS <= curr_time) or ((gametick_ticker % GAMETICK_INTERVAL_TICKS) == 0)): self.game_master.tick() gametick_time = curr_time gametick_ticker = 0 # Since this is more than once a second, abuse it to update # the timestamp as well. If the timestamp actually changed # then update the prompts for all players. if self.update_timestamp(): if self.update_day(): self.announce_midnight() self.update_prompts() self.log.log("Server shutting down.") def connect_client(self, client): # Log the connection and instantiate a new player for this connection. self.log.log("New client connection on port %s." % client.addrport()) new_player = Player(client, self) self.players.append(new_player) # Now set their state to the name entry screen. new_player.state = State("login") # Enable echo/char mode on the client connection client.request_will_echo() client.request_will_sga() def disconnect_client(self, client): self.log.log("Client disconnect on port %s." % client.addrport()) for player in self.players: if client == player.client: self.admin_manager.remove_player(player) self.channel_manager.remove_player(player) self.game_master.remove_player(player) self.players.remove(player) if player.location: player.location.remove_player(player, "^!%s^. has disconnected from the server.\n" % player) def handle_players(self): for player in self.players: curr_state = player.state.get() if curr_state == "login": try: self.login.handle(player) except Exception as e: player.tell_cc("^RSomething went horribly awry with login. Logging.^~\n") self.log.log("The login module bombed with player %s: %s\n%s" % (player.name, e, traceback.format_exc())) elif curr_state == "chat": try: self.chat.handle(player) except Exception as e: player.tell_cc("^RSomething went horribly awry with chat. Logging.^~\n") self.log.log("The chat module bombed with player %s: %s\n%s" % (player.name, e, traceback.format_exc())) player.prompt() def announce_midnight(self): for player in self.players: player.tell_cc("It is now ^C%s^~.\n" % self.current_day) def update_prompts(self): for player in self.players: if player.state.get() == "chat" and player.config["timestamps"]: player.prompt() def add_player(self, player): if player not in self.players: self.players.append(player) def remove_player(self, player): if player in self.players: self.players.remove(player) def get_space(self, space_name): for space in self.spaces: if space.name == space_name: return space # Didn't find the space. new_space = Location(space_name) self.spaces.append(new_space) return new_space def get_player(self, player_name): lower_name = player_name.lower() for player in self.players: if player.name == lower_name: return player return None def cleanup(self): for space in self.spaces: if len(space.players) == 0: self.log.log("Deleting stale space %s." % space.name) self.spaces.remove(space) del space def keepalive(self): # For now, just request a window size negotiation. Unexciting, # but it /is/ traffic over the TCP connection. for player in self.players: player.client.request_naws()
# Initial Cycles #------------------------------------------------------------------------------ Cycle(.1, process_lobby) Cycle(.1, process_players) Cycle(2, kick_idle) Cycle(5, fight) Cycle(10, mob_actions) #Cycle(2, dump_status) #------------------------------------------------------------------------------ # Initial Telnet Server #------------------------------------------------------------------------------ telnet_server = TelnetServer( port=status.SERVER_CONFIG.port, address=status.SERVER_CONFIG.address, on_connect=on_connect, on_disconnect=on_disconnect, timeout=status.SERVER_CONFIG.timeout, ) print(">> Listening for connections on port %d. CTRL-C to break." % telnet_server.port) #------------------------------------------------------------------------------ # Main Server Loop #------------------------------------------------------------------------------ while status.SERVER_RUN: telnet_server.poll() SCHEDULER.tick() print(">> Server shutdown.")
class MudderServer: def __init__(self): self.port=7777 #server object self.server=TelnetServer(self.port, "", self.onconnect, self.ondisconnect, .05) #clients (TelnetClient) self.clients=[] self.actors={} # mudlib actors key:fileno value:actor #Gamefield self.gamefield=GameField(self.actors) #Server state self.running=True def onconnect(self, client): client.send_cc("Witaj...\n") client.send_cc("Wprowadz imie:") client.request_terminal_type() #add client self.actors[client.fileno]=Actor(client) self.actors[client.fileno].onconnect() self.clients.append(client) print "++ User connected from %s" % str(client.address) def ondisconnect(self, client): self.actors[client.fileno].ondisconnect() self.actors.pop(client.fileno) self.clients.remove(client) print "-- User disconnected from %s" % str(client.address) def processclient(self): """Process client""" for client in self.clients: if client.idle()>300:client.deactivate() #Get actor reresented by connection actor=self.actors[client.fileno] if actor.login_state==4:client.deactivate() #if someone send message if client.active and client.cmd_ready: #get command cmd=client.get_command() if cmd=="":continue # skip empty messages #print "DD", client.address, cmd #If not logged in if actor.login_state!=3: Login(actor, cmd) # do login #logged in send command to gamefield else:self.gamefield.recv(actor, cmd) def serverloop(self): print "Server started at port %s" % str(self.port) try: while self.running: self.server.poll() self.processclient() self.gamefield.update() except KeyboardInterrupt, e:self.onexit(e) def onexit(self, error): print "\rStopping Server..." print error #Unload data self.gamefield.unloaddata() exit(1)