def getFunnelURL(self): if patcherVer() == ['OFFLINE']: return if not patcherVer(): patcherHTTP = HTTPClient() if checkParamFile() == None: patcherDoc = patcherHTTP.getDocument(URLSpec('http://download.toontown.com/english/currentVersion/content/patcher.ver')) vconGroup('w', self.cgRelease) else: patcherDoc = patcherHTTP.getDocument(URLSpec(checkParamFile())) vconGroup('w', self.cgBeta) rf = Ramfile() patcherDoc.downloadToRam(rf) self.patcherURL = rf.getData() if self.patcherURL.find('FUNNEL_LOG') == -1: patcherVer('w', 'OFFLINE') return self.patcherURL = self.patcherURL.split('\n') del rf del patcherDoc del patcherHTTP while self.patcherURL: self.confLine = self.patcherURL.pop() if self.confLine.find('FUNNEL_LOG=') != -1 and self.confLine.find('#FUNNEL_LOG=') == -1: self.dynamicVRFunnel = self.confLine[11:].strip('\n') patcherVer('w', self.confLine[11:].strip('\n')) else: self.dynamicVRFunnel = patcherVer()[0] return
def redownloadNews(self): if self.redownloadingNews: self.notify.warning( 'averting potential crash redownloadNews called twice, just returning' ) return self.percentDownloaded = 0.0 self.notify.info('starting redownloadNews') self.startRedownload = datetime.datetime.now() self.redownloadingNews = True self.addDownloadingTextTask() for issue in self.issues: issue.destroy() self.issues = [] self.curIssueIndex = 0 self.strFilenames = None self.needsParseNews = True self.newsUrl = self.getInGameNewsUrl() self.newsDir = Filename(self.findNewsDir()) Filename(self.newsDir + '/.').makeDir() http = HTTPClient.getGlobalPtr() self.url = self.newsUrl + self.NewsIndexFilename self.ch = http.makeChannel(True) self.ch.beginGetDocument(self.url) self.rf = Ramfile() self.ch.downloadToRam(self.rf) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadIndexTask, self.RedownloadTaskName) return
def getFunnelURL(self): if patcherVer() == ['OFFLINE']: return if patcherVer() == []: patcherHTTP = HTTPClient() if checkParamFile() == None: patcherDoc = patcherHTTP.getDocument(URLSpec('http://download.toontown.com/english/currentVersion/content/patcher.ver')) vconGroup('w', self.cgRelease) else: patcherDoc = patcherHTTP.getDocument(URLSpec(checkParamFile())) vconGroup('w', self.cgBeta) rf = Ramfile() patcherDoc.downloadToRam(rf) self.patcherURL = rf.getData() if self.patcherURL.find('FUNNEL_LOG') == -1: patcherVer('w', 'OFFLINE') return self.patcherURL = self.patcherURL.split('\n') del rf del patcherDoc del patcherHTTP while self.patcherURL: self.confLine = self.patcherURL.pop() if self.confLine.find('FUNNEL_LOG=') != -1 and self.confLine.find('#FUNNEL_LOG=') == -1: self.dynamicVRFunnel = self.confLine[11:].strip('\n') patcherVer('w', self.confLine[11:].strip('\n')) else: self.dynamicVRFunnel = patcherVer()[0] return
def redownloadNews(self): if self.redownloadingNews: self.notify.warning("averting potential crash redownloadNews called twice, just returning") return self.percentDownloaded = 0.0 self.notify.info("starting redownloadNews") self.startRedownload = datetime.datetime.now() self.redownloadingNews = True self.addDownloadingTextTask() for issue in self.issues: issue.destroy() self.issues = [] self.curIssueIndex = 0 self.strFilenames = None self.needsParseNews = True self.newsUrl = self.getInGameNewsUrl() self.newsDir = Filename(self.findNewsDir()) Filename(self.newsDir + "/.").makeDir() http = HTTPClient.getGlobalPtr() self.url = self.newsUrl + self.NewsIndexFilename self.ch = http.makeChannel(True) self.ch.beginGetDocument(self.url) self.rf = Ramfile() self.ch.downloadToRam(self.rf) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadIndexTask, self.RedownloadTaskName) return
def ban(self, avatarId, dislid, comment): parameters = '' parameters += 'app=%s' % self.App parameters += '&product=%s' % self.Product parameters += '&user_id=%s' % dislid parameters += '&event_name=%s' % self.EventName commentWithAvatarId = 'avId-%s ' % avatarId commentWithAvatarId += comment parameters += '&comments=%s' % urllib.quote(str(commentWithAvatarId)) baseUrlToUse = self.BanUrl osBaseUrl = os.getenv('BAN_URL') if osBaseUrl: baseUrlToUse = osBaseUrl fullUrl = baseUrlToUse + '?' + parameters self.notify.info('ban request %s dislid=%s comment=%s fullUrl=%s' % (self.curBanRequestNum, dislid, comment, fullUrl)) simbase.air.writeServerEvent('ban_request', avatarId, '%s|%s|%s' % (dislid, comment, fullUrl)) if simbase.config.GetBool('do-actual-ban', True): newTaskName = 'ban-task-%d' % self.curBanRequestNum newTask = taskMgr.add(self.doBanUrlTask, newTaskName) newTask.banRequestNum = self.curBanRequestNum http = HTTPClient.getGlobalPtr() channel = http.makeChannel(False) self.channels[self.curBanRequestNum] = channel rf = Ramfile() self.ramFiles[self.curBanRequestNum] = rf channel.beginGetDocument(fullUrl) channel.downloadToRam(rf) self.curBanRequestNum += 1
def SendHeartbeat(self, task = None): baseUrl = 'http://modifire.net/heartbeat.php?' values = {'name' : Settings.SERVER_NAME, 'currentPlayers' : Globals.CURRENT_PLAYERS, 'maxPlayers' : Globals.MAX_PLAYERS, 'public' : Settings.SERVER_PUBLIC, 'port' : Globals.PORT_SERVER_LISTENER, 'version' : Globals.VERSION} for key, value in values.iteritems(): values[key] = urllib.quote(str(value)) params = [ baseUrl, 'name=%s' % (values['name']), 'currentPlayers=%s' % (values['currentPlayers']), 'maxPlayers=%s' % (values['maxPlayers']), 'public=%s' % (values['public']), 'port=%s' % (values['port']), 'version=%s' % (values['version']) ] req = '&'.join(params) self.channel = self.http.makeChannel(True) self.channel.beginGetDocument(DocumentSpec(req)) self.rf = Ramfile() self.channel.downloadToRam(self.rf) taskMgr.add(self.downloadTask, 'download') if(task): return task.again
def redownloadNews(self): """Get the new issue that came out while he was playing.""" if self.redownloadingNews: self.notify.warning( "averting potential crash redownloadNews called twice, just returning" ) return # I know it's info, it's important enough I feel to appear in the logs self.percentDownloaded = 0.0 self.notify.info("starting redownloadNews") self.startRedownload = datetime.datetime.now() self.redownloadingNews = True self.addDownloadingTextTask() # Clean up the old issues and start new stuff downloading. for issue in self.issues: issue.destroy() self.issues = [] self.curIssueIndex = 0 self.strFilenames = None self.needsParseNews = True # Start by downloading the index file. self.newsUrl = self.getInGameNewsUrl() self.newsDir = Filename(self.findNewsDir()) # Ensure self.newsDir exists and is a directory. Filename(self.newsDir + '/.').makeDir() http = HTTPClient.getGlobalPtr() self.url = self.newsUrl + self.NewsIndexFilename self.ch = http.makeChannel(True) self.ch.beginGetDocument(self.url) self.rf = Ramfile() self.ch.downloadToRam(self.rf) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadIndexTask, self.RedownloadTaskName)
def getFunnelURL(self): # print 'VRS URL: ' + self.dynamicVRFunnel if (patcherVer() == ['OFFLINE']): # print "Funnel System Offline" return if (patcherVer() == []): # print "Funnel URL not set. Setting now" patcherHTTP = HTTPClient() if checkParamFile() == None: patcherDoc = patcherHTTP.getDocument( URLSpec( 'http://download.toontown.com/english/currentVersion/content/patcher.ver' )) # Now set vcon (Content Group) to the Release string vconGroup('w', self.cgRelease) else: patcherDoc = patcherHTTP.getDocument(URLSpec(checkParamFile())) # Set vcon (Content Group) to the Beta string vconGroup('w', self.cgBeta) # patcherDoc = patcherHTTP.getDocument(URLSpec('http://build64:3120/english/currentVersion/dev/content/patcher.ver')) rf = Ramfile() patcherDoc.downloadToRam(rf) self.patcherURL = rf.getData() if self.patcherURL.find('FUNNEL_LOG') == -1: # The file did not download, need to set # the patcherVer to offline patcherVer('w', 'OFFLINE') # print 'Patcher system could not be reached' return self.patcherURL = self.patcherURL.split('\n') del rf, patcherDoc, patcherHTTP while self.patcherURL: self.confLine = self.patcherURL.pop() if (self.confLine.find('FUNNEL_LOG=') != -1 and self.confLine.find('#FUNNEL_LOG=') == -1): self.dynamicVRFunnel = self.confLine[11:].strip('\n') patcherVer('w', self.confLine[11:].strip('\n')) else: self.dynamicVRFunnel = patcherVer()[0]
class Heartbeat(): def __init__(self): self.http = HTTPClient() self.SendHeartbeat() #taskMgr.doMethodLater(10, self.SendHeartbeat, 'SendHeartbeat') def SendHeartbeat(self, task = None): baseUrl = 'http://modifire.net/heartbeat.php?' values = {'name' : Settings.SERVER_NAME, 'currentPlayers' : Globals.CURRENT_PLAYERS, 'maxPlayers' : Globals.MAX_PLAYERS, 'public' : Settings.SERVER_PUBLIC, 'port' : Globals.PORT_SERVER_LISTENER, 'version' : Globals.VERSION} for key, value in values.iteritems(): values[key] = urllib.quote(str(value)) params = [ baseUrl, 'name=%s' % (values['name']), 'currentPlayers=%s' % (values['currentPlayers']), 'maxPlayers=%s' % (values['maxPlayers']), 'public=%s' % (values['public']), 'port=%s' % (values['port']), 'version=%s' % (values['version']) ] req = '&'.join(params) self.channel = self.http.makeChannel(True) self.channel.beginGetDocument(DocumentSpec(req)) self.rf = Ramfile() self.channel.downloadToRam(self.rf) taskMgr.add(self.downloadTask, 'download') if(task): return task.again def downloadTask(self, task): if self.channel.run(): return task.cont if not self.channel.isDownloadComplete(): return task.done data = self.rf.getData() return task.done
def ban(self, avatarId, dislid, comment): """Ban the player""" parameters = "" parameters += "app=%s" % self.App parameters += "&product=%s" % self.Product parameters += "&user_id=%s" % dislid parameters += "&event_name=%s" % self.EventName commentWithAvatarId = "avId-%s " % avatarId commentWithAvatarId += comment parameters += "&comments=%s" % urllib.quote(str(commentWithAvatarId)) # get the base ban url from the environment variable first baseUrlToUse = self.BanUrl osBaseUrl = os.getenv("BAN_URL") if osBaseUrl: baseUrlToUse = osBaseUrl fullUrl = baseUrlToUse + "?" + parameters self.notify.info("ban request %s dislid=%s comment=%s fullUrl=%s" % (self.curBanRequestNum, dislid, comment, fullUrl)) simbase.air.writeServerEvent('ban_request', avatarId, "%s|%s|%s" % (dislid, comment, fullUrl)) if simbase.config.GetBool('do-actual-ban', False): newTaskName = "ban-task-%d" % self.curBanRequestNum newTask = taskMgr.add(self.doBanUrlTask, newTaskName) newTask.banRequestNum = self.curBanRequestNum http = HTTPClient.getGlobalPtr() channel = http.makeChannel( False) # hmm should we make true for a persistent connection? self.channels[self.curBanRequestNum] = channel rf = Ramfile() self.ramFiles[self.curBanRequestNum] = rf channel.beginGetDocument(fullUrl) channel.downloadToRam(rf) self.curBanRequestNum += 1
class DirectNewsFrame(DirectObject.DirectObject): TaskName = 'HtmlViewUpdateTask' TaskChainName = 'RedownladTaskChain' RedownloadTaskName = 'RedownloadNewsTask' NewsBaseDir = config.GetString('news-base-dir', '/httpNews') NewsStageDir = config.GetString('news-stage-dir', 'news') FrameDimensions = (-1.30666637421, 1.30666637421, -0.751666665077, 0.751666665077) notify = DirectNotifyGlobal.directNotify.newCategory('DirectNewsFrame') NewsIndexFilename = config.GetString('news-index-filename', 'http_news_index.txt') NewsOverHttp = config.GetBool('news-over-http', True) CacheIndexFilename = 'cache_index.txt' SectionIdents = ['hom', 'new', 'evt', 'tot', 'att', 'tnr'] def __init__(self, parent=aspect2d): DirectObject.DirectObject.__init__(self) self.accept('newsSnapshot', self.doSnapshot) self.active = False self.parent = parent self.issues = [] self.accept('newsChangeWeek', self.changeWeek) self.curIssueIndex = 0 self.strFilenames = None self.redownloadingNews = False self.startRedownload = datetime.datetime.now() self.endRedownload = datetime.datetime.now() self.load() self.percentDownloaded = 0.0 self.numIssuesExpected = 0 self.needsParseNews = True self.newsIndexEntries = [] if self.NewsOverHttp: self.redownloadNews() self.accept('newIssueOut', self.handleNewIssueOut) self.accept('clientCleanup', self.handleClientCleanup) return def parseNewsContent(self): if not self.needsParseNews: return self.needsParseNews = False result = False newsDir = self.findNewsDir() if newsDir: allHomeFiles = self.getAllHomeFilenames(newsDir) self.notify.debug('len allHomeFiles = %s' % len(allHomeFiles)) self.numIssuesExpected = len(allHomeFiles) if allHomeFiles: for myIssueIndex, oneHomeFile in enumerate(allHomeFiles): if type(oneHomeFile) == type(''): justFilename = oneHomeFile else: justFilename = oneHomeFile.getFilename().getBasename() self.notify.debug('parseNewContent %s' % justFilename) parts = justFilename.split('_') dateStr = parts[3] majorVer, minorVer = self.calcIssueVersion(dateStr) if majorVer == 1: oneIssue = IssueFrame.IssueFrame( self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames) elif majorVer == 2: oneIssue = IssueFrameV2.IssueFrameV2( self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames, self.newsIndexEntries) else: self.notify.warning( 'Dont know how to handle version %s, asuming v2' % majorVer) oneIssue = IssueFrameV2.IssueFrameV2( self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames, self.newsIndexEntries) oneIssue.hide() self.issues.append(oneIssue) if self.issues: self.issues[-1].show() self.curIssueIndex = len(self.issues) - 1 result = True if hasattr(base.cr, 'inGameNewsMgr') and base.cr.inGameNewsMgr: self.createdTime = base.cr.inGameNewsMgr.getLatestIssue() self.notify.debug('setting created time to latest issue %s' % self.createdTime) else: self.createdTime = base.cr.toontownTimeManager.getCurServerDateTime( ) self.notify.debug('setting created time cur server time %s' % self.createdTime) return result def getAllHomeFilenames(self, newsDir): self.notify.debug('getAllHomeFilenames') newsDirAsFile = vfs.getFile(Filename(newsDir)) fileList = newsDirAsFile.scanDirectory() fileNames = fileList.getFiles() self.notify.debug('filenames=%s' % fileNames) homeFileNames = set([]) for name in fileNames: self.notify.debug('processing %s' % name) baseName = name.getFilename().getBasename() self.notify.debug('baseName=%s' % baseName) if 'hom1.' in baseName: homeFileNames.add(name) else: self.notify.debug('hom1. not in baseName') if not homeFileNames: self.notify.warning('couldnt find hom1. in %s' % fileNames) self.setErrorMessage(TTLocalizer.NewsPageNoIssues) return [] def fileCmp(fileA, fileB): return fileA.getFilename().compareTo(fileB.getFilename()) homeFileNames = list(homeFileNames) homeFileNames.sort(cmp=fileCmp) self.notify.debug('returned homeFileNames=%s' % homeFileNames) return homeFileNames def findNewsDir(self): if self.NewsOverHttp: return self.NewsStageDir searchPath = DSearchPath() if AppRunnerGlobal.appRunner: searchPath.appendDirectory( Filename.expandFrom('$TT_3_5_ROOT/phase_3.5/models/news')) else: basePath = os.path.expandvars('$TTMODELS') or './ttmodels' searchPath.appendDirectory( Filename.fromOsSpecific(basePath + '/built/' + self.NewsBaseDir)) searchPath.appendDirectory(Filename(self.NewsBaseDir)) pfile = Filename(self.NewsIndexFilename) found = vfs.resolveFilename(pfile, searchPath) if not found: self.notify.warning('findNewsDir - no path: %s' % self.NewsIndexFilename) self.setErrorMessage(TTLocalizer.NewsPageErrorDownloadingFile % self.NewsIndexFilename) return None self.notify.debug('found index file %s' % pfile) realDir = pfile.getDirname() return realDir def load(self): self.loadBackground() def loadBackground(self): upsellBackground = loader.loadModel( 'phase_3.5/models/gui/tt_m_gui_ign_newsStatusBackground') imageScaleX = self.FrameDimensions[1] - self.FrameDimensions[0] imageScaleY = self.FrameDimensions[3] - self.FrameDimensions[2] self.backFrame = DirectFrame(parent=self.parent, image=upsellBackground, image_scale=(imageScaleX, 1, imageScaleY), frameColor=(1, 1, 1, 0), frameSize=self.FrameDimensions, pos=(0, 0, 0), relief=DGG.FLAT, text=TTLocalizer.NewsPageDownloadingNews1, text_scale=0.06, text_pos=(0, -0.4)) def addDownloadingTextTask(self): self.removeDownloadingTextTask() task = taskMgr.doMethodLater(1, self.loadingTextTask, 'DirectNewsFrameDownloadingTextTask') task.startTime = globalClock.getFrameTime() self.loadingTextTask(task) def removeDownloadingTextTask(self): taskMgr.remove('DirectNewsFrameDownloadingTextTask') def loadMainPage(self): self.mainFrame = DirectFrame(parent=self.backFrame, frameSize=self.FrameDimensions, frameColor=(1, 0, 0, 1)) def activate(self): if hasattr( self, 'createdTime' ) and self.createdTime < base.cr.inGameNewsMgr.getLatestIssue( ) and self.NewsOverHttp and not self.redownloadingNews: self.redownloadNews() else: self.addDownloadingTextTask() if self.needsParseNews and not self.redownloadingNews: self.parseNewsContent() self.active = True def deactivate(self): self.removeDownloadingTextTask() self.active = False def unload(self): self.removeDownloadingTextTask() result = taskMgr.remove(self.RedownloadTaskName) self.ignore('newsSnapshot') self.ignore('newsChangeWeek') self.ignore('newIssueOut') self.ignore('clientCleanup') def handleClientCleanup(self): pass def doSnapshot(self): pass def changeWeek(self, issueIndex): if 0 <= issueIndex and issueIndex < len(self.issues): self.issues[self.curIssueIndex].hide() self.issues[issueIndex].show() self.curIssueIndex = issueIndex def loadingTextTask(self, task): timeIndex = int(globalClock.getFrameTime() - task.startTime) % 3 timeStrs = (TTLocalizer.NewsPageDownloadingNews0, TTLocalizer.NewsPageDownloadingNews1, TTLocalizer.NewsPageDownloadingNews2) textToDisplay = timeStrs[timeIndex] % int(self.percentDownloaded * 100) if self.backFrame['text'] != textToDisplay: if TTLocalizer.NewsPageDownloadingNewsSubstr in self.backFrame[ 'text']: self.backFrame['text'] = textToDisplay return task.again def setErrorMessage(self, errText): self.backFrame['text'] = errText def redownloadNews(self): if self.redownloadingNews: self.notify.warning( 'averting potential crash redownloadNews called twice, just returning' ) return self.percentDownloaded = 0.0 self.notify.info('starting redownloadNews') self.startRedownload = datetime.datetime.now() self.redownloadingNews = True self.addDownloadingTextTask() for issue in self.issues: issue.destroy() self.issues = [] self.curIssueIndex = 0 self.strFilenames = None self.needsParseNews = True self.newsUrl = self.getInGameNewsUrl() self.newsDir = Filename(self.findNewsDir()) Filename(self.newsDir + '/.').makeDir() http = HTTPClient.getGlobalPtr() self.url = self.newsUrl + self.NewsIndexFilename self.ch = http.makeChannel(True) self.ch.beginGetDocument(self.url) self.rf = Ramfile() self.ch.downloadToRam(self.rf) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadIndexTask, self.RedownloadTaskName) return def downloadIndexTask(self, task): if self.ch.run(): return task.cont if not self.ch.isValid(): self.notify.warning('Unable to download %s' % self.url) self.redownloadingNews = False return task.done self.newsFiles = [] filename = self.rf.readline() while filename: filename = filename.strip() if filename: self.newsFiles.append(filename) filename = self.rf.readline() del self.rf self.newsFiles.sort() self.newsIndexEntries = list(self.newsFiles) self.notify.info('Server lists %s news files' % len(self.newsFiles)) self.notify.debug('self.newsIndexEntries=%s' % self.newsIndexEntries) self.readNewsCache() for basename in os.listdir(self.newsDir.toOsSpecific()): if basename != self.CacheIndexFilename and basename not in self.newsCache: junk = Filename(self.newsDir, basename) self.notify.info('Removing %s' % junk) junk.unlink() self.nextNewsFile = 0 return self.downloadNextFile(task) def downloadNextFile(self, task): while self.nextNewsFile < len( self.newsFiles) and 'aaver' in self.newsFiles[ self.nextNewsFile]: self.nextNewsFile += 1 if self.nextNewsFile >= len(self.newsFiles): self.notify.info('Done downloading news.') self.percentDownloaded = 1 del self.newsFiles del self.nextNewsFile del self.newsUrl del self.newsDir del self.ch del self.url if hasattr(self, 'filename'): del self.filename self.redownloadingNews = False if self.active: self.parseNewsContent() return task.done self.percentDownloaded = float(self.nextNewsFile) / float( len(self.newsFiles)) self.filename = self.newsFiles[self.nextNewsFile] self.nextNewsFile += 1 self.url = self.newsUrl + self.filename localFilename = Filename(self.newsDir, self.filename) self.notify.info('testing for %s' % localFilename.getFullpath()) doc = DocumentSpec(self.url) if self.filename in self.newsCache: size, date = self.newsCache[self.filename] if date and localFilename.exists() and ( size == 0 or localFilename.getFileSize() == size): doc.setDate(date) doc.setRequestMode(doc.RMNewer) self.ch.beginGetDocument(doc) self.ch.downloadToFile(localFilename) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadCurrentFileTask, self.RedownloadTaskName) def downloadCurrentFileTask(self, task): if self.ch.run(): return task.cont if self.ch.getStatusCode() == 304: self.notify.info('already cached: %s' % self.filename) return self.downloadNextFile(task) localFilename = Filename(self.newsDir, self.filename) if not self.ch.isValid(): self.notify.warning('Unable to download %s' % self.url) localFilename.unlink() if self.filename in self.newsCache: del self.newsCache[self.filename] self.saveNewsCache() return self.downloadNextFile(task) self.notify.info('downloaded %s' % self.filename) size = self.ch.getFileSize() doc = self.ch.getDocumentSpec() date = '' if doc.hasDate(): date = doc.getDate().getString() self.newsCache[self.filename] = (size, date) self.saveNewsCache() return self.downloadNextFile(task) def readNewsCache(self): cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename) self.newsCache = {} if cacheIndexFilename.isRegularFile(): file = open(cacheIndexFilename.toOsSpecific(), 'r') for line in file.readlines(): line = line.strip() keywords = line.split('\t') if len(keywords) == 3: filename, size, date = keywords if filename in self.newsFiles: try: size = int(size) except ValueError: size = 0 self.newsCache[filename] = (size, date) def saveNewsCache(self): cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename) try: file = open(cacheIndexFilename.toOsSpecific(), 'w') except IOError, e: self.notify.warning('error opening news cache file %s: %s' % (cacheIndexFilename, str(e))) return for filename, (size, date) in self.newsCache.items(): print >> file, '%s\t%s\t%s' % (filename, size, date)
class DirectNewsFrame(DirectObject.DirectObject): TaskName = "HtmlViewUpdateTask" TaskChainName = "RedownladTaskChain" RedownloadTaskName = "RedownloadNewsTask" NewsBaseDir = config.GetString("news-base-dir", "/httpNews") NewsStageDir = config.GetString("news-stage-dir", "news") FrameDimensions = (-1.30666637421, 1.30666637421, -0.751666665077, 0.751666665077) notify = DirectNotifyGlobal.directNotify.newCategory("DirectNewsFrame") NewsIndexFilename = config.GetString("news-index-filename", "http_news_index.txt") NewsOverHttp = config.GetBool("news-over-http", True) CacheIndexFilename = "cache_index.txt" SectionIdents = ["hom", "new", "evt", "tot", "att", "tnr"] def __init__(self, parent=aspect2d): DirectObject.DirectObject.__init__(self) self.accept("newsSnapshot", self.doSnapshot) self.active = False self.parent = parent self.issues = [] self.accept("newsChangeWeek", self.changeWeek) self.curIssueIndex = 0 self.strFilenames = None self.redownloadingNews = False self.startRedownload = datetime.datetime.now() self.endRedownload = datetime.datetime.now() self.load() self.percentDownloaded = 0.0 self.numIssuesExpected = 0 self.needsParseNews = True self.newsIndexEntries = [] if self.NewsOverHttp: self.redownloadNews() self.accept("newIssueOut", self.handleNewIssueOut) self.accept("clientCleanup", self.handleClientCleanup) return def parseNewsContent(self): if not self.needsParseNews: return self.needsParseNews = False result = False newsDir = self.findNewsDir() if newsDir: allHomeFiles = self.getAllHomeFilenames(newsDir) self.notify.debug("len allHomeFiles = %s" % len(allHomeFiles)) self.numIssuesExpected = len(allHomeFiles) if allHomeFiles: for myIssueIndex, oneHomeFile in enumerate(allHomeFiles): if type(oneHomeFile) == type(""): justFilename = oneHomeFile else: justFilename = oneHomeFile.getFilename().getBasename() self.notify.debug("parseNewContent %s" % justFilename) parts = justFilename.split("_") dateStr = parts[3] majorVer, minorVer = self.calcIssueVersion(dateStr) if majorVer == 1: oneIssue = IssueFrame.IssueFrame( self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames ) elif majorVer == 2: oneIssue = IssueFrameV2.IssueFrameV2( self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames, self.newsIndexEntries, ) else: self.notify.warning("Dont know how to handle version %s, asuming v2" % majorVer) oneIssue = IssueFrameV2.IssueFrameV2( self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames, self.newsIndexEntries, ) oneIssue.hide() self.issues.append(oneIssue) if self.issues: self.issues[-1].show() self.curIssueIndex = len(self.issues) - 1 result = True if hasattr(base.cr, "inGameNewsMgr") and base.cr.inGameNewsMgr: self.createdTime = base.cr.inGameNewsMgr.getLatestIssue() self.notify.debug("setting created time to latest issue %s" % self.createdTime) else: self.createdTime = base.cr.toontownTimeManager.getCurServerDateTime() self.notify.debug("setting created time cur server time %s" % self.createdTime) return result def getAllHomeFilenames(self, newsDir): self.notify.debug("getAllHomeFilenames") newsDirAsFile = vfs.getFile(Filename(newsDir)) fileList = newsDirAsFile.scanDirectory() fileNames = fileList.getFiles() self.notify.debug("filenames=%s" % fileNames) homeFileNames = set([]) for name in fileNames: self.notify.debug("processing %s" % name) baseName = name.getFilename().getBasename() self.notify.debug("baseName=%s" % baseName) if "hom1." in baseName: homeFileNames.add(name) else: self.notify.debug("hom1. not in baseName") if not homeFileNames: self.notify.warning("couldnt find hom1. in %s" % fileNames) self.setErrorMessage(TTLocalizer.NewsPageNoIssues) return [] def fileCmp(fileA, fileB): return fileA.getFilename().compareTo(fileB.getFilename()) homeFileNames = list(homeFileNames) homeFileNames.sort(cmp=fileCmp) self.notify.debug("returned homeFileNames=%s" % homeFileNames) return homeFileNames def findNewsDir(self): if self.NewsOverHttp: return self.NewsStageDir searchPath = DSearchPath() if AppRunnerGlobal.appRunner: searchPath.appendDirectory(Filename.expandFrom("$TT_3_5_ROOT/phase_3.5/models/news")) else: basePath = os.path.expandvars("$TTMODELS") or "./ttmodels" searchPath.appendDirectory(Filename.fromOsSpecific(basePath + "/built/" + self.NewsBaseDir)) searchPath.appendDirectory(Filename(self.NewsBaseDir)) pfile = Filename(self.NewsIndexFilename) found = vfs.resolveFilename(pfile, searchPath) if not found: self.notify.warning("findNewsDir - no path: %s" % self.NewsIndexFilename) self.setErrorMessage(TTLocalizer.NewsPageErrorDownloadingFile % self.NewsIndexFilename) return None self.notify.debug("found index file %s" % pfile) realDir = pfile.getDirname() return realDir def load(self): self.loadBackground() def loadBackground(self): upsellBackground = loader.loadModel("phase_3.5/models/gui/tt_m_gui_ign_newsStatusBackground") imageScaleX = self.FrameDimensions[1] - self.FrameDimensions[0] imageScaleY = self.FrameDimensions[3] - self.FrameDimensions[2] self.backFrame = DirectFrame( parent=self.parent, image=upsellBackground, image_scale=(imageScaleX, 1, imageScaleY), frameColor=(1, 1, 1, 0), frameSize=self.FrameDimensions, pos=(0, 0, 0), relief=DGG.FLAT, text=TTLocalizer.NewsPageDownloadingNews1, text_scale=0.06, text_pos=(0, -0.4), ) def addDownloadingTextTask(self): self.removeDownloadingTextTask() task = taskMgr.doMethodLater(1, self.loadingTextTask, "DirectNewsFrameDownloadingTextTask") task.startTime = globalClock.getFrameTime() self.loadingTextTask(task) def removeDownloadingTextTask(self): taskMgr.remove("DirectNewsFrameDownloadingTextTask") def loadMainPage(self): self.mainFrame = DirectFrame(parent=self.backFrame, frameSize=self.FrameDimensions, frameColor=(1, 0, 0, 1)) def activate(self): if ( hasattr(self, "createdTime") and self.createdTime < base.cr.inGameNewsMgr.getLatestIssue() and self.NewsOverHttp and not self.redownloadingNews ): self.redownloadNews() else: self.addDownloadingTextTask() if self.needsParseNews and not self.redownloadingNews: self.parseNewsContent() self.active = True def deactivate(self): self.removeDownloadingTextTask() self.active = False def unload(self): self.removeDownloadingTextTask() result = taskMgr.remove(self.RedownloadTaskName) self.ignore("newsSnapshot") self.ignore("newsChangeWeek") self.ignore("newIssueOut") self.ignore("clientCleanup") def handleClientCleanup(self): pass def doSnapshot(self): pass def changeWeek(self, issueIndex): if 0 <= issueIndex and issueIndex < len(self.issues): self.issues[self.curIssueIndex].hide() self.issues[issueIndex].show() self.curIssueIndex = issueIndex def loadingTextTask(self, task): timeIndex = int(globalClock.getFrameTime() - task.startTime) % 3 timeStrs = ( TTLocalizer.NewsPageDownloadingNews0, TTLocalizer.NewsPageDownloadingNews1, TTLocalizer.NewsPageDownloadingNews2, ) textToDisplay = timeStrs[timeIndex] % int(self.percentDownloaded * 100) if self.backFrame["text"] != textToDisplay: if TTLocalizer.NewsPageDownloadingNewsSubstr in self.backFrame["text"]: self.backFrame["text"] = textToDisplay return task.again def setErrorMessage(self, errText): self.backFrame["text"] = errText def redownloadNews(self): if self.redownloadingNews: self.notify.warning("averting potential crash redownloadNews called twice, just returning") return self.percentDownloaded = 0.0 self.notify.info("starting redownloadNews") self.startRedownload = datetime.datetime.now() self.redownloadingNews = True self.addDownloadingTextTask() for issue in self.issues: issue.destroy() self.issues = [] self.curIssueIndex = 0 self.strFilenames = None self.needsParseNews = True self.newsUrl = self.getInGameNewsUrl() self.newsDir = Filename(self.findNewsDir()) Filename(self.newsDir + "/.").makeDir() http = HTTPClient.getGlobalPtr() self.url = self.newsUrl + self.NewsIndexFilename self.ch = http.makeChannel(True) self.ch.beginGetDocument(self.url) self.rf = Ramfile() self.ch.downloadToRam(self.rf) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadIndexTask, self.RedownloadTaskName) return def downloadIndexTask(self, task): if self.ch.run(): return task.cont if not self.ch.isValid(): self.notify.warning("Unable to download %s" % self.url) self.redownloadingNews = False return task.done self.newsFiles = [] filename = self.rf.readline() while filename: filename = filename.strip() if filename: self.newsFiles.append(filename) filename = self.rf.readline() del self.rf self.newsFiles.sort() self.newsIndexEntries = list(self.newsFiles) self.notify.info("Server lists %s news files" % len(self.newsFiles)) self.notify.debug("self.newsIndexEntries=%s" % self.newsIndexEntries) self.readNewsCache() for basename in os.listdir(self.newsDir.toOsSpecific()): if basename != self.CacheIndexFilename and basename not in self.newsCache: junk = Filename(self.newsDir, basename) self.notify.info("Removing %s" % junk) junk.unlink() self.nextNewsFile = 0 return self.downloadNextFile(task) def downloadNextFile(self, task): while self.nextNewsFile < len(self.newsFiles) and "aaver" in self.newsFiles[self.nextNewsFile]: self.nextNewsFile += 1 if self.nextNewsFile >= len(self.newsFiles): self.notify.info("Done downloading news.") self.percentDownloaded = 1 del self.newsFiles del self.nextNewsFile del self.newsUrl del self.newsDir del self.ch del self.url if hasattr(self, "filename"): del self.filename self.redownloadingNews = False if self.active: self.parseNewsContent() return task.done self.percentDownloaded = float(self.nextNewsFile) / float(len(self.newsFiles)) self.filename = self.newsFiles[self.nextNewsFile] self.nextNewsFile += 1 self.url = self.newsUrl + self.filename localFilename = Filename(self.newsDir, self.filename) self.notify.info("testing for %s" % localFilename.getFullpath()) doc = DocumentSpec(self.url) if self.filename in self.newsCache: size, date = self.newsCache[self.filename] if date and localFilename.exists() and (size == 0 or localFilename.getFileSize() == size): doc.setDate(date) doc.setRequestMode(doc.RMNewer) self.ch.beginGetDocument(doc) self.ch.downloadToFile(localFilename) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadCurrentFileTask, self.RedownloadTaskName) def downloadCurrentFileTask(self, task): if self.ch.run(): return task.cont if self.ch.getStatusCode() == 304: self.notify.info("already cached: %s" % self.filename) return self.downloadNextFile(task) localFilename = Filename(self.newsDir, self.filename) if not self.ch.isValid(): self.notify.warning("Unable to download %s" % self.url) localFilename.unlink() if self.filename in self.newsCache: del self.newsCache[self.filename] self.saveNewsCache() return self.downloadNextFile(task) self.notify.info("downloaded %s" % self.filename) size = self.ch.getFileSize() doc = self.ch.getDocumentSpec() date = "" if doc.hasDate(): date = doc.getDate().getString() self.newsCache[self.filename] = (size, date) self.saveNewsCache() return self.downloadNextFile(task) def readNewsCache(self): cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename) self.newsCache = {} if cacheIndexFilename.isRegularFile(): file = open(cacheIndexFilename.toOsSpecific(), "r") for line in file.readlines(): line = line.strip() keywords = line.split("\t") if len(keywords) == 3: filename, size, date = keywords if filename in self.newsFiles: try: size = int(size) except ValueError: size = 0 self.newsCache[filename] = (size, date) def saveNewsCache(self): cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename) try: file = open(cacheIndexFilename.toOsSpecific(), "w") except IOError, e: self.notify.warning("error opening news cache file %s: %s" % (cacheIndexFilename, str(e))) return for filename, (size, date) in self.newsCache.items(): print >> file, "%s\t%s\t%s" % (filename, size, date)
def downloadContentsFile(self, http, redownload = False, hashVal = None): """ Downloads the contents.xml file for this particular host, synchronously, and then reads it. Returns true on success, false on failure. If hashVal is not None, it should be a HashVal object, which will be filled with the hash from the new contents.xml file.""" if self.hasCurrentContentsFile(): # We've already got one. return True if self.appRunner and self.appRunner.verifyContents == self.appRunner.P3DVCNever: # Not allowed to. return False rf = None if http: if not redownload and self.appRunner and self.appRunner.superMirrorUrl: # We start with the "super mirror", if it's defined. url = self.appRunner.superMirrorUrl + 'contents.xml' request = DocumentSpec(url) self.notify.info("Downloading contents file %s" % (request)) rf = Ramfile() channel = http.makeChannel(False) channel.getDocument(request) if not channel.downloadToRam(rf): self.notify.warning("Unable to download %s" % (url)) rf = None if not rf: # Then go to the main host, if our super mirror let us # down. url = self.hostUrlPrefix + 'contents.xml' # Append a uniquifying query string to the URL to force the # download to go all the way through any caches. We use the # time in seconds; that's unique enough. url += '?' + str(int(time.time())) # We might as well explicitly request the cache to be disabled # too, since we have an interface for that via HTTPChannel. request = DocumentSpec(url) request.setCacheControl(DocumentSpec.CCNoCache) self.notify.info("Downloading contents file %s" % (request)) statusCode = None statusString = '' for attempt in range(ConfigVariableInt('contents-xml-dl-attempts', 3)): if attempt > 0: self.notify.info("Retrying (%s)..."%(attempt,)) rf = Ramfile() channel = http.makeChannel(False) channel.getDocument(request) if channel.downloadToRam(rf): self.notify.warning("Successfully downloaded %s" % (url,)) break else: rf = None statusCode = channel.getStatusCode() statusString = channel.getStatusString() self.notify.warning("Could not contact download server at %s" % (url,)) self.notify.warning("Status code = %s %s" % (statusCode, statusString)) if not rf: self.notify.warning("Unable to download %s" % (url,)) try: # Something screwed up. if statusCode == HTTPChannel.SCDownloadOpenError or \ statusCode == HTTPChannel.SCDownloadWriteError: launcher.setPandaErrorCode(2) elif statusCode == 404: # 404 not found launcher.setPandaErrorCode(5) elif statusCode < 100: # statusCode < 100 implies the connection attempt itself # failed. This is usually due to firewall software # interfering. Apparently some firewall software might # allow the first connection and disallow subsequent # connections; how strange. launcher.setPandaErrorCode(4) else: # There are other kinds of failures, but these will # generally have been caught already by the first test; so # if we get here there may be some bigger problem. Just # give the generic "big problem" message. launcher.setPandaErrorCode(6) except NameError,e: # no launcher pass except AttributeError, e: self.notify.warning("%s" % (str(e),)) pass return False
class DirectNewsFrame(DirectObject.DirectObject): TaskName = 'HtmlViewUpdateTask' TaskChainName = 'RedownladTaskChain' RedownloadTaskName = 'RedownloadNewsTask' NewsBaseDir = config.GetString('news-base-dir', '/httpNews') NewsStageDir = config.GetString('news-stage-dir', 'news') FrameDimensions = (-1.30666637421, 1.30666637421, -0.75166666507699997, 0.75166666507699997) notify = DirectNotifyGlobal.directNotify.newCategory('DirectNewsFrame') NewsIndexFilename = config.GetString('news-index-filename', 'http_news_index.txt') NewsOverHttp = config.GetBool('news-over-http', True) CacheIndexFilename = 'cache_index.txt' SectionIdents = [ 'hom', 'new', 'evt', 'tot', 'att', 'tnr'] def __init__(self, parent = aspect2d): DirectObject.DirectObject.__init__(self) self.accept('newsSnapshot', self.doSnapshot) self.active = False self.parent = parent self.issues = [] self.accept('newsChangeWeek', self.changeWeek) self.curIssueIndex = 0 self.strFilenames = None self.redownloadingNews = False self.startRedownload = datetime.datetime.now() self.endRedownload = datetime.datetime.now() self.load() self.percentDownloaded = 0.0 self.numIssuesExpected = 0 self.needsParseNews = True self.newsIndexEntries = [] if self.NewsOverHttp: self.redownloadNews() self.accept('newIssueOut', self.handleNewIssueOut) self.accept('clientCleanup', self.handleClientCleanup) def parseNewsContent(self): if not self.needsParseNews: return None self.needsParseNews = False result = False newsDir = self.findNewsDir() if newsDir: allHomeFiles = self.getAllHomeFilenames(newsDir) self.notify.debug('len allHomeFiles = %s' % len(allHomeFiles)) self.numIssuesExpected = len(allHomeFiles) if allHomeFiles: for (myIssueIndex, oneHomeFile) in enumerate(allHomeFiles): if type(oneHomeFile) == type(''): justFilename = oneHomeFile else: justFilename = oneHomeFile.getFilename().getBasename() self.notify.debug('parseNewContent %s' % justFilename) parts = justFilename.split('_') dateStr = parts[3] (majorVer, minorVer) = self.calcIssueVersion(dateStr) if majorVer == 1: oneIssue = IssueFrame.IssueFrame(self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames) elif majorVer == 2: oneIssue = IssueFrameV2.IssueFrameV2(self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames, self.newsIndexEntries) else: self.notify.warning('Dont know how to handle version %s, asuming v2' % majorVer) oneIssue = IssueFrameV2.IssueFrameV2(self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames, self.newsIndexEntries) oneIssue.hide() self.issues.append(oneIssue) if self.issues: self.issues[-1].show() self.curIssueIndex = len(self.issues) - 1 result = True if hasattr(base.cr, 'inGameNewsMgr') and base.cr.inGameNewsMgr: self.createdTime = base.cr.inGameNewsMgr.getLatestIssue() self.notify.debug('setting created time to latest issue %s' % self.createdTime) else: self.createdTime = base.cr.toontownTimeManager.getCurServerDateTime() self.notify.debug('setting created time cur server time %s' % self.createdTime) return result def getAllHomeFilenames(self, newsDir): self.notify.debug('getAllHomeFilenames') newsDirAsFile = vfs.getFile(Filename(newsDir)) fileList = newsDirAsFile.scanDirectory() fileNames = fileList.getFiles() self.notify.debug('filenames=%s' % fileNames) homeFileNames = set([]) for name in fileNames: self.notify.debug('processing %s' % name) baseName = name.getFilename().getBasename() self.notify.debug('baseName=%s' % baseName) if 'hom1.' in baseName: homeFileNames.add(name) continue self.notify.debug('hom1. not in baseName') if not homeFileNames: self.notify.warning('couldnt find hom1. in %s' % fileNames) self.setErrorMessage(TTLocalizer.NewsPageNoIssues) return [] def fileCmp(fileA, fileB): return fileA.getFilename().compareTo(fileB.getFilename()) homeFileNames = list(homeFileNames) homeFileNames.sort(cmp = fileCmp) self.notify.debug('returned homeFileNames=%s' % homeFileNames) return homeFileNames def findNewsDir(self): if self.NewsOverHttp: return self.NewsStageDir searchPath = DSearchPath() if AppRunnerGlobal.appRunner: searchPath.appendDirectory(Filename.expandFrom('$TT_3_5_ROOT/phase_3.5/models/news')) elif not os.path.expandvars('$TTMODELS'): pass basePath = './ttmodels' searchPath.appendDirectory(Filename.fromOsSpecific(basePath + '/built/' + self.NewsBaseDir)) searchPath.appendDirectory(Filename(self.NewsBaseDir)) pfile = Filename(self.NewsIndexFilename) found = vfs.resolveFilename(pfile, searchPath) if not found: self.notify.warning('findNewsDir - no path: %s' % self.NewsIndexFilename) self.setErrorMessage(TTLocalizer.NewsPageErrorDownloadingFile % self.NewsIndexFilename) return None self.notify.debug('found index file %s' % pfile) realDir = pfile.getDirname() return realDir def load(self): self.loadBackground() def loadBackground(self): upsellBackground = loader.loadModel('phase_3.5/models/gui/tt_m_gui_ign_newsStatusBackground') imageScaleX = self.FrameDimensions[1] - self.FrameDimensions[0] imageScaleY = self.FrameDimensions[3] - self.FrameDimensions[2] self.backFrame = DirectFrame(parent = self.parent, image = upsellBackground, image_scale = (imageScaleX, 1, imageScaleY), frameColor = (1, 1, 1, 0), frameSize = self.FrameDimensions, pos = (0, 0, 0), relief = DGG.FLAT, text = TTLocalizer.NewsPageDownloadingNews1, text_scale = 0.059999999999999998, text_pos = (0, -0.40000000000000002)) def addDownloadingTextTask(self): self.removeDownloadingTextTask() task = taskMgr.doMethodLater(1, self.loadingTextTask, 'DirectNewsFrameDownloadingTextTask') task.startTime = globalClock.getFrameTime() self.loadingTextTask(task) def removeDownloadingTextTask(self): taskMgr.remove('DirectNewsFrameDownloadingTextTask') def loadMainPage(self): self.mainFrame = DirectFrame(parent = self.backFrame, frameSize = self.FrameDimensions, frameColor = (1, 0, 0, 1)) def activate(self): if hasattr(self, 'createdTime') and self.createdTime < base.cr.inGameNewsMgr.getLatestIssue() and self.NewsOverHttp and not (self.redownloadingNews): self.redownloadNews() else: self.addDownloadingTextTask() if self.needsParseNews and not (self.redownloadingNews): self.parseNewsContent() self.active = True def deactivate(self): self.removeDownloadingTextTask() self.active = False def unload(self): self.removeDownloadingTextTask() result = taskMgr.remove(self.RedownloadTaskName) self.ignore('newsSnapshot') self.ignore('newsChangeWeek') self.ignore('newIssueOut') self.ignore('clientCleanup') def handleClientCleanup(self): pass def doSnapshot(self): pass def changeWeek(self, issueIndex): if 0 <= issueIndex and issueIndex < len(self.issues): self.issues[self.curIssueIndex].hide() self.issues[issueIndex].show() self.curIssueIndex = issueIndex def loadingTextTask(self, task): timeIndex = int(globalClock.getFrameTime() - task.startTime) % 3 timeStrs = (TTLocalizer.NewsPageDownloadingNews0, TTLocalizer.NewsPageDownloadingNews1, TTLocalizer.NewsPageDownloadingNews2) textToDisplay = timeStrs[timeIndex] % int(self.percentDownloaded * 100) if self.backFrame['text'] != textToDisplay: if TTLocalizer.NewsPageDownloadingNewsSubstr in self.backFrame['text']: self.backFrame['text'] = textToDisplay return task.again def setErrorMessage(self, errText): self.backFrame['text'] = errText def redownloadNews(self): if self.redownloadingNews: self.notify.warning('averting potential crash redownloadNews called twice, just returning') return None self.percentDownloaded = 0.0 self.notify.info('starting redownloadNews') self.startRedownload = datetime.datetime.now() self.redownloadingNews = True self.addDownloadingTextTask() for issue in self.issues: issue.destroy() self.issues = [] self.curIssueIndex = 0 self.strFilenames = None self.needsParseNews = True self.newsUrl = self.getInGameNewsUrl() self.newsDir = Filename(self.findNewsDir()) Filename(self.newsDir + '/.').makeDir() http = HTTPClient.getGlobalPtr() self.url = self.newsUrl + self.NewsIndexFilename self.ch = http.makeChannel(True) self.ch.beginGetDocument(self.url) self.rf = Ramfile() self.ch.downloadToRam(self.rf) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadIndexTask, self.RedownloadTaskName) def downloadIndexTask(self, task): if self.ch.run(): return task.cont if not self.ch.isValid(): self.notify.warning('Unable to download %s' % self.url) self.redownloadingNews = False return task.done self.newsFiles = [] filename = self.rf.readline() while filename: filename = filename.strip() if filename: self.newsFiles.append(filename) filename = self.rf.readline() del self.rf self.newsFiles.sort() self.newsIndexEntries = list(self.newsFiles) self.notify.info('Server lists %s news files' % len(self.newsFiles)) self.notify.debug('self.newsIndexEntries=%s' % self.newsIndexEntries) self.readNewsCache() for basename in os.listdir(self.newsDir.toOsSpecific()): if basename != self.CacheIndexFilename and basename not in self.newsCache: junk = Filename(self.newsDir, basename) self.notify.info('Removing %s' % junk) junk.unlink() continue self.nextNewsFile = 0 return self.downloadNextFile(task) def downloadNextFile(self, task): while self.nextNewsFile < len(self.newsFiles) and 'aaver' in self.newsFiles[self.nextNewsFile]: self.nextNewsFile += 1 if self.nextNewsFile >= len(self.newsFiles): self.notify.info('Done downloading news.') self.percentDownloaded = 1 del self.newsFiles del self.nextNewsFile del self.newsUrl del self.newsDir del self.ch del self.url if hasattr(self, 'filename'): del self.filename self.redownloadingNews = False if self.active: self.parseNewsContent() return task.done self.percentDownloaded = float(self.nextNewsFile) / float(len(self.newsFiles)) self.filename = self.newsFiles[self.nextNewsFile] self.nextNewsFile += 1 self.url = self.newsUrl + self.filename localFilename = Filename(self.newsDir, self.filename) self.notify.info('testing for %s' % localFilename.getFullpath()) doc = DocumentSpec(self.url) if self.filename in self.newsCache: (size, date) = self.newsCache[self.filename] if date and localFilename.exists(): if size == 0 or localFilename.getFileSize() == size: doc.setDate(date) doc.setRequestMode(doc.RMNewer) localFilename.getFileSize() == size self.ch.beginGetDocument(doc) self.ch.downloadToFile(localFilename) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadCurrentFileTask, self.RedownloadTaskName) def downloadCurrentFileTask(self, task): if self.ch.run(): return task.cont if self.ch.getStatusCode() == 304: self.notify.info('already cached: %s' % self.filename) return self.downloadNextFile(task) localFilename = Filename(self.newsDir, self.filename) if not self.ch.isValid(): self.notify.warning('Unable to download %s' % self.url) localFilename.unlink() if self.filename in self.newsCache: del self.newsCache[self.filename] self.saveNewsCache() return self.downloadNextFile(task) self.notify.info('downloaded %s' % self.filename) size = self.ch.getFileSize() doc = self.ch.getDocumentSpec() date = '' if doc.hasDate(): date = doc.getDate().getString() self.newsCache[self.filename] = (size, date) self.saveNewsCache() return self.downloadNextFile(task) def readNewsCache(self): cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename) self.newsCache = { } if cacheIndexFilename.isRegularFile(): file = open(cacheIndexFilename.toOsSpecific(), 'r') for line in file.readlines(): line = line.strip() keywords = line.split('\t') if len(keywords) == 3: (filename, size, date) = keywords if filename in self.newsFiles: try: size = int(size) except ValueError: size = 0 self.newsCache[filename] = (size, date) filename in self.newsFiles def saveNewsCache(self): cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename) try: file = open(cacheIndexFilename.toOsSpecific(), 'w') except IOError: e = None self.notify.warning('error opening news cache file %s: %s' % (cacheIndexFilename, str(e))) return None for (size, date) in self.newsCache.items(): print >>file, '%s\t%s\t%s' % (filename, size, date) def handleNewIssueOut(self): if hasattr(self, 'createdTime') and base.cr.inGameNewsMgr.getLatestIssue() < self.createdTime: self.createdTime = base.cr.inGameNewsMgr.getLatestIssue() elif self.NewsOverHttp and not (self.redownloadingNews): if not self.active: self.redownloadNews() def getInGameNewsUrl(self): result = base.config.GetString('fallback-news-url', 'http://cdn.toontown.disney.go.com/toontown/en/gamenews/') override = base.config.GetString('in-game-news-url', '') if override: self.notify.info('got an override url, using %s for in game news' % override) result = override else: try: launcherUrl = base.launcher.getValue('GAME_IN_GAME_NEWS_URL', '') if launcherUrl: result = launcherUrl self.notify.info('got GAME_IN_GAME_NEWS_URL from launcher using %s' % result) else: self.notify.info('blank GAME_IN_GAME_NEWS_URL from launcher, using %s' % result) except: self.notify.warning('got exception getting GAME_IN_GAME_NEWS_URL from launcher, using %s' % result) return result def calcIssueVersion(self, dateStr): majorVer = 1 minorVer = 0 for entry in self.newsIndexEntries: if 'aaver' in entry and dateStr in entry: parts = entry.split('_') if len(parts) > 5: try: majorVer = int(parts[5]) self.notify.warning('could not int %s' % parts[5]) else: self.notify.warning('expected more than 5 parts in %s' % entry) if len(parts) > 6: try: minorVer = int(parts[6]) self.notify.warning('could not int %s' % parts[6]) else: self.notify.warning('expected more than 6 parts in %s' % entry) break continue return (majorVer, minorVer)
class DirectNewsFrame(DirectObject.DirectObject): TaskName = 'HtmlViewUpdateTask' TaskChainName = "RedownladTaskChain" RedownloadTaskName = "RedownloadNewsTask" NewsBaseDir = config.GetString("news-base-dir", "/httpNews") NewsStageDir = config.GetString("news-stage-dir", "news") # taken from In Game NewsFrame FrameDimensions = (-1.30666637421, 1.30666637421, -0.751666665077, 0.751666665077) notify = DirectNotifyGlobal.directNotify.newCategory("DirectNewsFrame") NewsIndexFilename = config.GetString("news-index-filename", "http_news_index.txt") NewsOverHttp = config.GetBool("news-over-http", True) CacheIndexFilename = 'cache_index.txt' # home page is considered one section, must always be first # home, news, events, talk of the town, ask toontown, toon resistance SectionIdents = ['hom', 'new', 'evt', 'tot', 'att', 'tnr'] def __init__(self, parent=aspect2d): DirectObject.DirectObject.__init__(self) self.accept("newsSnapshot", self.doSnapshot) self.active = False self.parent = parent self.issues = [] self.accept("newsChangeWeek", self.changeWeek) self.curIssueIndex = 0 self.strFilenames = None self.redownloadingNews = False self.startRedownload = datetime.datetime.now() # just used for timing self.endRedownload = datetime.datetime.now() # just used for timing self.load() self.percentDownloaded = 0.0 self.numIssuesExpected = 0 self.needsParseNews = True if self.NewsOverHttp: self.redownloadNews() self.accept("newIssueOut", self.handleNewIssueOut) self.accept("clientCleanup", self.handleClientCleanup) def parseNewsContent(self): """Open up the directory, read all the files, and figure out the structure.""" if not self.needsParseNews: return assert not self.redownloadingNews self.needsParseNews = False result = False newsDir = self.findNewsDir() if newsDir: allHomeFiles = self.getAllHomeFilenames(newsDir) self.notify.debug("len allHomeFiles = %s" % len(allHomeFiles)) self.numIssuesExpected = len(allHomeFiles) if allHomeFiles: for myIssueIndex, oneHomeFile in enumerate(allHomeFiles): if type(oneHomeFile) == type(""): justFilename = oneHomeFile else: justFilename = oneHomeFile.getFilename().getBasename() self.notify.debug("parseNewContent %s" % justFilename) parts = justFilename.split('_') dateStr = parts[3] oneIssue = IssueFrame.IssueFrame(self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames) oneIssue.hide() self.issues.append(oneIssue) if self.issues: self.issues[-1].show() self.curIssueIndex = len(self.issues) - 1 result = True if hasattr(base.cr, 'inGameNewsMgr') and base.cr.inGameNewsMgr: # we should get here only when a new issue comes out mid game self.createdTime = base.cr.inGameNewsMgr.getLatestIssue() self.notify.debug("setting created time to latest issue %s" % self.createdTime) else: # this is sucky that at this point (initial load) we don't have in game news mgr self.createdTime = base.cr.toontownTimeManager.getCurServerDateTime( ) self.notify.debug("setting created time cur server time %s" % self.createdTime) return result def getAllHomeFilenames(self, newsDir): """Find all the issues that are available.""" self.notify.debug("getAllHomeFilenames") newsDirAsFile = vfs.getFile(Filename(newsDir)) fileList = newsDirAsFile.scanDirectory() fileNames = fileList.getFiles() self.notify.debug("filenames=%s" % fileNames) # scan through and find hom1. thats got to be a home page homeFileNames = set([]) for name in fileNames: self.notify.debug("processing %s" % name) baseName = name.getFilename().getBasename() self.notify.debug("baseName=%s" % baseName) if "hom1." in baseName: homeFileNames.add(name) else: self.notify.debug("hom1. not in baseName") if not homeFileNames: #self.notify.error("couldnt find hom1. in %s" % fileNames) self.notify.warning("couldnt find hom1. in %s" % fileNames) self.setErrorMessage(TTLocalizer.NewsPageNoIssues) return [] def fileCmp(fileA, fileB): return fileA.getFilename().compareTo(fileB.getFilename()) homeFileNames = list(homeFileNames) homeFileNames.sort(cmp=fileCmp) self.notify.debug("returned homeFileNames=%s" % homeFileNames) return homeFileNames def findNewsDir(self): """Returns the directory string for news content. Returns None if it cant find the directory """ if self.NewsOverHttp: # If we're running news-over-http, we dump the news into a # staging directory. return self.NewsStageDir searchPath = DSearchPath() if AppRunnerGlobal.appRunner: # In the web-publish runtime, it will always be here: searchPath.appendDirectory( Filename.expandFrom('$TT_3_5_ROOT/phase_3.5/models/news')) else: # In the launcher or dev environment, look here: basePath = os.path.expandvars('$TTMODELS') or './ttmodels' searchPath.appendDirectory( Filename.fromOsSpecific(basePath + '/built/' + self.NewsBaseDir)) searchPath.appendDirectory(Filename(self.NewsBaseDir)) pfile = Filename(self.NewsIndexFilename) found = vfs.resolveFilename(pfile, searchPath) if not found: self.notify.warning('findNewsDir - no path: %s' % self.NewsIndexFilename) self.setErrorMessage(TTLocalizer.NewsPageErrorDownloadingFile % self.NewsIndexFilename) return None self.notify.debug("found index file %s" % pfile) realDir = pfile.getDirname() return realDir def load(self): """Create the gui objects we need.""" self.loadBackground() #self.loadMainPage() def loadBackground(self): """Create a plain white background image, that covers over the shtickerbook""" # HtmlView: webFrame = -1.30666637421 1.30666637421 -0.751666665077 0.751666665077 upsellBackground = loader.loadModel( "phase_3.5/models/gui/tt_m_gui_ign_newsStatusBackground") imageScaleX = self.FrameDimensions[1] - self.FrameDimensions[0] imageScaleY = self.FrameDimensions[3] - self.FrameDimensions[2] self.backFrame = DirectFrame( parent=self.parent, image=upsellBackground, image_scale=(imageScaleX, 1, imageScaleY), frameColor=(1, 1, 1, 0), frameSize=self.FrameDimensions, pos=(0, 0, 0), relief=DGG.FLAT, text=TTLocalizer.NewsPageDownloadingNews1, text_scale=0.06, text_pos=(0, -0.4), ) def addDownloadingTextTask(self): """Add a simple little task to show in game news is downloading stuff.""" self.removeDownloadingTextTask() task = taskMgr.doMethodLater(1, self.loadingTextTask, "DirectNewsFrameDownloadingTextTask") task.startTime = globalClock.getFrameTime() self.loadingTextTask(task) def removeDownloadingTextTask(self): """Add a simple little task to show in game news is downloading stuff.""" taskMgr.remove("DirectNewsFrameDownloadingTextTask") def loadMainPage(self): """Create the other gui for this.""" self.mainFrame = DirectFrame( parent=self.backFrame, frameSize=self.FrameDimensions, frameColor=(1, 0, 0, 1), ) def activate(self): """ Check if we have a new issue, and prompt the user if we have one. """ if hasattr(self,"createdTime") and \ self.createdTime < base.cr.inGameNewsMgr.getLatestIssue() and \ self.NewsOverHttp and \ not self.redownloadingNews: # we have a new issue, ask the user if he wants to download it # let's assume he clicked yes self.redownloadNews() pass else: self.addDownloadingTextTask() # Load up the news content the first time the user asks to see # it. if self.needsParseNews and not self.redownloadingNews: self.parseNewsContent() self.active = True def deactivate(self): """ self.quad.hide() taskMgr.remove(self.TaskName) """ self.removeDownloadingTextTask() self.active = False def unload(self): """ self.deactivate() HtmlView.HtmlView.unload(self) """ self.removeDownloadingTextTask() result = taskMgr.remove(self.RedownloadTaskName) self.ignore("newsSnapshot") self.ignore("newsChangeWeek") self.ignore("newIssueOut") self.ignore("clientCleanup") def handleClientCleanup(self): """User killing toontown, detach the backframe.""" pass def doSnapshot(self): "Save the current browser contents to a png file." "" pass def changeWeek(self, issueIndex): """Change the issue we are displaying.""" if 0 <= issueIndex and issueIndex < len(self.issues): self.issues[self.curIssueIndex].hide() self.issues[issueIndex].show() self.curIssueIndex = issueIndex def loadingTextTask(self, task): """Change a visual element to indicate we're still downloading.""" timeIndex = int(globalClock.getFrameTime() - task.startTime) % 3 timeStrs = (TTLocalizer.NewsPageDownloadingNews0, TTLocalizer.NewsPageDownloadingNews1, TTLocalizer.NewsPageDownloadingNews2) textToDisplay = timeStrs[timeIndex] % (int( self.percentDownloaded * 100)) if self.backFrame["text"] != textToDisplay: if TTLocalizer.NewsPageDownloadingNewsSubstr in self.backFrame[ "text"]: # don't change the text if we're displaying an error message self.backFrame["text"] = textToDisplay return task.again def setErrorMessage(self, errText): """Tell the user something has gone wrong.""" self.backFrame["text"] = errText def redownloadNews(self): """Get the new issue that came out while he was playing.""" if self.redownloadingNews: self.notify.warning( "averting potential crash redownloadNews called twice, just returning" ) return # I know it's info, it's important enough I feel to appear in the logs self.percentDownloaded = 0.0 self.notify.info("starting redownloadNews") self.startRedownload = datetime.datetime.now() self.redownloadingNews = True self.addDownloadingTextTask() # Clean up the old issues and start new stuff downloading. for issue in self.issues: issue.destroy() self.issues = [] self.curIssueIndex = 0 self.strFilenames = None self.needsParseNews = True # Start by downloading the index file. self.newsUrl = self.getInGameNewsUrl() self.newsDir = Filename(self.findNewsDir()) # Ensure self.newsDir exists and is a directory. Filename(self.newsDir + '/.').makeDir() http = HTTPClient.getGlobalPtr() self.url = self.newsUrl + self.NewsIndexFilename self.ch = http.makeChannel(True) self.ch.beginGetDocument(self.url) self.rf = Ramfile() self.ch.downloadToRam(self.rf) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadIndexTask, self.RedownloadTaskName) def downloadIndexTask(self, task): """ Get the initial index file from the HTTP server. """ if self.ch.run(): return task.cont if not self.ch.isValid(): self.notify.warning("Unable to download %s" % (self.url)) self.redownloadingNews = False return task.done # OK, now we've got the list of files hosted by the server. # Parse the list. self.newsFiles = [] filename = self.rf.readline() while filename: filename = filename.strip() if filename: self.newsFiles.append(filename) filename = self.rf.readline() del self.rf self.newsFiles.sort() self.notify.info("Server lists %s news files" % (len(self.newsFiles))) # Now see if we already have copies of these files we # downloaded previously. self.readNewsCache() # Clean up any unexpected files in this directory--they might # be old news files, or partial failed downloads from before. for basename in os.listdir(self.newsDir.toOsSpecific()): if basename != self.CacheIndexFilename and basename not in self.newsCache: junk = Filename(self.newsDir, basename) self.notify.info("Removing %s" % (junk)) junk.unlink() # And start downloading the files. self.nextNewsFile = 0 return self.downloadNextFile(task) def downloadNextFile(self, task): """ Starts the next news file downloading from the HTTP server. """ if self.nextNewsFile >= len(self.newsFiles): # Hey, we're done! self.notify.info("Done downloading news.") self.percentDownloaded = 1 del self.newsFiles del self.nextNewsFile del self.newsUrl del self.newsDir del self.ch del self.url if hasattr(self, 'filename'): del self.filename self.redownloadingNews = False if self.active: # If we're looking at the page now, go ahead and load it. self.parseNewsContent() return task.done self.percentDownloaded = float(self.nextNewsFile) / float( len(self.newsFiles)) # Get the next file on the list. self.filename = self.newsFiles[self.nextNewsFile] self.nextNewsFile += 1 self.url = self.newsUrl + self.filename localFilename = Filename(self.newsDir, self.filename) doc = DocumentSpec(self.url) if self.filename in self.newsCache: # We have already downloaded this file. Ask the # server to give us another copy only if the server's # copy is newer. size, date = self.newsCache[self.filename] if date and localFilename.exists() and ( size == 0 or localFilename.getFileSize() == size): doc.setDate(date) doc.setRequestMode(doc.RMNewer) self.ch.beginGetDocument(doc) self.ch.downloadToFile(localFilename) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadCurrentFileTask, self.RedownloadTaskName) def downloadCurrentFileTask(self, task): """ Continues downloading the URL in self.url and self.filename. """ if self.ch.run(): return task.cont if self.ch.getStatusCode() == 304: # This file is still cached from before. We don't need to # download it again. Move on to the next file. self.notify.info("already cached: %s" % (self.filename)) return self.downloadNextFile(task) localFilename = Filename(self.newsDir, self.filename) if not self.ch.isValid(): self.notify.warning("Unable to download %s" % (self.url)) localFilename.unlink() if self.filename in self.newsCache: del self.newsCache[self.filename] self.saveNewsCache() # Might as well see if we can get the next file. return self.downloadNextFile(task) # Successfully downloaded. self.notify.info("downloaded %s" % (self.filename)) # The HTTP "Entity Tag" appears to be useless with our CDN: # different CDN servers will serve up different etag values # for the same file. We rely on file size and date instead. size = self.ch.getFileSize() doc = self.ch.getDocumentSpec() date = '' if doc.hasDate(): date = doc.getDate().getString() self.newsCache[self.filename] = (size, date) self.saveNewsCache() # Continue downloading files. return self.downloadNextFile(task) def readNewsCache(self): """ Reads cache_index.txt into self.newsCache. """ cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename) self.newsCache = {} if cacheIndexFilename.isRegularFile(): file = open(cacheIndexFilename.toOsSpecific(), 'r') for line in file.readlines(): line = line.strip() keywords = line.split('\t') if len(keywords) == 3: filename, size, date = keywords if filename in self.newsFiles: try: size = int(size) except ValueError: size = 0 self.newsCache[filename] = (size, date) def saveNewsCache(self): """ Saves self.newsCache to cache_index.txt """ cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename) file = open(cacheIndexFilename.toOsSpecific(), 'w') for filename, (size, date) in self.newsCache.items(): print >> file, '%s\t%s\t%s' % (filename, size, date) def handleNewIssueOut(self): """Handle getting this newIssueOut message.""" # we will get this immediately after DistributedInGameNewsManager gets created # we will get this again when a new issue comes out while we are playing if hasattr(self,"createdTime") and \ base.cr.inGameNewsMgr.getLatestIssue() < self.createdTime: self.createdTime = base.cr.inGameNewsMgr.getLatestIssue() else: # we got a new issue while playing the game if self.NewsOverHttp and not self.redownloadingNews: # let's not abruptly yank the page if he's reading the news if not self.active: self.redownloadNews() pass def getInGameNewsUrl(self): """Get the appropriate URL to use if we are in test, qa, or live.""" # First if all else fails, we hard code the live news url result = base.config.GetString( "fallback-news-url", "http://cdn.toontown.disney.go.com/toontown/en/gamenews/") # next check if we have an override, say they want to url to point to a file in their harddisk override = base.config.GetString("in-game-news-url", "") if override: self.notify.info( "got an override url, using %s for in game news" % override) result = override else: try: launcherUrl = base.launcher.getValue("GAME_IN_GAME_NEWS_URL", "") if launcherUrl: result = launcherUrl self.notify.info( "got GAME_IN_GAME_NEWS_URL from launcher using %s" % result) else: self.notify.info( "blank GAME_IN_GAME_NEWS_URL from launcher, using %s" % result) except: self.notify.warning( "got exception getting GAME_IN_GAME_NEWS_URL from launcher, using %s" % result) return result def calcIssueVersion(self, dateStr): majorVer = 1 minorVer = 0 for entry in self.newsIndexEntries: if 'aaver' in entry and dateStr in entry: parts = entry.split('_') if len(parts) > 5: try: majorVer = int(parts[5]) except: self.notify.warning('could not int %s' % parts[5]) else: self.notify.warning('expected more than 5 parts in %s' % entry) if len(parts) > 6: try: minorVer = int(parts[6]) except: self.notify.warning('could not int %s' % parts[6]) else: self.notify.warning('expected more than 6 parts in %s' % entry) break return (majorVer, minorVer)