1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309:
<?php
namespace Nethgui\Module;
class Tracker extends \Nethgui\Controller\AbstractController implements \Nethgui\Component\DependencyConsumer
{
const TRACKER_ERROR_TEMPLATE = '<i class="fa fa-li fa-exclamation-circle"></i> <span>{{genericLabel}}</span> <dl>{{#.}}<dt>{{title}} #{{id}} ({{codeLabel}} {{code}})</dt><dd class="wspreline">{{message}}</dd>{{/.}}</dl>';
const TRACKER_RUNNING_TEMPLATE = '<i class="fa fa-li fa-exclamation-triangle"></i> <span>{{message}}</span> <a class="Button link" href="{{btnLink}}">{{btnLabel}}</a>';
protected function initializeAttributes(\Nethgui\Module\ModuleAttributesInterface $base)
{
$attributes = new SystemModuleAttributesProvider();
$attributes->initializeFromModule($this);
return $attributes;
}
private $systemTasks;
private $notifications;
private $taskId = FALSE;
public function bind(\Nethgui\Controller\RequestInterface $request)
{
parent::bind($request);
if ( ! $this->getRequest()->getUser()->isAuthenticated()) {
return;
}
$taskId = \Nethgui\array_head($request->getPath());
if ($taskId) {
$this->bindTask($request, $taskId);
}
if ($request->isMutation() && count($this->systemTasks->getRunningTasks()) > 0) {
throw new \Nethgui\Exception\HttpException('Service Unavailable', 503, 1405692423);
}
}
private function bindTask(\Nethgui\Controller\RequestInterface $request, $taskId)
{
try {
$this->systemTasks->getTaskStatus($taskId);
$this->taskId = $taskId;
} catch (\RuntimeException $ex) {
if ($ex->getCode() === 1405613538) {
throw new \Nethgui\Exception\HttpException('Not found', 404, 1405612090, $ex);
} else {
$this->getLog()->exception($ex);
throw new \Nethgui\Exception\HttpException('Not found', 404, 1415120596, $ex);
}
}
}
private function applyTaskUiDefaults($ui, $context)
{
extract($context, EXTR_REFS);
return array_replace_recursive(array('conditions' => array(
'running' => array(
'dialog' => array(
'action' => 'open',
'title' => $view->translate('Tracker_title_taskRunning'),
),
'location' => array(
'url' => function($data) use ($view) {
return $view->getModuleUrl($data['taskInfo']['id']);
},
'sleep' => 4000,
'freeze' => FALSE,
),
'message' => function($data) {
return trim($data['last']['title'] . "\n" . $data['last']['message']);
},
'notification' => FALSE
),
'success' => array(
'dialog' => array(
'action' => 'close',
'title' => '',
),
'location' => FALSE,
'message' => "",
'notification' => FALSE,
),
'failure' => array(
'dialog' => array(
'action' => 'close',
'title' => '',
),
'location' => FALSE,
'message' => "",
'notification' => array(
'data' => function($data) {
return \Nethgui\Module\Tracker::findFailures($data);
},
'template' => 'trackerError',
),
),
)), is_array($ui) ? $ui : array());
}
private function evalUiStatus($A, $data, \Nethgui\View\ViewInterface $view)
{
array_walk_recursive($A, function(&$v) use ($data) {
if (is_callable($v)) {
$v = call_user_func($v, $data);
}
});
if(isset($A['location']['url'])) {
$url = &$A['location']['url'];
$url = strtr($url, array('{taskId}' => $this->taskId));
if($url{0} != '/') {
$url = $view->getModuleUrl('/' . $url);
}
}
return $A;
}
private function prepareRunningTaskView(\Nethgui\View\ViewInterface $view)
{
$data = $this->systemTasks->getTaskStatus($this->taskId);
$ui = $this->applyTaskUiDefaults(isset($data['ui']) ? $data['ui'] : array(), array('view' => $view, 'notifications' => $this->notifications));
$status = 'running';
if (isset($data['exit_code'])) {
$status = $data['exit_code'] ? 'failure' : 'success';
}
$data['taskInfo'] = array('id' => $this->taskId);
$s = $this->evalUiStatus($ui['conditions'][$status], $data, $view);
if(is_numeric($data['progress'])) {
$view['progress'] = intval(100 * $data['progress']);
} else {
$view['progress'] = '...';
}
$view['message'] = $s['message'];
$view['trackerState'] = array(
'dialog' => $s['dialog'],
'location' => $s['location']
);
if(is_array($s['notification'])) {
call_user_func(array($this->notifications, $s['notification']['template']), $s['notification']['data']);
unset($view['notification']);
} elseif(is_string($s['notification'])) {
$this->notifications->notice($s['notification']);
}
}
public static function findFailures($data)
{
$errors = array();
$nodes = array($data);
while ($elem = array_shift($nodes)) {
if (isset($elem['exit_code']) || intval($elem['code']) != 0) {
if (count($elem['children']) > 0 && ! $elem['message']) {
$nodes = array_merge($nodes, $elem['children']);
} else {
$errors[] = array(
'title' => $elem['title'],
'message' => $elem['message'],
'code' => $elem['code'],
'id' => $elem['id']
);
}
}
}
return $errors;
}
private function prepareInitializationView(\Nethgui\View\ViewInterface $view)
{
$firstRunningTask = \Nethgui\array_head(array_keys($this->systemTasks->getRunningTasks()));
if ($firstRunningTask) {
$this->notifications->trackerRunning(array('taskId' => $firstRunningTask));
$view['trackerState'] = FALSE;
$view['progress'] = FALSE;
$view['message'] = '';
return;
}
$firstStartingTask = \Nethgui\array_head(array_keys($this->systemTasks->getStartingTasks()));
if ($firstStartingTask) {
$view['progress'] = 0;
$view['message'] = '...';
$view['trackerState'] = array(
'dialog' => array('title' => $view->translate('Tracker_title_taskStarting'), 'action' => 'open'),
'location' => array('sleep' => 2000, 'url' => $view->getModuleUrl($firstStartingTask))
);
return;
}
}
public function defineNotificationTemplate($name, $value)
{
$this->notifications->defineTemplate($name, $value);
return $this;
}
public function prepareView(\Nethgui\View\ViewInterface $view)
{
parent::prepareView($view);
$this->notifications->defineTemplate('trackerError', strtr(self::TRACKER_ERROR_TEMPLATE, array(
'{{genericLabel}}' => $view->translate('Tracker_task_error_message'),
'{{codeLabel}}' => $view->translate('Tracker_code_label'),
)), 'bg-red');
$this->notifications->defineTemplate('trackerRunning', strtr(self::TRACKER_RUNNING_TEMPLATE, array(
'{{message}}' => $view->translate('Tracker_running_tasks_message'),
'{{btnLink}}' => $view->getModuleUrl('/Tracker/{{taskId}}'),
'{{btnLabel}}' => $view->translate('Tracker_button_label')
)), 'bg-yellow');
if( ! $this->getRequest()->getUser()->isAuthenticated()) {
return;
}
if ($this->taskId === FALSE) {
$this->prepareInitializationView($view);
} else {
$this->prepareRunningTaskView($view);
}
}
public function setSystemTasks(\Nethgui\Model\SystemTasks $t)
{
$this->systemTasks = $t;
return $this;
}
public function setUserNotifications(\Nethgui\Model\UserNotifications $n)
{
$this->notifications = $n;
return $this;
}
public function setModuleSet(\Nethgui\Module\ModuleSetInterface $s)
{
$this->moduleSet = $s;
return $this;
}
public function getDependencySetters()
{
return array(
'SystemTasks' => array($this, 'setSystemTasks'),
'UserNotifications' => array($this, 'setUserNotifications'),
'ModuleSet' => array($this, 'setModuleSet')
);
}
}