Beispiel #1
0
def run (no_debug, no_idle_add_debug, no_thread_debug, log_viewer, chess_file,
         ics_host, ics_port):
    # Start logging
    if log_viewer:
        log.logger.addHandler(GLogHandler(logemitter))
    log.logger.setLevel(logging.WARNING if no_debug is True else logging.DEBUG)
    oldlogs = [l for l in os.listdir(getUserDataPrefix()) if l.endswith(".log")]
    conf.set("max_log_files", conf.get("max_log_files", 10))
    if len(oldlogs) >= conf.get("max_log_files", 10):
        oldlogs.sort()
        try:
            os.remove(addUserDataPrefix(oldlogs[0]))
        except OSError as e:
            pass

    signal.signal(signal.SIGINT, Gtk.main_quit)
    def cleanup ():
        SubProcess.finishAllSubprocesses()
    atexit.register(cleanup)
    
    pychess = PyChess(log_viewer, chess_file)
    idle_add.debug = not no_idle_add_debug

    sys.stdout = LogPipe(sys.stdout, "stdout")
    sys.stderr = LogPipe(sys.stderr, "stdout")
    log.info("PyChess %s %s rev. %s %s started" % (VERSION_NAME, VERSION, pychess.hg_rev, pychess.hg_date))
    log.info("Command line args: '%s'" % chess_file)
    if not no_thread_debug:
        start_thread_dump()
    if ics_host:
        ICLogon.host = ics_host
    if ics_port:
        ICLogon.port = ics_port
    
    Gtk.main()
Beispiel #2
0
    def do_startup(self):
        Gtk.Application.do_startup(self)

        if self.purge_recent:
            items = recentManager.get_items()
            for item in items:
                uri = item.get_uri()
                if item.get_application_info("pychess"):
                    recentManager.remove_item(uri)

        self.git_rev = ""

        self.initGlade(self.log_viewer)
        self.addPerspectives()
        self.handleArgs(self.chess_file)
        checkversion()

        self.loaded_cids = {}
        self.saved_cids = {}
        self.terminated_cids = {}

        log.info("PyChess %s %s git %s" % (VERSION_NAME, VERSION, self.git_rev))
        log.info("Command line args: '%s'" % self.chess_file)
        log.info("Platform: %s" % platform.platform())
        log.info("Python version: %s.%s.%s" % sys.version_info[0:3])
        log.info("Pyglib version: %s.%s.%s" % GLib.pyglib_version)
Beispiel #3
0
    def __init__(self, handle, progressbar):
        ChessFile.__init__(self, handle)
        self.handle = handle
        self.progressbar = progressbar
        self.pgn_is_string = isinstance(handle, StringIO)

        if self.pgn_is_string:
            self.games = [self.load_game_tags(), ]
        else:
            self.skip = 0
            self.limit = 100
            self.order_col = game.c.offset
            self.is_desc = False
            self.reset_last_seen()

            # filter expressions to .sqlite .bin .scout
            self.tag_query = None
            self.fen = None
            self.scout_query = None

            self.init_tag_database()

            self.scoutfish = None
            self.init_scoutfish()

            self.chess_db = None
            self.init_chess_db()

            self.games, self.offs_ply = self.get_records(0)
            log.info("%s contains %s game(s)" % (self.path, self.count), extra={"task": "SQL"})
Beispiel #4
0
    def __init__(self):
        GObject.GObject.__init__(self)
        self.engines = []
        self.jsonpath = addUserConfigPrefix("engines.json")
        try:
            self._engines = json.load(open(self.jsonpath))
        except ValueError as err:
            log.warning(
                "engineNest: Couldn\'t read engines.json, renamed it to .bak\n%s\n%s"
                % (self.jsonpath, err))
            os.rename(self.jsonpath, self.jsonpath + ".bak")
            self._engines = deepcopy(backup)
        except IOError as err:
            log.info(
                "engineNest: Couldn\'t open engines.json, creating a new.\n%s"
                % err)
            self._engines = deepcopy(backup)

        # Try to detect engines shipping .eng files on Linux (suggested by HGM on talkcess.com forum)
        for protocol in ("xboard", "uci"):
            for path in ("/usr/local/share/games/plugins",
                         "/usr/share/games/plugins"):
                path = os.path.join(path, protocol)
                if os.path.isdir(path):
                    for entry in os.listdir(path):
                        ext = os.path.splitext(entry)[1]
                        if ext == ".eng":
                            with open(os.path.join(path,
                                                   entry)) as file_handle:
                                plugin_spec = file_handle.readline().strip()
                                if not plugin_spec.startswith("plugin spec"):
                                    continue

                                engine_command = file_handle.readline().strip()

                                supported_variants = file_handle.readline(
                                ).strip()
                                if not supported_variants.startswith("chess"):
                                    continue

                                new_engine = {}
                                if engine_command.startswith(
                                        "cd "
                                ) and engine_command.find(";") > 0:
                                    parts = engine_command.split(";")
                                    working_directory = parts[0][3:]
                                    engine_command = parts[1]
                                    new_engine[
                                        "workingDirectory"] = working_directory

                                find = False
                                for engine in self._engines:
                                    if engine["name"] == engine_command:
                                        find = True
                                        break

                                if not find:
                                    new_engine["protocol"] = protocol
                                    new_engine["name"] = engine_command
                                    self._engines.append(new_engine)
Beispiel #5
0
 def zero_reached(self, timemodel, color):
     if conf.get("autoCallFlag") and \
             self.gamemodel.status == RUNNING and \
             timemodel.getPlayerTime(1 - self.color) <= 0:
         log.info('Automatically sending flag call on behalf of player %s.'
                  % self.name)
         self.emit("offer", Offer(FLAG_CALL))
Beispiel #6
0
    def onGameStarted(self, gamemodel):
        if gamemodel.examined:
            if gamemodel.players[0].name == gamemodel.connection.username:
                self.player = gamemodel.players[0]
                self.opplayer = gamemodel.players[1]
            else:
                self.player = gamemodel.players[1]
                self.opplayer = gamemodel.players[0]
        elif gamemodel.isObservationGame():
            # no local player but enable chat to send/receive whisper/kibitz
            pass
        elif gamemodel.players[0].__type__ == LOCAL:
            self.player = gamemodel.players[0]
            self.opplayer = gamemodel.players[1]
            if gamemodel.players[1].__type__ == LOCAL:
                log.warning("Chatpanel loaded with two local players")
        elif gamemodel.players[1].__type__ == LOCAL:
            self.player = gamemodel.players[1]
            self.opplayer = gamemodel.players[0]
        else:
            log.info("Chatpanel loaded with no local players")
            self.chatView.hide()

        if isinstance(gamemodel, ICGameModel):
            if gamemodel.connection.ICC:
                gamemodel.connection.client.run_command("set-2 %s 1" % DG_PLAYERS_IN_MY_GAME)
            else:
                allob = 'allob ' + str(gamemodel.ficsgame.gameno)
                gamemodel.connection.client.run_command(allob)

        if hasattr(self, "player") and not gamemodel.examined:
            self.player_cid = self.player.connect("messageReceived", self.onMessageReieved)

        self.chatView.enable()
Beispiel #7
0
    def run (cls, uri=None):
        cls._ensureReady()
        if cls.widgets["newgamedialog"].props.visible:
            cls.widgets["newgamedialog"].present()
            return

        if not uri:
            res = ionest.opendialog.run()
            ionest.opendialog.hide()
            if res != Gtk.ResponseType.ACCEPT:
                return
        else:
            if not uri[uri.rfind(".")+1:] in ionest.enddir:
                log.info("Ignoring strange file: %s" % uri)
                return
            cls.loadSidePanel.set_filename(uri)
            cls.filechooserbutton.emit("file-activated")

        cls._hideOthers()
        cls.widgets["newgamedialog"].set_title(_("Open Game"))
        cls.widgets["loadsidepanel"].show()

        def _validate(gamemodel):
            return True

        def _callback (gamemodel, p0, p1):
            if not cls.loadSidePanel.isEmpty():
                uri =  cls.loadSidePanel.get_filename()
                loader = ionest.enddir[uri[uri.rfind(".")+1:]]
                position = cls.loadSidePanel.getPosition()
                gameno = cls.loadSidePanel.getGameno()
                ionest.generalStart(gamemodel, p0, p1, (uri, loader, gameno, position))
            else:
                ionest.generalStart(gamemodel, p0, p1)
        cls._generalRun(_callback, _validate)
Beispiel #8
0
    def onGameStarted(self, gamemodel):
        if gamemodel.examined:
            if gamemodel.players[0].name == gamemodel.connection.username:
                self.player = gamemodel.players[0]
                self.opplayer = gamemodel.players[1]
            else:
                self.player = gamemodel.players[1]
                self.opplayer = gamemodel.players[0]
        elif gamemodel.isObservationGame():
            # no local player but enable chat to send/receive whisper/kibitz
            pass
        elif gamemodel.players[0].__type__ == LOCAL:
            self.player = gamemodel.players[0]
            self.opplayer = gamemodel.players[1]
            if gamemodel.players[1].__type__ == LOCAL:
                log.warning("Chatpanel loaded with two local players")
        elif gamemodel.players[1].__type__ == LOCAL:
            self.player = gamemodel.players[1]
            self.opplayer = gamemodel.players[0]
        else:
            log.info("Chatpanel loaded with no local players")
            self.chatView.hide()

        if isinstance(gamemodel, ICGameModel):
            if gamemodel.connection.ICC:
                gamemodel.connection.client.run_command("set-2 %s 1" % DG_PLAYERS_IN_MY_GAME)
            else:
                allob = 'allob ' + str(gamemodel.ficsgame.gameno)
                gamemodel.connection.client.run_command(allob)

        if hasattr(self, "player") and not gamemodel.examined and self.player_cid is None:
            self.player_cid = self.player.connect("messageReceived", self.onMessageRecieved)

        self.chatView.enable()
Beispiel #9
0
    def __init__(self, handle, progressbar):
        ChessFile.__init__(self, handle)
        self.handle = handle
        self.progressbar = progressbar
        self.pgn_is_string = isinstance(handle, StringIO)

        if self.pgn_is_string:
            self.games = [
                self.load_game_tags(),
            ]
        else:
            self.skip = 0
            self.limit = 100
            self.last_seen_offs = [-1]

            # filter expressions to .sqlite .bin .scout
            self.text = ""
            self.fen = ""
            self.query = {}

            self.init_tag_database()

            self.scoutfish = None
            self.init_scoutfish()

            self.chess_db = None
            self.init_chess_db()

            self.games, self.offs_ply = self.get_records(0)
            log.info("%s contains %s game(s)" % (self.path, self.count),
                     extra={"task": "SQL"})
Beispiel #10
0
 def zero_reached(self, timemodel, color):
     if conf.get('autoCallFlag', False) and \
             self.gamemodel.status == RUNNING and \
             timemodel.getPlayerTime(1 - self.color) <= 0:
         log.info('Automatically sending flag call on behalf of player %s.'
                  % self.name)
         self.emit("offer", Offer(FLAG_CALL))
Beispiel #11
0
 def zero_reached(self, timemodel, color):
     if conf.get('autoCallFlag', False) and self.players[1 - color].__type__ == ARTIFICIAL:
         if self.status == RUNNING and timemodel.getPlayerTime(color) <= 0:
             log.info(
                 'Automatically sending flag call on behalf of player %s.' %
                 self.players[1 - color].name)
             self.players[1 - color].emit("offer", Offer(FLAG_CALL))
Beispiel #12
0
 def zero_reached(self, timemodel, color):
     if conf.get('autoCallFlag'):
         if self.status == RUNNING and timemodel.getPlayerTime(color) <= 0:
             log.info(
                 'Automatically sending flag call on behalf of player %s.' %
                 self.players[1 - color].name)
             self.players[1 - color].emit("offer", Offer(FLAG_CALL))
