Browse Source

Move to promises to prevent freezes in the linker

pull/277/head
Timothée Jaussoin 9 years ago
parent
commit
992689535e
  1. 1
      CHANGELOG.md
  2. 34
      app/helpers/UtilsHelper.php
  3. 16
      app/models/message/Message.php
  4. 70
      app/models/postn/Postn.php
  5. 4
      app/models/postn/PostnDAO.php
  6. 63
      app/widgets/Chat/Chat.php
  7. 7
      composer.json
  8. 260
      composer.lock
  9. 92
      linker.php
  10. 45
      src/Movim/Task/CheckSmallPicture.php
  11. 29
      src/Movim/Task/Engine.php
  12. 4
      themes/material/css/icon.css
  13. 53
      themes/material/css/listn.css

1
CHANGELOG.md

@ -3,6 +3,7 @@ Movim Changelog
v0.11 (trunk)
---------------------------
* Rewrite blocking code to asyncrone promises
* Navigation improvement
* Add previous/next post shortcut in the footer of each posts
* Highlight mentionned messages in chatrooms

34
app/helpers/UtilsHelper.php

@ -587,40 +587,6 @@ function requestURL($url, $timeout = 10, $post = false)
}
}
/*
* @desc Check if the URL is a small picture
*/
function isSmallPicture($url, $size = false)
{
if(!$size) $size = SMALL_PICTURE_LIMIT;
$client = new Client([
'request.options' => [
'timeout' => 2,
'connect_timeout' => 2
]
]);
try {
$response = $client->head($url);
$length = $response->getHeader('content-length');
if($length) {
$length = (int)$length[0];
$type = (string)$response->getHeader('content-type')[0];
$typearr = explode('/', $type);
return ($typearr[0] == 'image'
&& $length <= $size
&& $length >= 10000);
}
return false;
} catch(\Exception $e) {
return false;
}
}
/*
* @desc Get the URI of a smiley
*/

16
app/models/message/Message.php

