Skip to content

Commit

Permalink
core: Implement action factory (RSS-Bridge#1002)
Browse files Browse the repository at this point in the history
  • Loading branch information
logmanoriginal authored Feb 6, 2019
1 parent 4029e0f commit 89c2066
Show file tree
Hide file tree
Showing 12 changed files with 705 additions and 279 deletions.
50 changes: 50 additions & 0 deletions actions/DetectAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
/**
* This file is part of RSS-Bridge, a PHP project capable of generating RSS and
* Atom feeds for websites that don't have one.
*
* For the full license information, please view the UNLICENSE file distributed
* with this source code.
*
* @package Core
* @license http://unlicense.org/ UNLICENSE
* @link https://github.com/rss-bridge/rss-bridge
*/

class DetectAction extends ActionAbstract {
public function execute() {
$targetURL = $this->userData['url']
or returnClientError('You must specify a url!');

$format = $this->userData['format']
or returnClientError('You must specify a format!');

foreach(Bridge::getBridgeNames() as $bridgeName) {

if(!Bridge::isWhitelisted($bridgeName)) {
continue;
}

$bridge = Bridge::create($bridgeName);

if($bridge === false) {
continue;
}

$bridgeParams = $bridge->detectParameters($targetURL);

if(is_null($bridgeParams)) {
continue;
}

$bridgeParams['bridge'] = $bridgeName;
$bridgeParams['format'] = $format;

header('Location: ?action=display&' . http_build_query($bridgeParams), true, 301);
die();

}

returnClientError('No bridge found for given URL: ' . $targetURL);
}
}
234 changes: 234 additions & 0 deletions actions/DisplayAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
<?php
/**
* This file is part of RSS-Bridge, a PHP project capable of generating RSS and
* Atom feeds for websites that don't have one.
*
* For the full license information, please view the UNLICENSE file distributed
* with this source code.
*
* @package Core
* @license http://unlicense.org/ UNLICENSE
* @link https://github.com/rss-bridge/rss-bridge
*/

class DisplayAction extends ActionAbstract {
public function execute() {
$bridge = array_key_exists('bridge', $this->userData) ? $this->userData['bridge'] : null;

$format = $this->userData['format']
or returnClientError('You must specify a format!');

// DEPRECATED: 'nameFormat' scheme is replaced by 'name' in format parameter values
// this is to keep compatibility until futher complete removal
if(($pos = strpos($format, 'Format')) === (strlen($format) - strlen('Format'))) {
$format = substr($format, 0, $pos);
}

// whitelist control
if(!Bridge::isWhitelisted($bridge)) {
throw new \Exception('This bridge is not whitelisted', 401);
die;
}

// Data retrieval
$bridge = Bridge::create($bridge);

$noproxy = array_key_exists('_noproxy', $this->userData)
&& filter_var($this->userData['_noproxy'], FILTER_VALIDATE_BOOLEAN);

if(defined('PROXY_URL') && PROXY_BYBRIDGE && $noproxy) {
define('NOPROXY', true);
}

// Cache timeout
$cache_timeout = -1;
if(array_key_exists('_cache_timeout', $this->userData)) {

if(!CUSTOM_CACHE_TIMEOUT) {
unset($this->userData['_cache_timeout']);
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) . '?' . http_build_query($this->userData);
header('Location: ' . $uri, true, 301);
die();
}

$cache_timeout = filter_var($this->userData['_cache_timeout'], FILTER_VALIDATE_INT);

} else {
$cache_timeout = $bridge->getCacheTimeout();
}

// Remove parameters that don't concern bridges
$bridge_params = array_diff_key(
$this->userData,
array_fill_keys(
array(
'action',
'bridge',
'format',
'_noproxy',
'_cache_timeout',
'_error_time'
), '')
);

// Remove parameters that don't concern caches
$cache_params = array_diff_key(
$this->userData,
array_fill_keys(
array(
'action',
'format',
'_noproxy',
'_cache_timeout',
'_error_time'
), '')
);

// Initialize cache
$cache = Cache::create('FileCache');
$cache->setPath(PATH_CACHE);
$cache->purgeCache(86400); // 24 hours
$cache->setParameters($cache_params);

$items = array();
$infos = array();
$mtime = $cache->getTime();

if($mtime !== false
&& (time() - $cache_timeout < $mtime)
&& !Debug::isEnabled()) { // Load cached data

// Send "Not Modified" response if client supports it
// Implementation based on https://stackoverflow.com/a/10847262
if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
$stime = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);

if($mtime <= $stime) { // Cached data is older or same
header('Last-Modified: ' . gmdate('D, d M Y H:i:s ', $mtime) . 'GMT', true, 304);
die();
}
}

$cached = $cache->loadData();

if(isset($cached['items']) && isset($cached['extraInfos'])) {
foreach($cached['items'] as $item) {
$items[] = new \FeedItem($item);
}

$infos = $cached['extraInfos'];
}

} else { // Collect new data

try {
$bridge->setDatas($bridge_params);
$bridge->collectData();

$items = $bridge->getItems();

// Transform "legacy" items to FeedItems if necessary.
// Remove this code when support for "legacy" items ends!
if(isset($items[0]) && is_array($items[0])) {
$feedItems = array();

foreach($items as $item) {
$feedItems[] = new \FeedItem($item);
}

$items = $feedItems;
}

$infos = array(
'name' => $bridge->getName(),
'uri' => $bridge->getURI(),
'icon' => $bridge->getIcon()
);
} catch(Error $e) {
error_log($e);

$item = new \FeedItem();

// Create "new" error message every 24 hours
$this->userData['_error_time'] = urlencode((int)(time() / 86400));

// Error 0 is a special case (i.e. "trying to get property of non-object")
if($e->getCode() === 0) {
$item->setTitle(
'Bridge encountered an unexpected situation! ('
. $this->userData['_error_time']
. ')'
);
} else {
$item->setTitle(
'Bridge returned error '
. $e->getCode()
. '! ('
. $this->userData['_error_time']
. ')'
);
}

$item->setURI(
(isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '')
. '?'
. http_build_query($this->userData)
);

$item->setTimestamp(time());
$item->setContent(buildBridgeException($e, $bridge));

$items[] = $item;
} catch(Exception $e) {
error_log($e);

$item = new \FeedItem();

// Create "new" error message every 24 hours
$this->userData['_error_time'] = urlencode((int)(time() / 86400));

$item->setURI(
(isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '')
. '?'
. http_build_query($this->userData)
);

$item->setTitle(
'Bridge returned error '
. $e->getCode()
. '! ('
. $this->userData['_error_time']
. ')'
);
$item->setTimestamp(time());
$item->setContent(buildBridgeException($e, $bridge));

$items[] = $item;
}

// Store data in cache
$cache->saveData(array(
'items' => array_map(function($i){ return $i->toArray(); }, $items),
'extraInfos' => $infos
));

}

