public static function dataCompileLoop($opts) { self::log("Using database master: " . WH_DATABASE_MASTER . "\n"); $origToken = self::getToken(); $numErrors = 0; $stopMsg = ''; $data = new DashboardData(); // The dashboard is very susceptible to going down when we're doing // maintenance on our spare server. Using this flag is a way to hold // the stats steady by reading them once from the master DB and not again // until the daemon is restarted. $fakeStats = isset($opts['f']) || isset($opts['fake-stats']); if ($fakeStats) { $data->fetchOnFirstCallOnly(); } $staticData = $data->loadStaticGlobalOpts(); $baselines = (array) json_decode($staticData['cdo_baselines_json']); DashboardWidget::setBaselines($baselines); // Run the data compilation repeatedly, until token changes while (1) { $start = microtime(true); $success = $data->compileStatsData(); $end = microtime(true); $delta = $end - $start; $logMsg = sprintf('data refresh took %.3fs', $delta); if ($success) { $numErrors = 0; } else { $logMsg = sprintf('error was detected in data refresh (%.3fs)', $delta); $numErrors++; if ($numErrors >= self::STOP_AFTER_ERRORS) { $stopMsg = sprintf('there were %d errors in a row. stopping daemon.', self::STOP_AFTER_ERRORS); } } self::log($logMsg); if (!empty($stopMsg)) { break; } $until_refresh_seconds = self::REFRESH_SECONDS - $delta; if ($until_refresh_seconds >= 0.0) { $secs = (int) ceil($until_refresh_seconds); sleep($secs); } $token = self::getToken(); if ($token != $origToken) { $stopMsg = 'stop daemon requested through token change.'; break; } } if ($stopMsg) { self::log($stopMsg); } }
/** * Display the HTML for this special page with all the widgets in it */ private function displayContainer() { global $wgWidgetList, $wgUser, $wgWidgetShortCodes; $containerJS = array('community-dashboard.js', 'dashboard-widget.js', 'jquery.ui.sortable.min.js', 'jquery.json-2.2.min.js'); $containerCSS = array('community-dashboard.css'); $jsTags = $this->makeUrlTags('js', $containerJS); $cssTags = $this->makeUrlTags('css', $containerCSS); // get all commonly updating stats, to see the initial widget // displays with $this->refreshData = $this->dashboardData->getStatsData(); // get all data such as wikihow-defined structure goals, dynamic // global data, and user-specific data $staticData = $this->dashboardData->loadStaticGlobalOpts(); $priorities = json_decode($staticData['cdo_priorities_json'], true); if (!is_array($priorities)) { $priorities = array(); } $thresholds = json_decode($staticData['cdo_thresholds_json'], true); DashboardWidget::setThresholds($thresholds); $baselines = (array) json_decode($staticData['cdo_baselines_json']); DashboardWidget::setBaselines($baselines); DashboardWidget::setMaxUsernameLength(CommunityDashboard::USERNAME_MAX_LENGTH); // display the user-defined ordering of widgets inside an outside // container $userData = $this->dashboardData->loadUserData(); $prefs = !empty($userData['prefs']) ? $userData['prefs'] : array(); $userOrdering = isset($prefs['ordering']) ? $prefs['ordering'] : array(); $completion = !empty($userData['completion']) ? $userData['completion'] : array(); DashboardWidget::setCompletion($completion); // add any new widgets that have been added since the user last // customized foreach ($wgWidgetList as $name) { $found = false; foreach ($userOrdering as $arr) { if ($arr['wid'] == $name) { $found = true; break; } } if (!$found) { $userOrdering[] = array('wid' => $name, 'show' => 1); } } // create the user-defined ordering list, removing any community // priority widgets from the list so their not displayed twice $userWidgets = array(); foreach ($userOrdering as $arr) { $found = false; foreach ($priorities as $name) { if ($arr['wid'] == $name) { $found = true; break; } } if (!$found && $arr['show']) { $userWidgets[] = $arr['wid']; } } $func = array($this, 'displayWidgets'); $out = call_user_func($func, array('test')); $langKeys = array('howto', 'cd-pause-updates', 'cd-resume-updates', 'cd-current-priority', 'cd-network-error'); $langScript = Wikihow_i18n::genJSMsgs($langKeys); //TODO: Likely should move this somewhere else //but not sure where yet //load user specific info that only needs to be loaded //once if ($wgUser->getID() > 0) { $u = new User(); $u->setID($wgUser->getID()); $img = Avatar::getPicture($u->getName(), true); if ($img == '') { $img = Avatar::getDefaultPicture(); } $sk = $wgUser->getSkin(); $userName = $sk->makeLinkObj($u->getUserPage(), $u->getName()); $tipsLink = "/Special:TipsPatrol"; } else { $tipsLink = "/Special:Userlogin?returnto=Special:TipsPatrol"; } $tmpl = new EasyTemplate(dirname(__FILE__)); $tmpl->set_vars(array('jsTags' => $jsTags, 'cssTags' => $cssTags, 'thresholds' => $staticData['cdo_thresholds_json'], 'GLOBAL_DATA_REFRESH_TIME_SECS' => self::GLOBAL_DATA_REFRESH_TIME_SECS, 'USER_DATA_REFRESH_TIME_SECS' => self::USER_DATA_REFRESH_TIME_SECS, 'USERNAME_MAX_LENGTH' => self::USERNAME_MAX_LENGTH, 'widgetTitles' => DashboardData::getTitles(), 'priorityWidgets' => $priorities, 'userWidgets' => $userWidgets, 'prefsOrdering' => $userOrdering, 'userCounts' => $userData['counts'], 'userImage' => $img, 'userName' => $userName, 'displayWidgetsFunc' => array($this, 'displayWidgets'), 'appShortCodes' => $wgWidgetShortCodes, 'tipsLink' => $tipsLink)); $html = $tmpl->execute('dashboard-container.tmpl.php'); return $langScript . $html; }