commit vendor
This commit is contained in:
27
vendor/sabre/event/LICENSE
vendored
Normal file
27
vendor/sabre/event/LICENSE
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (C) 2013-2016 fruux GmbH (https://fruux.com/)
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name Sabre nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
19
vendor/sabre/event/lib/Emitter.php
vendored
Normal file
19
vendor/sabre/event/lib/Emitter.php
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Event;
|
||||
|
||||
/**
|
||||
* Emitter object.
|
||||
*
|
||||
* Instantiate this class, or subclass it for easily creating event emitters.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class Emitter implements EmitterInterface
|
||||
{
|
||||
use EmitterTrait;
|
||||
}
|
||||
78
vendor/sabre/event/lib/EmitterInterface.php
vendored
Normal file
78
vendor/sabre/event/lib/EmitterInterface.php
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Event;
|
||||
|
||||
/**
|
||||
* Event Emitter Interface.
|
||||
*
|
||||
* Anything that accepts listeners and emits events should implement this
|
||||
* interface.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
interface EmitterInterface
|
||||
{
|
||||
/**
|
||||
* Subscribe to an event.
|
||||
*/
|
||||
public function on(string $eventName, callable $callBack, int $priority = 100);
|
||||
|
||||
/**
|
||||
* Subscribe to an event exactly once.
|
||||
*/
|
||||
public function once(string $eventName, callable $callBack, int $priority = 100);
|
||||
|
||||
/**
|
||||
* Emits an event.
|
||||
*
|
||||
* This method will return true if 0 or more listeners were successfully
|
||||
* handled. false is returned if one of the events broke the event chain.
|
||||
*
|
||||
* If the continueCallBack is specified, this callback will be called every
|
||||
* time before the next event handler is called.
|
||||
*
|
||||
* If the continueCallback returns false, event propagation stops. This
|
||||
* allows you to use the eventEmitter as a means for listeners to implement
|
||||
* functionality in your application, and break the event loop as soon as
|
||||
* some condition is fulfilled.
|
||||
*
|
||||
* Note that returning false from an event subscriber breaks propagation
|
||||
* and returns false, but if the continue-callback stops propagation, this
|
||||
* is still considered a 'successful' operation and returns true.
|
||||
*
|
||||
* Lastly, if there are 5 event handlers for an event. The continueCallback
|
||||
* will be called at most 4 times.
|
||||
*/
|
||||
public function emit(string $eventName, array $arguments = [], callable $continueCallBack = null): bool;
|
||||
|
||||
/**
|
||||
* Returns the list of listeners for an event.
|
||||
*
|
||||
* The list is returned as an array, and the list of events are sorted by
|
||||
* their priority.
|
||||
*
|
||||
* @return callable[]
|
||||
*/
|
||||
public function listeners(string $eventName): array;
|
||||
|
||||
/**
|
||||
* Removes a specific listener from an event.
|
||||
*
|
||||
* If the listener could not be found, this method will return false. If it
|
||||
* was removed it will return true.
|
||||
*/
|
||||
public function removeListener(string $eventName, callable $listener): bool;
|
||||
|
||||
/**
|
||||
* Removes all listeners.
|
||||
*
|
||||
* If the eventName argument is specified, all listeners for that event are
|
||||
* removed. If it is not specified, every listener for every event is
|
||||
* removed.
|
||||
*/
|
||||
public function removeAllListeners(string $eventName = null);
|
||||
}
|
||||
178
vendor/sabre/event/lib/EmitterTrait.php
vendored
Normal file
178
vendor/sabre/event/lib/EmitterTrait.php
vendored
Normal file
@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Event;
|
||||
|
||||
/**
|
||||
* Event Emitter Trait.
|
||||
*
|
||||
* This trait contains all the basic functions to implement an
|
||||
* EventEmitterInterface.
|
||||
*
|
||||
* Using the trait + interface allows you to add EventEmitter capabilities
|
||||
* without having to change your base-class.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
trait EmitterTrait
|
||||
{
|
||||
/**
|
||||
* Subscribe to an event.
|
||||
*/
|
||||
public function on(string $eventName, callable $callBack, int $priority = 100)
|
||||
{
|
||||
if (!isset($this->listeners[$eventName])) {
|
||||
$this->listeners[$eventName] = [
|
||||
true, // If there's only one item, it's sorted
|
||||
[$priority],
|
||||
[$callBack],
|
||||
];
|
||||
} else {
|
||||
$this->listeners[$eventName][0] = false; // marked as unsorted
|
||||
$this->listeners[$eventName][1][] = $priority;
|
||||
$this->listeners[$eventName][2][] = $callBack;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to an event exactly once.
|
||||
*/
|
||||
public function once(string $eventName, callable $callBack, int $priority = 100)
|
||||
{
|
||||
$wrapper = null;
|
||||
$wrapper = function () use ($eventName, $callBack, &$wrapper) {
|
||||
$this->removeListener($eventName, $wrapper);
|
||||
|
||||
return \call_user_func_array($callBack, \func_get_args());
|
||||
};
|
||||
|
||||
$this->on($eventName, $wrapper, $priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits an event.
|
||||
*
|
||||
* This method will return true if 0 or more listeners were successfully
|
||||
* handled. false is returned if one of the events broke the event chain.
|
||||
*
|
||||
* If the continueCallBack is specified, this callback will be called every
|
||||
* time before the next event handler is called.
|
||||
*
|
||||
* If the continueCallback returns false, event propagation stops. This
|
||||
* allows you to use the eventEmitter as a means for listeners to implement
|
||||
* functionality in your application, and break the event loop as soon as
|
||||
* some condition is fulfilled.
|
||||
*
|
||||
* Note that returning false from an event subscriber breaks propagation
|
||||
* and returns false, but if the continue-callback stops propagation, this
|
||||
* is still considered a 'successful' operation and returns true.
|
||||
*
|
||||
* Lastly, if there are 5 event handlers for an event. The continueCallback
|
||||
* will be called at most 4 times.
|
||||
*/
|
||||
public function emit(string $eventName, array $arguments = [], callable $continueCallBack = null): bool
|
||||
{
|
||||
if (\is_null($continueCallBack)) {
|
||||
foreach ($this->listeners($eventName) as $listener) {
|
||||
$result = \call_user_func_array($listener, $arguments);
|
||||
if (false === $result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$listeners = $this->listeners($eventName);
|
||||
$counter = \count($listeners);
|
||||
|
||||
foreach ($listeners as $listener) {
|
||||
--$counter;
|
||||
$result = \call_user_func_array($listener, $arguments);
|
||||
if (false === $result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($counter > 0) {
|
||||
if (!$continueCallBack()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of listeners for an event.
|
||||
*
|
||||
* The list is returned as an array, and the list of events are sorted by
|
||||
* their priority.
|
||||
*
|
||||
* @return callable[]
|
||||
*/
|
||||
public function listeners(string $eventName): array
|
||||
{
|
||||
if (!isset($this->listeners[$eventName])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// The list is not sorted
|
||||
if (!$this->listeners[$eventName][0]) {
|
||||
// Sorting
|
||||
\array_multisort($this->listeners[$eventName][1], SORT_NUMERIC, $this->listeners[$eventName][2]);
|
||||
|
||||
// Marking the listeners as sorted
|
||||
$this->listeners[$eventName][0] = true;
|
||||
}
|
||||
|
||||
return $this->listeners[$eventName][2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a specific listener from an event.
|
||||
*
|
||||
* If the listener could not be found, this method will return false. If it
|
||||
* was removed it will return true.
|
||||
*/
|
||||
public function removeListener(string $eventName, callable $listener): bool
|
||||
{
|
||||
if (!isset($this->listeners[$eventName])) {
|
||||
return false;
|
||||
}
|
||||
foreach ($this->listeners[$eventName][2] as $index => $check) {
|
||||
if ($check === $listener) {
|
||||
unset($this->listeners[$eventName][1][$index]);
|
||||
unset($this->listeners[$eventName][2][$index]);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all listeners.
|
||||
*
|
||||
* If the eventName argument is specified, all listeners for that event are
|
||||
* removed. If it is not specified, every listener for every event is
|
||||
* removed.
|
||||
*/
|
||||
public function removeAllListeners(string $eventName = null)
|
||||
{
|
||||
if (!\is_null($eventName)) {
|
||||
unset($this->listeners[$eventName]);
|
||||
} else {
|
||||
$this->listeners = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of listeners.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $listeners = [];
|
||||
}
|
||||
20
vendor/sabre/event/lib/EventEmitter.php
vendored
Normal file
20
vendor/sabre/event/lib/EventEmitter.php
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Event;
|
||||
|
||||
/**
|
||||
* This is the old name for the Emitter class.
|
||||
*
|
||||
* Instead of of using EventEmitter, please use Emitter. They are identical
|
||||
* otherwise.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class EventEmitter implements EmitterInterface
|
||||
{
|
||||
use EmitterTrait;
|
||||
}
|
||||
341
vendor/sabre/event/lib/Loop/Loop.php
vendored
Normal file
341
vendor/sabre/event/lib/Loop/Loop.php
vendored
Normal file
@ -0,0 +1,341 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Event\Loop;
|
||||
|
||||
/**
|
||||
* A simple eventloop implementation.
|
||||
*
|
||||
* This eventloop supports:
|
||||
* * nextTick
|
||||
* * setTimeout for delayed functions
|
||||
* * setInterval for repeating functions
|
||||
* * stream events using stream_select
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class Loop
|
||||
{
|
||||
/**
|
||||
* Executes a function after x seconds.
|
||||
*/
|
||||
public function setTimeout(callable $cb, float $timeout)
|
||||
{
|
||||
$triggerTime = microtime(true) + ($timeout);
|
||||
|
||||
if (!$this->timers) {
|
||||
// Special case when the timers array was empty.
|
||||
$this->timers[] = [$triggerTime, $cb];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to insert these values in the timers array, but the timers
|
||||
// array must be in reverse-order of trigger times.
|
||||
//
|
||||
// So here we search the array for the insertion point.
|
||||
$index = count($this->timers) - 1;
|
||||
while (true) {
|
||||
if ($triggerTime < $this->timers[$index][0]) {
|
||||
array_splice(
|
||||
$this->timers,
|
||||
$index + 1,
|
||||
0,
|
||||
[[$triggerTime, $cb]]
|
||||
);
|
||||
break;
|
||||
} elseif (0 === $index) {
|
||||
array_unshift($this->timers, [$triggerTime, $cb]);
|
||||
break;
|
||||
}
|
||||
--$index;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a function every x seconds.
|
||||
*
|
||||
* The value this function returns can be used to stop the interval with
|
||||
* clearInterval.
|
||||
*/
|
||||
public function setInterval(callable $cb, float $timeout): array
|
||||
{
|
||||
$keepGoing = true;
|
||||
$f = null;
|
||||
|
||||
$f = function () use ($cb, &$f, $timeout, &$keepGoing) {
|
||||
if ($keepGoing) {
|
||||
$cb();
|
||||
$this->setTimeout($f, $timeout);
|
||||
}
|
||||
};
|
||||
$this->setTimeout($f, $timeout);
|
||||
|
||||
// Really the only thing that matters is returning the $keepGoing
|
||||
// boolean value.
|
||||
//
|
||||
// We need to pack it in an array to allow returning by reference.
|
||||
// Because I'm worried people will be confused by using a boolean as a
|
||||
// sort of identifier, I added an extra string.
|
||||
return ['I\'m an implementation detail', &$keepGoing];
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops a running interval.
|
||||
*/
|
||||
public function clearInterval(array $intervalId)
|
||||
{
|
||||
$intervalId[1] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a function immediately at the next iteration of the loop.
|
||||
*/
|
||||
public function nextTick(callable $cb)
|
||||
{
|
||||
$this->nextTick[] = $cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a read stream.
|
||||
*
|
||||
* The callback will be called as soon as there is something to read from
|
||||
* the stream.
|
||||
*
|
||||
* You MUST call removeReadStream after you are done with the stream, to
|
||||
* prevent the eventloop from never stopping.
|
||||
*
|
||||
* @param resource $stream
|
||||
*/
|
||||
public function addReadStream($stream, callable $cb)
|
||||
{
|
||||
$this->readStreams[(int) $stream] = $stream;
|
||||
$this->readCallbacks[(int) $stream] = $cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a write stream.
|
||||
*
|
||||
* The callback will be called as soon as the system reports it's ready to
|
||||
* receive writes on the stream.
|
||||
*
|
||||
* You MUST call removeWriteStream after you are done with the stream, to
|
||||
* prevent the eventloop from never stopping.
|
||||
*
|
||||
* @param resource $stream
|
||||
*/
|
||||
public function addWriteStream($stream, callable $cb)
|
||||
{
|
||||
$this->writeStreams[(int) $stream] = $stream;
|
||||
$this->writeCallbacks[(int) $stream] = $cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop watching a stream for reads.
|
||||
*
|
||||
* @param resource $stream
|
||||
*/
|
||||
public function removeReadStream($stream)
|
||||
{
|
||||
unset(
|
||||
$this->readStreams[(int) $stream],
|
||||
$this->readCallbacks[(int) $stream]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop watching a stream for writes.
|
||||
*
|
||||
* @param resource $stream
|
||||
*/
|
||||
public function removeWriteStream($stream)
|
||||
{
|
||||
unset(
|
||||
$this->writeStreams[(int) $stream],
|
||||
$this->writeCallbacks[(int) $stream]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the loop.
|
||||
*
|
||||
* This function will run continuously, until there's no more events to
|
||||
* handle.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->running = true;
|
||||
|
||||
do {
|
||||
$hasEvents = $this->tick(true);
|
||||
} while ($this->running && $hasEvents);
|
||||
$this->running = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all pending events.
|
||||
*
|
||||
* If $block is turned true, this function will block until any event is
|
||||
* triggered.
|
||||
*
|
||||
* If there are now timeouts, nextTick callbacks or events in the loop at
|
||||
* all, this function will exit immediately.
|
||||
*
|
||||
* This function will return true if there are _any_ events left in the
|
||||
* loop after the tick.
|
||||
*/
|
||||
public function tick(bool $block = false): bool
|
||||
{
|
||||
$this->runNextTicks();
|
||||
$nextTimeout = $this->runTimers();
|
||||
|
||||
// Calculating how long runStreams should at most wait.
|
||||
if (!$block) {
|
||||
// Don't wait
|
||||
$streamWait = 0;
|
||||
} elseif ($this->nextTick) {
|
||||
// There's a pending 'nextTick'. Don't wait.
|
||||
$streamWait = 0;
|
||||
} elseif (is_numeric($nextTimeout)) {
|
||||
// Wait until the next Timeout should trigger.
|
||||
$streamWait = $nextTimeout;
|
||||
} else {
|
||||
// Wait indefinitely
|
||||
$streamWait = null;
|
||||
}
|
||||
|
||||
$this->runStreams($streamWait);
|
||||
|
||||
return $this->readStreams || $this->writeStreams || $this->nextTick || $this->timers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops a running eventloop.
|
||||
*/
|
||||
public function stop()
|
||||
{
|
||||
$this->running = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all 'nextTick' callbacks.
|
||||
*
|
||||
* return void
|
||||
*/
|
||||
protected function runNextTicks()
|
||||
{
|
||||
$nextTick = $this->nextTick;
|
||||
$this->nextTick = [];
|
||||
|
||||
foreach ($nextTick as $cb) {
|
||||
$cb();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs all pending timers.
|
||||
*
|
||||
* After running the timer callbacks, this function returns the number of
|
||||
* seconds until the next timer should be executed.
|
||||
*
|
||||
* If there's no more pending timers, this function returns null.
|
||||
*
|
||||
* @return float|null
|
||||
*/
|
||||
protected function runTimers()
|
||||
{
|
||||
$now = microtime(true);
|
||||
while (($timer = array_pop($this->timers)) && $timer[0] < $now) {
|
||||
$timer[1]();
|
||||
}
|
||||
// Add the last timer back to the array.
|
||||
if ($timer) {
|
||||
$this->timers[] = $timer;
|
||||
|
||||
return max(0, $timer[0] - microtime(true));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs all pending stream events.
|
||||
*
|
||||
* If $timeout is 0, it will return immediately. If $timeout is null, it
|
||||
* will wait indefinitely.
|
||||
*
|
||||
* @param float|null timeout
|
||||
*/
|
||||
protected function runStreams($timeout)
|
||||
{
|
||||
if ($this->readStreams || $this->writeStreams) {
|
||||
$read = $this->readStreams;
|
||||
$write = $this->writeStreams;
|
||||
$except = null;
|
||||
if (stream_select($read, $write, $except, (null === $timeout) ? null : 0, $timeout ? (int) ($timeout * 1000000) : 0)) {
|
||||
// See PHP Bug https://bugs.php.net/bug.php?id=62452
|
||||
// Fixed in PHP7
|
||||
foreach ($read as $readStream) {
|
||||
$readCb = $this->readCallbacks[(int) $readStream];
|
||||
$readCb();
|
||||
}
|
||||
foreach ($write as $writeStream) {
|
||||
$writeCb = $this->writeCallbacks[(int) $writeStream];
|
||||
$writeCb();
|
||||
}
|
||||
}
|
||||
} elseif ($this->running && ($this->nextTick || $this->timers)) {
|
||||
usleep(null !== $timeout ? intval($timeout * 1000000) : 200000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the main loop active.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $running = false;
|
||||
|
||||
/**
|
||||
* A list of timers, added by setTimeout.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $timers = [];
|
||||
|
||||
/**
|
||||
* A list of 'nextTick' callbacks.
|
||||
*
|
||||
* @var callable[]
|
||||
*/
|
||||
protected $nextTick = [];
|
||||
|
||||
/**
|
||||
* List of readable streams for stream_select, indexed by stream id.
|
||||
*
|
||||
* @var resource[]
|
||||
*/
|
||||
protected $readStreams = [];
|
||||
|
||||
/**
|
||||
* List of writable streams for stream_select, indexed by stream id.
|
||||
*
|
||||
* @var resource[]
|
||||
*/
|
||||
protected $writeStreams = [];
|
||||
|
||||
/**
|
||||
* List of read callbacks, indexed by stream id.
|
||||
*
|
||||
* @var callable[]
|
||||
*/
|
||||
protected $readCallbacks = [];
|
||||
|
||||
/**
|
||||
* List of write callbacks, indexed by stream id.
|
||||
*
|
||||
* @var callable[]
|
||||
*/
|
||||
protected $writeCallbacks = [];
|
||||
}
|
||||
143
vendor/sabre/event/lib/Loop/functions.php
vendored
Normal file
143
vendor/sabre/event/lib/Loop/functions.php
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Event\Loop;
|
||||
|
||||
/**
|
||||
* Executes a function after x seconds.
|
||||
*/
|
||||
function setTimeout(callable $cb, float $timeout)
|
||||
{
|
||||
instance()->setTimeout($cb, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a function every x seconds.
|
||||
*
|
||||
* The value this function returns can be used to stop the interval with
|
||||
* clearInterval.
|
||||
*/
|
||||
function setInterval(callable $cb, float $timeout): array
|
||||
{
|
||||
return instance()->setInterval($cb, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops a running interval.
|
||||
*/
|
||||
function clearInterval(array $intervalId)
|
||||
{
|
||||
instance()->clearInterval($intervalId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a function immediately at the next iteration of the loop.
|
||||
*/
|
||||
function nextTick(callable $cb)
|
||||
{
|
||||
instance()->nextTick($cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a read stream.
|
||||
*
|
||||
* The callback will be called as soon as there is something to read from
|
||||
* the stream.
|
||||
*
|
||||
* You MUST call removeReadStream after you are done with the stream, to
|
||||
* prevent the eventloop from never stopping.
|
||||
*
|
||||
* @param resource $stream
|
||||
*/
|
||||
function addReadStream($stream, callable $cb)
|
||||
{
|
||||
instance()->addReadStream($stream, $cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a write stream.
|
||||
*
|
||||
* The callback will be called as soon as the system reports it's ready to
|
||||
* receive writes on the stream.
|
||||
*
|
||||
* You MUST call removeWriteStream after you are done with the stream, to
|
||||
* prevent the eventloop from never stopping.
|
||||
*
|
||||
* @param resource $stream
|
||||
*/
|
||||
function addWriteStream($stream, callable $cb)
|
||||
{
|
||||
instance()->addWriteStream($stream, $cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop watching a stream for reads.
|
||||
*
|
||||
* @param resource $stream
|
||||
*/
|
||||
function removeReadStream($stream)
|
||||
{
|
||||
instance()->removeReadStream($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop watching a stream for writes.
|
||||
*
|
||||
* @param resource $stream
|
||||
*/
|
||||
function removeWriteStream($stream)
|
||||
{
|
||||
instance()->removeWriteStream($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the loop.
|
||||
*
|
||||
* This function will run continuously, until there's no more events to
|
||||
* handle.
|
||||
*/
|
||||
function run()
|
||||
{
|
||||
instance()->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all pending events.
|
||||
*
|
||||
* If $block is turned true, this function will block until any event is
|
||||
* triggered.
|
||||
*
|
||||
* If there are now timeouts, nextTick callbacks or events in the loop at
|
||||
* all, this function will exit immediately.
|
||||
*
|
||||
* This function will return true if there are _any_ events left in the
|
||||
* loop after the tick.
|
||||
*/
|
||||
function tick(bool $block = false): bool
|
||||
{
|
||||
return instance()->tick($block);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops a running eventloop.
|
||||
*/
|
||||
function stop()
|
||||
{
|
||||
instance()->stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves or sets the global Loop object.
|
||||
*/
|
||||
function instance(Loop $newLoop = null): Loop
|
||||
{
|
||||
static $loop;
|
||||
if ($newLoop) {
|
||||
$loop = $newLoop;
|
||||
} elseif (!$loop) {
|
||||
$loop = new Loop();
|
||||
}
|
||||
|
||||
return $loop;
|
||||
}
|
||||
258
vendor/sabre/event/lib/Promise.php
vendored
Normal file
258
vendor/sabre/event/lib/Promise.php
vendored
Normal file
@ -0,0 +1,258 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Event;
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* An implementation of the Promise pattern.
|
||||
*
|
||||
* A promise represents the result of an asynchronous operation.
|
||||
* At any given point a promise can be in one of three states:
|
||||
*
|
||||
* 1. Pending (the promise does not have a result yet).
|
||||
* 2. Fulfilled (the asynchronous operation has completed with a result).
|
||||
* 3. Rejected (the asynchronous operation has completed with an error).
|
||||
*
|
||||
* To get a callback when the operation has finished, use the `then` method.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class Promise
|
||||
{
|
||||
/**
|
||||
* The asynchronous operation is pending.
|
||||
*/
|
||||
const PENDING = 0;
|
||||
|
||||
/**
|
||||
* The asynchronous operation has completed, and has a result.
|
||||
*/
|
||||
const FULFILLED = 1;
|
||||
|
||||
/**
|
||||
* The asynchronous operation has completed with an error.
|
||||
*/
|
||||
const REJECTED = 2;
|
||||
|
||||
/**
|
||||
* The current state of this promise.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $state = self::PENDING;
|
||||
|
||||
/**
|
||||
* Creates the promise.
|
||||
*
|
||||
* The passed argument is the executor. The executor is automatically
|
||||
* called with two arguments.
|
||||
*
|
||||
* Each are callbacks that map to $this->fulfill and $this->reject.
|
||||
* Using the executor is optional.
|
||||
*/
|
||||
public function __construct(callable $executor = null)
|
||||
{
|
||||
if ($executor) {
|
||||
$executor(
|
||||
[$this, 'fulfill'],
|
||||
[$this, 'reject']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method allows you to specify the callback that will be called after
|
||||
* the promise has been fulfilled or rejected.
|
||||
*
|
||||
* Both arguments are optional.
|
||||
*
|
||||
* This method returns a new promise, which can be used for chaining.
|
||||
* If either the onFulfilled or onRejected callback is called, you may
|
||||
* return a result from this callback.
|
||||
*
|
||||
* If the result of this callback is yet another promise, the result of
|
||||
* _that_ promise will be used to set the result of the returned promise.
|
||||
*
|
||||
* If either of the callbacks return any other value, the returned promise
|
||||
* is automatically fulfilled with that value.
|
||||
*
|
||||
* If either of the callbacks throw an exception, the returned promise will
|
||||
* be rejected and the exception will be passed back.
|
||||
*/
|
||||
public function then(callable $onFulfilled = null, callable $onRejected = null): Promise
|
||||
{
|
||||
// This new subPromise will be returned from this function, and will
|
||||
// be fulfilled with the result of the onFulfilled or onRejected event
|
||||
// handlers.
|
||||
$subPromise = new self();
|
||||
|
||||
switch ($this->state) {
|
||||
case self::PENDING:
|
||||
// The operation is pending, so we keep a reference to the
|
||||
// event handlers so we can call them later.
|
||||
$this->subscribers[] = [$subPromise, $onFulfilled, $onRejected];
|
||||
break;
|
||||
case self::FULFILLED:
|
||||
// The async operation is already fulfilled, so we trigger the
|
||||
// onFulfilled callback asap.
|
||||
$this->invokeCallback($subPromise, $onFulfilled);
|
||||
break;
|
||||
case self::REJECTED:
|
||||
// The async operation failed, so we call the onRejected
|
||||
// callback asap.
|
||||
$this->invokeCallback($subPromise, $onRejected);
|
||||
break;
|
||||
}
|
||||
|
||||
return $subPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a callback for when this promise is rejected.
|
||||
*
|
||||
* Its usage is identical to then(). However, the otherwise() function is
|
||||
* preferred.
|
||||
*/
|
||||
public function otherwise(callable $onRejected): Promise
|
||||
{
|
||||
return $this->then(null, $onRejected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this promise as fulfilled and sets its return value.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function fulfill($value = null)
|
||||
{
|
||||
if (self::PENDING !== $this->state) {
|
||||
throw new PromiseAlreadyResolvedException('This promise is already resolved, and you\'re not allowed to resolve a promise more than once');
|
||||
}
|
||||
$this->state = self::FULFILLED;
|
||||
$this->value = $value;
|
||||
foreach ($this->subscribers as $subscriber) {
|
||||
$this->invokeCallback($subscriber[0], $subscriber[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this promise as rejected, and set it's rejection reason.
|
||||
*/
|
||||
public function reject(Throwable $reason)
|
||||
{
|
||||
if (self::PENDING !== $this->state) {
|
||||
throw new PromiseAlreadyResolvedException('This promise is already resolved, and you\'re not allowed to resolve a promise more than once');
|
||||
}
|
||||
$this->state = self::REJECTED;
|
||||
$this->value = $reason;
|
||||
foreach ($this->subscribers as $subscriber) {
|
||||
$this->invokeCallback($subscriber[0], $subscriber[2]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops execution until this promise is resolved.
|
||||
*
|
||||
* This method stops execution completely. If the promise is successful with
|
||||
* a value, this method will return this value. If the promise was
|
||||
* rejected, this method will throw an exception.
|
||||
*
|
||||
* This effectively turns the asynchronous operation into a synchronous
|
||||
* one. In PHP it might be useful to call this on the last promise in a
|
||||
* chain.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function wait()
|
||||
{
|
||||
$hasEvents = true;
|
||||
while (self::PENDING === $this->state) {
|
||||
if (!$hasEvents) {
|
||||
throw new \LogicException('There were no more events in the loop. This promise will never be fulfilled.');
|
||||
}
|
||||
|
||||
// As long as the promise is not fulfilled, we tell the event loop
|
||||
// to handle events, and to block.
|
||||
$hasEvents = Loop\tick(true);
|
||||
}
|
||||
|
||||
if (self::FULFILLED === $this->state) {
|
||||
// If the state of this promise is fulfilled, we can return the value.
|
||||
return $this->value;
|
||||
} else {
|
||||
// If we got here, it means that the asynchronous operation
|
||||
// errored. Therefore we need to throw an exception.
|
||||
throw $this->value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of subscribers. Subscribers are the callbacks that want us to let
|
||||
* them know if the callback was fulfilled or rejected.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $subscribers = [];
|
||||
|
||||
/**
|
||||
* The result of the promise.
|
||||
*
|
||||
* If the promise was fulfilled, this will be the result value. If the
|
||||
* promise was rejected, this property hold the rejection reason.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $value = null;
|
||||
|
||||
/**
|
||||
* This method is used to call either an onFulfilled or onRejected callback.
|
||||
*
|
||||
* This method makes sure that the result of these callbacks are handled
|
||||
* correctly, and any chained promises are also correctly fulfilled or
|
||||
* rejected.
|
||||
*
|
||||
* @param callable $callBack
|
||||
*/
|
||||
private function invokeCallback(Promise $subPromise, callable $callBack = null)
|
||||
{
|
||||
// We use 'nextTick' to ensure that the event handlers are always
|
||||
// triggered outside of the calling stack in which they were originally
|
||||
// passed to 'then'.
|
||||
//
|
||||
// This makes the order of execution more predictable.
|
||||
Loop\nextTick(function () use ($callBack, $subPromise) {
|
||||
if (is_callable($callBack)) {
|
||||
try {
|
||||
$result = $callBack($this->value);
|
||||
if ($result instanceof self) {
|
||||
// If the callback (onRejected or onFulfilled)
|
||||
// returned a promise, we only fulfill or reject the
|
||||
// chained promise once that promise has also been
|
||||
// resolved.
|
||||
$result->then([$subPromise, 'fulfill'], [$subPromise, 'reject']);
|
||||
} else {
|
||||
// If the callback returned any other value, we
|
||||
// immediately fulfill the chained promise.
|
||||
$subPromise->fulfill($result);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
// If the event handler threw an exception, we need to make sure that
|
||||
// the chained promise is rejected as well.
|
||||
$subPromise->reject($e);
|
||||
}
|
||||
} else {
|
||||
if (self::FULFILLED === $this->state) {
|
||||
$subPromise->fulfill($this->value);
|
||||
} else {
|
||||
$subPromise->reject($this->value);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
128
vendor/sabre/event/lib/Promise/functions.php
vendored
Normal file
128
vendor/sabre/event/lib/Promise/functions.php
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Event\Promise;
|
||||
|
||||
use Sabre\Event\Promise;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* This file contains a set of functions that are useful for dealing with the
|
||||
* Promise object.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
|
||||
/**
|
||||
* This function takes an array of Promises, and returns a Promise that
|
||||
* resolves when all of the given arguments have resolved.
|
||||
*
|
||||
* The returned Promise will resolve with a value that's an array of all the
|
||||
* values the given promises have been resolved with.
|
||||
*
|
||||
* This array will be in the exact same order as the array of input promises.
|
||||
*
|
||||
* If any of the given Promises fails, the returned promise will immediately
|
||||
* fail with the first Promise that fails, and its reason.
|
||||
*
|
||||
* @param Promise[] $promises
|
||||
*/
|
||||
function all(array $promises): Promise
|
||||
{
|
||||
return new Promise(function ($success, $fail) use ($promises) {
|
||||
if (empty($promises)) {
|
||||
$success([]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$successCount = 0;
|
||||
$completeResult = [];
|
||||
|
||||
foreach ($promises as $promiseIndex => $subPromise) {
|
||||
$subPromise->then(
|
||||
function ($result) use ($promiseIndex, &$completeResult, &$successCount, $success, $promises) {
|
||||
$completeResult[$promiseIndex] = $result;
|
||||
++$successCount;
|
||||
if ($successCount === count($promises)) {
|
||||
$success($completeResult);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
)->otherwise(
|
||||
function ($reason) use ($fail) {
|
||||
$fail($reason);
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The race function returns a promise that resolves or rejects as soon as
|
||||
* one of the promises in the argument resolves or rejects.
|
||||
*
|
||||
* The returned promise will resolve or reject with the value or reason of
|
||||
* that first promise.
|
||||
*
|
||||
* @param Promise[] $promises
|
||||
*/
|
||||
function race(array $promises): Promise
|
||||
{
|
||||
return new Promise(function ($success, $fail) use ($promises) {
|
||||
$alreadyDone = false;
|
||||
foreach ($promises as $promise) {
|
||||
$promise->then(
|
||||
function ($result) use ($success, &$alreadyDone) {
|
||||
if ($alreadyDone) {
|
||||
return;
|
||||
}
|
||||
$alreadyDone = true;
|
||||
$success($result);
|
||||
},
|
||||
function ($reason) use ($fail, &$alreadyDone) {
|
||||
if ($alreadyDone) {
|
||||
return;
|
||||
}
|
||||
$alreadyDone = true;
|
||||
$fail($reason);
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Promise that resolves with the given value.
|
||||
*
|
||||
* If the value is a promise, the returned promise will attach itself to that
|
||||
* promise and eventually get the same state as the followed promise.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
function resolve($value): Promise
|
||||
{
|
||||
if ($value instanceof Promise) {
|
||||
return $value->then();
|
||||
} else {
|
||||
$promise = new Promise();
|
||||
$promise->fulfill($value);
|
||||
|
||||
return $promise;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Promise that will reject with the given reason.
|
||||
*/
|
||||
function reject(Throwable $reason): Promise
|
||||
{
|
||||
$promise = new Promise();
|
||||
$promise->reject($reason);
|
||||
|
||||
return $promise;
|
||||
}
|
||||
17
vendor/sabre/event/lib/PromiseAlreadyResolvedException.php
vendored
Normal file
17
vendor/sabre/event/lib/PromiseAlreadyResolvedException.php
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Event;
|
||||
|
||||
/**
|
||||
* This exception is thrown when the user tried to reject or fulfill a promise,
|
||||
* after either of these actions were already performed.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class PromiseAlreadyResolvedException extends \LogicException
|
||||
{
|
||||
}
|
||||
20
vendor/sabre/event/lib/Version.php
vendored
Normal file
20
vendor/sabre/event/lib/Version.php
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Event;
|
||||
|
||||
/**
|
||||
* This class contains the version number for this package.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class Version
|
||||
{
|
||||
/**
|
||||
* Full version number.
|
||||
*/
|
||||
const VERSION = '5.1.0';
|
||||
}
|
||||
36
vendor/sabre/event/lib/WildcardEmitter.php
vendored
Normal file
36
vendor/sabre/event/lib/WildcardEmitter.php
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Event;
|
||||
|
||||
/**
|
||||
* This class is an EventEmitter with support for wildcard event handlers.
|
||||
*
|
||||
* What this means is that you can emit events like this:
|
||||
*
|
||||
* emit('change:firstName')
|
||||
*
|
||||
* and listen to this event like this:
|
||||
*
|
||||
* on('change:*')
|
||||
*
|
||||
* A few notes:
|
||||
*
|
||||
* - Wildcards only work at the end of an event name.
|
||||
* - Currently you can only use 1 wildcard.
|
||||
* - Using ":" as a separator is optional, but it's highly recommended to use
|
||||
* some kind of separator.
|
||||
*
|
||||
* The WilcardEmitter is a bit slower than the regular Emitter. If you code
|
||||
* must be very high performance, it might be better to try to use the other
|
||||
* emitter. For must usage the difference is negligible though.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
class WildcardEmitter implements EmitterInterface
|
||||
{
|
||||
use WildcardEmitterTrait;
|
||||
}
|
||||
233
vendor/sabre/event/lib/WildcardEmitterTrait.php
vendored
Normal file
233
vendor/sabre/event/lib/WildcardEmitterTrait.php
vendored
Normal file
@ -0,0 +1,233 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Event;
|
||||
|
||||
/**
|
||||
* Wildcard Emitter Trait.
|
||||
*
|
||||
* This trait provides the implementation for WildCardEmitter
|
||||
* Refer to that class for the full documentation about this
|
||||
* trait.
|
||||
*
|
||||
* Normally you can just instantiate that class, but if you want to add
|
||||
* emitter functionality to existing classes, using the trait might be a
|
||||
* better way to do this.
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
trait WildcardEmitterTrait
|
||||
{
|
||||
/**
|
||||
* Subscribe to an event.
|
||||
*/
|
||||
public function on(string $eventName, callable $callBack, int $priority = 100)
|
||||
{
|
||||
// If it ends with a wildcard, we use the wildcardListeners array
|
||||
if ('*' === $eventName[\strlen($eventName) - 1]) {
|
||||
$eventName = \substr($eventName, 0, -1);
|
||||
$listeners = &$this->wildcardListeners;
|
||||
} else {
|
||||
$listeners = &$this->listeners;
|
||||
}
|
||||
|
||||
// Always fully reset the listener index. This is fairly sane for most
|
||||
// applications, because there's a clear "event registering" and "event
|
||||
// emitting" phase, but can be slow if there's a lot adding and removing
|
||||
// of listeners during emitting of events.
|
||||
$this->listenerIndex = [];
|
||||
|
||||
if (!isset($listeners[$eventName])) {
|
||||
$listeners[$eventName] = [];
|
||||
}
|
||||
$listeners[$eventName][] = [$priority, $callBack];
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to an event exactly once.
|
||||
*/
|
||||
public function once(string $eventName, callable $callBack, int $priority = 100)
|
||||
{
|
||||
$wrapper = null;
|
||||
$wrapper = function () use ($eventName, $callBack, &$wrapper) {
|
||||
$this->removeListener($eventName, $wrapper);
|
||||
|
||||
return \call_user_func_array($callBack, \func_get_args());
|
||||
};
|
||||
|
||||
$this->on($eventName, $wrapper, $priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits an event.
|
||||
*
|
||||
* This method will return true if 0 or more listeners were successfully
|
||||
* handled. false is returned if one of the events broke the event chain.
|
||||
*
|
||||
* If the continueCallBack is specified, this callback will be called every
|
||||
* time before the next event handler is called.
|
||||
*
|
||||
* If the continueCallback returns false, event propagation stops. This
|
||||
* allows you to use the eventEmitter as a means for listeners to implement
|
||||
* functionality in your application, and break the event loop as soon as
|
||||
* some condition is fulfilled.
|
||||
*
|
||||
* Note that returning false from an event subscriber breaks propagation
|
||||
* and returns false, but if the continue-callback stops propagation, this
|
||||
* is still considered a 'successful' operation and returns true.
|
||||
*
|
||||
* Lastly, if there are 5 event handlers for an event. The continueCallback
|
||||
* will be called at most 4 times.
|
||||
*/
|
||||
public function emit(string $eventName, array $arguments = [], callable $continueCallBack = null): bool
|
||||
{
|
||||
if (\is_null($continueCallBack)) {
|
||||
foreach ($this->listeners($eventName) as $listener) {
|
||||
$result = \call_user_func_array($listener, $arguments);
|
||||
if (false === $result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$listeners = $this->listeners($eventName);
|
||||
$counter = \count($listeners);
|
||||
|
||||
foreach ($listeners as $listener) {
|
||||
--$counter;
|
||||
$result = \call_user_func_array($listener, $arguments);
|
||||
if (false === $result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($counter > 0) {
|
||||
if (!$continueCallBack()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of listeners for an event.
|
||||
*
|
||||
* The list is returned as an array, and the list of events are sorted by
|
||||
* their priority.
|
||||
*
|
||||
* @return callable[]
|
||||
*/
|
||||
public function listeners(string $eventName): array
|
||||
{
|
||||
if (!\array_key_exists($eventName, $this->listenerIndex)) {
|
||||
// Create a new index.
|
||||
$listeners = [];
|
||||
$listenersPriority = [];
|
||||
if (isset($this->listeners[$eventName])) {
|
||||
foreach ($this->listeners[$eventName] as $listener) {
|
||||
$listenersPriority[] = $listener[0];
|
||||
$listeners[] = $listener[1];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->wildcardListeners as $wcEvent => $wcListeners) {
|
||||
// Wildcard match
|
||||
if (\substr($eventName, 0, \strlen($wcEvent)) === $wcEvent) {
|
||||
foreach ($wcListeners as $listener) {
|
||||
$listenersPriority[] = $listener[0];
|
||||
$listeners[] = $listener[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sorting by priority
|
||||
\array_multisort($listenersPriority, SORT_NUMERIC, $listeners);
|
||||
|
||||
// Creating index
|
||||
$this->listenerIndex[$eventName] = $listeners;
|
||||
}
|
||||
|
||||
return $this->listenerIndex[$eventName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a specific listener from an event.
|
||||
*
|
||||
* If the listener could not be found, this method will return false. If it
|
||||
* was removed it will return true.
|
||||
*/
|
||||
public function removeListener(string $eventName, callable $listener): bool
|
||||
{
|
||||
// If it ends with a wildcard, we use the wildcardListeners array
|
||||
if ('*' === $eventName[\strlen($eventName) - 1]) {
|
||||
$eventName = \substr($eventName, 0, -1);
|
||||
$listeners = &$this->wildcardListeners;
|
||||
} else {
|
||||
$listeners = &$this->listeners;
|
||||
}
|
||||
|
||||
if (!isset($listeners[$eventName])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($listeners[$eventName] as $index => $check) {
|
||||
if ($check[1] === $listener) {
|
||||
// Remove listener
|
||||
unset($listeners[$eventName][$index]);
|
||||
// Reset index
|
||||
$this->listenerIndex = [];
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all listeners.
|
||||
*
|
||||
* If the eventName argument is specified, all listeners for that event are
|
||||
* removed. If it is not specified, every listener for every event is
|
||||
* removed.
|
||||
*/
|
||||
public function removeAllListeners(string $eventName = null)
|
||||
{
|
||||
if (\is_null($eventName)) {
|
||||
$this->listeners = [];
|
||||
$this->wildcardListeners = [];
|
||||
} else {
|
||||
if ('*' === $eventName[\strlen($eventName) - 1]) {
|
||||
// Wildcard event
|
||||
unset($this->wildcardListeners[\substr($eventName, 0, -1)]);
|
||||
} else {
|
||||
unset($this->listeners[$eventName]);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset index
|
||||
$this->listenerIndex = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of listeners.
|
||||
*/
|
||||
protected $listeners = [];
|
||||
|
||||
/**
|
||||
* The list of "wildcard listeners".
|
||||
*/
|
||||
protected $wildcardListeners = [];
|
||||
|
||||
/**
|
||||
* An index of listeners for a specific event name. This helps speeding
|
||||
* up emitting events after all listeners have been set.
|
||||
*
|
||||
* If the list of listeners changes though, the index clears.
|
||||
*/
|
||||
protected $listenerIndex = [];
|
||||
}
|
||||
119
vendor/sabre/event/lib/coroutine.php
vendored
Normal file
119
vendor/sabre/event/lib/coroutine.php
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabre\Event;
|
||||
|
||||
use Generator;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Turn asynchronous promise-based code into something that looks synchronous
|
||||
* again, through the use of generators.
|
||||
*
|
||||
* Example without coroutines:
|
||||
*
|
||||
* $promise = $httpClient->request('GET', '/foo');
|
||||
* $promise->then(function($value) {
|
||||
*
|
||||
* return $httpClient->request('DELETE','/foo');
|
||||
*
|
||||
* })->then(function($value) {
|
||||
*
|
||||
* return $httpClient->request('PUT', '/foo');
|
||||
*
|
||||
* })->error(function($reason) {
|
||||
*
|
||||
* echo "Failed because: $reason\n";
|
||||
*
|
||||
* });
|
||||
*
|
||||
* Example with coroutines:
|
||||
*
|
||||
* coroutine(function() {
|
||||
*
|
||||
* try {
|
||||
* yield $httpClient->request('GET', '/foo');
|
||||
* yield $httpClient->request('DELETE', /foo');
|
||||
* yield $httpClient->request('PUT', '/foo');
|
||||
* } catch(\Throwable $reason) {
|
||||
* echo "Failed because: $reason\n";
|
||||
* }
|
||||
*
|
||||
* });
|
||||
*
|
||||
* @return \Sabre\Event\Promise
|
||||
*
|
||||
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||
* @author Evert Pot (http://evertpot.com/)
|
||||
* @license http://sabre.io/license/ Modified BSD License
|
||||
*/
|
||||
function coroutine(callable $gen): Promise
|
||||
{
|
||||
$generator = $gen();
|
||||
if (!$generator instanceof Generator) {
|
||||
throw new \InvalidArgumentException('You must pass a generator function');
|
||||
}
|
||||
|
||||
// This is the value we're returning.
|
||||
$promise = new Promise();
|
||||
|
||||
/**
|
||||
* So tempted to use the mythical y-combinator here, but it's not needed in
|
||||
* PHP.
|
||||
*/
|
||||
$advanceGenerator = function () use (&$advanceGenerator, $generator, $promise) {
|
||||
while ($generator->valid()) {
|
||||
$yieldedValue = $generator->current();
|
||||
if ($yieldedValue instanceof Promise) {
|
||||
$yieldedValue->then(
|
||||
function ($value) use ($generator, &$advanceGenerator) {
|
||||
$generator->send($value);
|
||||
$advanceGenerator();
|
||||
},
|
||||
function (Throwable $reason) use ($generator, $advanceGenerator) {
|
||||
$generator->throw($reason);
|
||||
$advanceGenerator();
|
||||
}
|
||||
)->otherwise(function (Throwable $reason) use ($promise) {
|
||||
// This error handler would be called, if something in the
|
||||
// generator throws an exception, and it's not caught
|
||||
// locally.
|
||||
$promise->reject($reason);
|
||||
});
|
||||
// We need to break out of the loop, because $advanceGenerator
|
||||
// will be called asynchronously when the promise has a result.
|
||||
break;
|
||||
} else {
|
||||
// If the value was not a promise, we'll just let it pass through.
|
||||
$generator->send($yieldedValue);
|
||||
}
|
||||
}
|
||||
|
||||
// If the generator is at the end, and we didn't run into an exception,
|
||||
// We're grabbing the "return" value and fulfilling our top-level
|
||||
// promise with its value.
|
||||
if (!$generator->valid() && Promise::PENDING === $promise->state) {
|
||||
$returnValue = $generator->getReturn();
|
||||
|
||||
// The return value is a promise.
|
||||
if ($returnValue instanceof Promise) {
|
||||
$returnValue->then(function ($value) use ($promise) {
|
||||
$promise->fulfill($value);
|
||||
}, function (Throwable $reason) use ($promise) {
|
||||
$promise->reject($reason);
|
||||
});
|
||||
} else {
|
||||
$promise->fulfill($returnValue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
$advanceGenerator();
|
||||
} catch (Throwable $e) {
|
||||
$promise->reject($e);
|
||||
}
|
||||
|
||||
return $promise;
|
||||
}
|
||||
2
vendor/sabre/event/phpstan.neon
vendored
Normal file
2
vendor/sabre/event/phpstan.neon
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
parameters:
|
||||
level: 1
|
||||
Reference in New Issue
Block a user