Git Product home page Git Product logo

await-generator's Introduction

Eng | |

await-generator

Build Status Codecov

A library to use async/await pattern in PHP.

Documentation

Read the await-generator tutorial for an introduction from generators and traditional async callbacks to await-generator.

Why await-generator?

Traditional async programming requires callbacks, which leads to spaghetti code known as "callback hell":

Click to reveal example callback hell
load_data(function($data) {
    $init = count($data) === 0 ? init_data(...) : fn($then) => $then($data);
    $init(function($data) {
        $output = [];
        foreach($data as $k => $datum) {
            processData($datum, function($result) use(&$output, $data) {
                $output[$k] = $result;
                if(count($output) === count($data)) {
                    createQueries($output, function($queries) {
                        $run = function($i) use($queries, &$run) {
                            runQuery($queries[$i], function() use($i, $queries, $run) {
                                if($i === count($queries)) {
                                    $done = false;
                                    commitBatch(function() use(&$done) {
                                        if(!$done) {
                                            $done = true;
                                            echo "Done!\n";
                                        }
                                    });
                                    onUserClose(function() use(&$done) {
                                        if(!$done) {
                                            $done = true;
                                            echo "User closed!\n";
                                        }
                                    });
                                    onTimeout(function() use(&$done) {
                                        if(!$done) {
                                            $done = true;
                                            echo "Timeout!\n";
                                        }
                                    });
                                } else {
                                    $run($i + 1);
                                }
                            });
                        };
                    });
                }
            });
        }
    });
});
With await-generator, this is simplified into:
$data = yield from load_data();
if(count($data) === 0) $data = yield from init_data();
$output = yield from Await::all(array_map(fn($datum) => processData($datum), $data));
$queries = yield from createQueries($output);
foreach($queries as $query) yield from runQuery($query);
[$which, ] = yield from Await::race([
    0 => commitBatch(),
    1 => onUserClose(),
    2 => onTimeout(),
])
echo match($which) {
    0 => "Done!\n",
    1 => "User closed!\n",
    2 => "Timeout!\n",
};

Can I maintain backward compatibility?

Yes, await-generator does not impose any restrictions on your existing API. You can wrap all await-generator calls as internal implementation detail, although you are strongly encouraged to expose the generator functions directly.

await-generator starts an await context with the Await::f2c method, with which you can adapt into the usual callback syntax:

function oldApi($args, Closure $onSuccess) {
    Await::f2c(fn() => $onSuccess(yield from newApi($args)));
}

Or if you want to handle errors too:

function newApi($args, Closure $onSuccess, Closure $onError) {
    Await::f2c(function() use($onSuccess, $onError) {
        try {
            $onSuccess(yield from newApi($args));
        } catch(Exception $ex) {
            $onError($ex);
        }
    });
}

You can continue to call functions implemented as callback style using the Await::promise method (similar to new Promise in JS):

yield from Await::promise(fn($resolve, $reject) => oldFunction($args, $resolve, $reject));

Why not await-generator

await-generator has a few common pitfalls:

  • Forgetting to yield from a Generator<void> method will end up doing nothing.
  • If you delete all yields from a function, it automatically becomes a non-generator function thanks to PHP magic. This issue can be mitigated by always adding : Generator to the function signature.
  • finally blocks may never get executed if an async function never resolves (e.g. Await::promise(fn($resolve) => null)).

While these pitfalls cause some trouble, await-generator style is still much less bug-prone than a callback hell.

But what about fibers?

This might be a subjective comment, but I do not prefer fibers for a few reasons:

Explicit suspension in type signature

fiber.jpg

For example, it is easy to tell from the type signature that $channel->send($value): Generator<void> suspends until the value is sent and $channel->sendBuffered($value): void is a non-suspending method that returns immediately. Type signatures are often self-explanatory.

