- Refactors and renames code

- Adds Queue menu option and displays status
This commit is contained in:
MrCasual
2015-11-25 21:07:52 -05:00
parent 4208b148b4
commit 436faea591
11 changed files with 264 additions and 95 deletions

56
assets/js/src/queue.jsx Normal file
View File

@@ -0,0 +1,56 @@
define(
[
'react',
'react-dom',
'mailpoet',
'classnames'
],
function (
React,
ReactDOM,
MailPoet,
classNames
) {
var QueueDaemonControl = React.createClass({
getInitialState: function () {
return (queueDaemon) ? {status: queueDaemon.status} : null;
},
getDaemonData: function () {
MailPoet.Ajax.post({
endpoint: 'queue',
action: 'getQueueStatus'
}).done(function (response) {
this.setState({status: response.status});
}.bind(this));
},
componentDidMount: function () {
this.getDaemonData;
setInterval(this.getDaemonData, 2000);
},
render: function () {
if (!this.state) {
return (
<div className="QueueControl">
If you're seeing this message, queue daemon has not even been created!
</div>
)
}
return (
<div>
Queue is currently <b>{this.state.status}</b>
</div>
);
}
});
let container = document.getElementById('queue_container');
if (container) {
ReactDOM.render(
<QueueDaemonControl />,
container
)
}
}
);

View File

