I used the awesome amphp async framework as base, on which to build the new MadelineProto APIs.
I heavily modified amphp coroutines and wrapped all of the AMPHP event loop methods to add native support for yielding generators.
I have also wrapped multiple amphp async libraries for ease of use and compatiblity with MadelineProto settings:
- MadelineProto artax HTTP client:
I wrapped the amphp artax HTTP library for greater security, and to add support for socks5 and HTTP proxies: the proxy settings are automatically extracted from MadelineProto settings.
Soon, MadelineProto's artax will support DNS over HTTPS by default.
I also provided a wrapper version of
file_get_contents:$file = yield $MadelineProto->file_get_contents('https://url');You can use this library to asynchronously download files from the web.
- ALL internal MadelineProto methods were converted to async automatically using an automatic script: with some changes and conversion to use php-parser, it can be used to automatically asyncify any script (will implement in a future version of MadelineProto).
- I created a custom async API to asynchronously construct objects:
This allows you to create multiple instances of MadelineProto asynchronously, because each instantiation will be done asynchronously.
$com = new \danog\MadelineProto\CombinedAPI('combined_session.madeline', ['bot.madeline' => $settings, 'user.madeline' => $settings, 'user2.madeline' => $settings]);
$com->async(true);
$com->loop(function () use ($com) {
$res = [];
foreach (['bot.madeline', 'user.madeline', 'user2.madeline'] as $session) {
$res []= $com->instances[$session]->start();
}
yield $com->all($res);
yield $com->setEventHandler('\EventHandler');
}
$com->loop();Internally, the combined event handler does
new \danog\MadelineProto\API, but it isn't blocking:this means that later, when I combine all the async `start()`s into one array and yield it using the async combinator function, initialization of sessions is done in parallel, and not one after the other.
A side effect of this is that you must not access or modify the settings property, at least not until the instance is ready; also, only non-namespaced methods can be called while the instance is still initializing.
To avoid these problems, simply
yield $MadelineProto->start() before doing anything else (put a $MadelineProto->async(true) before that, though).- I wrapped amphp's helper functions, and created some more:
The
all function you saw above is one of the many combinator functions that can be used to execute multiple async operations simultaneously and wait for the result of all of them.Each method has different error handling techniques, see the amphp docs.
Note that if you just take the result of these methods without yielding it, you can use it as a normal promise/generator.
Note: this is not the recommended method to make multiple method calls on the same instance of MadelineProto; use this only for non-API methods like
start(); for API methods, use multiple async.$promise1 = $MadelineProto->messages->sendMessage(...);
$promise2 = $MadelineProto->messages->sendMessage(...);
// $promise3 = ...;
// Equivalent to Amp\Promise\all(), but works with generators, too
$results = yield $MadelineProto->all([$promise1, $promise2, $generator3]);
// Equivalent to Amp\Promise\first(), but works with generators, too
$results = yield $MadelineProto->first([$promise1, $promise2, $generator3]);
// Equivalent to Amp\Promise\any(), but works with generators, too
$results = yield $MadelineProto->any([$promise1, $promise2, $generator3]);
// Equivalent to Amp\Promise\some(), but works with generators, too
$results = yield $MadelineProto->some([$promise1, $promise2, $generator3]);