class SimpleServerTest(unittest.TestCase): def verify_client_msg(self, msg): assert(not self.received_message) assert(msg == "hello server") self.received_message = True def got_client(self, client): assert(self.connected_client == None) client.set_read_callback(lambda msg: self.verify_client_msg(msg)) self.connected_client = client def setUp(self): # create a socket and server: self.test_socket = socket.socket(family=socket.AF_INET6, type=socket.SOCK_STREAM) self.server = SimpleServer(12345, lambda client: self.got_client(\ client)) def tearDown(self): # close test socket and server: self.test_socket.close() self.server.close() def test_server(self): print("test_server.py: test_server start") self.received_message = False self.connected_client = None # connect socket to server: self.test_socket.connect(("::1", 12345, 0, 0)) assert(self.connected_client == None) # only after a tick, the server should recognise the new client: assert(self.server.tick() == 1) assert(self.connected_client != None) assert(self.received_message == False) # send something from the server to the client: self.connected_client.send("hello client") assert(self.server.tick() == 1) received_str = self.test_socket.recv(512).decode("utf-8") assert(received_str == "hello client\n") # send something from the client to the server: self.test_socket.send("hello server\n".encode("utf-8")) assert(self.received_message == False) assert(self.server.tick() == 1) # only after a tick, the message should arrive with the server: assert(self.received_message == True) # send bye to client but close connection immediately afterwards: self.connected_client.send("bye client") self.connected_client.close() assert(self.server.tick() == 1) # the goodbye should still arrive: assert(self.test_socket.recv(512).decode("utf-8") == "bye client\n") assert(self.server.tick() == 0) # test complete! print("test_server.py: test_server end")
class OnlineGame(Game): def __init__(self, game_path, port, version_str): super(OnlineGame, self).__init__(game_path) self.connections = [] self.port = port self.version_str = version_str self.required_client_version = 1 module_instances = get_module_instances() logging.info("Starting game with " + str(len(module_instances))\ + " module instances available") for module in module_instances.values(): if isinstance(module, OnlineGameBaseModule): module.set_online_game_instance(self) else: module.set_game_instance(self) def split_args(self, args_line): if len(args_line) == 0: return [] splitted_list = args_line.split(":", 1) last_arg = "" if len(splitted_list) == 2: last_arg = splitted_list[1].strip() splittable_args = splitted_list[0] while splittable_args.find(" ") >= 0: splittable_args = splittable_args.replace(" ", " ") args = splittable_args.split(" ") if len(args[0]) == 0: del args[0] if len(last_arg) > 0: args.append(last_arg) return args def connection_has_data(self, connection, data): data = data.strip() if len(data) == 0: return module = data.split(" ", 1)[0] data = data[len(module)+1:] cmd = data.split(" ", 1)[0] args = self.split_args(data[len(cmd)+1:]) if len(cmd) == 0: connection.send("core error-empty-cmd") return if not module == "core": module_instances = get_module_instances() # forward to appropriate module: if module in module_instances: if not connection.connected_as_client: if not isinstance(module_instances[module], \ OnlineGameBaseModule): connection.send("core error-module-unavailable " +\ module) return self.process_cmd(connection, module, cmd, args) return self.process_cmd(connection.client, module, cmd, args) return # module not found: connection.send("core error-invalid-module :" + module) return else: if cmd == "quit": connection.send("core confirm-quit :Bye!") connection.close() self.connections.remove(connection) elif cmd == "ping": if len(args) == 0: connection.send("core error-missing-arguments core ping") return if len(args[0]) > 64: connection.send("core error-invalid-argument core " +\ "ping 1 :excessive length") return connection.send("core pong :" + args[0]) else: connection.send("core error-unknown-cmd core :" + cmd) def server_reports_new_connection(self, connection): connection.connected_as_client = False connection.set_read_callback(lambda data: self.connection_has_data(connection, data)) self.connections.append(connection) connection.send("core hello-msg :Hello client! This is Miracle "\ "Crafter Server Version " + self.version_str) connection.send("core version-info " + self.version_str + " :" + \ "unmodified") connection.send("core available-server-protocol-extensions :" + \ "core") connection.send("core required-client-protocol-extensions :" + \ "core") connection.send("core required-client-version " +\ str(self.required_client_version)) def run(self): self.server = SimpleServer(self.port, \ self.server_reports_new_connection) frame_time = 1/10 while 1: self.server.tick(frame_time)