Beispiel #13
0
    def __init__(self, handle, progressbar=None):
        ChessFile.__init__(self, handle)
        self.handle = handle
        self.progressbar = progressbar
        self.pgn_is_string = isinstance(handle, StringIO)

        if self.pgn_is_string:
            self.games = [
                self.load_game_tags(),
            ]
        else:
            self.skip = 0
            self.limit = 100
            self.order_col = game.c.offset
            self.is_desc = False
            self.reset_last_seen()

            # filter expressions to .sqlite .bin .scout
            self.tag_query = None
            self.fen = None
            self.scout_query = None

            self.scoutfish = None
            self.chess_db = None

            self.sqlite_path = os.path.splitext(self.path)[0] + '.sqlite'
            self.engine = dbmodel.get_engine(self.sqlite_path)
            self.tag_database = TagDatabase(self.engine)

            self.games, self.offs_ply = self.get_records(0)
            log.info("%s contains %s game(s)" % (self.path, self.count),
                     extra={"task": "SQL"})
Beispiel #14
0
 def start(self):
     try:
         if not self.isConnected():
             yield from self._connect()
         while self.isConnected():
             yield from self.client.parse()
     except CancelledError:
         pass
     except Exception as err:
         exc_type, exc_value, exc_traceback = sys.exc_info()
         traceback.print_exception(exc_type, exc_value, exc_traceback)
         log.info("FICSConnection.run: %s" % repr(err),
                  extra={"task": (self.host, "raw")})
         self.close()
         if isinstance(
                 err,
             (
                 IOError,
                 LogOnException,
                 EOFError,
                 socket.error,
                 socket.gaierror,
                 socket.herror,
             ),
         ):
             self.emit("error", err)
         else:
             raise
     finally:
         if isinstance(self, FICSMainConnection):
             self.emit("disconnected")
Beispiel #15
0
 def draw(self, game):
     if not game.opponent.adjournment:
         log.warning("AdjournManager.draw: no adjourned game vs %s" %
                     game.opponent)
         return
     log.info("AdjournManager.draw: offering sdraw for adjourned game=%s" %
              game)
     self.connection.client.run_command("sdraw %s" % game.opponent.name)
Beispiel #16
0
 def draw(self, game):
     if not game.opponent.adjournment:
         log.warning("AdjournManager.draw: no adjourned game vs %s" %
                     game.opponent)
         return
     log.info("AdjournManager.draw: offering sdraw for adjourned game=%s" %
              game)
     self.connection.client.run_command("sdraw %s" % game.opponent.name)
Beispiel #17
0
 def resume(self, game):
     if not game.opponent.adjournment:
         log.warning("AdjournManager.resume: no adjourned game vs %s" %
                     game.opponent)
         return
     log.info("AdjournManager.resume: offering resume for adjourned game=%s"
              % game)
     self.connection.client.run_command("match %s" % game.opponent.name)
Beispiel #18
0
 def abort(self, game):
     if not game.opponent.adjournment:
         log.warning("AdjournManager.abort: no adjourned game vs %s" %
                     game.opponent)
         return
     log.info("AdjournManager.abort: offering sabort for adjourned game=%s"
              % game)
     self.connection.client.run_command("sabort %s" % game.opponent.name)
Beispiel #19
0
 def abort(self, game):
     if not game.opponent.adjournment:
         log.warning("AdjournManager.abort: no adjourned game vs %s" %
                     game.opponent)
         return
     log.info("AdjournManager.abort: offering sabort for adjourned game=%s"
              % game)
     self.connection.client.run_command("sabort %s" % game.opponent.name)
Beispiel #20
0
 def resume(self, game):
     if not game.opponent.adjournment:
         log.warning("AdjournManager.resume: no adjourned game vs %s" %
                     game.opponent)
         return
     log.info("AdjournManager.resume: offering resume for adjourned game=%s"
              % game)
     self.connection.client.run_command("match %s" % game.opponent.name)
Beispiel #21
0
 def resign (self, game):
     """ This is (and draw and abort) are possible even when one's
         opponent is not logged on """
     if not game.opponent.adjournment:
         log.warning("AdjournManager.resign: no adjourned game vs %s" % game.opponent)
         return
     log.info("AdjournManager.resign: resigning adjourned game=%s" % game)
     self.connection.client.run_command("resign %s" % game.opponent.name)
Beispiel #22
0
    def write(self, string):
        logstr = "*" * len(string) if self.sensitive else string
        self.sensitive = False
        log.info(logstr, extra={"task": (self.name, "raw")})

        if self.timeseal:
            self.transport.write(self.protocol.encode(bytearray(string, "utf-8")) + b"\n")
        else:
            self.transport.write(string.encode() + b"\n")
Beispiel #23
0
 def resign(self, game):
     """ This is (and draw and abort) are possible even when one's
         opponent is not logged on """
     if not game.opponent.adjournment:
         log.warning("AdjournManager.resign: no adjourned game vs %s" %
                     game.opponent)
         return
     log.info("AdjournManager.resign: resigning adjourned game=%s" % game)
     self.connection.client.run_command("resign %s" % game.opponent.name)
Beispiel #24
0
    def write(self, string):
        logstr = "*" * len(string) if self.sensitive else string
        self.sensitive = False
        log.info(logstr, extra={"task": (self.name, "raw")})

        if self.timeseal:
            self.transport.write(self.protocol.encode(bytearray(string, "utf-8")) + b"\n")
        else:
            self.transport.write(string.encode() + b"\n")
Beispiel #25
0
    def __init__(self):
        GObject.GObject.__init__(self)
        self.engines = []
        self.jsonpath = addUserConfigPrefix("engines.json")
        try:
            self._engines = json.load(open(self.jsonpath))
        except ValueError as err:
            log.warning(
                "engineNest: Couldn\'t read engines.json, renamed it to .bak\n%s\n%s"
                % (self.jsonpath, err))
            os.rename(self.jsonpath, self.jsonpath + ".bak")
            self._engines = deepcopy(backup)
        except IOError as err:
            log.info(
                "engineNest: Couldn\'t open engines.json, creating a new.\n%s"
                % err)
            self._engines = deepcopy(backup)

        # Try to detect engines shipping .eng files on Linux (suggested by HGM on talkcess.com forum)
        for protocol in ("xboard", "uci"):
            for path in ("/usr/local/share/games/plugins",
                         "/usr/share/games/plugins"):
                path = os.path.join(path, protocol)
                if os.path.isdir(path):
                    for entry in os.listdir(path):
                        ext = os.path.splitext(entry)[1]
                        if ext == ".eng":
                            with open(os.path.join(path, entry)) as file_handle:
                                plugin_spec = file_handle.readline().strip()
                                if not plugin_spec.startswith("plugin spec"):
                                    continue

                                engine_command = file_handle.readline().strip()

                                supported_variants = file_handle.readline().strip()
                                if not supported_variants.startswith("chess"):
                                    continue

                                new_engine = {}
                                if engine_command.startswith("cd ") and engine_command.find(";") > 0:
                                    parts = engine_command.split(";")
                                    working_directory = parts[0][3:]
                                    engine_command = parts[1]
                                    new_engine["workingDirectory"] = working_directory

                                find = False
                                for engine in self._engines:
                                    if engine["name"] == engine_command:
                                        find = True
                                        break

                                if not find:
                                    new_engine["protocol"] = protocol
                                    new_engine["name"] = engine_command
                                    self._engines.append(new_engine)
Beispiel #26
0
    def __init__(self):
        self.libgtb = None
        self.initialized = False

        # Get a list of files in the tablebase folder.
        configuredTbPath = conf.get("egtb_path", "")
        tbPath = configuredTbPath or getDataPrefix()
        try:
            tbPathContents = os.listdir(tbPath)
        except OSError as e:
            if configuredTbPath:
                log.warning("Unable to open Gaviota TB folder: %s" % repr(e))
            return

        # Find files named *.gtb.cp# and pick the most common "#".
        # (This is the compression scheme; the library currently only uses one at a time.)
        schemeCount = [0] * 10
        for filename in tbPathContents:
            match = re.search("\.gtb\.cp(\d)$", filename)
            if match:
                schemeCount[int(match.group(1))] += 1
        compressionScheme = max(zip(schemeCount, range(10)))
        if compressionScheme[0] == 0:
            if configuredTbPath:
                log.warning("Could not find any Gaviota TB files in %s" %
                            configuredTbPath)
            return
        compressionScheme = compressionScheme[1]

        # Locate and load the library.
        if not self._loadLibrary():
            return
        self._setupFunctionPrototypes()

        self.pathList = self.tbpaths_init()
        self.pathList = self.tbpaths_add(self.pathList, tbPath.encode())
        initInfo = self.tb_init(True, compressionScheme, self.pathList)
        self.initialized = (self.tb_is_initialized() != 0)
        if not self.initialized:
            log.warning(initInfo or
                        "Failed to initialize Gaviota EGTB library")
            self.pathList = self.tbpaths_done(self.pathList)
            return
        elif initInfo:
            log.info(initInfo)

        # TODO: Set up a WDL cache area once the engine can use it.
        self.initialized &= self.tbcache_init(4 * 1024 * 1024, 0)
        if not self.initialized:
            log.warning("Failed to initialize Gaviota EGTB cache")
            self.tb_done()
            self.pathList = self.tbpaths_done(self.pathList)
            return

        self.availability = self.tb_availability()
Beispiel #27
0
    def __init__(self):
        self.libgtb = None
        self.initialized = False

        # Get a list of files in the tablebase folder.
        configuredTbPath = conf.get("egtb_path", "")
        tbPath = configuredTbPath or getDataPrefix()
        try:
            tbPathContents = os.listdir(tbPath)
        except OSError as e:
            if configuredTbPath:
                log.warning("Unable to open Gaviota TB folder: %s" % repr(e))
            return

        # Find files named *.gtb.cp# and pick the most common "#".
        # (This is the compression scheme; the library currently only uses one at a time.)
        schemeCount = [0] * 10
        for filename in tbPathContents:
            match = re.search("\.gtb\.cp(\d)$", filename)
            if match:
                schemeCount[int(match.group(1))] += 1
        compressionScheme = max(zip(schemeCount, range(10)))
        if compressionScheme[0] == 0:
            if configuredTbPath:
                log.warning("Could not find any Gaviota TB files in %s" %
                            configuredTbPath)
            return
        compressionScheme = compressionScheme[1]

        # Locate and load the library.
        if not self._loadLibrary():
            return
        self._setupFunctionPrototypes()

        self.pathList = self.tbpaths_init()
        self.pathList = self.tbpaths_add(self.pathList, tbPath.encode())
        initInfo = self.tb_init(True, compressionScheme, self.pathList)
        self.initialized = (self.tb_is_initialized() != 0)
        if not self.initialized:
            log.warning(initInfo
                        or "Failed to initialize Gaviota EGTB library")
            self.pathList = self.tbpaths_done(self.pathList)
            return
        elif initInfo:
            log.info(initInfo)

        # TODO: Set up a WDL cache area once the engine can use it.
        self.initialized &= self.tbcache_init(4 * 1024 * 1024, 0)
        if not self.initialized:
            log.warning("Failed to initialize Gaviota EGTB cache")
            self.tb_done()
            self.pathList = self.tbpaths_done(self.pathList)
            return

        self.availability = self.tb_availability()
Beispiel #28
0
def run(no_debug, idle_add_debug, thread_debug, log_viewer, purge_recent,
        chess_file, ics_host, ics_port):
    # Start logging
    if log_viewer:
        log.logger.addHandler(GLogHandler(logemitter))
    log.logger.setLevel(logging.WARNING if no_debug is True else logging.DEBUG)
    oldlogs = [
        l for l in os.listdir(getUserDataPrefix()) if l.endswith(".log")
    ]
    conf.set("max_log_files", conf.get("max_log_files", 10))
    oldlogs.sort()
    l = len(oldlogs)
    while l > conf.get("max_log_files", 10):
        try:
            os.remove(addUserDataPrefix(oldlogs[0]))
            del oldlogs[0]
        except OSError:
            pass
        l -= 1

    if purge_recent:
        items = recentManager.get_items()
        for item in items:
            uri = item.get_uri()
            if item.get_application_info("pychess"):
                recentManager.remove_item(uri)

    signal.signal(signal.SIGINT, Gtk.main_quit)
    signal.signal(signal.SIGTERM, Gtk.main_quit)

    def cleanup():
        ICLogon.stop()
        SubProcess.finishAllSubprocesses()

    atexit.register(cleanup)

    pychess = PyChess(log_viewer, chess_file)
    idle_add.debug = idle_add_debug

    sys.stdout = LogPipe(sys.stdout, "stdout")
    sys.stderr = LogPipe(sys.stderr, "stdout")
    log.info("PyChess %s %s git %s" % (VERSION_NAME, VERSION, pychess.git_rev))
    log.info("Command line args: '%s'" % chess_file)
    log.info("Platform: %s" % platform.platform())
    log.info("Python version: %s.%s.%s" % sys.version_info[0:3])
    log.info("Pyglib version: %s.%s.%s" % GLib.pyglib_version)
    if thread_debug:
        start_thread_dump()
    if ics_host:
        ICLogon.host = ics_host
    if ics_port:
        ICLogon.port = ics_port

    Gtk.main()