@@ -8,7 +8,9 @@
"tburry/pquery": "*",
"j4mie/paris": "1.5.4",
"swiftmailer/swiftmailer": "^5.4",
"phpseclib/phpseclib": "*"
"phpseclib/phpseclib": "*",
"mtdowling/cron-expression": "^1.0",
"nesbot/carbon": "^1.21"
},
"require-dev": {
"codeception/codeception": "*",

View File

@@ -137,7 +137,7 @@ class Initializer {
function runQueueSupervisor() {
try {
$supervisor = new Supervisor();
$supervisor->checkQueue();
$supervisor->checkDaemon();
} catch (\Exception $e) {
}
}

View File

@@ -2,16 +2,17 @@
namespace MailPoet\Config;
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
use \MailPoet\Models\Segment;
use \MailPoet\Models\Setting;
use \MailPoet\Models\Form;
use \MailPoet\Form\Block;
use \MailPoet\Form\Renderer as FormRenderer;
use \MailPoet\Settings\Hosts;
use \MailPoet\Settings\Pages;
use \MailPoet\Settings\Charsets;
use \MailPoet\Util\Permissions;
use \MailPoet\Util\DKIM;
use MailPoet\Form\Block;
use MailPoet\Form\Renderer as FormRenderer;
use MailPoet\Models\Form;
use MailPoet\Models\Segment;
use MailPoet\Models\Setting;
use MailPoet\Settings\Charsets;
use MailPoet\Settings\Hosts;
use MailPoet\Settings\Pages;
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
use MailPoet\Util\DKIM;
use MailPoet\Util\Permissions;
if(!defined('ABSPATH')) exit;
@@ -24,7 +25,10 @@ class Menu {
function init() {
add_action(
'admin_menu',
array($this, 'setup')
array(
$this,
'setup'
)
);
}
@@ -34,7 +38,10 @@ class Menu {
'MailPoet',
'manage_options',
'mailpoet',
array($this, 'home'),
array(
$this,
'home'
),
$this->assets_url . '/img/menu_icon.png',
30
);
@@ -44,7 +51,10 @@ class Menu {
__('Newsletters'),
'manage_options',
'mailpoet-newsletters',
array($this, 'newsletters')
array(
$this,
'newsletters'
)
);
add_submenu_page(
'mailpoet',
@@ -52,7 +62,10 @@ class Menu {
__('Forms'),
'manage_options',
'mailpoet-forms',
array($this, 'forms')
array(
$this,
'forms'
)
);
add_submenu_page(
'mailpoet',
@@ -60,7 +73,10 @@ class Menu {
__('Subscribers'),
'manage_options',
'mailpoet-subscribers',
array($this, 'subscribers')
array(
$this,
'subscribers'
)
);
add_submenu_page(
'mailpoet',
@@ -68,7 +84,10 @@ class Menu {
__('Segments'),
'manage_options',
'mailpoet-segments',
array($this, 'segments')
array(
$this,
'segments'
)
);
add_submenu_page(
'mailpoet',
@@ -76,7 +95,10 @@ class Menu {
__('Settings'),
'manage_options',
'mailpoet-settings',
array($this, 'settings')
array(
$this,
'settings'
)
);
add_submenu_page(
null,
@@ -84,7 +106,10 @@ class Menu {
__('Import'),
'manage_options',
'mailpoet-import',
array($this, 'import')
array(
$this,
'import'
)
);
add_submenu_page(
null,
@@ -92,7 +117,10 @@ class Menu {
__('Export'),
'manage_options',
'mailpoet-export',
array($this, 'export')
array(
$this,
'export'
)
);
add_submenu_page(
@@ -101,7 +129,10 @@ class Menu {
__('Welcome'),
'manage_options',
'mailpoet-welcome',
array($this, 'welcome')
array(
$this,
'welcome'
)
);
add_submenu_page(
@@ -110,7 +141,10 @@ class Menu {
__('Update'),
'manage_options',
'mailpoet-update',
array($this, 'update')
array(
$this,
'update'
)
);
add_submenu_page(
@@ -119,7 +153,10 @@ class Menu {
__('Form editor'),
'manage_options',
'mailpoet-form-editor',
array($this, 'formEditor')
array(
$this,
'formEditor'
)
);
add_submenu_page(
@@ -128,7 +165,22 @@ class Menu {
__('Newsletter editor'),
'manage_options',
'mailpoet-newsletter-editor',
array($this, 'newletterEditor')
array(
$this,
'newletterEditor'
)
);
add_submenu_page(
'mailpoet',
__('Queue'),
__('Queue'),
'manage_options',
'mailpoet-queue',
array(
$this,
'queue'
)
);
}
@@ -142,8 +194,8 @@ class Menu {
$current_url = home_url(add_query_arg($wp->query_string, $wp->request));
$redirect_url =
(!empty($_GET['mailpoet_redirect']))
? urldecode($_GET['mailpoet_redirect'])
: wp_get_referer();
? urldecode($_GET['mailpoet_redirect'])
: wp_get_referer();
if(
$redirect_url === $current_url
@@ -166,8 +218,8 @@ class Menu {
$current_url = home_url(add_query_arg($wp->query_string, $wp->request));
$redirect_url =
(!empty($_GET['mailpoet_redirect']))
? urldecode($_GET['mailpoet_redirect'])
: wp_get_referer();
? urldecode($_GET['mailpoet_redirect'])
: wp_get_referer();
if(
$redirect_url === $current_url
@@ -206,7 +258,8 @@ class Menu {
$data = array(
'settings' => $settings,
'segments' => Segment::getPublic()->findArray(),
'segments' => Segment::getPublished()
->findArray(),
'pages' => Pages::getAll(),
'flags' => $this->_getFlags(),
'charsets' => Charsets::getAll(),
@@ -234,11 +287,14 @@ class Menu {
// check if users can register
$flags['registration_enabled'] =
!(in_array($registration, array('none', 'blog')));
!(in_array($registration, array(
'none',
'blog'
)));
} else {
// check if users can register
$flags['registration_enabled'] =
(bool)get_option('users_can_register', false);
(bool) get_option('users_can_register', false);
}
return $flags;
@@ -272,7 +328,7 @@ class Menu {
$data['segments'] = Segment::findArray();
$settings = Setting::findArray();
$data['settings'] = array();
foreach($settings as $setting) {
foreach ($settings as $setting) {
$data['settings'][$setting['name']] = $setting['value'];
}
$data['roles'] = $wp_roles->get_names();
@@ -300,7 +356,7 @@ class Menu {
}
function formEditor() {
$id = (isset($_GET['id']) ? (int)$_GET['id'] : 0);
$id = (isset($_GET['id']) ? (int) $_GET['id'] : 0);
$form = Form::findOne($id);
if($form !== false) {
$form = $form->asArray();
@@ -309,7 +365,8 @@ class Menu {
$data = array(
'form' => $form,
'pages' => Pages::getAll(),
'segments' => Segment::getPublic()->findArray(),
'segments' => Segment::getPublished()
->findArray(),
'styles' => FormRenderer::getStyles($form),
'date_types' => Block\Date::getDateTypes(),
'date_formats' => Block\Date::getDateFormats()
@@ -317,4 +374,10 @@ class Menu {
echo $this->renderer->render('form/editor.html', $data);
}
function queue() {
$daemon = new \MailPoet\Queue\BootStrapMenu();
$data['daemon'] = json_encode($daemon->bootstrap());
echo $this->renderer->render('queue.html', $data);
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace MailPoet\Queue;
use MailPoet\Models\Setting;
class BootStrapMenu {
function __construct() {
$this->daemon = Setting::where('name', 'daemon')
->findOne()
->asArray();
}
function bootStrap() {
return ($this->daemon) ?
array_merge(
array(
'started_at' => $this->daemon['created_at'],
'updated_at' => $this->daemon['updated_at']
),
json_decode($this->daemon['value'], true)
) :
"false";
}
}

View File

@@ -12,7 +12,7 @@ class Daemon {
function __construct($payload = array()) {
set_time_limit(0);
ignore_user_abort();
list ($this->queue, $this->queueData) = $this->getQueue();
list ($this->daemon, $this->daemonData) = $this->getDaemon();
$this->refreshedToken = $this->refreshToken();
$this->payload = $payload;
$this->timer = microtime(true);
@@ -23,30 +23,30 @@ class Daemon {
$this->abortWithError('missing session ID');
}
$this->manageSession('start');
$queue = $this->queue;
$queueData = $this->queueData;
if(!$queue) {
$queue = Setting::create();
$queue->name = 'queue';
$queue->value = json_encode(array('status' => 'stopped'));
$queue->save();
$daemon = $this->daemon;
$daemonData = $this->daemonData;
if(!$daemon) {
$daemon = Setting::create();
$daemon->name = 'daemon';
$daemon->value = json_encode(array('status' => 'stopped'));
$daemon->save();
}
if($queueData['status'] !== 'started') {
$_SESSION['queue'] = 'started';
$queueData = array(
if($daemonData['status'] !== 'started') {
$_SESSION['daemon'] = 'started';
$daemonData = array(
'status' => 'started',
'token' => $this->refreshedToken,
'counter' => ($queueData['status'] === 'paused') ?
$queueData['counter'] :
'counter' => ($daemonData['status'] === 'paused') ?
$daemonData['counter'] :
0
);
$_SESSION['queue'] = array('result' => true);
$_SESSION['daemon'] = array('result' => true);
$this->manageSession('end');
$queue->value = json_encode($queueData);
$queue->save();
$daemon->value = json_encode($daemonData);
$daemon->save();
$this->callSelf();
} else {
$_SESSION['queue'] = array(
$_SESSION['daemon'] = array(
'result' => false,
'error' => 'already started'
);
@@ -55,33 +55,37 @@ class Daemon {
}
function run() {
if(!$this->queue || $this->queueData['status'] !== 'started') {
if(!$this->daemon || $this->daemonData['status'] !== 'started') {
$this->abortWithError('not running');
}
if(!isset($this->payload['token']) ||
$this->payload['token'] !== $this->queueData['token']
$this->payload['token'] !== $this->daemonData['token']
) {
$this->abortWithError('invalid token');
}
$worker = new Worker();
$worker->process();
// after each execution, read queue in case it's status was modified
list($queue, $queueData) = $this->getQueue();
$queueData['counter']++;
$queueData['token'] = $this->refreshedToken;
$queue->value = json_encode($queueData);
$queue->save();
$elapsedTime = microtime(true) - $this->timer;
if ($elapsedTime < 30) {
sleep(30 - $elapsedTime);
}
// after each execution, read daemon in case it's status was modified
list($daemon, $daemonData) = $this->getDaemon();
$daemonData['counter']++;
$daemonData['token'] = $this->refreshedToken;
$daemon->value = json_encode($daemonData);
$daemon->save();
$this->callSelf();
}
function getQueue() {
$queue = Setting::where('name', 'queue')
function getDaemon() {
$daemon = Setting::where('name', 'daemon')
->findOne();
return array(
($queue) ? $queue : null,
($queue) ? json_decode($queue->value, true) : null
($daemon) ? $daemon : null,
($daemon) ? json_decode($daemon->value, true) : null
);
}

View File

@@ -13,15 +13,16 @@ class Supervisor {
if(!Env::isPluginActivated()) {
throw new \Exception('Database has not been configured.');
}
list ($this->queue, $this->queueData) = $this->getQueue();
list ($this->daemon, $this->daemonData) = $this->getDaemon();
}
function checkQueue() {
if(!$this->queue) {
return $this->startQueue();
function checkDaemon() {
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])) return;
if(!$this->daemon) {
return $this->startDaemon();
} else {
if(!$this->forceStart && ($this->queueData['status'] === 'paused' ||
$this->queueData['status'] === 'stopped'
if(!$this->forceStart && ($this->daemonData['status'] === 'paused' ||
$this->daemonData['status'] === 'stopped'
)
) {
return;
@@ -29,40 +30,40 @@ class Supervisor {
$currentTime = Carbon::now('UTC');
$lastUpdateTime = Carbon::createFromFormat(
'Y-m-d H:i:s',
$this->queue->updated_at, 'UTC'
$this->daemon->updated_at, 'UTC'
);
$timeSinceLastStart = $currentTime->diffInSeconds($lastUpdateTime);
if($timeSinceLastStart < 5) return;
$this->queueData['status'] = 'paused';
$this->queue->value = json_encode($this->queueData);
$this->queue->save();
return $this->startQueue();
$this->daemonData['status'] = 'paused';
$this->daemon->value = json_encode($this->daemonData);
$this->daemon->save();
return $this->startDaemon();
}
}
function startQueue() {
function startDaemon() {
if(!session_id()) session_start();
$sessionId = session_id();
session_write_close();
$_SESSION['queue'] = null;
$_SESSION['daemon'] = null;
$payload = json_encode(array('session' => $sessionId));
self::getRemoteUrl(
'/?mailpoet-api&section=queue&action=start&payload=' . urlencode($payload)
);
session_start();
$queueStatus = $_SESSION['queue'];
unset($_SESSION['queue']);
$daemonStatus = $_SESSION['daemon'];
unset($_SESSION['daemon']);
session_write_close();
return $queueStatus;
return $daemonStatus;
}
function getQueue() {
$queue = Setting::where('name', 'queue')
function getDaemon() {
$daemon = Setting::where('name', 'daemon')
->findOne();
$queueData = ($queue) ? json_decode($queue->value, true) : false;
$daemonData = ($daemon) ? json_decode($daemon->value, true) : false;
return array(
$queue,
$queueData
$daemon,
$daemonData
);
}

View File

@@ -28,8 +28,9 @@ class Worker {
if(!isset($subscribers['processed'])) $subscribers['processed'] = array();
$subscribersToProcess = $subscribers['to_process'];
foreach ($subscribersToProcess as $subscriber) {
if(microtime(true) - $this->timer >= 28) break;
// TODO: remove
$elapsedTime = microtime(true) - $this->timer;
if($elapsedTime >= 28) break;
// TODO: hook up to mailer
sleep(1);
$newsletterStatistics = NewsletterStatistics::create();
$newsletterStatistics->subscriber_id = $subscriber;

View File

@@ -1,6 +1,7 @@
<?php
namespace MailPoet\Router;
use MailPoet\Models\Setting;
use MailPoet\Queue\Daemon;
use MailPoet\Queue\Supervisor;
@@ -11,7 +12,7 @@ class Queue {
$supervisor = new Supervisor();
wp_send_json(
array(
'result' => ($supervisor->checkQueue($forceStart = true)) ?
'result' => ($supervisor->checkDaemon($forceStart = true)) ?
true :
false
)
@@ -27,13 +28,13 @@ class Queue {
$status = 'paused';
break;
}
$queue = new Daemon();
if(!$queue->queue || $queue->queueData['status'] !== 'started') {
$daemon = new Daemon();
if(!$daemon->daemon || $daemon->daemonData['status'] !== 'started') {
$result = false;
} else {
$queue->queueData['status'] = $status;
$queue->queue->value = json_encode($queue->queueData);
$result = $queue->queue->save();
$daemon->daemonData['status'] = $status;
$daemon->daemon->value = json_encode($daemon->daemonData);
$result = $daemon->daemon->save();
}
wp_send_json(
array(
@@ -41,4 +42,10 @@ class Queue {
)
);
}
function getQueueStatus() {
$daemon = new \MailPoet\Queue\BootStrapMenu();
wp_send_json($daemon->bootStrap());
}
}

10
views/queue.html Normal file
View File

@@ -0,0 +1,10 @@
<% extends 'layout.html' %>
<% block content %>
<div id="queue_container"></div>
<script type="text/javascript">
</script>
<script>
var queueDaemon = <%= daemon|raw %>
</script>
<% endblock %>

View File

@@ -102,7 +102,8 @@ config.push(_.extend({}, baseConfig, {
'settings/tabs.js',
'subscribers/importExport/import.js',
'subscribers/importExport/export.js',
'helpscout'
'helpscout',
'queue.jsx'
],
form_editor: [
'form_editor/form_editor.js',