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 else: 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 perform_post_request(self, url, headers={}, content_type=None, post_body={}, callback=None): """ """ self.notify.debug('Sending POST request: %s' % url) request_channel = self._http_client.make_channel(True) if content_type != None: request_channel.set_content_type(content_type) for header_key in headers: header_value = headers[header_key] request_channel.send_extra_header(header_key, header_value) post_body = json.dumps(post_body) request_channel.begin_post_form(DocumentSpec(url), post_body) ram_file = Ramfile() request_channel.download_to_ram(ram_file, False) request_id = self._request_allocator.allocate() http_request = HTTPRequest(self, request_id, request_channel, ram_file, callback) self._requests[request_id] = http_request return request_id
def perform_get_request(self, url, headers={}, content_type=None, callback=None): """ Performs an HTTP restful GET call and returns the request's unique itentifier """ self.notify.debug('Sending GET request: %s' % url) request_channel = self._http_client.make_channel(True) if content_type != None: request_channel.set_content_type(content_type) for header_key in headers: header_value = headers[header_key] request_channel.send_extra_header(header_key, header_value) request_channel.begin_get_document(DocumentSpec(url)) ram_file = Ramfile() request_channel.download_to_ram(ram_file, False) request_id = self._request_allocator.allocate() http_request = HTTPRequest(self, request_id, request_channel, ram_file, callback) self._requests[request_id] = http_request return request_id
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 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( int(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.info("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.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' % str(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 else: 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 else: 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 as 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 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]) 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)
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 and self.NewsOverHttp and not self.redownloadingNews: self.active = False 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(int(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.info("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 as e: # no launcher pass except AttributeError as e: self.notify.warning("%s" % (str(e),)) pass return False tempFilename = Filename.temporary('', 'p3d_', '.xml') if rf: f = open(tempFilename.toOsSpecific(), 'wb') f.write(rf.getData()) f.close() if hashVal: hashVal.hashString(rf.getData()) if not self.readContentsFile(tempFilename, freshDownload = True): self.notify.warning("Failure reading %s" % (url)) tempFilename.unlink() return False tempFilename.unlink() return True # Couldn't download the file. Maybe we should look for a # previously-downloaded copy already on disk? return False