Beispiel #29
0
def run(no_debug, idle_add_debug, thread_debug, log_viewer, purge_recent,
        chess_file, ics_host, ics_port):
    # Start logging
    if log_viewer:
        log.logger.addHandler(GLogHandler(logemitter))
    log.logger.setLevel(logging.WARNING if no_debug is True else logging.DEBUG)
    oldlogs = [l for l in os.listdir(getUserDataPrefix())
               if l.endswith(".log")]
    conf.set("max_log_files", conf.get("max_log_files", 10))
    oldlogs.sort()
    l = len(oldlogs)
    while l > conf.get("max_log_files", 10):
        try:
            os.remove(addUserDataPrefix(oldlogs[0]))
            del oldlogs[0]
        except OSError:
            pass
        l -= 1

    if purge_recent:
        items = recentManager.get_items()
        for item in items:
            uri = item.get_uri()
            if item.get_application_info("pychess"):
                recentManager.remove_item(uri)

    signal.signal(signal.SIGINT, Gtk.main_quit)
    signal.signal(signal.SIGTERM, Gtk.main_quit)

    def cleanup():
        ICLogon.stop()
        SubProcess.finishAllSubprocesses()

    atexit.register(cleanup)

    pychess = PyChess(log_viewer, chess_file)
    idle_add.debug = idle_add_debug

    sys.stdout = LogPipe(sys.stdout, "stdout")
    sys.stderr = LogPipe(sys.stderr, "stdout")
    log.info("PyChess %s %s git %s" % (VERSION_NAME, VERSION, pychess.git_rev))
    log.info("Command line args: '%s'" % chess_file)
    log.info("Platform: %s" % platform.platform())
    log.info("Python version: %s.%s.%s" % sys.version_info[0:3])
    log.info("Pyglib version: %s.%s.%s" % GLib.pyglib_version)
    if thread_debug:
        start_thread_dump()
    if ics_host:
        ICLogon.host = ics_host
    if ics_port:
        ICLogon.port = ics_port

    Gtk.main()
Beispiel #30
0
    def __init__(self, path, games):
        PGNFile.__init__(self, path, games)
        self.path = path
        self.engine = dbmodel.get_engine(path)
        self.DB_MAXINT_SHIFT = get_maxint_shift(self.engine)

        self.cols = [
            game.c.id.label("Id"),
            pl1.c.name.label('White'),
            pl2.c.name.label('Black'),
            game.c.result.label('Result'),
            event.c.name.label('Event'),
            site.c.name.label('Site'),
            game.c.round.label('Round'),
            game.c.date_year.label('Year'),
            game.c.date_month.label('Month'),
            game.c.date_day.label('Day'),
            game.c.white_elo.label('WhiteElo'),
            game.c.black_elo.label('BlackElo'),
            game.c.ply_count.label('PlyCount'),
            game.c.eco.label('ECO'),
            game.c.time_control.label('TimeControl'),
            game.c.fen.label('Board'),
            game.c.fen.label('FEN'),
            game.c.variant.label('Variant'),
            annotator.c.name.label('Annotator')
        ]

        self.from_obj = [
            game.outerjoin(pl1, game.c.white_id == pl1.c.id).outerjoin(
                pl2, game.c.black_id == pl2.c.id).outerjoin(
                    event, game.c.event_id == event.c.id).outerjoin(
                        site, game.c.site_id == site.c.id).outerjoin(
                            annotator, game.c.annotator_id == annotator.c.id)
        ]

        self.count = self.engine.execute(count_games).scalar()
        log.info("%s contains %s game(s)" % (self.path, self.count),
                 extra={"task": "SQL"})

        self.update_count_stats()

        self.select = select(self.cols, from_obj=self.from_obj)

        self.colnames = self.engine.execute(self.select).keys()

        self.query = self.select
        self.orderby = None
        self.where_tags = None
        self.where_bitboards = None
        self.ply = None
Beispiel #31
0
 def write(self, str):
     self.writebuf += bytearray(str, "utf-8")
     if b"\n" not in self.writebuf:
         return
     if not self.connected:
         return
     
     i = self.writebuf.rfind(b"\n")
     str = self.writebuf[:i]
     self.writebuf = self.writebuf[i+1:]
     
     logstr = "*"*len(str) if self.sensitive else str
     log.info(logstr, extra={"task": (self.name, "raw")})
     str = self.encode(str)
     self.sock.send(str+b"\n")
Beispiel #32
0
    def write(self, str):
        self.writebuf += bytearray(str, "utf-8")
        if b"\n" not in self.writebuf:
            return
        if not self.connected:
            return

        i = self.writebuf.rfind(b"\n")
        str = self.writebuf[:i]
        self.writebuf = self.writebuf[i + 1:]

        logstr = "*" * len(str) if self.sensitive else str
        log.info(logstr, extra={"task": (self.name, "raw")})
        str = self.encode(str)
        self.sock.send(str + b"\n")
Beispiel #33
0
    def __init__(self):
        GObject.GObject.__init__(self)
        self.engines = []
        self.jsonpath = addUserConfigPrefix("engines.json")
        try:
            self._engines = json.load(open(self.jsonpath))
        except ValueError as e:
            log.warning(
                "engineNest: Couldn\'t read engines.json, renamed it to .bak\n%s"
                % (self.jsonpath, e))
            os.rename(self.jsonpath, self.jsonpath + ".bak")
            self._engines = deepcopy(backup)
        except IOError as e:
            log.info(
                "engineNest: Couldn\'t open engines.json, creating a new.\n%s"
                % e)
            self._engines = deepcopy(backup)

        for protocol in ("xboard", "uci"):
            for path in ("/usr/local/share/games/plugins",
                         "/usr/share/games/plugins"):
                path = os.path.join(path, protocol)
                if os.path.isdir(path):
                    for entry in os.listdir(path):
                        name, ext = os.path.splitext(entry)
                        if ext == ".eng":
                            with open(os.path.join(path, entry)) as f:
                                plugin_spec = f.readline().strip()
                                engine_command = f.readline().strip()
                                new_engine = {}
                                if engine_command.startswith(
                                        "cd "
                                ) and engine_command.find(";") > 0:
                                    parts = engine_command.split(";")
                                    working_directory = parts[0][3:]
                                    engine_command = parts[1]
                                    new_engine[
                                        "workingDirectory"] = working_directory

                                find = False
                                for engine in self._engines:
                                    if engine["name"] == engine_command:
                                        find = True
                                        break
                                if not find:
                                    new_engine["protocol"] = protocol
                                    new_engine["name"] = engine_command
                                    self._engines.append(new_engine)
Beispiel #34
0
 def run(self):
     try:
         try:
             if not self.isConnected():
                 self._connect()
             while self.isConnected():
                 self.client.parse()
         except Exception as e:
             log.info("FICSConnection.run: %s" % repr(e), extra={"task": (self.host, "raw")})
             self.close()
             if isinstance(e, (IOError, LogOnException, EOFError, socket.error, socket.gaierror, socket.herror)):
                 self.emit("error", e)
             else:
                 raise
     finally:
         self.emit("disconnected")
Beispiel #35
0
    def end(self, status, reason):
        if self.status not in UNFINISHED_STATES:
            log.info(
                "GameModel.end: Can't end a game that's already ended: %s %s" %
                (status, reason))
            return
        if self.status not in (WAITING_TO_START, PAUSED, RUNNING):
            self.needsSave = True

        log.debug("GameModel.end: players=%s, self.ply=%s: Ending a game with status %d for reason %d" % (
            repr(self.players), str(self.ply), status, reason))
        self.status = status
        self.reason = reason

        self.emit("game_ended", reason)

        self.__pause()
Beispiel #36
0
    def onGameStarted(self, gamemodel):
        if gamemodel.players[0].__type__ == LOCAL:
            self.player = gamemodel.players[0]
            self.opplayer = gamemodel.players[1]
            if gamemodel.players[1].__type__ == LOCAL:
                log.warning("Chatpanel loaded with two local players")
        elif gamemodel.players[1].__type__ == LOCAL:
            self.player = gamemodel.players[1]
            self.opplayer = gamemodel.players[0]
        else:
            log.info("Chatpanel loaded with no local players")
            self.chatView.hide()

        if hasattr(self, "player"):
            self.player.connect("messageRecieved", self.onMessageReieved)

        self.chatView.enable()
Beispiel #37
0
 def onGameStarted (self, gamemodel):
     if gamemodel.players[0].__type__ == LOCAL:
         self.player = gamemodel.players[0]
         self.opplayer = gamemodel.players[1]
         if gamemodel.players[1].__type__ == LOCAL:
             log.warning("Chatpanel loaded with two local players")
     elif gamemodel.players[1].__type__ == LOCAL:
         self.player = gamemodel.players[1]
         self.opplayer = gamemodel.players[0]
     else:
         log.info("Chatpanel loaded with no local players")
         self.chatView.hide()
     
     if hasattr(self, "player"):
         self.player.connect("messageRecieved", self.onMessageReieved)
     
     self.chatView.enable()
Beispiel #38
0
    def end(self, status, reason):
        if self.status not in UNFINISHED_STATES:
            log.info(
                "GameModel.end: Can't end a game that's already ended: %s %s" %
                (status, reason))
            return
        if self.status not in (WAITING_TO_START, PAUSED, RUNNING):
            self.needsSave = True

        log.debug("GameModel.end: players=%s, self.ply=%s: Ending a game with status %d for reason %d" % (
            repr(self.players), str(self.ply), status, reason))
        self.status = status
        self.reason = reason

        self.emit("game_ended", reason)

        self.__pause()
Beispiel #39
0
 def run(self):
     try:
         try:
             if not self.isConnected():
                 self._connect()
             while self.isConnected():
                 self.client.parse()
         except Exception as e:
             log.info("FICSConnection.run: %s" % repr(e),
                      extra={"task": (self.host, "raw")})
             self.close()
             if isinstance(e,
                           (IOError, LogOnException, EOFError, socket.error,
                            socket.gaierror, socket.herror)):
                 self.emit("error", e)
             else:
                 raise
     finally:
         self.emit("disconnected")
Beispiel #40
0
def run(no_debug, no_idle_add_debug, no_thread_debug, log_viewer, chess_file,
        ics_host, ics_port):
    # Start logging
    if log_viewer:
        log.logger.addHandler(GLogHandler(logemitter))
    log.logger.setLevel(logging.WARNING if no_debug is True else logging.DEBUG)
    oldlogs = [
        l for l in os.listdir(getUserDataPrefix()) if l.endswith(".log")
    ]
    conf.set("max_log_files", conf.get("max_log_files", 10))
    if len(oldlogs) >= conf.get("max_log_files", 10):
        oldlogs.sort()
        try:
            os.remove(addUserDataPrefix(oldlogs[0]))
        except OSError as e:
            pass

    signal.signal(signal.SIGINT, Gtk.main_quit)

    def cleanup():
        SubProcess.finishAllSubprocesses()

    atexit.register(cleanup)

    pychess = PyChess(log_viewer, chess_file)
    idle_add.debug = not no_idle_add_debug

    sys.stdout = LogPipe(sys.stdout, "stdout")
    sys.stderr = LogPipe(sys.stderr, "stdout")
    log.info("PyChess %s %s git %s" % (VERSION_NAME, VERSION, pychess.git_rev))
    log.info("Command line args: '%s'" % chess_file)
    log.info("Platform: %s" % platform.platform())
    log.info("Python version: %s.%s.%s" % sys.version_info[0:3])
    log.info("Pyglib version: %s.%s.%s" % GLib.pyglib_version)
    if not no_thread_debug:
        start_thread_dump()
    if ics_host:
        ICLogon.host = ics_host
    if ics_port:
        ICLogon.port = ics_port

    Gtk.main()