@ -150,17 +150,25 @@ class Message extends Model {
else
$this->published = gmdate('Y-m-d H:i:s');
$this->checkPicture();
return $this->checkPicture();
}
}
public function checkPicture()
{
$body = trim($this->body);
if(Validator::url()->notEmpty()->validate($body)
&& isSmallPicture($body)) {
$this->picture = $body;
if(Validator::url()->notEmpty()->validate($body)) {
$check = new \Movim\Task\CheckSmallPicture;
return $check->run($body)
->then(function($small) use($body) {
$this->picture = $body;
});
}
return new \React\Promise\Promise(function($resolve) {
$resolve(true);
});
}
public function convertEmojis()

70
app/models/postn/Postn.php

@ -244,29 +244,6 @@ class Postn extends Model {
$this->__set('content', trim($content));
$this->contentcleaned = purifyHTML(html_entity_decode($this->content));
$extra = false;
// We try to extract a picture
$xml = \simplexml_load_string('<div>'.$this->contentcleaned.'</div>');
if($xml) {
$results = $xml->xpath('//img/@src');
if(is_array($results) && !empty($results)) {
$extra = (string)$results[0];
if(isSmallPicture($extra)) {
$this->picture = $extra;
}
}
$results = $xml->xpath('//video/@poster');
if(is_array($results) && !empty($results)) {
$extra = (string)$results[0];
if(isSmallPicture($extra)) {
$this->picture = $extra;
}
}
}
$this->setAttachments($entry->entry->link, $extra);
if($entry->entry->geoloc) {
if($entry->entry->geoloc->lat != 0)
$this->__set('lat', (string)$entry->entry->geoloc->lat);
@ -291,19 +268,58 @@ class Postn extends Model {
$this->__set('reply', serialize($reply));
}
$extra = false;
// We try to extract a picture
$xml = \simplexml_load_string('<div>'.$this->contentcleaned.'</div>');
if($xml) {
$results = $xml->xpath('//img/@src');
$check = new \Movim\Task\CheckSmallPicture;
if(is_array($results) && !empty($results)) {
$extra = (string)$results[0];
return $check->run($extra)
->then(function($small) use($extra, $entry) {
if($small) $this->picture = $extra;
$this->setAttachments($entry->entry->link, $extra);
});
} else {
$results = $xml->xpath('//video/@poster');
if(is_array($results) && !empty($results)) {
$extra = (string)$results[0];
return $check->run($extra)
->then(function($small) use($extra, $entry) {
$this->picture = $extra;
$this->setAttachments($entry->entry->link, $extra);
});
}
}
}
$this->setAttachments($entry->entry->link, $extra);
return new \React\Promise\Promise(function($resolve) {
$resolve(true);
});
}
private function typeIsPicture($type) {
private function typeIsPicture($type)
{
return in_array($type, ['image/jpeg', 'image/png', 'image/jpg', 'image/gif']);
}
private function typeIsLink($link) {
private function typeIsLink($link)
{
return (isset($link['rel'])
&& in_array($link['rel'], ['related', 'alternate'])
&& Validator::url()->validate($link['href']));
}
private function setAttachments($links, $extra = false) {
private function setAttachments($links, $extra = false)
{
$l = [];
foreach($links as $attachment) {
@ -315,7 +331,7 @@ class Postn extends Model {
if($this->picture == null
&& isset($enc['type'])
&& $this->typeIsPicture($enc['type'])
&& isSmallPicture($enc['href'])) {
/*&& isSmallPicture($enc['href'])*/) {
$this->picture = $enc['href'];
}

4
app/models/postn/PostnDAO.php

@ -579,7 +579,9 @@ class PostnDAO extends SQL {
$this->_sql = '
select count(*) from postn
where origin = :origin
and node = :node';
and node = :node
and (title != \'\'
or contentraw != \'\')';
$this->prepare(
'Postn',

63
app/widgets/Chat/Chat.php

@ -280,43 +280,46 @@ class Chat extends \Movim\Widget\Base
}
$m->body = $body;
$m->checkPicture();
//$m->html = prepareString($m->body, false, true);
$promise = $m->checkPicture();
if($resource != false) {
$to = $to . '/' . $resource;
}
// We decode URL codes to send the correct message to the XMPP server
$p = new Publish;
$p->setTo($to);
//$p->setHTML($m->html);
$p->setContent($m->body);
$promise->done(function() use ($m, $to, $muc, $resource, $replace) {
//$m->html = prepareString($m->body, false, true);
if($replace != false) {
$p->setId($m->newid);
$p->setReplace($m->id);
} else {
$p->setId($m->id);
}
if($resource != false) {
$to = $to . '/' . $resource;
}
if($muc) {
$p->setMuc();
}
// We decode URL codes to send the correct message to the XMPP server
$p = new Publish;
$p->setTo($to);
//$p->setHTML($m->html);
$p->setContent($m->body);
$p->request();
if($replace != false) {
$p->setId($m->newid);
$p->setReplace($m->id);
} else {
$p->setId($m->id);
}
/* Is it really clean ? */
if(!$p->getMuc()) {
if(!preg_match('#^\?OTR#', $m->body)) {
$md = new \Modl\MessageDAO;
$md->set($m);
if($muc) {
$p->setMuc();
}
$packet = new Moxl\Xec\Payload\Packet;
$packet->content = $m;
$this->onMessage($packet/*, true*/);
}
$p->request();
/* Is it really clean ? */
if(!$p->getMuc()) {
if(!preg_match('#^\?OTR#', $m->body)) {
$md = new \Modl\MessageDAO;
$md->set($m);
}
$packet = new Moxl\Xec\Payload\Packet;
$packet->content = $m;
$this->onMessage($packet/*, true*/);
}
});
}
/**

7
composer.json

@ -17,15 +17,13 @@
"movim/modl": "dev-master",
"movim/sasl2": "dev-master",
"movim/moxl": "dev-master#5a6dc21bfd93bc42779b4a7b8079597af77d4d9b",
"movim/moxl": "dev-master#39b8a43bf8f24d08fa7bfe2223956f4a421e2359",
"embed/embed": "dev-master",
"heyupdate/emoji": "0.2.*@dev",
"cboden/ratchet": "0.3.*",
"react/child-process": "dev-master",
"react/socket-client": "dev-master",
"react/stream": "0.4.*",
"react/http": "dev-master#cd15204bd15d106d7832c680e4fb0ca0ce2f5e30",
"react/promise-timer": "^1.1",
@ -36,6 +34,7 @@
"ramsey/uuid": "^3.2",
"symfony/console": "^3.0",
"cocur/slugify": "^2.1",
"guzzlehttp/guzzle": "^6.2"
"guzzlehttp/guzzle": "^6.2",
"clue/buzz-react": "^1.0"
}
}

260
composer.lock

@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "9adc4077ee82141506beee86b04f5faf",
"content-hash": "4c51ae333e7d609396813667ff08fa1e",
"hash": "bd2862efa454d71557574a68b0b2309e",
"content-hash": "0bf5ab4df20ab58892020d7ae4b4d2ca",
"packages": [
{
"name": "cboden/ratchet",
@ -55,6 +55,61 @@
],
"time": "2016-05-25 12:55:03"
},
{
"name": "clue/buzz-react",
"version": "v1.0.1",
"source": {
"type": "git",
"url": "https://github.com/clue/php-buzz-react.git",
"reference": "0b2bdeefaf4e09aed5bd122909589e3573afb5f4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/clue/php-buzz-react/zipball/0b2bdeefaf4e09aed5bd122909589e3573afb5f4",
"reference": "0b2bdeefaf4e09aed5bd122909589e3573afb5f4",
"shasum": ""
},
"require": {
"php": ">=5.3",
"psr/http-message": "^1.0",
"react/dns": "^0.4.1 || ^0.3",
"react/event-loop": "^0.4 || ^0.3",
"react/http-client": "^0.4 || ^0.3",
"react/promise": "^2 || ^1.1",
"react/socket-client": "^0.5 || ^0.4.5",
"react/stream": "^0.4 || ^0.3.1",
"ringcentral/psr7": "^1.2"
},
"require-dev": {
"clue/block-react": "^1.0",
"phpunit/phpunit": "^4.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Clue\\React\\Buzz\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Christian Lück",
"email": "christian@lueck.tv"
}
],
"description": "Simple, async HTTP client for concurrently processing any number of HTTP requests, built on top of React PHP",
"homepage": "https://github.com/clue/php-buzz-react",
"keywords": [
"async",
"http",
"http client",
"reactphp"
],
"time": "2016-08-12 11:50:24"
},
{
"name": "cocur/slugify",
"version": "v2.3",
@ -886,12 +941,12 @@
"source": {
"type": "git",
"url": "https://github.com/movim/moxl.git",
"reference": "5a6dc21bfd93bc42779b4a7b8079597af77d4d9b"
"reference": "39b8a43bf8f24d08fa7bfe2223956f4a421e2359"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/movim/moxl/zipball/5a6dc21bfd93bc42779b4a7b8079597af77d4d9b",
"reference": "5a6dc21bfd93bc42779b4a7b8079597af77d4d9b",
"url": "https://api.github.com/repos/movim/moxl/zipball/39b8a43bf8f24d08fa7bfe2223956f4a421e2359",
"reference": "39b8a43bf8f24d08fa7bfe2223956f4a421e2359",
"shasum": ""
},
"require": {
@ -926,7 +981,7 @@
"php",
"xmpp"
],
"time": "2016-09-26 20:26:44"
"time": "2016-10-05 21:33:05"
},
{
"name": "movim/sasl2",
@ -1213,16 +1268,16 @@
},
{
"name": "ramsey/uuid",
"version": "3.5.0",
"version": "3.5.1",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
"reference": "a6d15c8618ea3951fd54d34e326b68d3d0bc0786"
"reference": "a07797b986671b0dc823885a81d5e3516b931599"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/a6d15c8618ea3951fd54d34e326b68d3d0bc0786",
"reference": "a6d15c8618ea3951fd54d34e326b68d3d0bc0786",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/a07797b986671b0dc823885a81d5e3516b931599",
"reference": "a07797b986671b0dc823885a81d5e3516b931599",
"shasum": ""
},
"require": {
@ -1289,7 +1344,7 @@
"identifier",
"uuid"
],
"time": "2016-08-02 18:39:32"
"time": "2016-10-02 15:51:17"
},
{
"name": "react/cache",
@ -1482,6 +1537,46 @@
],
"time": "2016-07-06 23:51:32"
},
{
"name": "react/http-client",
"version": "v0.4.11",
"source": {
"type": "git",
"url": "https://github.com/reactphp/http-client.git",
"reference": "4d367ff9909954bafe6a04762ec68e6b1e12bcf8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/http-client/zipball/4d367ff9909954bafe6a04762ec68e6b1e12bcf8",
"reference": "4d367ff9909954bafe6a04762ec68e6b1e12bcf8",
"shasum": ""
},
"require": {
"evenement/evenement": "~2.0",
"guzzlehttp/psr7": "^1.0",
"php": ">=5.4.0",
"react/dns": "0.4.*",
"react/event-loop": "0.4.*",
"react/promise": "~2.2",
"react/socket-client": "^0.5 || ^0.4 || ^0.3",
"react/stream": "0.4.*"
},
"type": "library",
"autoload": {
"psr-4": {
"React\\HttpClient\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Asynchronous HTTP client library.",
"keywords": [
"http"
],
"time": "2016-09-15 20:59:05"
},
{
"name": "react/promise",
"version": "v2.4.1",
@ -1619,7 +1714,7 @@
},
{
"name": "react/socket-client",
"version": "dev-master",
"version": "v0.5.0",
"source": {
"type": "git",
"url": "https://github.com/reactphp/socket-client.git",
@ -1766,6 +1861,64 @@
],
"time": "2016-09-19 16:22:39"
},
{
"name": "ringcentral/psr7",
"version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/ringcentral/psr7.git",
"reference": "2594fb47cdc659f3fcf0aa1559b7355460555303"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ringcentral/psr7/zipball/2594fb47cdc659f3fcf0aa1559b7355460555303",
"reference": "2594fb47cdc659f3fcf0aa1559b7355460555303",
"shasum": ""
},
"require": {
"php": ">=5.3",
"psr/http-message": "~1.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"RingCentral\\Psr7\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "PSR-7 message implementation",
"keywords": [
"http",
"message",
"stream",
"uri"
],
"time": "2016-03-25 17:36:49"
},
{
"name": "stojg/crop",
"version": "dev-master",
@ -1814,20 +1967,21 @@
},
{
"name": "symfony/console",
"version": "v3.1.4",
"version": "v3.1.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "8ea494c34f0f772c3954b5fbe00bffc5a435e563"
"reference": "6cb0872fb57b38b3b09ff213c21ed693956b9eb0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/8ea494c34f0f772c3954b5fbe00bffc5a435e563",
"reference": "8ea494c34f0f772c3954b5fbe00bffc5a435e563",
"url": "https://api.github.com/repos/symfony/console/zipball/6cb0872fb57b38b3b09ff213c21ed693956b9eb0",
"reference": "6cb0872fb57b38b3b09ff213c21ed693956b9eb0",
"shasum": ""
},
"require": {
"php": ">=5.5.9",
"symfony/debug": "~2.8|~3.0",
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
@ -1870,11 +2024,68 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2016-08-19 06:48:39"
"time": "2016-09-28 00:11:12"
},
{
"name": "symfony/debug",
"version": "v3.1.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "e2b3f74a67fc928adc3c1b9027f73e1bc01190a8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/e2b3f74a67fc928adc3c1b9027f73e1bc01190a8",
"reference": "e2b3f74a67fc928adc3c1b9027f73e1bc01190a8",
"shasum": ""
},
"require": {
"php": ">=5.5.9",
"psr/log": "~1.0"
},
"conflict": {
"symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2"
},
"require-dev": {
"symfony/class-loader": "~2.8|~3.0",
"symfony/http-kernel": "~2.8|~3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Debug\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
"time": "2016-09-06 11:02:40"
},
{
"name": "symfony/event-dispatcher",
"version": "v3.1.4",
"version": "v3.1.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
@ -1934,16 +2145,16 @@
},
{
"name": "symfony/http-foundation",
"version": "v3.1.4",
"version": "v3.1.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "63592e00fd90632b57ee50220a1ddb29b6bf3bb4"
"reference": "5114f1becca9f29e3af94374f1689c83c1aa3d97"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/63592e00fd90632b57ee50220a1ddb29b6bf3bb4",
"reference": "63592e00fd90632b57ee50220a1ddb29b6bf3bb4",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/5114f1becca9f29e3af94374f1689c83c1aa3d97",
"reference": "5114f1becca9f29e3af94374f1689c83c1aa3d97",
"shasum": ""
},
"require": {
@ -1983,7 +2194,7 @@
],
"description": "Symfony HttpFoundation Component",
"homepage": "https://symfony.com",
"time": "2016-08-22 12:11:19"
"time": "2016-09-21 20:55:10"
},
{
"name": "symfony/polyfill-mbstring",
@ -2046,7 +2257,7 @@
},
{
"name": "symfony/routing",
"version": "v3.1.4",
"version": "v3.1.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
@ -2132,7 +2343,6 @@
"embed/embed": 20,
"heyupdate/emoji": 20,
"react/child-process": 20,
"react/socket-client": 20,
"react/http": 20,
"stojg/crop": 20
},

92
linker.php

@ -16,6 +16,8 @@ $loop = React\EventLoop\Factory::create();
$connector = new React\SocketClient\TcpConnector($loop);
$stdin = new React\Stream\Stream(STDIN, $loop);
\Movim\Task\Engine::init($loop);
fwrite(STDERR, colorize(getenv('sid'), 'yellow')." widgets before : ".\sizeToCleanSize(memory_get_usage())."\n");
// We load and register all the widgets
@ -55,6 +57,28 @@ $loop->addPeriodicTimer(5, function() use(&$conn, &$timestamp) {
}
});*/
function emptyBuffers() {
global $conn;
$msg = \RPC::commit();
if(!empty($msg)) {
echo base64_encode(gzcompress(json_encode($msg), 9))."";
//fwrite(STDERR, colorize(json_encode($msg).' '.strlen($msg), 'yellow')." : ".colorize('sent to browser', 'green')."\n");
}
\RPC::clear();
$xml = \Moxl\API::commit();
if(!empty($xml) && $conn) {
$conn->write(trim($xml));
#fwrite(STDERR, colorize(trim($xml), 'yellow')." : ".colorize('sent to XMPP', 'green')."\n");
}
\Moxl\API::clear();
}
$stdin_behaviour = function ($data) use (&$conn, $loop, &$buffer, &$connector, &$xmpp_behaviour, &$parser, &$timestamp) {
if(substr($data, -1) == "") {
$messages = explode("", $buffer . substr($data, 0, -1));
@ -125,36 +149,10 @@ $stdin_behaviour = function ($data) use (&$conn, $loop, &$buffer, &$connector, &
return;
}
$resolver = function (callable $resolve, callable $reject) use (&$conn, $msg) {
$rpc = new \RPC();
$rpc->handle_json($msg);
$resolve(true);
};
$canceller = function (callable $resolve, callable $reject) {
$reject(new \Exception('Promise cancelled'));
};
$promise = new React\Promise\Promise($resolver, $canceller);
$promise->then(function ($value) use ($conn) {
$msg = \RPC::commit();
\RPC::clear();
if(!empty($msg)) {
echo base64_encode(gzcompress(json_encode($msg), 9))."";
}
$xml = \Moxl\API::commit();
\Moxl\API::clear();
if(!empty($xml) && $conn) {
$conn->write(trim($xml));
#fwrite(STDERR, colorize(trim($xml), 'yellow')." : ".colorize('sent to XMPP', 'green')."\n");
}
});
$rpc = new \RPC();
$rpc->handle_json($msg);
emptyBuffers($conn);
}
} else {
$buffer .= $data;
@ -214,9 +212,6 @@ $xmpp_behaviour = function (React\Stream\Stream $stream) use (&$conn, $loop, &$s
#fwrite(STDERR, colorize(getenv('sid'), 'yellow')." widgets : ".\sizeToCleanSize(memory_get_usage())."\n");
\Moxl\API::clear();
\RPC::clear();
$timestamp = time();
if($restart) {
@ -232,42 +227,15 @@ $xmpp_behaviour = function (React\Stream\Stream $stream) use (&$conn, $loop, &$s
while($parser->nodes && !$parser->nodes->isEmpty()) {
$node = $parser->nodes->dequeue();
$resolver = function (callable $resolve, callable $reject) use (&$parser, &$conn, $message, $node) {
\Moxl\Xec\Handler::handle($node);
$resolve(true);
};
$canceller = function (callable $resolve, callable $reject) {
$reject(new \Exception('Promise cancelled'));
};
$promise = new React\Promise\Promise($resolver, $canceller);
$promise->then(function ($value) use ($conn) {
$msg = \RPC::commit();
if(!empty($msg)) {
echo base64_encode(gzcompress(json_encode($msg), 9))."";
//fwrite(STDERR, colorize(json_encode($msg).' '.strlen($msg), 'yellow')." : ".colorize('sent to browser', 'green')."\n");
}
\RPC::clear();
$xml = \Moxl\API::commit();
if(!empty($xml)) {
$conn->write(trim($xml));
#fwrite(STDERR, colorize(trim($xml), 'yellow')." : ".colorize('sent to XMPP', 'green')."\n");
}
\Moxl\API::clear();
});
\Moxl\Xec\Handler::handle($node);
$loop->tick();
unset($node);
}
emptyBuffers($conn);
//gc_collect_cycles();
//fwrite(STDERR, colorize(getenv('sid'), 'yellow')." end data : ".\sizeToCleanSize(memory_get_usage())."\n");
//memprof_dump_callgrind(fopen("/tmp/callgrind.out", "w"));

45
src/Movim/Task/CheckSmallPicture.php

@ -0,0 +1,45 @@
<?php
namespace Movim\Task;
use Clue\React\Buzz\Browser;
use Psr\Http\Message\ResponseInterface;
class CheckSmallPicture extends Engine {
private $_client;
public function __construct()
{
$engine = parent::start();
$browser = new Browser($engine->_loop);
$this->_client = $browser->withOptions([
'timeout' => 2
]);
}
public function run($url)
{
return $this->_client->head($url)
->then(function (ResponseInterface $response) {
$length = $response->getHeader('content-length');
$size = 300000;
if($length) {
$length = (int)$length[0];
$type = (string)$response->getHeader('content-type')[0];
$typearr = explode('/', $type);
return ($typearr[0] == 'image'
&& $length <= $size
&& $length >= 10000);
}
return false;
},
function (\Exception $error) {
return false;
})
->always(function() { emptyBuffers(); });
}
}

29
src/Movim/Task/Engine.php

@ -0,0 +1,29 @@
<?php
namespace Movim\Task;
use React\EventLoop\LoopInterface;
class Engine
{
private static $_instance;
public $_loop;
private function __construct(LoopInterface $loop)
{
$this->_loop = $loop;
}
public static function init(LoopInterface $loop)
{
if(!isset(self::$_instance)) {
self::$_instance = new self($loop);
} else {
self::start();
}
}
public static function start()
{
return self::$_instance;
}
}

4
themes/material/css/icon.css

@ -33,6 +33,10 @@ span.icon.primary.thumb {
line-height: 7.5rem;
}
*[dir="rtl"] span.icon.primary.thumb {
right: 0;
}
li.oppose span.icon {
left: auto;
right: 2rem;

53
themes/material/css/listn.css

@ -448,3 +448,56 @@ ul.list li.divided,
width: calc(100% - 9rem);
}
/* RTL */
*[dir="rtl"] :not(nav) ul.list li > .primary {
left: auto;
right: 1.5rem;
}
*[dir="rtl"] :not(nav) ul.list li > .primary.bubble {
left: auto;
right: 2rem;
}
*[dir="rtl"] :not(nav) ul.list li > .primary ~ *:not(.primary):not(.counter):not(.bubble):not(.control):not(ul) {
padding-left: 2rem;
padding-right: 9rem;
}
*[dir="rtl"] :not(nav) ul.list li > .top + .primary ~ *:not(.primary):not(.counter):not(.bubble):not(.control) {
padding-left: 2rem;
padding-right: 2rem;
}
*[dir="rtl"] :not(nav) ul.list li > .control {
right: auto;
left: 0;
}
*[dir="rtl"] :not(nav) ul.list li > .control ~ .control {
right: auto;
left: 6rem;
}
*[dir="rtl"] :not(nav) ul.list li > .control ~ .control ~ .control {
right: auto;
left: 12rem;
}
*[dir="rtl"] :not(nav) ul.list li > .control ~ *:not(.control):not(.bubble):not(.counter) {
margin-right: auto;
margin-left: 6rem;
}
*[dir="rtl"] :not(nav) ul.list li > .control ~ .control ~ *:not(.control):not(.bubble):not(.counter) {
margin-right: auto;
margin-left: 12rem;
}
*[dir="rtl"] :not(nav) ul.list li > .control ~ .control ~ .control ~ *:not(.control):not(.bubble):not(.counter) {
margin-right: 0;
margin-left: 18rem;
}
Loading…
Cancel
Save