コード例 #1
0
    def connect(self, host, port=15000):
        self.sock.connect((host, port))
        # and ensure correct port
        self._handshake()
        if "[version]" not in self.receive_string():
            raise WesException("Server did not ask for version").quit()

        self.send_wml_string('[version]\nversion="' + self.wesnothVersion +
                             '"\n[/version]\n')

        response = self.receive_string()
        parser = wmlparser.Parser(None)
        wml = parser.parse_text(response)
        result = {}
        if type(wml) is wmlparser.RootNode:
            wml = wml.get_all()
            for i in wml:
                for j in i.get_all():
                    result[j.get_name()] = j.get_text()
        if "port" in result:
            self.main.log.debug("need to use different port %s", result)
            self.shutdown()
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.settimeout(WesSock.socketTimeout)
            self.connect(result["host"], int(result["port"]))
コード例 #2
0
 def receive(self):
     try:
         response: str = self.sock.recv(4096).decode("utf8")
         response = self.responseBuffer + response
         # if len(response) == 0:
         #     raise WesException("IRC recv returned len 0").addAction(WesException.QUIT_IRC)
         self.responseBuffer = ""
         splitlines = response.splitlines(True)
         unhandledResponse = ""
         for i in range(len(splitlines)):
             line = splitlines[i]
             if len(line) == len(line.rstrip()):
                 if i == len(splitlines) - 1:
                     # Save it to buffer
                     self.responseBuffer = line
                     break
                 else:
                     # Line does not end with newline symbol, but there is another line somehow, should never happen
                     raise WesException(
                         "line without newline but is not last").addAction(
                             WesException.QUIT_IRC)
             if not self._actOnLine(line):
                 unhandledResponse += line
         return unhandledResponse
     except socket.timeout:
         self.ensure_connected()
         return ""
コード例 #3
0
 def onServerMessage(self, message: str, private):
     self.log.info("Got server message: " + message)
     if "The server has been restarted" in message and not private:
         raise WesException().reconnectWes()
     if "Can't find '" in message:
         name = message.split("'")[2]
         self.log.info("User " + name + "is offline")
         del self.pingUsers[name]
コード例 #4
0
 def _send_bytes(self, msg: bytes):
     totalsent = 0
     MSGLEN = len(msg)
     while totalsent < MSGLEN:
         sent = self.sock.send(msg[totalsent:])
         if sent == 0:
             raise WesException("socket connection broken").addAction(
                 WesException.QUIT_WES)
         totalsent = totalsent + sent
コード例 #5
0
    def _receive_byte_string(self) -> bytes:
        try:
            chunks = []
            bytes_recd = 0
            chunk = self.sock.recv(4)
            if len(chunk) == 0:
                raise WesException("wes recv len 0").addAction(
                    WesException.QUIT_WES)

            bytes_wanted = int.from_bytes(chunk, byteorder="big")
            while bytes_recd != bytes_wanted:
                chunk = self.sock.recv(min(4096, bytes_wanted - bytes_recd))
                if not chunk:
                    self.main.log.warn("chunk not")
                    break
                if chunk == b'':
                    raise WesException("socket connection broken").addAction(
                        WesException.QUIT_WES)
                chunks.append(chunk)

                bytes_recd = bytes_recd + len(chunk)
            try:
                result: bytes = gzip.decompress(b''.join(chunks))
            except OSError:
                self.main.log.error(
                    "Problem when decompressing received chunks")
                self.main.log.error("Bytes wanted {}".format(bytes_wanted))
                self.main.log.error("Bytes read {}".format(bytes_recd))
                self.main.log.error(b''.join(chunks))
                raise
            if len(result) == 0:
                raise WesException("Received empty, so quitting").addAction(
                    WesException.QUIT_WES)
            if self.LOG_RECEIVED:
                self.log_rec.debug(result)
            return result
        except socket.timeout:
            return b''