Beispiel #41
0
    def write(self, string):
        self.writebuf += bytearray(string, "utf-8")
        if b"\n" not in self.writebuf:
            return
        if not self.connected:
            return

        i = self.writebuf.rfind(b"\n")
        string = self.writebuf[:i]
        self.writebuf = self.writebuf[i + 1:]

        logstr = "*" * len(string) if self.sensitive else string
        self.sensitive = False
        log.info(logstr, extra={"task": (self.name, "raw")})
        if not self.ICC:
            string = self.encode(string)
        try:
            self.sock.send(string + b"\n")
        except:
            pass
Beispiel #42
0
    def onGameStarted (self, gamemodel):
        if gamemodel.isObservationGame() or gamemodel.examined:
            # no local player but enable chat to send/receive whisper/kibitz
            pass
        elif gamemodel.players[0].__type__ == LOCAL:
            self.player = gamemodel.players[0]
            self.opplayer = gamemodel.players[1]
            if gamemodel.players[1].__type__ == LOCAL:
                log.warning("Chatpanel loaded with two local players")
        elif gamemodel.players[1].__type__ == LOCAL:
            self.player = gamemodel.players[1]
            self.opplayer = gamemodel.players[0]
        else:
            log.info("Chatpanel loaded with no local players")
            self.chatView.hide()

        if hasattr(self, "player"):
            self.player.connect("messageReceived", self.onMessageReieved)

        self.chatView.enable()
Beispiel #43
0
def run(no_debug, no_glock_debug, no_thread_debug, log_viewer, chess_file,
        ics_host, ics_port):
    # Start logging
    log.logger.setLevel(logging.WARNING if no_debug is True else logging.DEBUG)
    if log_viewer:
        Log.set_gui_log_emitter()
    oldlogs = [
        l for l in os.listdir(getUserDataPrefix()) if l.endswith(".log")
    ]
    conf.set("max_log_files", conf.get("max_log_files", 10))
    if len(oldlogs) >= conf.get("max_log_files", 10):
        oldlogs.sort()
        try:
            os.remove(addUserDataPrefix(oldlogs[0]))
        except OSError as e:
            pass

    signal.signal(signal.SIGINT, Gtk.main_quit)

    def cleanup():
        SubProcess.finishAllSubprocesses()

    atexit.register(cleanup)
    Gdk.threads_init()
    GObject.threads_init()
    Gdk.threads_enter()

    pychess = PyChess(log_viewer, chess_file)
    glock.debug = not no_glock_debug
    log.info("PyChess %s %s rev. %s %s started" %
             (VERSION_NAME, VERSION, pychess.hg_rev, pychess.hg_date))
    log.info("Command line args: '%s'" % chess_file)
    if not no_thread_debug:
        start_thread_dump()
    if ics_host:
        ICLogon.host = ics_host
    if ics_port:
        ICLogon.port = ics_port

    Gtk.main()
    Gdk.threads_leave()
Beispiel #44
0
    def onGameStarted(self, gamemodel):
        if gamemodel.isObservationGame() or gamemodel.examined:
            # no local player but enable chat to send/receive whisper/kibitz
            allob = 'allob ' + str(gamemodel.ficsgame.gameno)
            gamemodel.connection.client.run_command(allob)
        elif gamemodel.players[0].__type__ == LOCAL:
            self.player = gamemodel.players[0]
            self.opplayer = gamemodel.players[1]
            if gamemodel.players[1].__type__ == LOCAL:
                log.warning("Chatpanel loaded with two local players")
        elif gamemodel.players[1].__type__ == LOCAL:
            self.player = gamemodel.players[1]
            self.opplayer = gamemodel.players[0]
        else:
            log.info("Chatpanel loaded with no local players")
            self.chatView.hide()

        if hasattr(self, "player"):
            self.player.connect("messageReceived", self.onMessageReieved)

        self.chatView.enable()
Beispiel #45
0
    def __init__(self):
        GObject.GObject.__init__(self)
        self.engines = []
        self.jsonpath = addUserConfigPrefix("engines.json")
        try:
            self._engines = json.load(open(self.jsonpath))
        except ValueError as e:
            log.warning("engineNest: Couldn't read engines.json, renamed it to .bak\n%s" % (self.jsonpath, e))
            os.rename(self.jsonpath, self.jsonpath + ".bak")
            self._engines = deepcopy(backup)
        except IOError as e:
            log.info("engineNest: Couldn't open engines.json, creating a new.\n%s" % e)
            self._engines = deepcopy(backup)

        for protocol in ("xboard", "uci"):
            for path in ("/usr/local/share/games/plugins", "/usr/share/games/plugins"):
                path = os.path.join(path, protocol)
                if os.path.isdir(path):
                    for entry in os.listdir(path):
                        name, ext = os.path.splitext(entry)
                        if ext == ".eng":
                            with open(os.path.join(path, entry)) as f:
                                plugin_spec = f.readline().strip()
                                engine_command = f.readline().strip()
                                new_engine = {}
                                if engine_command.startswith("cd ") and engine_command.find(";") > 0:
                                    parts = engine_command.split(";")
                                    working_directory = parts[0][3:]
                                    engine_command = parts[1]
                                    new_engine["workingDirectory"] = working_directory

                                find = False
                                for engine in self._engines:
                                    if engine["name"] == engine_command:
                                        find = True
                                        break
                                if not find:
                                    new_engine["protocol"] = protocol
                                    new_engine["name"] = engine_command
                                    self._engines.append(new_engine)
Beispiel #46
0
 def start(self):
     try:
         try:
             if not self.isConnected():
                 yield from self._connect()
             while self.isConnected():
                 yield from self.client.parse()
         except Exception as err:
             exc_type, exc_value, exc_traceback = sys.exc_info()
             traceback.print_exception(exc_type, exc_value, exc_traceback)
             log.info("FICSConnection.run: %s" % repr(err),
                      extra={"task": (self.host, "raw")})
             self.close()
             if isinstance(err,
                           (IOError, LogOnException, EOFError, socket.error,
                            socket.gaierror, socket.herror)):
                 self.emit("error", err)
             else:
                 raise
     finally:
         if isinstance(self, FICSMainConnection):
             self.emit("disconnected")
Beispiel #47
0
    def run(cls, uri=None):
        cls._ensureReady()
        if cls.widgets["newgamedialog"].props.visible:
            cls.widgets["newgamedialog"].present()
            return

        if not uri:
            res = ionest.opendialog.run()
            ionest.opendialog.hide()
            if res != Gtk.ResponseType.ACCEPT:
                return
        else:
            if not uri[uri.rfind(".") + 1:] in ionest.enddir:
                log.info("Ignoring strange file: %s" % uri)
                return
            cls.loadSidePanel.set_filename(uri)
            cls.filechooserbutton.emit("file-activated")

        cls._hideOthers()
        cls.widgets["newgamedialog"].set_title(_("Open Game"))
        cls.widgets["loadsidepanel"].show()

        def _validate(gamemodel):
            return True

        def _callback(gamemodel, p0, p1):
            if not cls.loadSidePanel.isEmpty():
                uri = cls.loadSidePanel.get_filename()
                loader = ionest.enddir[uri[uri.rfind(".") + 1:]]
                position = cls.loadSidePanel.getPosition()
                gameno = cls.loadSidePanel.getGameno()
                ionest.generalStart(gamemodel, p0, p1,
                                    (uri, loader, gameno, position))
            else:
                ionest.generalStart(gamemodel, p0, p1)

        cls._generalRun(_callback, _validate)
Beispiel #48
0
    def start(self, host, port, connected_event, timeseal=True):
        if self.canceled:
            raise CanceledException()
        self.port = port
        self.host = host
        self.connected_event = connected_event
        self.timeseal = timeseal

        self.name = host

        if host == "chessclub.com":
            self.ICC = True
            self.timeseal = False

            # You can get ICC timestamp from
            # https://www.chessclub.com/user/resources/icc/timestamp/
            if sys.platform == "win32":
                timestamp = "timestamp_win32.exe"
            else:
                timestamp = "timestamp_linux_2.6.8"

            altpath = getEngineDataPrefix()
            path = shutil.which(timestamp, os.X_OK, path=altpath)
            if path is None:
                binary = "https://www.chessclub.com/user/resources/icc/timestamp/%s" % timestamp
                filename = download_file(binary)
                if filename is not None:
                    dest = shutil.move(filename, os.path.join(altpath, timestamp))
                    os.chmod(dest, stat.S_IEXEC | stat.S_IREAD | stat.S_IWRITE)

            if path:
                self.host = "127.0.0.1"
                self.port = 5500
                try:
                    self.timestamp_proc = subprocess.Popen(["%s" % path, "-p", "%s" % self.port])
                    log.info("%s started OK" % path)
                except OSError as err:
                    log.info("Can't start %s OSError: %s %s" % (path, err.errno, err.strerror))
                    self.port = port
                    self.host = host
            else:
                log.info("%s not found, downloading..." % path)

        def cb(reader, writer):
            reader.stream_writer = writer
            reader.connected_event.set()

        loop = asyncio.get_event_loop()
        self.reader = ICSStreamReader(_DEFAULT_LIMIT, loop, self.connected_event, self.name)
        self.protocol = ICSStreamReaderProtocol(self.reader, cb, loop, self.name, self.timeseal)
        coro = loop.create_connection(lambda: self.protocol, self.host, self.port)
        self.transport, _protocol = yield from coro
        # writer = asyncio.StreamWriter(transport, protocol, reader, loop)

        if self.timeseal:
            self.write(self.get_init_string())
Beispiel #49
0
    def onGameStarted(self, gamemodel):
        if gamemodel.isObservationGame() or gamemodel.examined:
            # no local player but enable chat to send/receive whisper/kibitz
            pass
        elif gamemodel.players[0].__type__ == LOCAL:
            self.player = gamemodel.players[0]
            self.opplayer = gamemodel.players[1]
            if gamemodel.players[1].__type__ == LOCAL:
                log.warning("Chatpanel loaded with two local players")
        elif gamemodel.players[1].__type__ == LOCAL:
            self.player = gamemodel.players[1]
            self.opplayer = gamemodel.players[0]
        else:
            log.info("Chatpanel loaded with no local players")
            self.chatView.hide()

        if isinstance(gamemodel, ICGameModel):
            allob = 'allob ' + str(gamemodel.ficsgame.gameno)
            gamemodel.connection.client.run_command(allob)

        if hasattr(self, "player"):
            self.player.connect("messageReceived", self.onMessageReieved)

        self.chatView.enable()
Beispiel #50
0
    def start(self, host, port, connected_event):
        if self.canceled:
            raise CanceledException()
        self.port = port
        self.host = host
        self.connected_event = connected_event

        self.name = host

        if host == "chessclub.com":
            self.ICC = True

            if self.timeseal and timestamp_path is not None:
                self.host = "127.0.0.1"
                self.port = 5500
                try:
                    if sys.platform == "win32":
                        # To prevent engines opening console window
                        startupinfo = subprocess.STARTUPINFO()
                        startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
                    else:
                        startupinfo = None
                    create = asyncio.create_subprocess_exec(
                        *["%s" % timestamp_path, "-p",
                          "%s" % self.port],
                        startupinfo=startupinfo)
                    self.timestamp_proc = yield from create
                    log.info("%s started OK" % timestamp_path)
                except OSError as err:
                    log.info("Can't start %s OSError: %s %s" %
                             (timestamp_path, err.errno, err.strerror))
                    self.port = port
                    self.host = host
            else:
                log.info("%s not found" % timestamp_path)

            self.timeseal = False

        def cb(reader, writer):
            reader.stream_writer = writer
            reader.connected_event.set()

        loop = asyncio.get_event_loop()
        self.reader = ICSStreamReader(_DEFAULT_LIMIT, loop,
                                      self.connected_event, self.name)
        self.protocol = ICSStreamReaderProtocol(self.reader, cb, loop,
                                                self.name, self.timeseal)
        coro = loop.create_connection(lambda: self.protocol, self.host,
                                      self.port)
        self.transport, _protocol = yield from coro
        # writer = asyncio.StreamWriter(transport, protocol, reader, loop)

        if self.timeseal:
            self.write(self.get_init_string())