Of course, users could call sleep() anyway, but it is quite obvious to everyone that sleep() blocks the whole runtime (if they didn't already know, they will find out when the whole world stops).

Concurrent states

When a function suspends, many other things can happen. Indeed, calling a function allows the implementation to call any other functions which could modify your states anyway, but a sane, genuine implementation of e.g. an HTTP request wouldn't call functions that modify the private states of your library. But this assumption does not hold with fibers because the fiber is preempted and other fibers can still modify the private states. This means you have to check for possible changes in private properties every time you call any function that might be suspending.

On the other hand, using explicit await, it is obvious where exactly the suspension points are, and you only need to check for state mutations at the known suspension points.

Trapping suspension points

await-generator provides a feature called "trapping", which allows users to add pre-suspend and pre-resume hooks to a generator. This is simply achieved by adding an adapter to the generator, and does not even require explicit support from the await-generator runtime. This is currently not possible with fibers.

await-generator's People

Contributors

aieuo avatar dependabot-preview[bot] avatar dependabot[bot] avatar encritary avatar endermanbugzjfc avatar frago9876543210 avatar fuyutsuki avatar javierleon9966 avatar sof3 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

await-generator's Issues

Errer

Unhandled async exception: Position world is null or has been unloaded
File: /home/user/pm/virions/await-generator_dev-130.phar/src/SOFe/AwaitGenerator/Await
Line: 587
Type: SOFe\AwaitGenerator\AwaitException
Backtrace:
#0 /home/user/pm/virions/await-generator_dev-130.phar/src/SOFe/AwaitGenerator/Await(334): SOFe\AwaitGenerator\Await->reject(object pocketmine\utils\AssumptionFailedError#1000839)
#1 /home/user/pm/virions/await-generator_dev-130.phar/src/SOFe/AwaitGenerator/Await(317): SOFe\AwaitGenerator\Await->wakeup(object Closure#1038912)
#2 /home/user/pm/virions/await-generator_dev-130.phar/src/SOFe/AwaitGenerator/Await(552): SOFe\AwaitGenerator\Await->wakeupFlat(object Closure#1038912)
#3 /home/user/pm/virions/await-generator_dev-130.phar/src/SOFe/AwaitGenerator/AwaitChild(52): SOFe\AwaitGenerator\Await->recheckPromiseQueue(object SOFe\AwaitGenerator\AwaitChild#1226974)
#4 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/DataConnectorImpl(124): SOFe\AwaitGenerator\AwaitChild->resolve()
#5 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/DataConnectorImpl(181): poggit\libasynql\base\DataConnectorImpl::poggit\libasynql\base\{closure}(object poggit\libasynql\SqlResult#1208972)
#6 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/DataConnectorImpl(239): poggit\libasynql\base\DataConnectorImpl::poggit\libasynql\base\{closure}(array[1])
#7 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/SqlThreadPool(116): poggit\libasynql\base\DataConnectorImpl->poggit\libasynql\base\{closure}(array[1])
#8 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/DataConnectorImpl(322): poggit\libasynql\base\SqlThreadPool->readResults(array[17], null)
#9 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/SqlThreadPool(64): poggit\libasynql\base\DataConnectorImpl->checkResults()
#10 pmsrc/vendor/pocketmine/snooze/src/SleeperHandler(120): poggit\libasynql\base\SqlThreadPool->poggit\libasynql\base\{closure}()
#11 pmsrc/src/TimeTrackingSleeperHandler(58): pocketmine\snooze\SleeperHandler->processNotifications()
#12 pmsrc/vendor/pocketmine/snooze/src/SleeperHandler(79): pocketmine\TimeTrackingSleeperHandler->processNotifications()
#13 pmsrc/src/Server(1683): pocketmine\snooze\SleeperHandler->sleepUntil(float 1699953122.1125)
#14 (): �[33m--- below is the original stack trace ---�[m�()
#15 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/DataConnectorImpl(223): poggit\libasynql\base\DataConnectorImpl->executeImplRaw(array[1], array[1], array[1], object Closure#1230929, object Closure#1229989)
#16 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/DataConnectorImpl(180): poggit\libasynql\base\DataConnectorImpl->executeImpl(string[29] bcp.generic.begin_transaction, array[0], int 0, object Closure#1230929, object Closure#1229989)
#17 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/DataConnectorImpl(122): poggit\libasynql\base\DataConnectorImpl->executeImplLast(string[29] bcp.generic.begin_transaction, array[0], int 0, object Closure#1231765, object Closure#1229989)
#18 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/DataConnectorImpl(132): poggit\libasynql\base\DataConnectorImpl->executeGeneric(string[29] bcp.generic.begin_transaction, array[0], object Closure#1229948, object Closure#1229989)
#19 plugins/BedcoreProtect-stable/src/matcracker/BedcoreProtect/storage/queries/BlocksQueries(262): poggit\libasynql\base\DataConnectorImpl->asyncGeneric(string[29] bcp.generic.begin_transaction)
#20 /home/user/pm/virions/await-generator_dev-130.phar/src/SOFe/AwaitGenerator/Mutex(114): matcracker\BedcoreProtect\storage\queries\BlocksQueries->matcracker\BedcoreProtect\storage\queries\{closure}()
#21 /home/user/pm/virions/await-generator_dev-130.phar/src/SOFe/AwaitGenerator/Mutex(103): SOFe\AwaitGenerator\Mutex->run(object Generator#818296)
#22 (): SOFe\AwaitGenerator\Mutex->runClosure(object Closure#679801)
#23 /home/user/pm/virions/await-generator_dev-130.phar/src/SOFe/AwaitGenerator/Await(376): Generator->send(object Closure#1229989)
#24 /home/user/pm/virions/await-generator_dev-130.phar/src/SOFe/AwaitGenerator/Await(332): SOFe\AwaitGenerator\Await->SOFe\AwaitGenerator\{closure}()
#25 /home/user/pm/virions/await-generator_dev-130.phar/src/SOFe/AwaitGenerator/Await(317): SOFe\AwaitGenerator\Await->wakeup(object Closure#1230922)
#26 /home/user/pm/virions/await-generator_dev-130.phar/src/SOFe/AwaitGenerator/Await(552): SOFe\AwaitGenerator\Await->wakeupFlat(object Closure#1230922)
#27 /home/user/pm/virions/await-generator_dev-130.phar/src/SOFe/AwaitGenerator/AwaitChild(52): SOFe\AwaitGenerator\Await->recheckPromiseQueue(object SOFe\AwaitGenerator\AwaitChild#1229965)
#28 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/DataConnectorImpl(165): SOFe\AwaitGenerator\AwaitChild->resolve(array[2])
#29 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/DataConnectorImpl(156): poggit\libasynql\base\DataConnectorImpl::poggit\libasynql\base\{closure}(int 388910, int 1)
#30 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/DataConnectorImpl(181): poggit\libasynql\base\DataConnectorImpl::poggit\libasynql\base\{closure}(object poggit\libasynql\result\SqlInsertResult#1191444)
#31 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/DataConnectorImpl(239): poggit\libasynql\base\DataConnectorImpl::poggit\libasynql\base\{closure}(array[1])
#32 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/SqlThreadPool(116): poggit\libasynql\base\DataConnectorImpl->poggit\libasynql\base\{closure}(array[1])
#33 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/DataConnectorImpl(322): poggit\libasynql\base\SqlThreadPool->readResults(array[12], null)
#34 /home/user/pm/virions/libasynql_dev-204.phar/src/poggit/libasynql/base/SqlThreadPool(64): poggit\libasynql\base\DataConnectorImpl->checkResults()
#35 pmsrc/vendor/pocketmine/snooze/src/SleeperHandler(120): poggit\libasynql\base\SqlThreadPool->poggit\libasynql\base\{closure}()
#36 pmsrc/src/TimeTrackingSleeperHandler(58): pocketmine\snooze\SleeperHandler->processNotifications()
#37 pmsrc/vendor/pocketmine/snooze/src/SleeperHandler(79): pocketmine\TimeTrackingSleeperHandler->processNotifications()
#38 pmsrc/src/Server(1683): pocketmine\snooze\SleeperHandler->sleepUntil(float 1699953121.9125)
#39 pmsrc/src/Server(1065): pocketmine\Server->tickProcessor()
#40 pmsrc/src/PocketMine(341): pocketmine\Server->__construct(object pocketmine\thread\ThreadSafeClassLoader#3, object pocketmine\utils\MainLogger#6, string[14] /home/user/pm/, string[22] /home/user/pm/plugins/)
#41 pmsrc/src/PocketMine(364): pocketmine\server()
#42 pmsrc(11): require(string[58] phar:///home/user/pm/PocketMine-MP.phar/src/PocketMine.php)

Undefined variable $name

SOFe\AwaitGenerator\AwaitException: "Unhandled async exception: Undefined variable $name" (EXCEPTION) in "/root/virions/await-generator_dev-130.phar/src/SOFe/AwaitGenerator/Await" at line 587

Help

Crash !!

hex2bin() At Line 588 in Await!!
Look at this fast!

Channel tries to call null function

Error: "Value of type null is not callable" (EXCEPTION) in "/home/sofe/proj/WebConsole/local/WebConsole.phar/src/libs/_aeb2c40fe5790109/SOFe/AwaitGenerator/Channel" at line 52
  #0 (): libs\_aeb2c40fe5790109\SOFe\AwaitGenerator\Channel->sendAndWait(object pocketmine\event\player\PlayerMoveEvent#128506)
  #1 /home/sofe/proj/WebConsole/local/WebConsole.phar/src/libs/_aeb2c40fe5790109/SOFe/AwaitGenerator/Await(332): Generator->rewind()
  #2 /home/sofe/proj/WebConsole/local/WebConsole.phar/src/libs/_aeb2c40fe5790109/SOFe/AwaitGenerator/Await(129): libs\_aeb2c40fe5790109\SOFe\AwaitGenerator\Await->wakeup(array[2])
  #3 /home/sofe/proj/WebConsole/local/WebConsole.phar/src/libs/_aeb2c40fe5790109/SOFe/AwaitGenerator/Channel(85): libs\_aeb2c40fe5790109\SOFe\AwaitGenerator\Await::g2c(object Generator#128426)
  #4 /home/sofe/proj/WebConsole/local/WebConsole.phar/src/libs/_aeb2c40fe5790109/SOFe/WebConsole/Lib/Util(36): libs\_aeb2c40fe5790109\SOFe\AwaitGenerator\Channel->sendWithoutWait(object pocketmine\event\player\PlayerMoveEvent#128506)
  #5 pmsrc/src/event/RegisteredListener(60): libs\_aeb2c40fe5790109\SOFe\WebConsole\Lib\Util::libs\_aeb2c40fe5790109\SOFe\WebConsole\Lib\{closure}(object pocketmine\event\player\PlayerMoveEvent#128506)
  #6 pmsrc/src/event/Event(62): pocketmine\event\RegisteredListener->callEvent(object pocketmine\event\player\PlayerMoveEvent#128506)
  #7 pmsrc/src/player/Player(1277): pocketmine\event\Event->call()
  #8 pmsrc/src/player/Player(1368): pocketmine\player\Player->processMostRecentMovements()
  #9 pmsrc/src/world/World(976): pocketmine\player\Player->onUpdate(int 130)
  #10 pmsrc/src/world/World(902): pocketmine\world\World->actuallyDoTick(int 130)
  #11 pmsrc/src/world/WorldManager(350): pocketmine\world\World->doTick(int 130)
  #12 pmsrc/src/Server(1815): pocketmine\world\WorldManager->tick(int 130)
  #13 pmsrc/src/Server(1697): pocketmine\Server->tick()
  #14 pmsrc/src/Server(1056): pocketmine\Server->tickProcessor()
  #15 pmsrc/src/PocketMine(339): pocketmine\Server->__construct(object BaseClassLoader#2, object pocketmine\utils\MainLogger#5, string[41] /home/sofe/proj/WebConsole/local/install/, string[49] /home/sofe/proj/WebConsole/local/install/plugins/)
  #16 pmsrc/src/PocketMine(362): pocketmine\server()
  #17 pmsrc(11): require(string[85] phar:///home/sofe/proj/WebConsole/local/install/PocketMine-MP.phar/src/PocketMin)

Channels

Unbuffered channels

class Channel<T> {
    public static function new(): array{ChannelSender<T>, ChannelReceiver<T>};
}
class ChannelSender<T> {
    public function send(T $value): Generator<void>;
}
class ChannelReceiver<T> {
    public function receive(): Generator<T>;
}

send suspends until receive is called, and receive suspends until send is called. No buffering is involved.

Buffered channels

Buffering does not affect receive logic. This can be created by wrapping ChannelSender:

class BufferedChannelSender<T> {
    public function __construct(private ChannelSender<T> $sender) {}

    public function send(T $value): void {
        Await::g2c($this->sender->send($value));
    }
}

send does not suspend. It simply spawns a background coroutine that calls send().

Await::RESOLVE_MULTI

Allow yield Await::RESOLVE_MULTI at all locations yield Await::RESOLVE is allowed. Returns a closure that sends func_get_args() rather than the first parameter.

Undefined offset in recheckPromiseQueue

https://github.com/SOF3/await-generator/blob/master/await-generator/src/SOFe/AwaitGenerator/Await.php#L410

[20:59:42] [Server thread/CRITICAL]: SOFe\AwaitGenerator\AwaitException: "Unhandled async exception" (EXCEPTION) in "/home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await" at line 440
[20:59:42] [Server thread/DEBUG]: #0 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(206): SOFe\AwaitGenerator\Await->reject(object ErrorException)
[20:59:42] [Server thread/DEBUG]: #1 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(180): SOFe\AwaitGenerator\Await->wakeup(object Closure)
[20:59:42] [Server thread/DEBUG]: #2 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(411): SOFe\AwaitGenerator\Await->wakeupFlat(object Closure)
[20:59:42] [Server thread/DEBUG]: #3 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/AwaitChild(48): SOFe\AwaitGenerator\Await->recheckPromiseQueue(object SOFe\AwaitGenerator\AwaitChild)
[20:59:42] [Server thread/DEBUG]: #4 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(436): SOFe\AwaitGenerator\AwaitChild->reject(object ErrorException)
[20:59:42] [Server thread/DEBUG]: #5 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(206): SOFe\AwaitGenerator\Await->reject(object ErrorException)
[20:59:42] [Server thread/DEBUG]: #6 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(180): SOFe\AwaitGenerator\Await->wakeup(object Closure)
[20:59:42] [Server thread/DEBUG]: #7 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(411): SOFe\AwaitGenerator\Await->wakeupFlat(object Closure)
[20:59:42] [Server thread/DEBUG]: #8 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/AwaitChild(48): SOFe\AwaitGenerator\Await->recheckPromiseQueue(object SOFe\AwaitGenerator\AwaitChild)
[20:59:42] [Server thread/DEBUG]: #9 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(436): SOFe\AwaitGenerator\AwaitChild->reject(object ErrorException)
[20:59:42] [Server thread/DEBUG]: #10 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(206): SOFe\AwaitGenerator\Await->reject(object ErrorException)
[20:59:42] [Server thread/DEBUG]: #11 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(180): SOFe\AwaitGenerator\Await->wakeup(object Closure)
[20:59:42] [Server thread/DEBUG]: #12 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(411): SOFe\AwaitGenerator\Await->wakeupFlat(object Closure)
[20:59:42] [Server thread/DEBUG]: #13 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/AwaitChild(48): SOFe\AwaitGenerator\Await->recheckPromiseQueue(object SOFe\AwaitGenerator\AwaitChild)
[20:59:42] [Server thread/DEBUG]: #14 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(436): SOFe\AwaitGenerator\AwaitChild->reject(object ErrorException)
[20:59:42] [Server thread/DEBUG]: #15 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(206): SOFe\AwaitGenerator\Await->reject(object ErrorException)
[20:59:42] [Server thread/DEBUG]: #16 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(180): SOFe\AwaitGenerator\Await->wakeup(object Closure)
[20:59:42] [Server thread/DEBUG]: #17 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(411): SOFe\AwaitGenerator\Await->wakeupFlat(object Closure)
[20:59:42] [Server thread/DEBUG]: #18 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/AwaitChild(41): SOFe\AwaitGenerator\Await->recheckPromiseQueue(object SOFe\AwaitGenerator\AwaitChild)
[20:59:42] [Server thread/DEBUG]: #19 /home/sofe/proj/php/await-std/src/SOFe/AwaitStd/AwaitStd(118): SOFe\AwaitGenerator\AwaitChild->resolve(object pocketmine\event\player\PlayerChatEvent)
[20:59:42] [Server thread/DEBUG]: #20 /home/sofe/proj/php/await-std/src/SOFe/AwaitStd/AwaitExecutor(58): SOFe\AwaitStd\AwaitStd->SOFe\AwaitStd\{closure}(object pocketmine\event\player\PlayerChatEvent)
[20:59:42] [Server thread/DEBUG]: #21 src/pocketmine/plugin/RegisteredListener(80): SOFe\AwaitStd\AwaitExecutor->execute(object SOFe\AwaitStd\DummyListener, object pocketmine\event\player\PlayerChatEvent)
[20:59:42] [Server thread/DEBUG]: #22 src/pocketmine/event/Event(88): pocketmine\plugin\RegisteredListener->callEvent(object pocketmine\event\player\PlayerChatEvent)
[20:59:42] [Server thread/DEBUG]: #23 src/pocketmine/Player(2222): pocketmine\event\Event->call()
[20:59:42] [Server thread/DEBUG]: #24 src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter(131): pocketmine\Player->chat(string[6] cancel)
[20:59:42] [Server thread/DEBUG]: #25 src/pocketmine/network/mcpe/protocol/TextPacket(123): pocketmine\network\mcpe\PlayerNetworkSessionAdapter->handleText(object pocketmine\network\mcpe\protocol\TextPacket)
[20:59:42] [Server thread/DEBUG]: #26 /home/sofe/proj/php/await-std-examples/Specter/src/specter/network/SpecterInterface(302): pocketmine\network\mcpe\protocol\TextPacket->handle(object pocketmine\network\mcpe\PlayerNetworkSessionAdapter)
[20:59:42] [Server thread/DEBUG]: #27 /home/sofe/proj/php/await-std-examples/Specter/src/specter/network/SpecterInterface(276): specter\network\SpecterInterface->sendPacket(object specter\network\SpecterPlayer, object pocketmine\network\mcpe\protocol\TextPacket)
[20:59:42] [Server thread/DEBUG]: #28 src/pocketmine/network/Network(109): specter\network\SpecterInterface->process()
[20:59:42] [Server thread/DEBUG]: #29 src/pocketmine/Server(2376): pocketmine\network\Network->processInterfaces()
[20:59:42] [Server thread/DEBUG]: #30 src/pocketmine/Server(2143): pocketmine\Server->tick()
[20:59:42] [Server thread/DEBUG]: #31 src/pocketmine/Server(1990): pocketmine\Server->tickProcessor()
[20:59:42] [Server thread/DEBUG]: #32 src/pocketmine/Server(1584): pocketmine\Server->start()
[20:59:42] [Server thread/DEBUG]: #33 src/pocketmine/PocketMine(272): pocketmine\Server->__construct(object BaseClassLoader, object pocketmine\utils\MainLogger, string[34] /home/sofe/proj/php/PocketMine-MP/, string[42] /home/sofe/proj/php/PocketMine-MP/plugins/)
[20:59:42] [Server thread/DEBUG]: #34 src/pocketmine/PocketMine(295): pocketmine\server()
[20:59:42] [Server thread/DEBUG]: Previous: ErrorException: "Undefined offset: 0" (EXCEPTION) in "/home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await" at line 410
[20:59:42] [Server thread/DEBUG]:   #0 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(410): pocketmine\utils\Utils::errorExceptionHandler(integer 8, string[19] Undefined offset: 0, string[85] /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Awai, integer 410, array[2])
[20:59:42] [Server thread/DEBUG]:   #1 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(204): SOFe\AwaitGenerator\Await->SOFe\AwaitGenerator\{closure}()
[20:59:42] [Server thread/DEBUG]:   #2 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(180): SOFe\AwaitGenerator\Await->wakeup(object Closure)
[20:59:42] [Server thread/DEBUG]:   #3 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(411): SOFe\AwaitGenerator\Await->wakeupFlat(object Closure)
[20:59:42] [Server thread/DEBUG]:   #4 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/AwaitChild(48): SOFe\AwaitGenerator\Await->recheckPromiseQueue(object SOFe\AwaitGenerator\AwaitChild)
[20:59:42] [Server thread/DEBUG]:   #5 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(436): SOFe\AwaitGenerator\AwaitChild->reject(object ErrorException)
[20:59:42] [Server thread/DEBUG]:   #6 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(206): SOFe\AwaitGenerator\Await->reject(object ErrorException)
[20:59:42] [Server thread/DEBUG]:   #7 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(180): SOFe\AwaitGenerator\Await->wakeup(object Closure)
[20:59:42] [Server thread/DEBUG]:   #8 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(411): SOFe\AwaitGenerator\Await->wakeupFlat(object Closure)
[20:59:42] [Server thread/DEBUG]:   #9 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/AwaitChild(48): SOFe\AwaitGenerator\Await->recheckPromiseQueue(object SOFe\AwaitGenerator\AwaitChild)
[20:59:42] [Server thread/DEBUG]:   #10 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(436): SOFe\AwaitGenerator\AwaitChild->reject(object ErrorException)
[20:59:42] [Server thread/DEBUG]:   #11 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(206): SOFe\AwaitGenerator\Await->reject(object ErrorException)
[20:59:42] [Server thread/DEBUG]:   #12 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(180): SOFe\AwaitGenerator\Await->wakeup(object Closure)
[20:59:42] [Server thread/DEBUG]:   #13 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(411): SOFe\AwaitGenerator\Await->wakeupFlat(object Closure)
[20:59:42] [Server thread/DEBUG]:   #14 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/AwaitChild(48): SOFe\AwaitGenerator\Await->recheckPromiseQueue(object SOFe\AwaitGenerator\AwaitChild)
[20:59:42] [Server thread/DEBUG]:   #15 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(436): SOFe\AwaitGenerator\AwaitChild->reject(object ErrorException)
[20:59:42] [Server thread/DEBUG]:   #16 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(206): SOFe\AwaitGenerator\Await->reject(object ErrorException)
[20:59:42] [Server thread/DEBUG]:   #17 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(180): SOFe\AwaitGenerator\Await->wakeup(object Closure)
[20:59:42] [Server thread/DEBUG]:   #18 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/Await(411): SOFe\AwaitGenerator\Await->wakeupFlat(object Closure)
[20:59:42] [Server thread/DEBUG]:   #19 /home/sofe/proj/php/await-generator/await-generator/src/SOFe/AwaitGenerator/AwaitChild(41): SOFe\AwaitGenerator\Await->recheckPromiseQueue(object SOFe\AwaitGenerator\AwaitChild)
[20:59:42] [Server thread/DEBUG]:   #20 /home/sofe/proj/php/await-std/src/SOFe/AwaitStd/AwaitStd(118): SOFe\AwaitGenerator\AwaitChild->resolve(object pocketmine\event\player\PlayerChatEvent)
[20:59:42] [Server thread/DEBUG]:   #21 /home/sofe/proj/php/await-std/src/SOFe/AwaitStd/AwaitExecutor(58): SOFe\AwaitStd\AwaitStd->SOFe\AwaitStd\{closure}(object pocketmine\event\player\PlayerChatEvent)
[20:59:42] [Server thread/DEBUG]:   #22 src/pocketmine/plugin/RegisteredListener(80): SOFe\AwaitStd\AwaitExecutor->execute(object SOFe\AwaitStd\DummyListener, object pocketmine\event\player\PlayerChatEvent)
[20:59:42] [Server thread/DEBUG]:   #23 src/pocketmine/event/Event(88): pocketmine\plugin\RegisteredListener->callEvent(object pocketmine\event\player\PlayerChatEvent)
[20:59:42] [Server thread/DEBUG]:   #24 src/pocketmine/Player(2222): pocketmine\event\Event->call()
[20:59:42] [Server thread/DEBUG]:   #25 src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter(131): pocketmine\Player->chat(string[6] cancel)
[20:59:42] [Server thread/DEBUG]:   #26 src/pocketmine/network/mcpe/protocol/TextPacket(123): pocketmine\network\mcpe\PlayerNetworkSessionAdapter->handleText(object pocketmine\network\mcpe\protocol\TextPacket)
[20:59:42] [Server thread/DEBUG]:   #27 /home/sofe/proj/php/await-std-examples/Specter/src/specter/network/SpecterInterface(302): pocketmine\network\mcpe\protocol\TextPacket->handle(object pocketmine\network\mcpe\PlayerNetworkSessionAdapter)
[20:59:42] [Server thread/DEBUG]:   #28 /home/sofe/proj/php/await-std-examples/Specter/src/specter/network/SpecterInterface(276): specter\network\SpecterInterface->sendPacket(object specter\network\SpecterPlayer, object pocketmine\network\mcpe\protocol\TextPacket)
[20:59:42] [Server thread/DEBUG]:   #29 src/pocketmine/network/Network(109): specter\network\SpecterInterface->process()
[20:59:42] [Server thread/DEBUG]:   #30 src/pocketmine/Server(2376): pocketmine\network\Network->processInterfaces()
[20:59:42] [Server thread/DEBUG]:   #31 src/pocketmine/Server(2143): pocketmine\Server->tick()
[20:59:42] [Server thread/DEBUG]:   #32 src/pocketmine/Server(1990): pocketmine\Server->tickProcessor()
[20:59:42] [Server thread/DEBUG]:   #33 src/pocketmine/Server(1584): pocketmine\Server->start()
[20:59:42] [Server thread/DEBUG]:   #34 src/pocketmine/PocketMine(272): pocketmine\Server->__construct(object BaseClassLoader, object pocketmine\utils\MainLogger, string[34] /home/sofe/proj/php/PocketMine-MP/, string[42] /home/sofe/proj/php/PocketMine-MP/plugins/)
[20:59:42] [Server thread/DEBUG]:   #35 src/pocketmine/PocketMine(295): pocketmine\server()
[20:59:42] [Server thread/DEBUG]:   #36 Internal(0): Corrected generator stack trace()
[20:59:42] [Server thread/DEBUG]:   #37 /home/sofe/proj/php/await-std-examples/BanHammer/src/SOFe/BanHammer/Main(63): SOFe\BanHammer\{closure}()

Improve documentation

The current README is more like a guide than a documentation, and is not useful as reference if users understand a bit concept of what is attempted here. A rewrite of documentation and reference is recommended.

Ideally, there should be 3 separate articles:

  • Rationale of await-generator: What it is intended to do and what not
  • Step-by-step tutorial to transform callback style into await-generator style
  • Technical reference of what each yielded value does and returns

Workflows are referencing vulnerable actions

Hello, there!

As part of the university research we are currently doing regarding the security of Github Actions, we noticed that one or many of the workflows that are part of this repository are referencing vulnerable versions of the third-party actions. As part of a disclosure process, we decided to open issues to notify GitHub Community.

Please note that there are could be some false positives in our methodology, thus not all of the open issues could be valid. If that is the case, please let us know, so that we can improve on our approach. You can contact me directly using an email: ikoishy [at] ncsu.edu

Thanks in advance

  1. The workflow ci.yml is referencing action shivammathur/setup-php using references v1. However this reference is missing the commit 7163319 which may contain fix to the vulnerability.
  2. The workflow ci.yml is referencing action shivammathur/setup-php using references v1. However this reference is missing the commit 7163319 which may contain fix to the vulnerability.
  3. The workflow ci.yml is referencing action shivammathur/setup-php using references v1. However this reference is missing the commit 7163319 which may contain fix to the vulnerability.

The vulnerability fix that is missing by actions' versions could be related to:
(1) CVE fix
(2) upgrade of vulnerable dependency
(3) fix to secret leak and others.
Please consider updating the reference to the action.

If you end up updating the reference, please let us know. We need the stats for the paper :-)

Cancellable interface

I don't know if "cancel" is a good term; I am not even sure if cancellation is a correct thing to do in a promise framework, where promise is just a state machine (unlike Rust futures, where you need to await a future to actually execute it).

Design

function read_line_await(LineBufReader $reader) {
    $resolve = yield Await::RESOLVE;
    $isCancelled = yield Await::IS_CANCEL;
    $reader->shiftLineCallback(function($line) use($isCancelled, $resolve) {
        if($isCancelled()) {
            $reader->unshiftLine($line);
        } else {
            $resolve($line);
        }
    });
}

When we Await::race multiple generators, the losing generators are set to be cancelled

Concerns

Coroutines are not necessarily cancellatoin-aware. They need to explicitly indicate what they do when they are cancelled (in particular, stateful promises need to reset the states they changed), which is a usability issue.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.