コード例 #6
0
    def actOnGamelistDiff(self, node: wmlparser.TagNode):
        self.main.log.log(2, "in actOnGamelistDiff with %s", node.get_name())
        usersToRemove = set()
        usersToAdd = set()
        for child in node.get_all(tag="delete_child"):
            index = int(child.get_text_val("index"))
            if len(child.get_all(tag="user")) == 1:
                self.main.log.log(5, "user %s should be removed" % index)
                usersToRemove.add(self.main.lobby.users.getI(index).name)

        for child in node.get_all(tag="insert_child"):
            index = int(child.get_text_val("index"))
            self.main.log.log(3, "%s %s", child.get_name(), index)
            for child in child.get_all(tag="user"):
                u = User(child)
                self.main.log.log(5, "user %s should be inserted to %s", u.name, index)
                usersToAdd.add(u.name)
                if u.name in usersToRemove:
                    self.main.lobby.users.insertUser(u, index, None)
                else:
                    self.main.lobby.users.insertUser(u, index)
            for child in child.get_all(tag="game"):
                g = Game(child)
                self.main.log.log(5, "game %s(%s) should be inserted to %s", g.name, g.id, index)
                self.main.lobby.games.insertGame(g, index)

        for child in node.get_all(tag="delete_child"):
            index = int(child.get_text_val("index"))
            self.main.log.log(3, "%s %s", child.get_name(), index)
            if len(child.get_all(tag="user")) == 1:
                self.main.log.log(5, "user %s should be removed" % index)
                if self.main.lobby.users.getI(index).name in usersToAdd:
                    self.main.lobby.users.deleteI(index, None)
                else:
                    self.main.lobby.users.deleteI(index)
            elif len(child.get_all(tag="game")) == 1:
                self.main.log.log(5, "game %s should be removed" % index)
                self.main.lobby.games.removeGame(index)
            else:
                self.main.log.error("actOnGamelistDiff with %s users and %s games",
                                    len(child.get_all(tag="user")),
                                    len(child.get_all(tag="game")))
        for child in node.get_all(tag="change_child"):
            if int(child.get_text_val("index")) != 0:
                raise WesException("[gamelist_diff][change_child]index={}, 0 expected"
                                   .format(node.get_text_val("index")))
            # This has subtags like delete_child, instead of initial uncondition addition
            gamelists = child.get_all(tag="gamelist")
            assert len(gamelists) == 1
            self.actOnGamelistDiff(gamelists[0])
コード例 #7
0
 def actOnWML(self, wml, path=None):
     if path is None:
         path = []
     if (type(wml) is wmlparser.TagNode) or (type(wml) is wmlparser.RootNode):
         attr: List[wmlparser.AttributeNode] = []
         attrPath = path[:]
         for node in wml.get_all():
             if type(node) is wmlparser.AttributeNode:
                 attr.append(node)
             else:
                 self.main.log.log(2, "got node %s", node.get_name())
                 if node.get_name() == "gamelist_diff":
                     self.actOnGamelistDiff(node)
                 elif node.get_name() == "user":
                     self.actOnUser(node)
                 elif node.get_name() == "gamelist":
                     self.actOnGamelist(node)
                 elif node.get_name() == "whisper":
                     self.actOnWhisper(node)
                 elif node.get_name() == "message":
                     # TODO only use relevant messages, not those in scenario code
                     self.actOnMessage(node)
                 elif node.get_name() == "speak":
                     self.actOnSpeak(node)
                 elif node.get_name() == "error":
                     self.actOnError(node)
                 elif node.get_name() == "observer":
                     self.actOnObserver(node)
                 elif node.get_name() == "observer_quit":
                     self.actOnObserverQuit(node)
                 else:
                     for sub in node.get_all():
                         self.actOnWML(sub, path + [node.get_name()])
         self.parseAttr(attr, attrPath)
     elif type(wml) is list:
         raise WesException("actOnWML got wml as list")
         # attr = []
         # attrPath = path[:]
         # tags = []
         # for node in wml:
         #     if type(node) is wmlparser.AttributeNode:
         #         attr.append(node)
         #     else:
         #         tags.append(node)
         # self.parseAttr(attr, attrPath)
         # for node in tags:
         #     self.actOnWML(node.get_all(), path + [node.get_name()])
     elif type(wml) is wmlparser.AttributeNode:
         self.main.log.log(2, "AttributeNode @%s %s %s", path, wml.get_name(), wml.get_text())