Beispiel #51
0
    def start(self, host, port, connected_event):
        if self.canceled:
            raise CanceledException()
        self.port = port
        self.host = host
        self.connected_event = connected_event

        self.name = host

        if host == "chessclub.com":
            self.ICC = True

            if self.timeseal and timestamp_path is not None:
                self.host = "127.0.0.1"
                self.port = 5500
                try:
                    if sys.platform == "win32":
                        # To prevent engines opening console window
                        startupinfo = subprocess.STARTUPINFO()
                        startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
                    else:
                        startupinfo = None
                    create = asyncio.create_subprocess_exec(* ["%s" % timestamp_path, "-p", "%s" % self.port], startupinfo=startupinfo)
                    self.timestamp_proc = yield from create
                    log.info("%s started OK" % timestamp_path)
                except OSError as err:
                    log.info("Can't start %s OSError: %s %s" % (timestamp_path, err.errno, err.strerror))
                    self.port = port
                    self.host = host
            else:
                log.info("%s not found" % timestamp_path)

            self.timeseal = False

        def cb(reader, writer):
            reader.stream_writer = writer
            reader.connected_event.set()

        loop = asyncio.get_event_loop()
        self.reader = ICSStreamReader(_DEFAULT_LIMIT, loop, self.connected_event, self.name)
        self.protocol = ICSStreamReaderProtocol(self.reader, cb, loop, self.name, self.timeseal)
        coro = loop.create_connection(lambda: self.protocol, self.host, self.port)
        self.transport, _protocol = yield from coro
        # writer = asyncio.StreamWriter(transport, protocol, reader, loop)

        if self.timeseal:
            self.write(self.get_init_string())
Beispiel #52
0
    def do_startup(self):
        Gtk.Application.do_startup(self)

        if self.purge_recent:
            items = recent_manager.get_items()
            for item in items:
                uri = item.get_uri()
                if item.get_application_info("pychess"):
                    recent_manager.remove_item(uri)

        self.git_rev = ""

        self.initGlade(self.log_viewer)
        self.addPerspectives()
        self.handleArgs(self.chess_file)
        create_task(checkversion())

        self.loaded_cids = {}
        self.saved_cids = {}
        self.terminated_cids = {}

        log.info("PyChess %s %s git %s" % (VERSION_NAME, VERSION, self.git_rev))
        log.info("Command line args: '%s'" % self.chess_file)
        log.info("Platform: %s" % platform.platform())
        log.info("Python version: %s.%s.%s" % sys.version_info[0:3])
        log.info("Pyglib version: %s.%s.%s" % GLib.pyglib_version)
        log.info("Gtk version: %s.%s.%s" % (Gtk.get_major_version(),
                                            Gtk.get_minor_version(),
                                            Gtk.get_micro_version()))
Beispiel #53
0
    def _connect(self):
        self.connecting = True
        self.emit("connecting")
        try:

            self.emit('connectingMsg', _("Connecting to server"))
            for i, port in enumerate(self.ports):
                log.debug("Trying port %d" % port,
                          extra={"task": (self.host, "raw")})
                try:
                    connected_event = asyncio.Event()
                    self.client = ICSTelnet()
                    asyncio.async(self.client.start(self.host, port, connected_event))
                    yield from connected_event.wait()
                except socket.error as err:
                    log.debug("Failed to open port %d %s" % (port, err),
                              extra={"task": (self.host, "raw")})
                    if i + 1 == len(self.ports):
                        raise
                    else:
                        continue
                else:
                    break

            yield from self.client.read_until("login: "******"Logging on to server"))

            # login with registered handle
            if self.password:
                self.client.write(self.username)
                got = yield from self.client.read_until(
                    "password:"******"enter the server as", "Try again.")
                if got == 0:
                    self.client.sensitive = True
                    self.client.write(self.password)
                # No such name
                elif got == 1:
                    raise LogOnException(NOTREG % self.username)
                # Bad name
                elif got == 2:
                    raise LogOnException(NOTREG % self.username)
            else:
                if self.username:
                    self.client.write(self.username)
                else:
                    self.client.write("guest")
                got = yield from self.client.read_until(
                    "Press return",
                    "You are connected as a guest",
                    "If it is yours, type the password.",
                    "guest connections have been prevented",
                    "nobody from your site may login without an account.")
                # got = 3
                if got == 2:
                    raise LogOnException(REGISTERED % self.username)
                elif got == 3 or got == 4:
                    raise LogOnException(PREVENTED)
                self.client.write("")

            while True:
                line = yield from self.client.readline()
                if "Invalid password" in line:
                    raise LogOnException(BADPAS)
                elif "is already logged in" in line:
                    raise LogOnException(ALREADYIN % self.username)

                match = re.search(
                    "\*\*\*\* Starting FICS session as " + "(%s)%s \*\*\*\*" %
                    (ic.NAMES_RE, ic.TITLES_RE), line)
                if match:
                    self.username = match.groups()[0]
                    break

                # USCN specific line
                match = re.search("Created temporary login '(%s)'" % ic.NAMES_RE, line)
                if match:
                    self.username = match.groups()[0]
                    break

                match = re.search("For a list of events, click here:", line)
                if match:
                    break

                # ICC specific line
                match = re.search("help anonymous", line)
                if match:
                    break

                match = re.search("This is the admin message of the day", line)
                if match:
                    break

            self.emit('connectingMsg', _("Setting up environment"))
            lines = yield from self.client.readuntil(b"ics%")
            self._post_connect_hook(lines)
            self.FatICS = self.client.FatICS
            self.USCN = self.client.USCN
            self.ICC = self.client.ICC
            self.client.name = self.username
            self.client = PredictionsTelnet(self.client, self.predictions, self.reply_cmd_dict,
                                            self.replay_dg_dict, self.replay_cn_dict)
            self.client.lines.line_prefix = "aics%" if self.ICC else "fics%"

            if not self.USCN and not self.ICC:
                self.client.run_command("iset block 1")
                self.client.lines.block_mode = True

            if self.ICC:
                self.client.run_command("set level1 5")
                self.client.run_command("set prompt 0")
                self.client.lines.datagram_mode = True

                ic.GAME_TYPES_BY_SHORT_FICS_NAME["B"] = ic.GAME_TYPES["bullet"]
            else:
                ic.GAME_TYPES_BY_SHORT_FICS_NAME["B"] = ic.GAME_TYPES["bughouse"]

            self.client.run_command("iset defprompt 1")
            self.client.run_command("iset ms 1")

            self._start_managers(lines)
            self.connecting = False
            self.connected = True
            self.emit("connected")

            @asyncio.coroutine
            def keep_alive():
                while self.isConnected():
                    self.client.run_command("date")
                    yield from asyncio.sleep(30 * 60)
            self.keep_alive_task = asyncio.async(keep_alive())

        except CanceledException as err:
            log.info("FICSConnection._connect: %s" % repr(err),
                     extra={"task": (self.host, "raw")})
        finally:
            self.connecting = False
Beispiel #54
0
    def _connect (self):
        self.connecting = True
        self.emit("connecting")
        try:
            self.client = TimeSeal()
            
            self.emit('connectingMsg', _("Connecting to server"))
            for i, port in enumerate(self.ports):
                log.debug("Trying port %d" % port, extra={"task": (self.host, "raw")})
                try:
                    self.client.open(self.host, port)
                except socket.error as e:
                    log.debug("Failed to open port %d %s" % (port, e), extra={"task": (self.host, "raw")})
                    if i+1 == len(self.ports):
                        raise
                    else:
                        continue
                else:
                    break
            
            self.client.read_until("login: "******"Logging on to server"))
            
            # login with registered handle
            if self.password:
                print(self.username, file=self.client)
                got = self.client.read_until("password:"******"enter the server as",
                                             "Try again.")
                if got == 0:
                    self.client.sensitive = True
                    print(self.password, file=self.client)
                    self.client.sensitive = False
                # No such name
                elif got == 1:
                    raise LogOnException(NOTREG % self.username)
                # Bad name
                elif got == 2:
                    raise LogOnException(NOTREG % self.username)
            else:
                if self.username:
                    print(self.username, file=self.client)
                else:
                    print("guest", file=self.client)
                got = self.client.read_until("Press return",
                                             "If it is yours, type the password.")
                if got == 1:
                    raise LogOnException(REGISTERED % self.username)
                print(file=self.client)
            
            while True:
                line = self.client.readline()
                if "Invalid password" in line:
                    raise LogOnException(BADPAS)
                elif "is already logged in" in line:
                    raise LogOnException(ALREADYIN % self.username)
                
                match = re.search("\*\*\*\* Starting FICS session as " +
                    "(%s)%s \*\*\*\*" % (NAMES_RE, TITLES_RE), line)
                if match:
                    self.username = match.groups()[0]
                    break
                
            self.emit('connectingMsg', _("Setting up environment"))
            lines = self.client.readuntil(b"ics%")
            self._post_connect_hook(lines)
            self.FatICS = self.client.FatICS
            self.client.name = self.username
            self.client = PredictionsTelnet(self.client, self.predictions,
                                            self.reply_cmd_dict)
            self.client.lines.line_prefix = "fics%"
            self.client.run_command("iset block 1")
            self.client.lines.block_mode = True
            self.client.run_command("iset defprompt 1")
            self.client.run_command("iset ms 1")
            self.client.run_command("set seek 0")
            
            self._start_managers()
            self.connecting = False
            self.connected = True
            self.emit("connected")

            def keep_alive():
                last = time.time()
                while self.isConnected():
                    if time.time()-last > 59*60:
                        self.client.run_command("date")
                        last = time.time()
                    time.sleep(30)
            t = threading.Thread(target=keep_alive, name=fident(keep_alive))
            t.daemon = True
            t.start()
        
        except CanceledException as e:
            log.info("FICSConnection._connect: %s" % repr(e),
                     extra={"task": (self.host, "raw")})
        finally:
            self.connecting = False
