def checkMovie(self, movie): imdbNumber = movie["imdbnumber"] oldPosition = movie["top250"] if imdbNumber == "": util.logWarning("%(label)s: no IMDb id" % movie) return None if imdbNumber in self.top250: newPosition = self.top250[imdbNumber]["position"] self.notMissing.add(imdbNumber) if oldPosition == newPosition: util.logDebug("%(label)s: up to date" % movie) return None self.updateMovie(movie, newPosition) if oldPosition == 0: util.log("%s: added at position %s" % (movie["label"], newPosition)) return "added" util.log("%s: updated from %s to %s" % (movie["label"], oldPosition, newPosition)) return "updated" if oldPosition != 0: util.log("%(label)s: was removed because no more in IMDb Top250" % movie) self.updateMovie(movie, 0) return "removed"
def remote_tableRemoved(self, tableid, message, *args): """update table list""" Client.remote_tableRemoved(self, tableid, message, *args) self.__updateTableList() if message: if not self.name in args or not message.endswith('has logged out'): logWarning(m18n(message, *args))
def disagree(about): """do not bother to translate this, it should normally not happen""" self.game.close() msg = 'The data bases for game %s have different %s' % ( self.game.seed, about) logWarning(msg) raise pb.Error(msg)
def rollback(self, silent=None): """rollback and log it""" if QSqlDatabase.rollback(self): if not silent and Debug.sql: logDebug('%x rollbacked transaction' % id(self)) else: logWarning('%s cannot rollback: %s' % (self.name, self.lastError()))
def __checkExistingConnections(self): """do we already have a connection to the wanted URL?""" for client in self.client.humanClients: if client.connection and client.connection.url == self.url: logWarning(m18n('You are already connected to server %1', self.url)) client.tableList.activateWindow() raise CancelledError
def transaction(self, silent=None): """commit and log it""" if QSqlDatabase.transaction(self): if not silent and Debug.sql: logDebug('%x started transaction' % id(self)) else: logWarning('%s cannot start transaction: %s' % (self.name, self.lastError()))
def __checkExistingConnections(self): """do we already have a connection to the wanted URL?""" for client in self.client.humanClients: if client.connection and client.connection.url == self.url: logWarning( m18n('You are already connected to server %1', self.url)) client.tableList.activateWindow() raise CancelledError
def commit(self, silent=None): """commit and log it""" result = QSqlDatabase.commit(self) if result: if not silent and Debug.sql: logDebug('%x committed transaction' % id(self)) else: logWarning('%s cannot commit: %s :' % (self.name, self.lastError()))
def tableError(self, err): """log the twisted error""" if not self.connection: # lost connection to server if self.tableList: self.tableList.hide() self.tableList = None else: logWarning(err.getErrorMessage())
def __init__(self, name=None, dbhandle=None): """start a transaction""" self.dbhandle = dbhandle or Query.dbhandle if name is None: dummy, dummy, name, dummy = traceback.extract_stack()[-2] self.name = '%s on %s' % (name or '', self.dbhandle.databaseName()) if not self.dbhandle.transaction(): logWarning('%s cannot start: %s' % ( self.name, self.dbhandle.lastError().text())) self.active = True self.startTime = datetime.datetime.now()
def tableError(self, err): """log the twisted error""" if not self.client.perspective: # lost connection to server for table in self.view.model().tables: if table.chatWindow: table.chatWindow.hide() self.hide() self.client.tableList = None else: logWarning(err.getErrorMessage())
def findOgg(): """sets __hasogg to True or False""" if Sound.__hasogg is None: oggName = r'c:\vorbis\oggdec.exe' if os.name == 'nt' else 'ogg123' if not which(oggName): Sound.enabled = False # checks again at next reenable logWarning(m18n('No voices will be heard because the program %1 is missing', oggName)) return Sound.__hasogg = True return Sound.__hasogg
def __init__(self, desktopFileName=None): if desktopFileName is None: desktopFileName = 'default' self.tileSize = None self.faceSize = None self.__renderer = None self.__shadowOffsets = None self.defineCatalog() self.path = locateTileset(desktopFileName + '.desktop') if self.path.isEmpty(): self.path = locateTileset('default.desktop') if self.path.isEmpty(): directories = '\n\n' +'\n'.join(str(x) for x in KGlobal.dirs().resourceDirs("kmahjonggtileset")) logException(TileException(m18n( \ 'cannot find any tileset in the following directories, is libkmahjongg installed?') + directories)) else: logWarning(m18n('cannot find tileset %1, using default', desktopFileName)) self.desktopFileName = 'default' else: self.desktopFileName = desktopFileName self.darkenerAlpha = 120 if self.desktopFileName == 'jade' else 50 tileconfig = KConfig(self.path, KConfig.SimpleConfig) group = KConfigGroup(tileconfig.group("KMahjonggTileset")) self.name = group.readEntry("Name", "unknown tileset").toString() # Returns translated data self.author = group.readEntry("Author", "unknown author").toString() self.description = group.readEntry("Description", "no description available").toString() self.authorEmail = group.readEntry("AuthorEmail", "no E-Mail address available").toString() #Version control tileversion, entryOK = group.readEntry("VersionFormat", QVariant(0)).toInt() #Format is increased when we have incompatible changes, meaning that # older clients are not able to use the remaining information safely if not entryOK or tileversion > TILESETVERSIONFORMAT: logException(TileException('tileversion file / program: %d/%d' % \ (tileversion, TILESETVERSIONFORMAT))) graphName = QString(group.readEntry("FileName")) self.__graphicspath = locateTileset(graphName) if self.__graphicspath.isEmpty(): logException(TileException('cannot find kmahjongglib/tilesets/%s for %s' % \ (graphName, self.desktopFileName ))) self.renderer() # now that we get the sizes from the svg, we need the renderer right away self.svgName = { 'wn': 'WIND_1', 'ws': 'WIND_2', 'we': 'WIND_3', 'ww': 'WIND_4', 'db': 'DRAGON_1', 'dg': 'DRAGON_2', 'dr': 'DRAGON_3'} for value in '123456789': self.svgName['s%s' % value] = 'ROD_%s' % value self.svgName['b%s' % value] = 'BAMBOO_%s' % value self.svgName['c%s' % value] = 'CHARACTER_%s' % value for idx, wind in enumerate('eswn'): self.svgName['f%s' % wind] = 'FLOWER_%d' % (idx + 1) self.svgName['y%s' % wind] = 'SEASON_%d' % (idx + 1)
def scoreMatchesServer(self, score): """do we compute the same score as the server does?""" if score is None: return True if 'Xy' in self.__concealedTileNames: return True if str(self.hand) == score: return True self.game.debug('%s localScore:%s' % (self, self.hand)) self.game.debug('%s serverScore:%s' % (self, score)) logWarning('Game %s: client and server disagree about scoring, see logfile for details' % self.game.seed) return False
def remote_abort(self, tableid, message, *args): """the server aborted this game""" if self.table and self.table.tableid == tableid: # translate Robot to Roboter: if self.game: args = self.game.players.translatePlayerNames(args) logWarning(m18n(message, *args)) if self.game: self.game.close() if self.game.autoPlay: if Internal.field: Internal.field.close()
def __exit__(self, exc_type, exc_value, trback): """end the transaction""" diff = datetime.datetime.now() - self.startTime if diff > datetime.timedelta(seconds=1.0): logWarning('%s took %d.%06d seconds' % ( self.dbhandle.name, diff.seconds, diff.microseconds)) if self.active and trback is None: self.dbhandle.commit(silent=self.silent) else: self.dbhandle.rollback(silent=self.silent) if exc_type: exc_type(exc_value)
def canReuseSession(self): """Return True if prior session can be used to communicate with engine.""" self.dprint("test if session can be reused") if not self.sessionFilename or not os.path.exists(self.sessionFilename): return False try: f = open(self.sessionFilename) sessionInfo = json.load(f) f.close() except (IOError, OSError, ValueError), err: trutil.logWarning("problem reading session file: %s" % str(err)) return False
def __exit__(self, exc_type, exc_value, trback): """end the transaction""" diff = datetime.datetime.now() - self.startTime if diff > datetime.timedelta(seconds=1.0): logWarning('%s took %d.%06d seconds' % (self.dbhandle.name, diff.seconds, diff.microseconds)) if self.active and trback is None: self.dbhandle.commit(silent=self.silent) else: self.dbhandle.rollback(silent=self.silent) if exc_type: exc_type(exc_value)
def __init__(self, desktopFileName=None): if desktopFileName is None: desktopFileName = 'default' self.__svg = None self.__pmap = None QPixmapCache.setCacheLimit(20480) # the chinese landscape needs much self.defineCatalog() self.desktopFileName = desktopFileName self.path = locatebackground(desktopFileName + '.desktop') if self.path.isEmpty(): self.path = locatebackground('default.desktop') if self.path.isEmpty(): directories = '\n\n' + '\n'.join( str(x) for x in KGlobal.dirs().resourceDirs( "kmahjonggbackground")) logException(BackgroundException(m18n( \ 'cannot find any background in the following directories, is libkmahjongg installed?') + directories)) else: logWarning( m18n('cannot find background %1, using default', desktopFileName)) self.desktopFileName = 'default' config, group = konfigGroup(self.path, "KMahjonggBackground") assert config self.name = group.readEntry( "Name", "unknown background").toString() # Returns translated data #Version control backgroundversion, entryOK = group.readEntry("VersionFormat", QVariant(0)).toInt() #Format is increased when we have incompatible changes, meaning that # older clients are not able to use the remaining information safely if not entryOK or backgroundversion > BACKGROUNDVERSIONFORMAT: logException(BackgroundException('backgroundversion file / program: %d/%d' % \ (backgroundversion, BACKGROUNDVERSIONFORMAT))) self.tiled = group.readEntry('Tiled') == '1' if self.tiled: self.imageWidth, entryOk = group.readEntry('Width').toInt() if not entryOk: raise Exception('cannot scan Width from background file') self.imageHeight, entryOk = group.readEntry('Height').toInt() if not entryOk: raise Exception('cannot scan Height from background file') self.isPlain = bool(group.readEntry('Plain')) if not self.isPlain: graphName = QString(group.readEntry("FileName")) self.__graphicspath = locatebackground(graphName) if self.__graphicspath.isEmpty(): logException(BackgroundException( 'cannot find kmahjongglib/backgrounds/%s for %s' % \ (graphName, self.desktopFileName )))
def parseCategory(self): cate = [] for c in self.category: category = self.site.convertToConfigedCategory(c) if category: if category not in cate: cate_obj = Category(self.site, category) cate.append(cate_obj) else: util.logInfo( "category: '%s' already exists IN '%s'", c, self.site.getRelativePath(self.source) ) else: util.logWarning( "unavailable category: '%s' IN %s", c, self.site.getRelativePath(self.source) ) self.category = cate
def _loginReallyFailed(self, failure): """login failed, not fixable by adding missing user""" msg = self._prettifyErrorMessage(failure) if failure.check(CancelledError): # show no warning, just leave return failure if 'Errno 5' in msg: # The server is running but something is wrong with it if self.useSocket and os.name != 'nt': if removeIfExists(socketName()): logInfo(m18n('removed stale socket <filename>%1</filename>', socketName())) msg += '\n\n\n' + m18n('Please try again') logWarning(msg) return failure
def findOgg(): """sets __hasogg to True or False""" if Sound.__hasogg is None: oggName = r'c:\vorbis\oggdec.exe' if os.name == 'nt' else 'ogg123' if not which(oggName): Sound.enabled = False # checks again at next reenable logWarning( m18n( 'No voices will be heard because the program %1 is missing', oggName)) return Sound.__hasogg = True return Sound.__hasogg
def kajonggServer(): """start the server""" from optparse import OptionParser parser = OptionParser() defaultPort = InternalParameters.defaultPort() parser.add_option('', '--port', dest='port', help=m18n('the server will listen on PORT (%d)' % defaultPort), type=int, default=defaultPort) parser.add_option('', '--socket', dest='socket', help=m18n('the server will listen on SOCKET'), default=None) parser.add_option('', '--db', dest='dbpath', help=m18n('name of the database'), default=None) parser.add_option('', '--local', dest='local', action='store_true', help=m18n('start a local game server'), default=False) parser.add_option('', '--continue', dest='continueServer', action='store_true', help=m18n('do not terminate local game server after last client disconnects'), default=False) parser.add_option('', '--debug', dest='debug', help=Debug.help()) (options, args) = parser.parse_args() if args and ''.join(args): logWarning(m18n('unrecognized arguments:%1', ' '.join(args))) sys.exit(2) InternalParameters.continueServer |= options.continueServer if options.dbpath: InternalParameters.dbPath = os.path.expanduser(options.dbpath) if options.local: InternalParameters.socket = socketName() if options.socket: InternalParameters.socket = options.socket Debug.setOptions(options.debug) Query.dbhandle = initDb() realm = MJRealm() realm.server = MJServer() kajonggPortal = portal.Portal(realm, [DBPasswordChecker()]) # pylint: disable=E1101 # pylint thinks reactor is missing listen* and run loadPredefinedRulesets() try: if InternalParameters.socket: if os.name == 'nt': logInfo('local server listening on 127.0.0.1 port %d' % options.port) reactor.listenTCP(options.port, pb.PBServerFactory(kajonggPortal), interface='127.0.0.1') else: logInfo('local server listening on UNIX socket %s' % InternalParameters.socket) reactor.listenUNIX(InternalParameters.socket, pb.PBServerFactory(kajonggPortal)) else: logInfo('server listening on port %d' % options.port) reactor.listenTCP(options.port, pb.PBServerFactory(kajonggPortal)) except error.CannotListenError, errObj: logWarning(errObj)
def updateMovie(self, movie, httphandler, LANG_MPAA): if movie["imdbnumber"] == "": util.logWarning("%(label)s: no IMDb id" % movie) else: mpaa = imdbMpaa(movie["imdbnumber"], httphandler, LANG_MPAA) formattedRating = ("%s%s" if ":" in FORM_MPAA else "%s %s") % (FORM_MPAA, mpaa.rating()) if mpaa.error(): util.logError("%s: problem with MPAA site" % movie["label"]) elif movie["mpaa"] != formattedRating: util.executeJSON('VideoLibrary.SetMovieDetails', {'movieid':movie['movieid'], 'mpaa':formattedRating}) util.log("%s: updated from %s to %s" % (movie["label"], movie["mpaa"], formattedRating)) return 1 return 0
def _loginReallyFailed(self, failure): """login failed, not fixable by adding missing user""" msg = self._prettifyErrorMessage(failure) if failure.check(CancelledError): # show no warning, just leave return failure if 'Errno 5' in msg: # The server is running but something is wrong with it if self.useSocket and os.name != 'nt': if removeIfExists(socketName()): logInfo( m18n('removed stale socket <filename>%1</filename>', socketName())) msg += '\n\n\n' + m18n('Please try again') logWarning(msg) return failure
def contentFilter(self, content): if self.isMarkdown: content = util.markdown(content) #! 临时将 plugins目录添加到系统目录 #? 如果不加 mod = __import__(f) 会失败 WHY? sys.path.insert(0, os.path.join(SCRIPT_PATH, 'plugins')) filters = self.site.contentFilter; for f in filters: #if True: try: mod = __import__(f) content = getattr(mod, 'parse')(content, gude_site=self.site, gude_article=self) except: util.logWarning( 'content filter fail: %s', f ) #! 删除目录 del sys.path[0] return content
def __init__(self, desktopFileName=None): if desktopFileName is None: desktopFileName = 'default' self.__svg = None self.__pmap = None QPixmapCache.setCacheLimit(20480) # the chinese landscape needs much self.defineCatalog() self.desktopFileName = desktopFileName self.path = locatebackground(desktopFileName + '.desktop') if self.path.isEmpty(): self.path = locatebackground('default.desktop') if self.path.isEmpty(): directories = '\n\n' +'\n'.join(str(x) for x in KGlobal.dirs().resourceDirs("kmahjonggbackground")) logException(BackgroundException(m18n( \ 'cannot find any background in the following directories, is libkmahjongg installed?') + directories)) else: logWarning(m18n('cannot find background %1, using default', desktopFileName)) self.desktopFileName = 'default' config, group = konfigGroup(self.path, "KMahjonggBackground") assert config self.name = group.readEntry("Name", "unknown background").toString() # Returns translated data #Version control backgroundversion, entryOK = group.readEntry("VersionFormat", QVariant(0)).toInt() #Format is increased when we have incompatible changes, meaning that # older clients are not able to use the remaining information safely if not entryOK or backgroundversion > BACKGROUNDVERSIONFORMAT: logException(BackgroundException('backgroundversion file / program: %d/%d' % \ (backgroundversion, BACKGROUNDVERSIONFORMAT))) self.tiled = group.readEntry('Tiled') == '1' if self.tiled: self.imageWidth, entryOk = group.readEntry('Width').toInt() if not entryOk: raise Exception('cannot scan Width from background file') self.imageHeight, entryOk = group.readEntry('Height').toInt() if not entryOk: raise Exception('cannot scan Height from background file') self.isPlain = bool(group.readEntry('Plain')) if not self.isPlain: graphName = QString(group.readEntry("FileName")) self.__graphicspath = locatebackground(graphName) if self.__graphicspath.isEmpty(): logException(BackgroundException( 'cannot find kmahjongglib/backgrounds/%s for %s' % \ (graphName, self.desktopFileName )))
def selectScoringGame(self): """show all games, select an existing game or create a new game""" Players.load() if len(Players.humanNames) < 4: logWarning(m18n('Please define four players in <interface>Settings|Players</interface>')) return False gameSelector = Games(self) if gameSelector.exec_(): selected = gameSelector.selectedGame if selected is not None: ScoringGame.loadFromDB(selected) else: self.newGame() if self.game: self.game.throwDices() gameSelector.close() self.updateGUI() return bool(self.game)
def updateMovie(self, movie): if movie["imdbnumber"] == "": util.logWarning("%s: no IMDb id" % movie["label"]) else: imdb = imdbMovie(movie["imdbnumber"]) if imdb.error(): util.logError("%s: problem with omdbapi.com" % movie["label"]) elif (imdb.votes() == "0") or (imdb.votes() == "N/A"): util.logWarning("%s: no votes available" % movie["label"]) elif not(imdb.shouldUpdate(movie)): util.logDebug("%s: is up to date" % movie["label"]) else: util.executeJSON('VideoLibrary.SetMovieDetails', {'movieid': movie['movieid'], 'rating': float(imdb.rating()), 'votes': imdb.votes()}) util.log("%s: updated from %s (%s) to %s (%s)" % (movie["label"], movie["rating"], movie["votes"], imdb.rating(), imdb.votes())) return 1 return 0
def updateMovie(self, movie, httphandler, LANG_MPAA): if movie["imdbnumber"] == "": util.logWarning("%(label)s: no IMDb id" % movie) else: mpaa = imdbMpaa(movie["imdbnumber"], httphandler, LANG_MPAA) formattedRating = ("%s%s" if ":" in FORM_MPAA else "%s %s") % (FORM_MPAA, mpaa.rating()) if mpaa.error(): util.logError("%s: problem with MPAA site" % movie["label"]) elif movie["mpaa"] != formattedRating: util.executeJSON('VideoLibrary.SetMovieDetails', { 'movieid': movie['movieid'], 'mpaa': formattedRating }) util.log("%s: updated from %s to %s" % (movie["label"], movie["mpaa"], formattedRating)) return 1 return 0
def selectScoringGame(self): """show all games, select an existing game or create a new game""" Players.load() if len(Players.humanNames) < 4: logWarning( m18n( 'Please define four players in <interface>Settings|Players</interface>' )) return False gameSelector = Games(self) if gameSelector.exec_(): selected = gameSelector.selectedGame if selected is not None: ScoringGame.loadFromDB(selected) else: self.newGame() if self.game: self.game.throwDices() gameSelector.close() self.updateGUI() return bool(self.game)
def callServer(self, *args): """if we are online, call server""" if self.connection: if args[0] is None: args = args[1:] try: if Debug.traffic: if self.game: self.game.debug('callServer(%s)' % repr(args)) else: logDebug('callServer(%s)' % repr(args)) def callServerError(result): """if serverDisconnected has been called meanwhile, just ignore msg about connection lost in a non-clean fashion""" if self.connection: return result return self.connection.perspective.callRemote(*args).addErrback(callServerError) except pb.DeadReferenceError: logWarning(m18n('The connection to the server %1 broke, please try again later.', self.connection.url)) self.remote_serverDisconnects() return succeed(None) else: return succeed(None)
def parse(self): relative_source_path = self.site.getRelativePath(self.source) lines = [] try: with codecs.open(self.source, 'r', encoding='utf-8') as fp: lines = fp.readlines() except UnicodeDecodeError: util.logWarning( "invalid article: file encoding error, must be utf-8. '%s'", relative_source_path ) return False except Exception, e: util.logWarning( "invalid article: open fail fail '%s'", relative_source_path ) util.logWarning(e)
def __scanGameOption(self, wanted): """scan the --game option. Return roundsFinished, rotations, notRotated""" part = wanted.split('/')[1] roundsFinished = 'ESWN'.index(part[0]) if roundsFinished > self.ruleset.minRounds: logWarning('Ruleset %s has %d minimum rounds but you want round %d(%s)' % ( self.ruleset.name, self.ruleset.minRounds, roundsFinished + 1, part[0])) return self.ruleset.minRounds, 0 rotations = int(part[1]) - 1 notRotated = 0 if rotations > 3: logWarning('You want %d rotations, reducing to maximum of 3' % rotations) return roundsFinished, 3, 0 for char in part[2:]: if char < 'a': logWarning('you want %s, changed to a' % char) char = 'a' if char > 'z': logWarning('you want %s, changed to z' % char) char = 'z' notRotated = notRotated * 26 + ord(char) - ord('a') + 1 return roundsFinished, rotations, notRotated
def __exit__(self, exc_type, exc_value, trback): """end the transaction""" diff = datetime.datetime.now() - self.startTime if diff > datetime.timedelta(seconds=1.0): logWarning('%s took %d.%06d seconds' % ( self.name, diff.seconds, diff.microseconds)) if self.active and trback is None: if not self.dbhandle.commit(): logWarning('%s: cannot commit: %s' % ( self.name, self.dbhandle.lastError().text())) else: if not self.dbhandle.rollback(): logWarning('%s: cannot rollback: %s' % ( self.name, self.dbhandle.databaseName())) if exc_type: exc_type(exc_value)
def clientAction(self, dummyClient, move): """show the error message from server""" return logWarning(move.source)
self.custom = config.get('custom', self.custom) self.unlisted = config.get('unlisted', self.unlisted) self.status = config.get('status', self.status); self.category = util.tryToList(self.category) self.tag = util.tryToList(self.tag) self.unlisted = util.tryToList(self.unlisted) try: self.status = self.status.lower(); except Exception, e: self.status = str(self.status).lower() # 草稿 且 不是本地模式 if self.isDraft(): util.logWarning( "draft: '%s'", relative_source_path ) if not self.site.isLocalMode: return False # 检查date if not self.checkDateAvailable(): util.logWarning( "invalid article: date error '%s'", relative_source_path ) return False # 时间超出现在的文章 if self.date > datetime.now(): util.logWarning( "date out: %s", relative_source_path) return False # 不列出的文章 if len(self.unlisted):
def toolTip(self, dummyButton, dummyTile): """returns text and warning flag for button and text for tile for button and text for tile""" txt = 'toolTip is not defined for %s' % self.name logWarning(txt) return txt, True, ''
def __versionError(err): """log the twisted error""" logWarning(err.getErrorMessage()) Internal.field.abortGame() return err