// Data transformation
try {
$format = Format::create($format);
$format->setItems($items);
$format->setExtraInfos($infos);
$format->setLastModified($cache->getTime());
$format->display();
} catch(Error $e) {
error_log($e);
header('Content-Type: text/html', true, $e->getCode());
die(buildTransformException($e, $bridge));
} catch(Exception $e) {
error_log($e);
header('Content-Type: text/html', true, $e->getCode());
die(buildTransformException($e, $bridge));
}
}
}
53 changes: 53 additions & 0 deletions actions/ListAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php
/**
* This file is part of RSS-Bridge, a PHP project capable of generating RSS and
* Atom feeds for websites that don't have one.
*
* For the full license information, please view the UNLICENSE file distributed
* with this source code.
*
* @package Core
* @license http://unlicense.org/ UNLICENSE
* @link https://github.com/rss-bridge/rss-bridge
*/

class ListAction extends ActionAbstract {
public function execute() {
$list = new StdClass();
$list->bridges = array();
$list->total = 0;

foreach(Bridge::getBridgeNames() as $bridgeName) {

$bridge = Bridge::create($bridgeName);

if($bridge === false) { // Broken bridge, show as inactive

$list->bridges[$bridgeName] = array(
'status' => 'inactive'
);

continue;

}

$status = Bridge::isWhitelisted($bridgeName) ? 'active' : 'inactive';

$list->bridges[$bridgeName] = array(
'status' => $status,
'uri' => $bridge->getURI(),
'name' => $bridge->getName(),
'icon' => $bridge->getIcon(),
'parameters' => $bridge->getParameters(),
'maintainer' => $bridge->getMaintainer(),
'description' => $bridge->getDescription()
);

}

$list->total = count($list->bridges);

header('Content-Type: application/json');
echo json_encode($list, JSON_PRETTY_PRINT);
}
}
Loading

0 comments on commit 89c2066

Please sign in to comment.