Beispiel #55
0
    def parseLine(self, proc):
        while True:
            line = yield from wait_signal(proc, 'line')
            if not line:
                break
            else:
                line = line[1]
                parts = line.split()
                if not parts:
                    continue
                # Initializing
                if parts[0] == "id":
                    if parts[1] == "name":
                        self.ids[parts[1]] = " ".join(parts[2:])
                        self.setName(self.ids["name"])
                    continue

                if parts[0] == "uciok":
                    self.emit("readyForOptions")
                    continue

                if parts[0] == "readyok":
                    self.emit("readyForMoves")
                    continue

                # Options parsing
                if parts[0] == "option":
                    dic = {}
                    last = 1
                    varlist = []
                    for i in range(2, len(parts) + 1):
                        if i == len(parts) or parts[i] in OPTKEYS:
                            key = parts[last]
                            value = " ".join(parts[last + 1:i])
                            if "type" in dic and dic["type"] in TYPEDIC:
                                value = TYPEDIC[dic["type"]](value)

                            if key == "var":
                                varlist.append(value)
                            elif key == "type" and value == "string":
                                dic[key] = "text"
                            else:
                                dic[key] = value

                            last = i
                    if varlist:
                        dic["choices"] = varlist

                    if "name" in dic:
                        self.options[dic["name"]] = dic
                    continue

                # A Move
                if self.mode == NORMAL and parts[0] == "bestmove":
                    self.needBestmove = False
                    self.bestmove_event.set()
                    self.__sendQueuedGo()

                    if self.ignoreNext:
                        log.debug(
                            "__parseLine: line='%s' self.ignoreNext==True, returning" % line.strip(),
                            extra={"task": self.defname})
                        self.ignoreNext = False
                        self.readyForStop = True
                        continue

                    movestr = parts[1]
                    if not self.waitingForMove:
                        log.warning("__parseLine: self.waitingForMove==False, ignoring move=%s" % movestr,
                                    extra={"task": self.defname})
                        self.pondermove = None
                        continue
                    self.waitingForMove = False

                    try:
                        move = parseAny(self.board, movestr)
                    except ParsingError:
                        self.invalid_move = movestr
                        log.info(
                            "__parseLine: ParsingError engine move: %s %s"
                            % (movestr, self.board),
                            extra={"task": self.defname})
                        self.end(WHITEWON if self.board.color == BLACK else
                                 BLACKWON, WON_ADJUDICATION)
                        continue

                    if not validate(self.board, move):
                        # This is critical. To avoid game stalls, we need to resign on
                        # behalf of the engine.
                        log.error("__parseLine: move=%s didn't validate, putting 'del' \
                                  in returnQueue. self.board=%s" % (
                            repr(move), self.board), extra={"task": self.defname})
                        self.invalid_move = movestr
                        self.end(WHITEWON if self.board.color == BLACK else
                                 BLACKWON, WON_ADJUDICATION)
                        continue

                    self._recordMove(self.board.move(move), move, self.board)
                    log.debug("__parseLine: applied move=%s to self.board=%s" % (
                        move, self.board), extra={"task": self.defname})

                    if self.ponderOn:
                        self.pondermove = None
                        # An engine may send an empty ponder line, simply to clear.
                        if len(parts) == 4:
                            # Engines don't always check for everything in their
                            # ponders. Hence we need to validate.
                            # But in some cases, what they send may not even be
                            # correct AN - specially in the case of promotion.
                            try:
                                pondermove = parseAny(self.board, parts[3])
                            except ParsingError:
                                pass
                            else:
                                if validate(self.board, pondermove):
                                    self.pondermove = pondermove
                                    self._startPonder()

                    self.queue.put_nowait(move)
                    log.debug("__parseLine: put move=%s into self.queue=%s" % (
                        move, self.queue), extra={"task": self.defname})
                    continue

                # An Analysis
                if self.mode != NORMAL and parts[0] == "info" and "pv" in parts:
                    multipv = 1
                    if "multipv" in parts:
                        multipv = int(parts[parts.index("multipv") + 1])
                    scoretype = parts[parts.index("score") + 1]
                    if scoretype in ('lowerbound', 'upperbound'):
                        score = None
                    else:
                        score = int(parts[parts.index("score") + 2])
                        if scoretype == 'mate':
                            #                    print >> self.engine, "stop"
                            if score != 0:
                                sign = score / abs(score)
                                score = sign * (MATE_VALUE - abs(score))

                    movstrs = parts[parts.index("pv") + 1:]

                    if "depth" in parts:
                        depth = parts[parts.index("depth") + 1]
                    else:
                        depth = ""

                    if "nps" in parts:
                        nps = parts[parts.index("nps") + 1]
                    else:
                        nps = ""

                    if multipv <= len(self.analysis):
                        self.analysis[multipv - 1] = (self.board.ply, movstrs, score, depth, nps)
                    self.emit("analyze", self.analysis)
                    continue

                # An Analyzer bestmove
                if self.mode != NORMAL and parts[0] == "bestmove":
                    log.debug("__parseLine: processing analyzer bestmove='%s'" % line.strip(),
                              extra={"task": self.defname})
                    self.needBestmove = False
                    self.bestmove_event.set()
                    if parts[1] == "(none)":
                        self.emit("analyze", [])
                    else:
                        self.__sendQueuedGo(sendlast=True)
                    continue

                # Stockfish complaining it received a 'stop' without a corresponding 'position..go'
                if line.strip() == "Unknown command: stop":
                    log.debug("__parseLine: processing '%s'" % line.strip(),
                              extra={"task": self.defname})
                    self.ignoreNext = False
                    self.needBestmove = False
                    self.readyForStop = False
                    self.__sendQueuedGo()
                    continue
Beispiel #56
0
    def __parseLine (self, line):
        if line[0:1] == "#":
            # Debug line which we shall ignore as specified in CECPv2 specs
            return

#        log.debug("__parseLine: line=\"%s\"\n" % line.strip(), self.defname)
        parts = whitespaces.split(line.strip())
        
        if parts[0] == "pong":
            self.lastpong = int(parts[1])
            return
        
        # Illegal Move
        if parts[0].lower().find("illegal") >= 0:
            log.warn("__parseLine: illegal move: line=\"%s\", board=%s" \
                % (line.strip(), self.board), self.defname)
            if parts[-2] == "sd" and parts[-1].isdigit():
                print >> self.engine, "depth", parts[-1] 
            return
        
        # A Move (Perhaps)
        if self.board:
            if parts[0] == "move":
                movestr = parts[1]
            # Old Variation
            elif d_plus_dot_expr.match(parts[0]) and parts[1] == "...":
                movestr = parts[2]
            else:
                movestr = False
            
            if movestr:
                log.debug("__parseLine: acquiring self.boardLock\n", self.defname)
                self.waitingForMove = False
                self.readyForMoveNowCommand = False
                self.boardLock.acquire()
                try:
                    if self.engineIsInNotPlaying:
                        # If engine was set in pause just before the engine sent its
                        # move, we ignore it. However the engine has to know that we
                        # ignored it, and thus we step it one back
                        log.info("__parseLine: Discarding engine's move: %s\n" % movestr, self.defname)
                        print >> self.engine, "undo"
                        return
                    else:
                        try:
                            move = parseAny(self.board, movestr)
                        except ParsingError, e:
                            self.end(WHITEWON if self.board.color == BLACK else BLACKWON, WON_ADJUDICATION)
                            return
                        
                        if validate(self.board, move):
                            self.board = None
                            self.returnQueue.put(move)
                            return
                        self.end(WHITEWON if self.board.color == BLACK else BLACKWON, WON_ADJUDICATION)
                        return
                finally:
                    log.debug("__parseLine(): releasing self.boardLock\n", self.defname)
                    self.boardLock.release()
                    self.movecon.acquire()
                    self.movecon.notifyAll()
                    self.movecon.release()
        
        # Analyzing
        if self.engineIsInNotPlaying:
            if parts[:4] == ["0","0","0","0"]:
                # Crafty doesn't analyze until it is out of book
                print >> self.engine, "book off"
                return
            
            match = anare.match(line)
            if match:
                score, moves = match.groups()
                
                if "mat" in score.lower() or "#" in moves:
                    # Will look either like -Mat 3 or Mat3
                    scoreval = MATE_VALUE
                    if score.startswith('-'):
                        scoreval = -scoreval
                else:
                    scoreval = int(score)
                
                mvstrs = movere.findall(moves)
                try:
                    moves = listToMoves (self.board, mvstrs, type=None, validate=True, ignoreErrors=False)
                except:
                    # Errors may happen when parsing "old" lines from
                    # analyzing engines, which haven't yet noticed their new tasks
                    log.debug('Ignored an "old" line from analyzer: %s\n' % mvstrs, self.defname)
                    return
                
                # Don't emit if we weren't able to parse moves, or if we have a move
                # to kill the opponent king - as it confuses many engines
                if moves and not self.board.board.opIsChecked():
                    #self.emit("analyze", [(moves, scoreval)])
                
                return
        
        # Offers draw
        if parts[0:2] == ["offer", "draw"]:
            #self.emit("accept", Offer(DRAW_OFFER))
            return
        
        # Resigns
        if parts[0] == "resign" or \
            (parts[0] == "tellics" and parts[1] == "resign"): # buggy crafty

            # Previously: if "resign" in parts,
            # however, this is too generic, since "hint", "bk",
            # "feature option=.." and possibly other, future CECPv2
            # commands can validly contain the word "resign" without this
            # being an intentional resign offer.

            #self.emit("offer", Offer(RESIGNATION))
            return
        
        #if parts[0].lower() == "error":
        #    return
        
        #Tell User Error
        if parts[0] == "tellusererror":
            # Create a non-modal non-blocking message dialog with the error:
            dlg = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=gtk.BUTTONS_CLOSE, message_format=None)

            # Use the engine name if already known, otherwise the defname:
            displayname = self.name
            if not displayname:
                displayname = self.defname

            # Compose the dialog text:
            dlg.set_markup(gobject.markup_escape_text(_("The engine %s reports an error:") % displayname) + "\n\n" + gobject.markup_escape_text(" ".join(parts[1:])))

            # handle response signal so the "Close" button works:
            dlg.connect("response", lambda dlg, x: dlg.destroy())

            dlg.show_all()
            return
        
        # Tell Somebody
        if parts[0][:4] == "tell" and \
                parts[0][4:] in ("others", "all", "ics", "icsnoalias"):
            
            log.info("Ignoring tell %s: %s\n" % (parts[0][4:], " ".join(parts[1:])))
            return
        
        if "feature" in parts:
            # Some engines send features after done=1, so we will iterate after done=1 too
            done1 = False
            # We skip parts before 'feature', as some engines give us lines like
            # White (1) : feature setboard=1 analyze...e="GNU Chess 5.07" done=1
            parts = parts[parts.index("feature"):]
            for i, pair in enumerate(parts[1:]):
                
                # As "parts" is split with no thoughs on quotes or double quotes
                # we need to do some extra handling.
                
                if pair.find("=") < 0: continue
                key, value = pair.split("=",1)
                
                if value[0] in ('"',"'") and value[-1] in ('"',"'"):
                    value = value[1:-1]
                
                # If our pair was unfinished, like myname="GNU, we search the
                # rest of the pairs for a quotating mark.
                elif value[0] in ('"',"'"):
                    rest = value[1:] + " " + " ".join(parts[2+i:])
                    i = rest.find('"')
                    j = rest.find("'")
                    if i + j == -2:
                        log.warn("Missing endquotation in %s feature", self.defname)
                        value = rest
                    elif min(i, j) != -1:
                        value = rest[:min(i, j)]
                    else:
                        l = max(i, j)
                        value = rest[:l]
                
                elif value.isdigit():
                    value = int(value)
                
                if key in self.supported_features:
                    print >> self.engine, "accepted %s" % key
                else:
                    print >> self.engine, "rejected %s" % key
                
                if key == "done":
                    if value == 1:
                        done1 = True
                        continue
                    elif value == 0:
                        log.info("Adds %d seconds timeout\n" % TIME_OUT_SECOND, self.defname)
                        # This'll buy you some more time
                        self.timeout = time.time()+TIME_OUT_SECOND
                        self.returnQueue.put("not ready")
                        return
                
                if key == "smp" and value == 1:
                    self.options["cores"] = {"name": "cores", "type": "spin", "default": 1, "min": 1, "max": 64}
                elif key == "memory" and value == 1:
                    self.options["memory"] = {"name": "memory", "type": "spin", "default": 32, "min": 1, "max": 4096}
                elif key == "option" and key != "done":
                    option = self.__parse_option(value)
                    self.options[option["name"]] = option
                else:
                    self.features[key] = value

                if key == "myname" and not self.name:
                    self.setName(value)
        
            if done1:
                # Start a new game before using the engine:
                # (CECPv2 engines)
                print >> self.engine, "new"

                # We are now ready for play:
                #self.emit("readyForOptions")
                #self.emit("readyForMoves")
                self.returnQueue.put("ready")

        # A hack to get better names in protover 1.
        # Unfortunately it wont work for now, as we don't read any lines from
        # protover 1 engines. When should we stop?
        if self.protover == 1:
            if self.defname[0] in ''.join(parts):
                basis = self.defname[0]
                name = ' '.join(itertools.dropwhile(lambda part: basis not in part, parts))
                self.features['myname'] = name
                if not self.name:
                    self.setName(name)

    def __parse_option(self, option):
        if " -check " in option:
            name, value = option.split(" -check ")
            return {"type": "check", "name": name, "default": bool(int(value))}
        elif " -spin " in option:
            name, value = option.split(" -spin ")
            defv, minv, maxv = value.split()
            return {"type": "spin", "name": name, "default": int(defv), "min": int(minv), "max": int(maxv)}
        elif " -slider " in option:
            name, value = option.split(" -slider ")
            defv, minv, maxv = value.split()
            return {"type": "spin", "name": name, "default": int(defv), "min": int(minv), "max": int(maxv)}
        elif " -string " in option:
            name, value = option.split(" -string ")
            return {"type": "text", "name": name, "default": value}
        elif " -file " in option:
            name, value = option.split(" -file ")
            return {"type": "text", "name": name, "default": value}
        elif " -path " in option:
            name, value = option.split(" -path ")
            return {"type": "text", "name": name, "default": value}
        elif " -combo " in option:
            name, value = option.split(" -combo ")
            return {"type": "combo", "name": name, "default": value}
        elif " -button" in option:
            pos = option.find(" -button")
            return {"type": "button", "name": option[:pos]}
        elif " -save" in option:
            pos = option.find(" -save")
            return {"type": "button", "name": option[:pos]}
        elif " -reset" in option:
            pos = option.find(" -reset")
            return {"type": "button", "name": option[:pos]}

    #===========================================================================
    #    Info
    #===========================================================================
    
    def canAnalyze (self):
        assert self.ready, "Still waiting for done=1"
        return self.features["analyze"]
    
    def maxAnalysisLines (self):
        return 1
    
    def requestMultiPV (self, setting):
        return 1
    
    def isAnalyzing (self):
        return self.mode in (ANALYZING, INVERSE_ANALYZING)
    
    def __repr__ (self):
        if self.name:
            return self.name
        return self.features["myname"]