コード例 #8
0
    def onIrcMessage(self, data):
        self.log.debug("with unparsed irc message in commandhandler %s", data)
        # message = data.split('#',1)[1].split(":",1)[1].strip("\r\n")
        message = data.split(":", 2)[2]
        sender = data[1:].split("!", 1)[0]
        if sender == "IRC":
            if "Too many connections from your IP" in message:
                net_ = self.main.cfg.ircNetAlt
                if self.main.cfg.ircNet in net_:
                    net_.remove(self.main.cfg.ircNet)
                    self.main.cfg.ircNet = random.choice(list(net_))
                    raise WesException().reconnectIrc()
            return  # Message from IRC network, not something that should be treated as user message
        target = data.split(" ", 3)[2]
        self.log.debug("target %s", target)
        whisper = "#" not in target
        self.log.debug("with irc message in commandhandler %s %s %s", sender,
                       ">", message)
        permission = 0
        if sender in self.ircMasters:
            permission = PERMISSION_ADMIN + 5

        self.onMessage(message, sender, permission, "irc", whisper)
コード例 #9
0
 def restart(**kwargs):
     """Restarts bot"""
     kwargs["reply"]("restarting")
     raise WesException("restart command used").restart()
コード例 #10
0
 def q(**kwargs):
     """Quits bot"""
     kwargs["reply"]("quitting")
     raise WesException("quit command used").quit()
コード例 #11
0
    def onCommand(self, message, sender, permission, origin):
        def reply(message):
            self.sendPrivately(sender, origin, str(message))

        if " " in message:
            message = message.split(" ", 1)
            command = message[0]
            args = message[1]
        else:
            command = message
            args = ""
        self.log.debug("got command %s %s %s", command, "with args", args)

        if command in self.commands and permission > self.commands[
                command].permission:
            self.commands[command].command(reply=reply,
                                           args=args,
                                           permission=permission,
                                           sender=sender)

        if command == "join" and permission > PERMISSION_ADMIN:
            self.irc.join(args)
        elif command == "part" and permission > PERMISSION_ADMIN:
            self.irc.part(args)
        elif command == "quitwes" and permission > PERMISSION_ADMIN:
            raise WesException("quitwes command used").addAction(
                WesException.QUIT_WES)
        elif command == "quitirc" and permission > PERMISSION_ADMIN:
            raise WesException("quitirc command used").addAction(
                WesException.QUIT_IRC)
        elif command == "ircreconnect" and permission > PERMISSION_ADMIN:
            raise WesException("ircreconnect command used").reconnectIrc()
        elif command == "wesreconnect" and permission > PERMISSION_ADMIN:
            raise WesException("wesreconnect command used").reconnectWes()
        elif command == "follow" and permission > PERMISSION_ADMIN:
            if not args or args == "":
                args = sender
            try:
                user = self.main.lobby.users.get(args)
                self.wes.send_wml_string(
                    "[join]\nid={}\nobserve=yes\n[/join]".format(user.game_id))
            except WesException as e:
                if e.action != [WesException.ASSERT]:
                    raise e
                reply("User {} not found".format(args))
        elif command == "control" and permission > PERMISSION_ADMIN:
            parts = args.split(" ", 1)
            if len(parts) == 2:
                side, target = parts[0], parts[1]
                self.wes.send_wml_string("""[change_controller]
controller="human"
player="%s"
side="%s"
[/change_controller]""" % (target, side))
            else:
                reply("control needs to have two arguments")
        elif command == "leave" and permission > PERMISSION_ADMIN:
            self.wes.send_wml_string("[leave_game]\n[/leave_game]")
        elif command == "trust" and permission > PERMISSION_ADMIN:
            self.main.cfg.botTrustedNames.append(args.strip())
            reply("Added '{}' to trusted names. Current list: {}".format(
                args.strip(), self.main.cfg.botTrustedNames))
        else:
            if command not in self.commands:
                reply("Command {} not recognized".format(command))