*/ // must be run within Dokuwiki if(!defined('DOKU_INC')) die(); class helper_plugin_ghissues_apiCacheInterface extends DokuWiki_Plugin { var $_GH_API_limit; /** * Return info about supported methods in this Helper Plugin * * @return array of public methods */ public function getMethods() { return array( array( 'name' => 'checkIssuesCache', 'desc' => 'Takes an api URL, checks local cache for up-to-date, then returns cache path for use in depends["files"]', 'params' => array( 'apiURL' => 'string', ), 'return' => array('cachePath' => 'string') ), array( 'name' => 'checkCacheFreshness', 'desc' => 'returns true if the cache is up-to-date. Includes API call if required', 'params' => array( 'apiURL' => 'string', 'cache (optional)' => 'class' ), 'return' => array('useCache' => 'boolean') ), array( 'name' => 'callGithubAPI', 'desc' => 'makes the API call given by apiUrl. Saves result in a cache after formatting', 'params' => array( 'apiURL' => 'string', 'cache (optional)' => 'class' ), 'return' => array('useCache' => 'boolean') ), array( 'name' => 'formatApiResponse', 'desc' => 'takes JSON response from API and returns formatted output in xhtml', 'params' => array( 'rawJSON' => 'string', ), 'return' => array('outputXML' => 'string') ), array( 'name' => 'getRenderedRequest', 'desc' => 'returns rendered output from an API request, using cache if valid', 'params' => array( 'apiURL' => 'string', ), 'return' => array('outputXML' => 'string') ) ); } // Master cache checker. First checks if the cache expired, then checks if the page is older than the (possibly updated) cache public function checkIssuesCache( $apiURL ) { $cache = new cache_ghissues_api($apiURL); $this->checkCacheFreshness($apiURL, $cache); return ($cache->cache); } // return true if still fresh. Otherwise you'll confuse the bears public function checkCacheFreshness($apiURL, &$cache=NULL) { //dbglog('ghissues: In checkCacheFreshness'); if ( !isset($cache) ) { $cache = new cache_ghissues_api($apiURL); } // Check if we've done a cached API call recently. If you have, the cache is plenty fresh if ( $cache->sniffETag($this->getConf('ghissuerefresh')) ) return true; // Old cache, time to check in with GH. return $this->callGithubAPI($apiURL, $cache); } // return true if no update since the last time we asked. public function callGithubAPI($apiURL, &$cache=NULL) { //dbglog('ghissues: In callGithubAPI'); if ( !isset($cache) ) { $cache = new cache_ghissues_api($apiURL); } //dbglog('ghissues: Make HTTP Client'); $http = new DokuHTTPClient(); //dbglog('ghissues: Made HTTP Client'); $oauth_token = $this->getConf('ghissueoauth'); if ( !empty($oauth_token) ) { $http->user = $oauth_token; $http->pass = 'x-oauth-basic'; } $http->agent = substr($http->agent,0,-1).' via ghissue plugin from user '.$this->getConf('ghissueuser').')'; $http->headers['Accept'] = 'application/vnd.github.v3.text+json'; $http->keep_alive = FALSE; //dbglog('ghissues: Set Base Headers'); $lastETag = $cache->retrieveETag(); //dbglog('ghissues: Cache etag retrieval: '.$lastETag); if ( !empty($lastETag) ) { $http->headers['If-None-Match'] = $lastETag; } //dbglog('ghissues: Start request'); $apiResp = $http->get($apiURL); $apiHead = array(); //dbglog('ghissues: madeRequest'); $apiHead = $http->resp_headers; //dbglog('ghissues: '.$apiURL); //dbglog('ghissues: '.var_export($http->resp_headers, TRUE)); $this->_GH_API_limit = intval($apiHead['x-ratelimit-remaining']); //dbglog('ghissues: rateLimit='.$this->_GH_API_limit); $apiStatus = substr($apiHead['status'],0,3); //dbglog('ghissues: status='.$apiHead['status']); if ( $apiStatus == '304' ) { // No modification $cache->storeETag($apiHead['etag']); // Update the last time we checked return true; } else if ( $apiStatus == '200' ) { // Updated content! But will the table change? // Collate results if GitHub paginated them. (Walk the URL ladder) if ( !empty($apiHead['link']) ) { $nextLink = $apiHead['link']; $matches = array(); if(preg_match('/<(.*?)>; rel="next"/', $nextLink, $matches)) { $apiResp = substr($apiResp,0,-1); $apiResp .= $this->_chaseGithubNextLinks($http, $matches[1]); } }; // Build the actual table using the response, then make sure it has changed. // Because we don't use all information from the resopnse, it is possible only // things we don't check updated. If that is the case, no need to change the cache $newTable = $this->formatApiResponse($apiResp); if ( $newTable != $cache->retrieveCache() ) { if (!$cache->storeCache($newTable)) { //dbglog('ghissues: Unable to save cache file. Hint: disk full; file permissions; safe_mode setting.',-1); return true; // Couldn't save the update, can't reread from new cache } $cache->storeETag($apiHead['etag']); // Update the last time we checked return false; } $cache->storeETag($apiHead['etag']); // Update the last time we checked return true; // All that for a table that looks the same... } else { // Some other HTTP status, we're not handling. Save old table plus error message // Don't update when we checked in case it was a temporary thing (it probably wasn't though) // $cache->storeETag($apiHead['etag']); // Update the last time we checked $errorTable = '