Beispiel #57
0
 def extendlog(self, messages):
     [log.info(m+"\n") for m in messages]
     self.log.extend(messages)
     del self.log[:-10]
Beispiel #58
0
    def parseLine(self, proc):
        while True:
            line = yield from wait_signal(proc, 'line')
            if not line:
                break
            else:
                line = line[1]
                parts = line.split()
                if not parts:
                    continue
                # Initializing
                if parts[0] == "id":
                    if parts[1] == "name":
                        self.ids[parts[1]] = " ".join(parts[2:])
                        self.setName(self.ids["name"])
                    continue

                if parts[0] == "uciok":
                    self.emit("readyForOptions")
                    continue

                if parts[0] == "readyok":
                    self.emit("readyForMoves")
                    continue

                # Options parsing
                if parts[0] == "option":
                    dic = {}
                    last = 1
                    varlist = []
                    for i in range(2, len(parts) + 1):
                        if i == len(parts) or parts[i] in OPTKEYS:
                            key = parts[last]
                            value = " ".join(parts[last + 1:i])
                            if "type" in dic and dic["type"] in TYPEDIC:
                                value = TYPEDIC[dic["type"]](value)

                            if key == "var":
                                varlist.append(value)
                            elif key == "type" and value == "string":
                                dic[key] = "text"
                            else:
                                dic[key] = value

                            last = i
                    if varlist:
                        dic["choices"] = varlist

                    if "name" in dic:
                        self.options[dic["name"]] = dic
                    continue

                # A Move
                if self.mode == NORMAL and parts[0] == "bestmove":
                    self.needBestmove = False
                    self.bestmove_event.set()
                    self.__sendQueuedGo()

                    if self.ignoreNext:
                        log.debug(
                            "__parseLine: line='%s' self.ignoreNext==True, returning"
                            % line.strip(),
                            extra={"task": self.defname})
                        self.ignoreNext = False
                        self.readyForStop = True
                        continue

                    movestr = parts[1]
                    if not self.waitingForMove:
                        log.warning(
                            "__parseLine: self.waitingForMove==False, ignoring move=%s"
                            % movestr,
                            extra={"task": self.defname})
                        self.pondermove = None
                        continue
                    self.waitingForMove = False

                    try:
                        move = parseAny(self.board, movestr)
                    except ParsingError:
                        self.invalid_move = movestr
                        log.info(
                            "__parseLine: ParsingError engine move: %s %s" %
                            (movestr, self.board),
                            extra={"task": self.defname})
                        self.end(
                            WHITEWON if self.board.color == BLACK else
                            BLACKWON, WON_ADJUDICATION)
                        continue

                    if not validate(self.board, move):
                        # This is critical. To avoid game stalls, we need to resign on
                        # behalf of the engine.
                        log.error(
                            "__parseLine: move=%s didn't validate, putting 'del' \
                                  in returnQueue. self.board=%s" %
                            (repr(move), self.board),
                            extra={"task": self.defname})
                        self.invalid_move = movestr
                        self.end(
                            WHITEWON if self.board.color == BLACK else
                            BLACKWON, WON_ADJUDICATION)
                        continue

                    self._recordMove(self.board.move(move), move, self.board)
                    log.debug("__parseLine: applied move=%s to self.board=%s" %
                              (move, self.board),
                              extra={"task": self.defname})

                    if self.ponderOn:
                        self.pondermove = None
                        # An engine may send an empty ponder line, simply to clear.
                        if len(parts) == 4:
                            # Engines don't always check for everything in their
                            # ponders. Hence we need to validate.
                            # But in some cases, what they send may not even be
                            # correct AN - specially in the case of promotion.
                            try:
                                pondermove = parseAny(self.board, parts[3])
                            except ParsingError:
                                pass
                            else:
                                if validate(self.board, pondermove):
                                    self.pondermove = pondermove
                                    self._startPonder()

                    self.queue.put_nowait(move)
                    log.debug("__parseLine: put move=%s into self.queue=%s" %
                              (move, self.queue),
                              extra={"task": self.defname})
                    continue

                # An Analysis
                if self.mode != NORMAL and parts[0] == "info" and "pv" in parts:
                    multipv = 1
                    if "multipv" in parts:
                        multipv = int(parts[parts.index("multipv") + 1])
                    scoretype = parts[parts.index("score") + 1]
                    if scoretype in ('lowerbound', 'upperbound'):
                        score = None
                    else:
                        score = int(parts[parts.index("score") + 2])
                        if scoretype == 'mate':
                            #                    print >> self.engine, "stop"
                            if score != 0:
                                sign = score / abs(score)
                                score = sign * (MATE_VALUE - abs(score))

                    movstrs = parts[parts.index("pv") + 1:]

                    if "depth" in parts:
                        depth = parts[parts.index("depth") + 1]
                    else:
                        depth = ""

                    if "nps" in parts:
                        nps = parts[parts.index("nps") + 1]
                    else:
                        nps = ""

                    if multipv <= len(self.analysis):
                        self.analysis[multipv - 1] = (self.board.ply, movstrs,
                                                      score, depth, nps)
                    self.emit("analyze", self.analysis)
                    continue

                # An Analyzer bestmove
                if self.mode != NORMAL and parts[0] == "bestmove":
                    log.debug(
                        "__parseLine: processing analyzer bestmove='%s'" %
                        line.strip(),
                        extra={"task": self.defname})
                    self.needBestmove = False
                    self.bestmove_event.set()
                    if parts[1] == "(none)":
                        self.emit("analyze", [])
                    else:
                        self.__sendQueuedGo(sendlast=True)
                    continue

                # Stockfish complaining it received a 'stop' without a corresponding 'position..go'
                if line.strip() == "Unknown command: stop":
                    log.debug("__parseLine: processing '%s'" % line.strip(),
                              extra={"task": self.defname})
                    self.ignoreNext = False
                    self.needBestmove = False
                    self.readyForStop = False
                    self.__sendQueuedGo()
                    continue
Beispiel #59
0
    def do_import(self, filename, info=None, progressbar=None):
        self.progressbar = progressbar

        orig_filename = filename
        count_source = self.conn.execute(
            self.count_source.where(source.c.name == orig_filename)).scalar()
        if count_source > 0:
            log.info("%s is already imported" % filename)
            return

        # collect new names not in they dict yet
        self.event_data = []
        self.site_data = []
        self.player_data = []
        self.annotator_data = []
        self.source_data = []

        # collect new games and commit them in big chunks for speed
        self.game_data = []
        self.tag_game_data = []

        if filename.startswith("http"):
            filename = download_file(filename, progressbar=progressbar)
            if filename is None:
                return
        else:
            if not os.path.isfile(filename):
                log.info("Can't open %s" % filename)
                return

        if filename.lower().endswith(".zip") and zipfile.is_zipfile(filename):
            with zipfile.ZipFile(filename, "r") as zf:
                path = os.path.dirname(filename)
                files = [
                    os.path.join(path, f) for f in zf.namelist()
                    if f.lower().endswith(".pgn")
                ]
                zf.extractall(path)
        else:
            files = [filename]

        for pgnfile in files:
            base_offset = self.chessfile.size if self.append_pgn else 0

            basename = os.path.basename(pgnfile)
            if progressbar is not None:
                GLib.idle_add(progressbar.set_text,
                              _("Reading %s ..." % basename))
            else:
                log.info("Reading %s ..." % pgnfile)

            size = os.path.getsize(pgnfile)
            handle = protoopen(pgnfile)

            # estimated game count
            all_games = max(size / 840, 1)

            get_id = self.get_id

            # use transaction to avoid autocommit slowness
            # and to let undo importing (rollback) if self.cancel was set
            trans = self.conn.begin()
            try:
                i = 0
                for tags in read_games(handle):
                    if not tags:
                        log.info("Empty game #%s" % (i + 1))
                        continue

                    if self.cancel:
                        trans.rollback()
                        return

                    fenstr = tags["FEN"]

                    variant = tags["Variant"]
                    if variant:
                        if "fischer" in variant.lower() or "960" in variant:
                            variant = "Fischerandom"
                        else:
                            variant = variant.lower().capitalize()

                    # Fixes for some non statndard Chess960 .pgn
                    if fenstr and variant == "Fischerandom":
                        parts = fenstr.split()
                        parts[0] = parts[0].replace(".", "/").replace("0", "")
                        if len(parts) == 1:
                            parts.append("w")
                            parts.append("-")
                            parts.append("-")
                        fenstr = " ".join(parts)

                    if variant:
                        if variant not in name2variant:
                            log.info("Unknown variant: %s" % variant)
                            continue
                        variant = name2variant[variant].variant
                        if variant == NORMALCHESS:
                            # lichess uses tag [Variant "Standard"]
                            variant = 0
                    else:
                        variant = 0

                    if basename == "eco.pgn":
                        white = tags["Opening"]
                        black = tags["Variation"]
                    else:
                        white = tags["White"]
                        black = tags["Black"]

                    event_id = get_id(tags["Event"], event, EVENT)

                    site_id = get_id(tags["Site"], site, SITE)

                    date = tags["Date"]

                    game_round = tags['Round']

                    white_id = get_id(white, player, PLAYER)
                    black_id = get_id(black, player, PLAYER)

                    result = tags["Result"]
                    if result in pgn2Const:
                        result = pgn2Const[result]
                    else:
                        result = RUNNING

                    white_elo = tags['WhiteElo']
                    black_elo = tags['BlackElo']

                    time_control = tags["TimeControl"]

                    eco = tags["ECO"][:3]

                    fen = tags["FEN"]

                    board_tag = int(tags["Board"]) if "Board" in tags else 0

                    annotator_id = get_id(tags["Annotator"], annotator,
                                          ANNOTATOR)

                    source_id = get_id(orig_filename,
                                       source,
                                       SOURCE,
                                       info=info)

                    ply_count = tags["PlyCount"] if "PlyCount" in tags else 0

                    offset = base_offset + int(tags["offset"])

                    self.game_data.append({
                        'offset': offset,
                        'offset8': (offset >> 3) << 3,
                        'event_id': event_id,
                        'site_id': site_id,
                        'date': date,
                        'round': game_round,
                        'white_id': white_id,
                        'black_id': black_id,
                        'result': result,
                        'white_elo': white_elo,
                        'black_elo': black_elo,
                        'ply_count': ply_count,
                        'eco': eco,
                        'fen': fen,
                        'variant': variant,
                        'board': board_tag,
                        'time_control': time_control,
                        'annotator_id': annotator_id,
                        'source_id': source_id,
                    })

                    for tag in tags:
                        if tag not in dedicated_tags and tag not in other_game_tags and tags[
                                tag]:
                            self.tag_game_data.append({
                                'game_id':
                                self.next_id[GAME],
                                'tag_name':
                                tag,
                                'tag_value':
                                tags[tag],
                            })

                    self.next_id[GAME] += 1
                    i += 1

                    if len(self.game_data) >= self.CHUNK:
                        if self.event_data:
                            self.conn.execute(self.ins_event, self.event_data)
                            self.event_data = []

                        if self.site_data:
                            self.conn.execute(self.ins_site, self.site_data)
                            self.site_data = []

                        if self.player_data:
                            self.conn.execute(self.ins_player,
                                              self.player_data)
                            self.player_data = []

                        if self.annotator_data:
                            self.conn.execute(self.ins_annotator,
                                              self.annotator_data)
                            self.annotator_data = []

                        if self.source_data:
                            self.conn.execute(self.ins_source,
                                              self.source_data)
                            self.source_data = []

                        if self.tag_game_data:
                            self.conn.execute(self.ins_tag_game,
                                              self.tag_game_data)
                            self.tag_game_data = []

                        self.conn.execute(self.ins_game, self.game_data)
                        self.game_data = []

                        if progressbar is not None:
                            GLib.idle_add(progressbar.set_fraction,
                                          i / float(all_games))
                            GLib.idle_add(
                                progressbar.set_text,
                                _("%(counter)s game headers from %(filename)s imported"
                                  % ({
                                      "counter": i,
                                      "filename": basename
                                  })))
                        else:
                            log.info("From %s imported %s" % (pgnfile, i))

                if self.event_data:
                    self.conn.execute(self.ins_event, self.event_data)
                    self.event_data = []

                if self.site_data:
                    self.conn.execute(self.ins_site, self.site_data)
                    self.site_data = []

                if self.player_data:
                    self.conn.execute(self.ins_player, self.player_data)
                    self.player_data = []

                if self.annotator_data:
                    self.conn.execute(self.ins_annotator, self.annotator_data)
                    self.annotator_data = []

                if self.source_data:
                    self.conn.execute(self.ins_source, self.source_data)
                    self.source_data = []

                if self.tag_game_data:
                    self.conn.execute(self.ins_tag_game, self.tag_game_data)
                    self.tag_game_data = []

                if self.game_data:
                    self.conn.execute(self.ins_game, self.game_data)
                    self.game_data = []

                if progressbar is not None:
                    GLib.idle_add(progressbar.set_fraction,
                                  i / float(all_games))
                    GLib.idle_add(
                        progressbar.set_text,
                        _("%(counter)s game headers from %(filename)s imported"
                          % ({
                              "counter": i,
                              "filename": basename
                          })))
                else:
                    log.info("From %s imported %s" % (pgnfile, i))
                trans.commit()

                if self.append_pgn:
                    # reopen database to write
                    self.db_handle.close()
                    with protosave(self.chessfile.path,
                                   self.append_pgn) as self.db_handle:
                        log.info("Append from %s to %s" %
                                 (pgnfile, self.chessfile.path))
                        handle.seek(0)
                        self.db_handle.writelines(handle)
                        handle.close()

                    if self.chessfile.scoutfish is not None:
                        # create new .scout from pgnfile we are importing
                        from pychess.Savers.pgn import scoutfish_path
                        args = [
                            scoutfish_path, "make", pgnfile,
                            "%s" % base_offset
                        ]
                        output = subprocess.check_output(
                            args, stderr=subprocess.STDOUT).decode()

                        # append it to our existing one
                        if output.find("Processing...done") > 0:
                            old_scout = self.chessfile.scoutfish.db
                            new_scout = os.path.splitext(pgnfile)[0] + '.scout'

                            with open(old_scout,
                                      "ab") as file1, open(new_scout,
                                                           "rb") as file2:
                                file1.write(file2.read())

                self.chessfile.handle = protoopen(self.chessfile.path)

            except SQLAlchemyError as e:
                trans.rollback()
                log.info("Importing %s failed! \n%s" % (pgnfile, e))
Beispiel #60
0
    def parseLine(self, proc):
        while True:
            line = yield from wait_signal(proc, 'line')
            if not line:
                break
            else:
                line = line[1]
                if line[0:1] == "#":
                    # Debug line which we shall ignore as specified in CECPv2 specs
                    continue

        #        log.debug("__parseLine: line=\"%s\"" % line.strip(), extra={"task":self.defname})
                parts = whitespaces.split(line.strip())
                if parts[0] == "pong":
                    self.lastpong = int(parts[1])
                    continue

                # Illegal Move
                if parts[0].lower().find("illegal") >= 0:
                    log.warning("__parseLine: illegal move: line=\"%s\", board=%s" % (
                        line.strip(), self.board), extra={"task": self.defname})
                    if parts[-2] == "sd" and parts[-1].isdigit():
                        print("depth", parts[-1], file=self.engine)
                    continue

                # A Move (Perhaps)
                if self.board:
                    if parts[0] == "move":
                        movestr = parts[1]
                    # Old Variation
                    elif d_plus_dot_expr.match(parts[0]) and parts[1] == "...":
                        movestr = parts[2]
                    else:
                        movestr = False

                    if movestr:
                        self.waitingForMove = False
                        self.readyForMoveNowCommand = False
                        if self.engineIsInNotPlaying:
                            # If engine was set in pause just before the engine sent its
                            # move, we ignore it. However the engine has to know that we
                            # ignored it, and thus we step it one back
                            log.info("__parseLine: Discarding engine's move: %s" %
                                     movestr,
                                     extra={"task": self.defname})
                            print("undo", file=self.engine)
                            continue
                        else:
                            try:
                                move = parseAny(self.board, movestr)
                            except ParsingError:
                                self.invalid_move = movestr
                                log.info(
                                    "__parseLine: ParsingError engine move: %s %s"
                                    % (movestr, self.board),
                                    extra={"task": self.defname})
                                self.end(WHITEWON if self.board.color == BLACK else
                                         BLACKWON, WON_ADJUDICATION)
                                continue

                            if validate(self.board, move):
                                self.board = None
                                self.queue.put_nowait(move)
                                continue
                            else:
                                self.invalid_move = movestr
                                log.info(
                                    "__parseLine: can't validate engine move: %s %s"
                                    % (movestr, self.board),
                                    extra={"task": self.defname})
                                self.end(WHITEWON if self.board.color == BLACK else
                                         BLACKWON, WON_ADJUDICATION)
                                continue

                # Analyzing
                if self.engineIsInNotPlaying:
                    if parts[:4] == ["0", "0", "0", "0"]:
                        # Crafty doesn't analyze until it is out of book
                        print("book off", file=self.engine)
                        continue

                    match = anare.match(line)
                    if match:
                        depth, score, moves = match.groups()

                        if "mat" in score.lower() or "#" in moves:
                            # Will look either like -Mat 3 or Mat3
                            scoreval = MATE_VALUE
                            if score.startswith('-'):
                                scoreval = -scoreval
                        else:
                            scoreval = int(score)

                        mvstrs = movere.findall(moves)
                        if mvstrs:
                            self.emit("analyze", [(mvstrs, scoreval, depth.strip())])

                        continue

                # Offers draw
                if parts[0:2] == ["offer", "draw"]:
                    self.emit("accept", Offer(DRAW_OFFER))
                    continue

                # Resigns
                if parts[0] == "resign" or \
                        (parts[0] == "tellics" and parts[1] == "resign"):  # buggy crafty

                    # Previously: if "resign" in parts,
                    # however, this is too generic, since "hint", "bk",
                    # "feature option=.." and possibly other, future CECPv2
                    # commands can validly contain the word "resign" without this
                    # being an intentional resign offer.

                    self.emit("offer", Offer(RESIGNATION))
                    continue

                # if parts[0].lower() == "error":
                #    continue

                # Tell User Error
                if parts[0] == "tellusererror":
                    # We don't want to see our stop analyzer hack as an error message
                    if "8/8/8/8/8/8/8/8" in "".join(parts[1:]):
                        continue
                    # Create a non-modal non-blocking message dialog with the error:
                    dlg = Gtk.MessageDialog(parent=None,
                                            flags=0,
                                            type=Gtk.MessageType.WARNING,
                                            buttons=Gtk.ButtonsType.CLOSE,
                                            message_format=None)

                    # Use the engine name if already known, otherwise the defname:
                    displayname = self.name
                    if not displayname:
                        displayname = self.defname

                    # Compose the dialog text:
                    dlg.set_markup(GObject.markup_escape_text(_(
                        "The engine %s reports an error:") % displayname) + "\n\n" +
                        GObject.markup_escape_text(" ".join(parts[1:])))

                    # handle response signal so the "Close" button works:
                    dlg.connect("response", lambda dlg, x: dlg.destroy())

                    dlg.show_all()
                    continue

                # Tell Somebody
                if parts[0][:4] == "tell" and \
                        parts[0][4:] in ("others", "all", "ics", "icsnoalias"):

                    log.info("Ignoring tell %s: %s" %
                             (parts[0][4:], " ".join(parts[1:])))
                    continue

                if "feature" in parts:
                    # Some engines send features after done=1, so we will iterate after done=1 too
                    done1 = False
                    # We skip parts before 'feature', as some engines give us lines like
                    # White (1) : feature setboard=1 analyze...e="GNU Chess 5.07" done=1
                    parts = parts[parts.index("feature"):]
                    for i, pair in enumerate(parts[1:]):

                        # As "parts" is split with no thoughs on quotes or double quotes
                        # we need to do some extra handling.

                        if pair.find("=") < 0:
                            continue
                        key, value = pair.split("=", 1)

                        if key not in self.features:
                            continue

                        if value.startswith('"') and value.endswith('"'):
                            value = value[1:-1]

                        # If our pair was unfinished, like myname="GNU, we search the
                        # rest of the pairs for a quotating mark.
                        elif value[0] == '"':
                            rest = value[1:] + " " + " ".join(parts[2 + i:])
                            j = rest.find('"')
                            if j == -1:
                                log.warning("Missing endquotation in %s feature",
                                            extra={"task": self.defname})
                                value = rest
                            else:
                                value = rest[:j]

                        elif value.isdigit():
                            value = int(value)

                        if key in self.supported_features:
                            print("accepted %s" % key, file=self.engine)
                        else:
                            print("rejected %s" % key, file=self.engine)

                        if key == "done":
                            if value == 1:
                                done1 = True
                                continue
                            elif value == 0:
                                log.info("Adds %d seconds timeout" % TIME_OUT_SECOND,
                                         extra={"task": self.defname})
                                # This'll buy you some more time
                                self.queue.put_nowait("not ready")
                                break

                        if key == "smp" and value == 1:
                            self.options["cores"] = {"name": "cores",
                                                     "type": "spin",
                                                     "default": 1,
                                                     "min": 1,
                                                     "max": 64}
                        elif key == "memory" and value == 1:
                            self.options["memory"] = {"name": "memory",
                                                      "type": "spin",
                                                      "default": 32,
                                                      "min": 1,
                                                      "max": 4096}
                        elif key == "option" and key != "done":
                            option = self.__parse_option(value)
                            self.options[option["name"]] = option
                        else:
                            self.features[key] = value

                        if key == "myname" and not self.name:
                            self.setName(value)

                    if done1:
                        # Start a new game before using the engine:
                        # (CECPv2 engines)
                        print("new", file=self.engine)

                        # We are now ready for play:
                        self.emit("readyForOptions")
                        self.emit("readyForMoves")
                        self.queue.put_nowait("ready")

                # A hack to get better names in protover 1.
                # Unfortunately it wont work for now, as we don't read any lines from
                # protover 1 engines. When should we stop?
                if self.protover == 1:
                    if self.defname[0] in ''.join(parts):
                        basis = self.defname[0]
                        name = ' '.join(itertools.dropwhile(
                            lambda part: basis not in part, parts))
                        self.features['myname'] = name
                        if not self.name:
                            self.setName(name)