This commit is contained in:
Daniil Gentili 2019-10-28 22:39:23 +01:00
parent e81ecc87c9
commit cb7d5f6155
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
30 changed files with 492 additions and 1075 deletions

View File

@ -1,3 +0,0 @@
{
"presets": ["php"]
}

3
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[submodule "docs"] [submodule "docs"]
path = docs path = docs
url = https://github.com/danog/MadelineProtoDocs url = https://github.com/danog/MadelineProtoDocs
[submodule "userbots/magnaluna"]
path = userbots/magnaluna
url = https://github.com/danog/magnaluna

View File

@ -1,398 +0,0 @@
# Changelog
## 4.0.0 Full async
**Fully asynchronous MadelineProto!**
MadelineProto now features async, for **incredible speed improvements**, and **parallel processing**.
Powered by [amphp](https://amphp.org), MadelineProto wraps the AMPHP APIs to provide a simpler generator-based async API.
What exactly __is__ **async**, you may ask, and how is it better than **threading** or **multiprocessing**?
Async is a relatively new programming pattern that allows you to easily write **non-blocking** code **as if you were using standard** blocking functions, all without the need for complex message exchange systems and synchronization handling for threaded programs, that only add overhead and complexity to your programs, making everything slower and error-prone.
More simply put: with **MadelineProto 4.0**, each update is handled in **parallel** using a separate **thread**, and everything is done in **parallel** (even on restricted webhosts, perfect for creating **file downloader bots**!).
To enable async, you have to do two simple things:
1) [Load the latest version of MadelineProto](https://docs.madelineproto.xyz/docs/ASYNC.html#loading-the-latest-version-of-madelineproto)
2) [`yield` your method calls](https://docs.madelineproto.xyz/docs/ASYNC.html#enabling-the-madelineproto-async-api).
That's it!
**No need** to set up thread pools (that don't even work in PHP), use synchronization primitives, and so on...
Just `yield $MadelineProto->messages->sendMessage` instead of `$MadelineProto->messages->sendMessage`.
***
And now, on to the **API changes**:
* First of all, we've got several bucketloads of telegram API changes, that can be viewed in the first posts.
* **Very important**, I wrote [documentation](https://docs.madelineproto.xyz/docs/LOGIN.html#getting-permission-to-use-the-telegram-api) on what to do if your account gets banned. * Dropped support for PHP 5 and PHP 7.0: these versions of PHP have [officially reached their EOL](http://php.net/eol.php), so MadelineProto will not support them anymore.
You should use MadelineProto with PHP 7.3 (or PHP 7.2; PHP 7.1 is supported but not recommended).
* **Dropped support for get_updates**: it won't work properly on async, and I really recommend you stop using it
* You can now use the `@support` username in sendMessage and other methods to send messages to the support user!
* Now MadelineProto will automatically try to get the access hash of users not present in the internal peer database (this should reduce errors)!
* If any file cannot be downloaded to due issues with the tg media server that is hosting it, it will be automatically sent to the `@support` user ([settings](https://docs.madelineproto.xyz/docs/SETTINGS.html#settingsdownloadreport_broken_media)).
* Documented the [MyTelegramOrgWrapper](https://docs.madelineproto.xyz/docs/LOGIN.html#api-id) API, that can be used to login programmaticaly to the [my.telegram.org](https://my.telegram.org management page).
* Added an [update_2fa](https://docs.madelineproto.xyz/update_2fa.html) method to update the login password
* Added a [get_full_dialogs](https://docs.madelineproto.xyz/docs/DIALOGS.html#get_full_dialogs-now-fully-async) method to get a full list of all chats youre member of, including **dialog info** (such as the pinned/last message ID, unread count, tag count, notification settings and message drafts).
* [Added support for automatic file uploads by name in secret chats (as with normal chats); you can also now send secret chat messages using the sendMessage method as if it were a normal chat](https://github.com/danog/MadelineProto/blob/master/secret_bot.php)
* Added a [resetUpdateState](https://docs.madelineproto.xyz/docs/UPDATES.html#fetch-all-updates-from-the-beginning) method to reset the update state and fetch ALL updates from the beginning
* Improved chat message splitting algorithm (if the message you're trying to send is too long): performance improvements, and it will now notify you via the logs if there are too many entities in the logs, or if the entities are too long.
* Improved the get_self method.
* [Added a __magic_sleep](https://docs.madelineproto.xyz/docs/UPDATES.html#async-combined-event-driven) substitute for `__sleep` in the `CombinedEventHandler`
* Removed all dependencies to `curl`: now all HTTP requests are made asynchronously using a custom version of [artax](https://docs.madelineproto.xyz/docs/ASYNC.html#madelineproto-artax-http-client) (more on that later).
* Updated [php-libtgvoip](https://voip.madelineproto.xyz) and introduced a [common API](https://docs.madelineproto.xyz/docs/CALLS.html#changing-audio-quality) for changing phone call settings
* Improved the `madeline.php` loader
* Removed the old serialization APIs: now serialization is done automatically by MadelineProto!
* Increased the default flood wait limit to 10 minutes, since with async waiting for the flood wait isn't blocking anymore
* When running from web, MadelineProto will also automatically enable logging of **PHP errors** (not MadelineProto logs) to `MadelineProto.log`, located in the same directory as the script that loaded MadelineProto.
***
Naturally, async is not the only feature present in MadelineProto 4.0: to implement async in MadelineProto, I rewrote the **entire codebase two times** over the course of the last six months, as shown in the diff:
```
~$ git diff --stat old master
187 files changed, 28692 insertions(+), 12288 deletions(-)
```
- I **completely refactored** the connection stack:
I threw out of the window my custom OOP wrapper for vanilla PHP sockets and created a brand new OOP connection stack.
The new connection stack uses a brand new incremental buffered async socket wrapper [Stream API](https://github.com/danog/MadelineProto/tree/master/src/danog/MadelineProto/Stream), that greatly simplifies work with layered protocols like MTProto.
Each MTProto packet is passed through a Stream layer, each one taking care of one part of the MTProto envelope, finally sending off everything to telegram using a simple AMPHP socket.
The simplified async buffered implementation of AMPHP sockets I created allowed me to easily add support for ALL **MTProto protocols**, including a few I haven't implemented before like the padded protocol.
Obfuscation is now handled via a separate setting, and can be enabled for **all** transports, not just `tcp_abridged` (it can be used to prevent ISP blocks in combination with the padded protocol, for example).
I also added support for different **MTProto transports**, including the brand new **websocket transport** and **secure websocket transport (HTTPS)**, until now only implemented in tdlib!
If you want all communcations with telegram to be **triple**-encrypted using HTTPS+MTProto+obfuscation, you can enable the `wss` transport (the third layer of encryption w/ obfuscation will be enabled automatically).
Note: the **websocket HTTPS MTProto transport** is different from the **HTTPS MTProto protocol** (both are supported by MadelineProto).
The **websocket HTTPS MTProto transport** is more reliable and faster than the **HTTPS MTProto protocol**, since MadelineProto does not have to handle HTTP long polls.
(the websocket transport may or may not also be used in future to implement MadelineProto in the browser with webassembly ;)
The new [proxy API](https://docs.madelineproto.xyz/docs/PROXY.html) is also based on the new stream API, and now supports **MTProxies**!
You can still use the socks5 and HTTP transports if you want.
[Writing your custom proxies](https://docs.madelineproto.xyz/docs/PROXY.html#build-your-proxy) now is now a LOT easier, thanks to the neat structure of the stream APIs and the abundant PHPDOC comments.
***
Streams and proxies aren't the only things that have been completely rewritten in this release:
I have written a **unique** socket message handler API based on [MadelineProto's loop API](https://docs.madelineproto.xyz/docs/ASYNC.html#async-loop-apis), and guarantees **maximum reliability** while communicating with telegram.
By the way, the new async background loop API can also be used by **you**! It is perfect for repeating tasks in a cron-like manner, running multiple resumable event loops and much more! More on that later.
The new **message handler loops** run in the background, and guarantee that every single method call you make gets delivered to telegram.
**Two signal loops** running in two separate green threads take care of writing and reading data from the socket asynchronously.
A **third signal loop** uses state request messages to make sure that the method calls were received by telegram, and queries replies/resend method calls if something's wrong.
A **fourth signal loop** takes care of HTTP long polling.
This guarantees maximum stability even if telegram's having server issues.
The write loop also greatly reduces overhead, increasing performances by automatically wrapping in containers multiple method calls: this is especially useful when making multiple method calls simultaneously with async (more on that later).
The update state is now stored using a custom `UpdatesState` API, that will simplify backup to a DBMS backend later on :).
***
Possibly the most __exciting__ thing to work on in this version of MadelineProto was the new **update management system**: I whipped it up in merely two days a few weeks ago, and it has **absolutely improved** the overall reliability of MadelineProto.
Huge thanks to Aliaksei Levin, the developer of tdlib, for explaining to me how exactly does the MTProto update API work: he saved me a lot of time, and was really nice <3<3<3.
While thinking of an easy way I could implement the new update system, **I had an inspiration**:
I created a **unique**, **reliable**, **fast** and **extremely simple** update handling system based on [MadelineProto's loop API](https://docs.madelineproto.xyz/docs/ASYNC.html#async-loop-apis), **not present in any** other MTProto client, **not even tdlib**.
Instead of messing around with various synchronization locks, checks and cluttered update receivers, **I implemented three simple feed loops**.
Updates are fed to the first update loop, where some simple duplicate/hole checks are done.
Updates are then fed to a second update loop, where secondary duplicate/hole checks are done.
A third loop type takes care of eventual holes and periodically fetches updates for all supergroups, channels.
All of this is implemented without **any** kind of additional synchronization or locking due to the nature of the **MadelineProto loop APIs**, with **1%** of the complexity of the official clients (which means less bugs and more pony time for me).
***
Even if most of MadelineProto's logic is now concentrated in the new **loop** and **stream** APIs, some parts like the TL parser are still there, albeit with many changes.
For example: now the TL parser is fully asynchronous (that may sound a bit weird to some of you, but for dynamic TL parsers, this greatly increases performances and allows parallelism).
The TL deserializer now uses yet another well-structured API called the **TLCallback API** to automatically populate internal databases directly on deserialization: again, this paradigm greatly **reduces complexity**, **increases performance** and is **absolutely unique** to MadelineProto; no other MTProto client has it, not even official clients.
One of the **completely new** modules that I created for MadelineProto async is the **file reference database**: a **very complex** module, required to handle files in the newer versions of the Telegram API.
It makes use of the **TLCallback** API to map files to their origins, to be able to refetch them at any given time when the file reference expires.
Another new module I've implemented is the **PasswordCalculator**, that is used to calculate the new password hashes for the 2FA login, __really cool__.
I've also rewritten the **APIFactory**, the abstraction layer that stands between you and MadelineProto when you do `$MadelineProto->method()`: it is now fully async, and MUCH faster thanks to a new cached method mapping system.
The same cached method mapping system is also used for the **event handler**, which means that now the **event handler is the fastest update management method**.
***
And now, let's elaborate on async:
With **MadelineProto 4.0**, each update is handled in **parallel** using a separate **thread**, and everything is done in **parallel** (even on restricted webhosts, perfect for creating **file downloader bots**!).
When I say **thread**, I actually mean **green thread** ([wikipedia](https://en.wikipedia.org/wiki/Green_threads)), often called **strand**.
**Strands** are behave exactly like normal **threads**, except that they're implemented in user-space, and they're much **faster**, **more reliable**, and **do not suffer** from synchronization issues present with normal threads.
Each update you receive using the **event handler** or the **callback handler** is managed in parallel in separate **green threads**: the **only thing** you have to do to enable **async** with **green threads** is add a `yield` before calling MadelineProto methods.
[Full async documentation with examples](https://docs.madelineproto.xyz/docs/ASYNC.html).
If your code still relies on the **old synchronous behaviour**, __don't worry__, there is backward compatibility.
However, old synchronous behaviour is deprecated, and I **highly recommend** you switch to async, due to the **huge performance** and **parallelism benefits**.
***
To implement async, I wrote loads of new async APIs in MadelineProto, as you may have seen above.
I used the **awesome** [amphp](https://amphp.org) 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](https://docs.madelineproto.xyz/docs/ASYNC.html#madelineproto-and-amphp-async-apis) 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](https://docs.madelineproto.xyz/docs/ASYNC.html#madelineproto-artax-http-client):
I wrapped the amphp [artax](https://amphp.org/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`:
```php
$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](https://github.com/danog/MadelineProto/blob/master/asyncify.php): with some changes and conversion to use [php-parser](https://github.com/nikic/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.
```php
$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](https://docs.madelineproto.xyz/docs/ASYNC.html#combining-async-operations), initialization of sessions is done in parallel, and not one after the other.
* 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](https://amphp.org/amp/promises/combinators).
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](https://docs.madelineproto.xyz/docs/ASYNC.html#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]);
```
* Handling timeouts
These methods can be used to wait for a certain amount of time for a result, and then throw an `Amp\TimeoutException` or simply continue execution if no result was obtained.
```
// Waits for the result for 2 seconds and then throws an \Amp\TimeoutException
$result = yield $MadelineProto->timeout($promise, 2)
// Waits for the result for 2 seconds, returns the result or null (which is the result of sleep())
$result = yield $MadelineProto->first([$promise, $MadelineProto->sleep(2)]);
```
* Async forking (does async green thread forking)
Useful if you need to start a process in the background and you want throwed exceptions to surface up.
These exceptions will exit the event loop, turning off the script unless you wrap `$MadelineProto->loop()` with a try-catch.
Use it when you do not need the result of a method (see [ignored async](https://docs.madelineproto.xyz/docs/ASYNC.html#ignored-async)), but you want eventual errors to crash the script.
Otherwise, just use the method without yield.
```php
// Exceptions will surface out of the event loop()
$MadelineProto->callFork($MadelineProto->messages->sendMessage([...]));
// Exceptions will be ignored
$MadelineProto->messages->sendMessage([...]);
// Like the first one, but the call will be deferred to the next event loop tick
$MadelineProto->callForkDefer($MadelineProto->messages->sendMessage([...]));
```
Ignoring exceptions is usually not good practice, so it's best to wrap the method you're calling in a closure with a try-catch with some error handling code inside of it, calling it right after that and passing it to callFork:
```php
$MadelineProto->callFork((function () use ($MadelineProto) {
try {
$MadelineProto->messages->sendMessage([...])
} catch (\Exception $e) {
// Handle by logging and stuff
}
})());
```
* I also created some wrapper functions to work asynchronously with console/browser output
Async sleep:
```php
yield $MadelineProto->sleep(3);
```
Async readline:
```php
$res = yield $MadelineProto->readLine('Optional prompt');
```
* Logging in MadelineProto is now completely asynchronous and easier:
```php
$MadelineProto->logger("Message");
```
No need to yield here, because the logging must be done in background.
* Simultaneous method calls
```php
yield $MadelineProto->messages->sendMessage([
'multiple' => true,
['peer' => '@danogentili', 'message' => 'hi'],
['peer' => '@apony', 'message' => 'hi']
]);
```
This is the preferred way of combining multiple method calls: this way, the MadelineProto async WriteLoop will combine **all method calls in one container**, making everything **WAY faster**.
The result of this will be an array of results, whose type is determined by the original return type of the method (see [API docs](https://docs.madelineproto.xyz/API_docs)).
The order of method calls can be guaranteed (server-side, not by MadelineProto) by using [call queues](https://docs.madelineproto.xyz/docs/USING_METHODS.html#queues).
* Exceptions:
**NOTE**: Due to the async nature of MadelineProto 4.0, sometimes the exception that is thrown and logged may not be the actual exception that caused the crash of the script.
To let me properly debug the issue, when reporting issues you also have to provide [**full logs**](https://docs.madelineproto.xyz/docs/LOGGING.html).
* Finally, [async loops](https://docs.madelineproto.xyz/docs/ASYNC.html#async-loop-apis).
MadelineProto provides some very useful async loop APIs, for executing operations periodically or on demand.
They are the perfect solution for implementing **async cron** loops, signal threads and much more!
I'll just link you all to the [documentation](https://docs.madelineproto.xyz/docs/ASYNC.html#async-loop-apis): it has full examples for each and every async API (you can also check out the [code](https://github.com/danog/MadelineProto/tree/master/src/danog/MadelineProto/Loop), it's full of PHPDOC comments).
***
Writing MadelineProto async, I **really enjoyed** working with the AMPHP framework: it is **very fast**, has [multiple packages](https://amphp.org/packages) to work asynchronously with HTTP requests, websockets, databases (MySQL, redis, postgres, DNS, sockets and [much more](https://github.com/amphp/))!
I chose AMPHP instead of the more famous ReactPHP due to its **speed**, **rich set of libraries** and **extreme ease of use**.
Working with its devs is also nice; I already contributed to the amphp's libraries with some improvements and bugfixes (I will soon also implement a DNS over HTTPS client for AMPHP, to implement in [MadelineProto's artax](https://docs.madelineproto.xyz/docs/ASYNC.html#madelineproto-artax-http-client)), and I invite you to do the same!
Even if you can't contribute to AMPHP, you can still use it: as I mentioned above, there are MANY libraries to work asynchronously with files, databases, DNS, HTTP; there's even an async windows registry client, used by the DNS client to fetch default DNS servers on windows!
When you use MadelineProto async, you **have** to also use an amphp async database client, **artax** instead of curl and guzzle, and so on: otherwise, the speed of MadelineProto async may be reduced by blocking behaviour of your code.
***
In case you missed it, [quick reminder that MadelineProto now supports MTProxy](https://docs.madelineproto.xyz/docs/PROXY.html)!
***
MadelineProto started as a hobby project, back when I knew nothing about cryptography, telegram's APIs, async or programming standards:
before, MadelineProto was created piece by piece as a single monolothic class composed of multiple traits;
now, MadelineProto is composed of **multiple modular APIs** that are **well-structured**, **heavily commented**, **wrappable**, **extendable** in any possible and immaginable way.
I am really happy with how MadelineProto async turned out.
I had an absolute blast working on this update, and implementing async really opened a **whole sea** of possible innovations and features I can implement in MadelineProto now:
* Async file upload by url (1.5gb)
* Get direct download url of any file (1.5gb)
* TON (this is actually going to be a lot of fun)
* group calls (the php-libtgvoip APIs are actually ready, I just need to wrap them in php-libtgvoip)
* video calls (~)
* native calls:
With MadelineProto async, I can finally properly implement **native async phone calls in PHP**:
this will allow handling **phone calls on webhosts**!
I already have some code I created a year ago for this backed up in a private gitlab repo :)
* async iterators:
I've been thinking of using AMPHP's [async iterator API](https://amphp.org/amp/iterators/) (after some modding obviously) to create async iterators for easily iterating over the messages of a group, and for doing other operations that would normally require using offsets:
```php
foreach ($MadelineProto->getMessages('@group') as $message) {
}
```
This shouldn't be too hard to implement, and with a proper (maybe separate OOP) API, it's going to be fun to make and use.
* `snake_case` => `CamelCase` conversion for all API methods:
Previously, MadelineProto's custom API methods (`get_info`, `download_to_dir`) used `snake_case`, which contrasted with the Telegram API methods (`sendMessage`), and is against PHP coding standards.
Soon, I plan to update MadelineProto's docs to only use `CamelCase` for method names.
The old method name will still be available after that; right now, you can already use both naming conventions for **all** MadelineProto methods:
```php
$MadelineProto->get_pwr_chat('user'); // OK!
$MadelineProto->getPwrChat('user'); // OK!
```
However, I recommend you now use the `CamelCase` version of methods.
* ArrayAccess on promises (to be able to do `yield $method()['result']` instead of `(yield $method)['result']`)
* An `openChat` method, inspired by tdlib, to enable fetching updates from groups **you aren't a member of**
* Add support for Telegram passport in 2FA and write some wrapper APIs
* Write some simplified APIs for takeout (can be implemented using async iterators)
* #MadelineProtoForNode async and lua async (the second can already be done now, the first is also pretty easy now that async is here :)))))
* DNS over HTTPS everywhere
* Parallelize some methods like the download method, or getPwrChat (upload is already fully parallelized)
* Get sponsor of MTProxies
* Optional max_id and min_id params in methods
* #phase1 🇮🇷🇷🇺
***
To use MadelineProto 4.0 w/ async, you have to load the **latest version** of MadelineProto from the **master** branch by loading it through composer (`dev-master`) or with madeline.php:
```php
<?php
if (!file_exists('madeline.php')) {
copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
}
define('MADELINE_BRANCH', '');
include 'madeline.php';
```
In a few weeks I will set MadelineProto 4.0 **as default** with `madeline.php`: in the meantime, I **do not provide support** for the old version.
***
* Write some docs for the useful get mime funcs
* Figure out web file proxying (might be interesting)
* Re-enable gzip in the write loop
* no defer logs
* startedLoop docs
tell about restart
tell about madeline.php loading in the same dire
remind about using the define
Handle auth_restart
splitting

View File

@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe
## Enforcement ## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at daniil@daniil.jt. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at daniil@daniil.it. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.

View File

@ -511,12 +511,10 @@ Tip: if you receive an error (or nothing), [send us](https://t.me/pwrtelegramgro
## Very complex and complete examples ## Very complex and complete examples
You can find examples for nearly every MadelineProto function in You can find examples for nearly every MadelineProto function in
* [magnaluna webradio](https://magna.madelineproto.xyz) - Multifeatured Telegram VoIP webradio
* [`tests/testing.php`](https://github.com/danog/MadelineProto/blob/master/tests/testing.php) - examples for making/receiving calls, making secret chats, sending secret chat messages, videos, audios, voice recordings, gifs, stickers, photos, sending normal messages, videos, audios, voice recordings, gifs, stickers, photos. * [`tests/testing.php`](https://github.com/danog/MadelineProto/blob/master/tests/testing.php) - examples for making/receiving calls, making secret chats, sending secret chat messages, videos, audios, voice recordings, gifs, stickers, photos, sending normal messages, videos, audios, voice recordings, gifs, stickers, photos.
* [`bot.php`](https://github.com/danog/MadelineProto/blob/master/bot.php) - examples for sending normal messages, downloading any media * [`bot.php`](https://github.com/danog/MadelineProto/blob/master/examples/bot.php) - examples for sending normal messages, downloading any media
* [`secret_bot.php`](https://github.com/danog/MadelineProto/blob/master/secret_bot.php) - secret chat bot * [`secret_bot.php`](https://github.com/danog/MadelineProto/blob/master/examples/secret_bot.php) - secret chat bot
* [`magna.php`](https://github.com/danog/MadelineProto/blob/master/magna.php) - examples for receiving calls * [`pipesbot.php`](https://github.com/danog/MadelineProto/blob/master/examples/pipesbot.php) - examples for creating inline bots and using other inline bots via a userbot
* [`userbots/pipesbot.php`](https://github.com/danog/MadelineProto/blob/master/userbots/pipesbot.php) - examples for creating inline bots and using other inline bots via a userbot
* [`userbots/MadelineProto_bot.php`](https://github.com/danog/MadelineProto/blob/master/userbots/MadelineProto_bot.php) - Multi-function bot
* [`userbots/pwrtelegram_debug_bot`](https://github.com/danog/MadelineProto/blob/master/userbots/pwrtelegram_debug_bot.php) - Multi-function bot

85
bot.php
View File

@ -1,85 +0,0 @@
#!/usr/bin/env php
<?php
/*
Copyright 2016-2019 Daniil Gentili
(https://daniil.it)
This file is part of MadelineProto.
MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Affero General Public License for more details.
You should have received a copy of the GNU General Public License along with MadelineProto.
If not, see <http://www.gnu.org/licenses/>.
*/
\set_include_path(\get_include_path().':'.\realpath(\dirname(__FILE__).'/MadelineProto/'));
/*
* Various ways to load MadelineProto
*/
if (!\file_exists(__DIR__.'/vendor/autoload.php')) {
if (!\file_exists('madeline.php')) {
\copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
}
include 'madeline.php';
} else {
require_once 'vendor/autoload.php';
}
class EventHandler extends \danog\MadelineProto\EventHandler
{
public function onAny($update)
{
if (isset($update['message']['out']) && $update['message']['out']) {
return;
}
if ($update['_'] === 'updateReadChannelOutbox') {
return;
}
if (isset($update['message']['_']) && $update['message']['_'] === 'messageEmpty') {
return;
}
$res = \json_encode($update, JSON_PRETTY_PRINT);
try {
yield $this->messages->sendMessage(['peer' => $update, 'message' => "<code>$res</code>", 'reply_to_msg_id' => isset($update['message']['id']) ? $update['message']['id'] : null, 'parse_mode' => 'HTML']);
if (isset($update['message']['media']) && $update['message']['media']['_'] !== 'messageMediaGame') {
yield $this->messages->sendMedia(['peer' => $update, 'message' => $update['message']['message'], 'media' => $update]);
/* '_' => 'inputMediaUploadedDocument',
'file' => $update,
'attributes' => [
['_' => 'documentAttributeFilename', 'file_name' => 'document.txt']
]
],]);*/
//yield $this->download_to_dir($update, '/tmp');
}
} catch (\danog\MadelineProto\RPCErrorException $e) {
$this->logger((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR);
} catch (\danog\MadelineProto\Exception $e) {
if (\stripos($e->getMessage(), 'invalid constructor given') === false) {
$this->logger((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR);
}
//$this->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
}
}
}
$settings = [
'logger' => [
'logger_level' => 5
],
'serialization' => [
'serialization_interval' => 30,
'cleanup_before_serialization' => true
],
];
$MadelineProto = new \danog\MadelineProto\API('bot.madeline', $settings);
$MadelineProto->async(true);
$MadelineProto->loop(function () use ($MadelineProto) {
yield $MadelineProto->start();
yield $MadelineProto->setEventHandler('\EventHandler');
});
$MadelineProto->loop();

1
bot.php Symbolic link
View File

@ -0,0 +1 @@
examples/bot.php

95
examples/bot.php Executable file
View File

@ -0,0 +1,95 @@
#!/usr/bin/env php
<?php
/**
* Example bot.
*
* Copyright 2016-2019 Daniil Gentili
* (https://daniil.it)
* This file is part of MadelineProto.
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU General Public License along with MadelineProto.
* If not, see <http://www.gnu.org/licenses/>.
*
* @author Daniil Gentili <daniil@daniil.it>
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
*
* @link https://docs.madelineproto.xyz MadelineProto documentation
*/
/*
* Various ways to load MadelineProto
*/
if (\file_exists(__DIR__.'/vendor/autoload.php')) {
include 'vendor/autoload.php';
} else {
if (!\file_exists('madeline.php')) {
\copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
}
include 'madeline.php';
}
/**
* Event handler class.
*/
class EventHandler extends \danog\MadelineProto\EventHandler
{
public function onUpdateNewChannelMessage($update)
{
yield $this->onUpdateNewMessage($update);
}
public function onUpdateNewMessage($update)
{
if (isset($update['message']['out']) && $update['message']['out']) {
return;
}
if ($update['_'] === 'updateReadChannelOutbox') {
return;
}
if (isset($update['message']['_']) && $update['message']['_'] === 'messageEmpty') {
return;
}
$res = \json_encode($update, JSON_PRETTY_PRINT);
try {
yield $this->messages->sendMessage(['peer' => $update, 'message' => "<code>$res</code>", 'reply_to_msg_id' => isset($update['message']['id']) ? $update['message']['id'] : null, 'parse_mode' => 'HTML']);
if (isset($update['message']['media']) && $update['message']['media']['_'] !== 'messageMediaGame') {
yield $this->messages->sendMedia(['peer' => $update, 'message' => $update['message']['message'], 'media' => $update]);
/* '_' => 'inputMediaUploadedDocument',
'file' => $update,
'attributes' => [
['_' => 'documentAttributeFilename', 'file_name' => 'document.txt']
]
],]);*/
//yield $this->download_to_dir($update, '/tmp');
}
} catch (\danog\MadelineProto\RPCErrorException $e) {
$this->logger((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR);
} catch (\danog\MadelineProto\Exception $e) {
if (\stripos($e->getMessage(), 'invalid constructor given') === false) {
$this->logger((string) $e, \danog\MadelineProto\Logger::FATAL_ERROR);
}
//$this->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
}
}
}
$settings = [
'logger' => [
'logger_level' => 5
],
'serialization' => [
'serialization_interval' => 30,
'cleanup_before_serialization' => true
],
];
$MadelineProto = new \danog\MadelineProto\API('bot.madeline', $settings);
$MadelineProto->async(true);
$MadelineProto->loop(function () use ($MadelineProto) {
yield $MadelineProto->start();
yield $MadelineProto->setEventHandler('\EventHandler');
});
$MadelineProto->loop();

View File

@ -1,33 +1,48 @@
#!/usr/bin/env php #!/usr/bin/env php
<?php <?php
/* /**
Copyright 2016-2019 Daniil Gentili * Example combined event handler bot.
(https://daniil.it) *
This file is part of MadelineProto. * Copyright 2016-2019 Daniil Gentili
MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * (https://daniil.it)
MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * This file is part of MadelineProto.
See the GNU Affero General Public License for more details. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
You should have received a copy of the GNU General Public License along with MadelineProto. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
If not, see <http://www.gnu.org/licenses/>. * See the GNU Affero General Public License for more details.
*/ * You should have received a copy of the GNU General Public License along with MadelineProto.
* If not, see <http://www.gnu.org/licenses/>.
*
* @author Daniil Gentili <daniil@daniil.it>
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
*
* @link https://docs.madelineproto.xyz MadelineProto documentation
*/
\set_include_path(\get_include_path().':'.\realpath(\dirname(__FILE__).'/MadelineProto/')); \set_include_path(\get_include_path().':'.\realpath(\dirname(__FILE__).'/MadelineProto/'));
/* /*
* Various ways to load MadelineProto * Various ways to load MadelineProto
*/ */
if (!\file_exists(__DIR__.'/vendor/autoload.php')) { if (\file_exists(__DIR__.'/vendor/autoload.php')) {
echo 'You did not run composer update, using madeline.php'.PHP_EOL; include 'vendor/autoload.php';
} else {
if (!\file_exists('madeline.php')) { if (!\file_exists('madeline.php')) {
\copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php'); \copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
} }
include 'madeline.php'; include 'madeline.php';
} else {
require_once 'vendor/autoload.php';
} }
/**
* Combined event handler class.
*/
class EventHandler extends \danog\MadelineProto\CombinedEventHandler class EventHandler extends \danog\MadelineProto\CombinedEventHandler
{ {
public function onAny($update, $path) public function onUpdateNewChannelMessage($update, $path)
{
yield $this->onUpdateNewMessage($update, $path);
}
public function onUpdateNewMessage($update, $path)
{ {
if (isset($update['message']['out']) && $update['message']['out']) { if (isset($update['message']['out']) && $update['message']['out']) {
return; return;

41
examples/index.php Normal file
View File

@ -0,0 +1,41 @@
<?php
/**
* Example script.
*
* Copyright 2016-2019 Daniil Gentili
* (https://daniil.it)
* This file is part of MadelineProto.
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU General Public License along with MadelineProto.
* If not, see <http://www.gnu.org/licenses/>.
*
* @author Daniil Gentili <daniil@daniil.it>
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
*
* @link https://docs.madelineproto.xyz MadelineProto documentation
*/
require 'vendor/autoload.php';
$MadelineProto = new \danog\MadelineProto\API('session.madeline');
$me = $MadelineProto->start();
$me = $MadelineProto->get_self();
\danog\MadelineProto\Logger::log($me);
if (!$me['bot']) {
$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => "Hi!\nThanks for creating MadelineProto! <3"]);
$MadelineProto->channels->joinChannel(['channel' => '@MadelineProto']);
try {
$MadelineProto->messages->importChatInvite(['hash' => 'https://t.me/joinchat/Bgrajz6K-aJKu0IpGsLpBg']);
} catch (\danog\MadelineProto\RPCErrorException $e) {
}
$MadelineProto->messages->sendMessage(['peer' => 'https://t.me/joinchat/Bgrajz6K-aJKu0IpGsLpBg', 'message' => 'Testing MadelineProto!']);
}
echo 'OK, done!'.PHP_EOL;

52
examples/mtproxyd Executable file
View File

@ -0,0 +1,52 @@
#!/usr/bin/env php
<?php
$debug = false; // Set this to true to avoid automatic updates of this script
/**
* MTProxy.
*
* Copyright 2016-2019 Daniil Gentili
* (https://daniil.it)
* This file is part of MadelineProto.
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU General Public License along with MadelineProto.
* If not, see <http://www.gnu.org/licenses/>.
*
* @author Daniil Gentili <daniil@daniil.it>
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
*
* @link https://docs.madelineproto.xyz MadelineProto documentation
*/
echo "mtproxyd - Copyright by Daniil Gentili, licensed under AGPLv3\n\n";
if (!isset($argv[2])) {
echo "Usage: ".$argv[0]." seed port\n\nseed is any string or word that will be used as seed to generate the proxy secret\nport is the port where to start listening for connections\n";
exit(1);
}
if (!\file_exists('madeline.php')) {
\copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
}
if (!$debug) {
$mtproxyd = \file_get_contents('https://phar.madelineproto.xyz/mtproxyd?v=new');
if ($mtproxyd) {
\file_put_contents($argv[0], $mtproxyd);
}
}
\define('MADELINE_BRANCH', 'deprecated');
require_once 'madeline.php';
$secret = \md5($argv[1]);
echo "Secret is $secret\n";
$MadelineProto = new \danog\MadelineProto\API('proxy.madeline');
$MadelineProto->parse_dc_options($MadelineProto->help->getConfig()['dc_options']);
$handler = new \danog\MadelineProto\Server(['type' => AF_INET, 'protocol' => 0, 'address' => '0.0.0.0', 'port' => $argv[2], 'handler' => '\danog\MadelineProto\Server\Proxy', 'extra' => ['madeline' => $MadelineProto->API->datacenter->sockets, 'secret' => \hex2bin($secret), 'timeout' => 10]]);
$handler->start();

228
examples/pipesbot.php Executable file
View File

@ -0,0 +1,228 @@
#!/usr/bin/env php
<?php
/**
* Pipes bot.
*
* Copyright 2016-2019 Daniil Gentili
* (https://daniil.it)
* This file is part of MadelineProto.
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU General Public License along with MadelineProto.
* If not, see <http://www.gnu.org/licenses/>.
*
* @author Daniil Gentili <daniil@daniil.it>
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
*
* @link https://docs.madelineproto.xyz MadelineProto documentation
*/
if (!\file_exists('madeline.php')) {
\copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
}
include 'madeline.php';
/**
* Event handler class.
*/
class pipesbot extends \danog\MadelineProto\EventHandler
{
const WELCOME = "This bot can create a pipeline between inline bots.
To use it, simply type an inline query with the following syntax:
```
@pipesbot text | @botname:filter | @botname2 \$
```
Example:
```
@pipesbot Hey I'm writing this using the leet filter of @filtersbot w/ @lolcatzbot | @filtersbot:eleet | @lolcatzbot \$
```
@pipesbot will:
1) Make an inline query with text \"Hey I'm writing this using the leet filter of @filtersbot w/ @lolcatzbot\" to @filtersbot
2) Take the result that has the word \"eleet\" in the title (regexes are supported; omit the selector to select the first result)
3) If it's a text message it will make an inline query to `@lolcatzbot` with the text received from the first bot
4) Fetch all results of the query to @lolcatzbot and return them to you.
Intermediate media results will be ignored.
Note that the query must be terminated by a \$.
Created by @daniilgentili using @MadelineProto (https://docs.madelineproto.xyz).";
const SWITCH_PM = ['switch_pm' => ['_' => 'inlineBotSwitchPM', 'text' => 'FAQ', 'start_param' => 'lel']];
const ADMIN = '@danogentili';
/**
* User instance of MadelineProto.
*
* @var \danog\MadelineProto\API
*/
private $u;
private function inputify(&$stuff)
{
$stuff['_'] = 'input'.\ucfirst($stuff['_']);
return $stuff;
}
private function translatetext(&$value)
{
$this->inputify($value);
if (isset($value['entities'])) {
foreach ($value['entities'] as &$entity) {
if ($entity['_'] === 'messageEntityMentionName') {
$this->inputify($entity);
}
}
}
if (isset($value['geo'])) {
$value['geo_point'] = $this->inputify($value['geo']);
}
}
private function translate(&$value, $key)
{
switch ($value['_']) {
case 'botInlineResult':
$value['_'] = 'inputBotInlineResult';
$this->translatetext($value['send_message']);
return $value;
case 'botInlineMediaResult':
if (isset($value['game'])) {
throw new \danog\MadelineProto\Exception('Games are not supported.');
}
if (isset($value['photo'])) {
$value['_'] = 'inputBotInlineResultPhoto';
}
if (isset($value['document'])) {
$value['_'] = 'inputBotInlineResultDocument';
}
$this->translatetext($value['send_message']);
return $value;
}
}
public function onUpdateNewChannelMessage($update)
{
yield $this->onUpdateNewMessage($update);
}
public function onUpdateNewMessage($update)
{
try {
if (\strpos($update['message']['message'], '/start') === 0) {
yield $this->messages->sendMessage(['peer' => $update, 'message' => self::WELCOME, 'reply_to_msg_id' => $update['message']['id'], 'parse_mode' => 'markdown']);
}
} catch (\Throwable $e) {
$this->logger($e);
}
}
public function onUpdateBotInlineQuery($update)
{
try {
$result = ['query_id' => $update['query_id'], 'results' => [], 'cache_time' => 0];
if ($update['query'] === '') {
yield $this->messages->setInlineBotResults($result + self::SWITCH_PM);
} else {
$result['private'] = true;
yield $this->messages->setInlineBotResults(yield $this->processNonEmptyQuery($update['query'], $update['user_id'], $result));
}
} catch (\Throwable $e) {
try {
yield $this->messages->sendMessage(['peer' => self::ADMIN, 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
yield $this->messages->sendMessage(['peer' => $update['user_id'], 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
} catch (\danog\MadelineProto\RPCErrorException $e) {
$this->logger($e);
} catch (\danog\MadelineProto\Exception $e) {
$this->logger($e);
}
try {
yield $this->messages->setInlineBotResults($result + self::SWITCH_PM);
} catch (\danog\MadelineProto\RPCErrorException $e) {
$this->logger($e);
} catch (\danog\MadelineProto\Exception $e) {
$this->logger($e);
}
}
}
private function processNonEmptyQuery($query, $user_id, $toset)
{
if (\preg_match('|(.*)\$\s*$|', $query, $content)) {
$exploded = \array_map('trim', \explode('|', $content[1]));
$query = \array_shift($exploded);
foreach ($exploded as $current => $botSelector) {
if (\strpos($botSelector, ':') === false) {
$botSelector .= ':';
}
list($bot, $selector) = \explode(':', $botSelector);
if ($bot === '' || yield $this->u->getInfo($bot)['bot_api_id'] === yield $this->getSelf()['id']) {
return $toset + self::SWITCH_PM;
}
$results = yield $this->u->messages->getInlineBotResults(['bot' => $bot, 'peer' => $user_id, 'query' => $query, 'offset' => $offset]);
if (isset($results['switch_pm'])) {
$toset['switch_pm'] = $results['switch_pm'];
return $toset;
}
$toset['gallery'] = $results['gallery'];
$toset['results'] = [];
if (\is_numeric($selector)) {
$toset['results'][0] = $results['results'][$selector - 1];
} elseif ($selector === '') {
$toset['results'] = $results['results'];
} else {
foreach ($results['results'] as $result) {
if (isset($result['send_message']['message']) && \preg_match('|'.$select.'|', $result['send_message']['message'])) {
$toset['results'][0] = $result;
}
}
}
if (!isset($toset['results'][0])) {
$toset['results'] = $results['results'];
}
if (\count($exploded) - 1 === $current || !isset($toset['results'][0]['send_message']['message'])) {
break;
}
$query = $toset['results'][0]['send_message']['message'];
}
}
if (empty($toset['results'])) {
$toset += self::SWITCH_PM;
} else {
\array_walk($toset['results'], 'translate');
}
return $toset;
}
public function setUMadelineProto($uMadelineProto)
{
$this->u = $uMadelineProto;
}
}
$uMadelineProto = new \danog\MadelineProto\API('pipesuser.madeline');
$uMadelineProto->async(true);
$uMadelineProto->call(function () use ($uMadelineProto) {
yield $uMadelineProto->echo("User login: ".PHP_EOL);
yield $uMadelineProto->start();
});
var_dump("past here");
$MadelineProto = new \danog\MadelineProto\API('pipesbot.madeline');
$MadelineProto->async(true);
$MadelineProto->call(function () use ($MadelineProto, $uMadelineProto) {
yield $MadelineProto->echo("Bot login: ".PHP_EOL);
yield $MadelineProto->start();
yield $MadelineProto->setEventHandler(PipesBot::class);
yield $MadelineProto->getEventHandler()->setUMadelineProto($uMadelineProto);
});

View File

@ -11,14 +11,13 @@ You should have received a copy of the GNU General Public License along with Mad
If not, see <http://www.gnu.org/licenses/>. If not, see <http://www.gnu.org/licenses/>.
*/ */
if (!\file_exists(__DIR__.'/../vendor/autoload.php')) { if (\file_exists(__DIR__.'/vendor/autoload.php')) {
echo 'You did not run composer update, using madeline.php'.PHP_EOL; include 'vendor/autoload.php';
} else {
if (!\file_exists('madeline.php')) { if (!\file_exists('madeline.php')) {
\copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php'); \copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
} }
include 'madeline.php'; include 'madeline.php';
} else {
require_once 'vendor/autoload.php';
} }
$settings = []; $settings = [];

View File

@ -1,28 +1,36 @@
#!/usr/bin/env php #!/usr/bin/env php
<?php <?php
/* /**
Copyright 2016-2019 Daniil Gentili * Secret chat bot.
(https://daniil.it) *
This file is part of MadelineProto. * Copyright 2016-2019 Daniil Gentili
MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * (https://daniil.it)
MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * This file is part of MadelineProto.
See the GNU Affero General Public License for more details. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
You should have received a copy of the GNU General Public License along with MadelineProto. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
If not, see <http://www.gnu.org/licenses/>. * See the GNU Affero General Public License for more details.
*/ * You should have received a copy of the GNU General Public License along with MadelineProto.
* If not, see <http://www.gnu.org/licenses/>.
*
* @author Daniil Gentili <daniil@daniil.it>
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
*
* @link https://docs.madelineproto.xyz MadelineProto documentation
*/
\set_include_path(\get_include_path().':'.\realpath(\dirname(__FILE__).'/MadelineProto/')); \set_include_path(\get_include_path().':'.\realpath(\dirname(__FILE__).'/MadelineProto/'));
/* /*
* Various ways to load MadelineProto * Various ways to load MadelineProto
*/ */
if (!\file_exists(__DIR__.'/vendor/autoload.php')) { if (\file_exists(__DIR__.'/vendor/autoload.php')) {
echo 'You did not run composer update, using madeline.php'.PHP_EOL; include 'vendor/autoload.php';
} else {
if (!\file_exists('madeline.php')) { if (!\file_exists('madeline.php')) {
\copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php'); \copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
} }
include 'madeline.php'; include 'madeline.php';
} else {
require_once 'vendor/autoload.php';
} }
class EventHandler extends \danog\MadelineProto\EventHandler class EventHandler extends \danog\MadelineProto\EventHandler

View File

@ -1,23 +0,0 @@
<?php
require 'vendor/autoload.php';
$MadelineProto = new \danog\MadelineProto\API('session.madeline');
$me = $MadelineProto->start();
$me = $MadelineProto->get_self();
\danog\MadelineProto\Logger::log($me);
if (!$me['bot']) {
$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => "Hi!\nThanks for creating MadelineProto! <3"]);
$MadelineProto->channels->joinChannel(['channel' => '@MadelineProto']);
try {
$MadelineProto->messages->importChatInvite(['hash' => 'https://t.me/joinchat/Bgrajz6K-aJKu0IpGsLpBg']);
} catch (\danog\MadelineProto\RPCErrorException $e) {
}
$MadelineProto->messages->sendMessage(['peer' => 'https://t.me/joinchat/Bgrajz6K-aJKu0IpGsLpBg', 'message' => 'Testing MadelineProto!']);
}
echo 'OK, done!'.PHP_EOL;

View File

@ -1,64 +0,0 @@
#!/usr/bin/env php
<?php
/*
Copyright 2016-2019 Daniil Gentili
(https://daniil.it)
This file is part of MadelineProto.
MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Affero General Public License for more details.
You should have received a copy of the GNU General Public License along with MadelineProto.
If not, see <http://www.gnu.org/licenses/>.
*/
require '../vendor/autoload.php';
$settings = [];
$Lua = false;
try {
$Lua = \danog\MadelineProto\Serialization::deserialize('bot.madeline');
} catch (\danog\MadelineProto\Exception $e) {
}
if (!\is_object($Lua)) {
$MadelineProto = new \danog\MadelineProto\API($settings);
while (!\in_array(($res = \readline('Do you want to login as a user or as a bot (u/b)? ')), ['u', 'b'])) {
echo 'Please write either u or b'.PHP_EOL;
}
switch ($res) {
case 'u':
$sentCode = $MadelineProto->phone_login(\readline('Enter your phone number: '));
\danog\MadelineProto\Logger::log($sentCode, \danog\MadelineProto\Logger::NOTICE);
echo 'Enter the code you received: ';
$code = \fgets(STDIN, (isset($sentCode['type']['length']) ? $sentCode['type']['length'] : 5) + 1);
$authorization = $MadelineProto->complete_phone_login($code);
\danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE);
if ($authorization['_'] === 'account.noPassword') {
throw new \danog\MadelineProto\Exception('2FA is enabled but no password is set!');
}
if ($authorization['_'] === 'account.password') {
\danog\MadelineProto\Logger::log('2FA is enabled', \danog\MadelineProto\Logger::NOTICE);
$authorization = $MadelineProto->complete_2fa_login(\readline('Please enter your password (hint '.$authorization['hint'].'): '));
}
if ($authorization['_'] === 'account.needSignup') {
\danog\MadelineProto\Logger::log('Registering new user', \danog\MadelineProto\Logger::NOTICE);
$authorization = $MadelineProto->complete_signup(\readline('Please enter your first name: '), \readline('Please enter your last name (can be empty): '));
}
\danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE);
$Lua = new \danog\MadelineProto\Lua('madeline.lua', $MadelineProto);
break;
case 'b':
$authorization = $MadelineProto->bot_login(\readline('Please enter a bot token: '));
\danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE);
$Lua = new \danog\MadelineProto\Lua('madeline.lua', $MadelineProto);
break;
}
}
$offset = 0;
while (true) {
$updates = $Lua->MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
foreach ($updates as $update) {
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
$Lua->madeline_update_callback($update['update']);
}
echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('bot.madeline', $Lua).' bytes'.PHP_EOL;
}

View File

@ -1,34 +0,0 @@
#!/usr/bin/env php
<?php
$debug = false; // Set this to true to avoid automatic updates of this script
echo "mtproxyd - Copyright by Daniil Gentili, licensed under AGPLv3\n\n";
if (!isset($argv[2])) {
echo "Usage: ".$argv[0]." seed port\n\nseed is any string or word that will be used as seed to generate the proxy secret\nport is the port where to start listening for connections\n";
exit(1);
}
if (!file_exists('madeline.php')) {
copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
}
if (!$debug) {
$mtproxyd = file_get_contents('https://phar.madelineproto.xyz/mtproxyd?v=new');
if ($mtproxyd) {
file_put_contents($argv[0], $mtproxyd);
}
}
require_once 'madeline.php';
$secret = md5($argv[1]);
echo "Secret is $secret\n";
$MadelineProto = new \danog\MadelineProto\API('proxy.madeline');
$MadelineProto->parse_dc_options($MadelineProto->help->getConfig()['dc_options']);
$handler = new \danog\MadelineProto\Server(['type' => AF_INET, 'protocol' => 0, 'address' => '0.0.0.0', 'port' => $argv[2], 'handler' => '\danog\MadelineProto\Server\Proxy', 'extra' => ['madeline' => $MadelineProto->API->datacenter->sockets, 'secret' => hex2bin($secret), 'timeout' => 10]]);
$handler->start();

View File

@ -96,7 +96,7 @@ for f in $(find phar5 -type f -name '*.php'); do php -l $f;done
branch="-$TRAVIS_BRANCH" branch="-$TRAVIS_BRANCH"
cd $madelinePath cd $madelinePath
php makephar.php $HOME/phar5 "madeline$php$branch.phar" $TRAVIS_COMMIT php tools/makephar.php $HOME/phar5 "madeline$php$branch.phar" $TRAVIS_COMMIT
curl -s https://api.telegram.org/bot$BOT_TOKEN/sendDocument -F chat_id=101374607 -F document="@$TRAVIS_PHAR" curl -s https://api.telegram.org/bot$BOT_TOKEN/sendDocument -F chat_id=101374607 -F document="@$TRAVIS_PHAR"
@ -134,7 +134,7 @@ cd MadelineProtoPhar
} }
cp "../madeline$php$branch.phar" . cp "../madeline$php$branch.phar" .
cp ../phar.php ../mtproxyd . cp ../tools/phar.php ../examples/mtproxyd .
echo -n $TRAVIS_COMMIT > release$php$branch echo -n $TRAVIS_COMMIT > release$php$branch
[ "$IS_RELEASE" == "y" ] && { [ "$IS_RELEASE" == "y" ] && {

View File

@ -45,5 +45,5 @@ cp phar5/vendor/danog/madelineproto/src/danog/MadelineProto/Coroutine.php phar5/
sed -i 's/namespace danog\\MadelineProto;//g' phar5/vendor/amphp/amp/lib/Coroutine.php sed -i 's/namespace danog\\MadelineProto;//g' phar5/vendor/amphp/amp/lib/Coroutine.php
php makephar.php phar5 madeline.phar $(cat .git/refs/heads/master) php tools/makephar.php phar5 madeline.phar $(cat .git/refs/heads/master)

View File

@ -1,16 +1,18 @@
#!/usr/bin/env php #!/usr/bin/env php
<?php <?php
/* /**
Copyright 2016-2019 Daniil Gentili * Copyright 2016-2019 Daniil Gentili
(https://daniil.it) * (https://daniil.it)
This file is part of MadelineProto. * This file is part of MadelineProto.
MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Affero General Public License for more details. * See the GNU Affero General Public License for more details.
You should have received a copy of the GNU General Public License along with MadelineProto. * You should have received a copy of the GNU General Public License along with MadelineProto.
If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
require 'vendor/autoload.php'; require 'vendor/autoload.php';
$param = 1; $param = 1;
\danog\MadelineProto\Logger::constructor($param); \danog\MadelineProto\Logger::constructor($param);
$logger = \danog\MadelineProto\Logger::$default; $logger = \danog\MadelineProto\Logger::$default;

View File

@ -1,162 +0,0 @@
#!/usr/bin/env php
<?php
/*
Copyright 2016-2019 Daniil Gentili
(https://daniil.it)
This file is part of MadelineProto.
MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Affero General Public License for more details.
You should have received a copy of the GNU General Public License along with MadelineProto.
If not, see <http://www.gnu.org/licenses/>.
*/
if (!\file_exists(__DIR__.'/../vendor/autoload.php')) {
echo 'You did not run composer update, using madeline.php'.PHP_EOL;
if (!\file_exists('madeline.php')) {
\copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
}
include 'madeline.php';
} else {
require_once 'vendor/autoload.php';
}
$settings = [];
$MadelineProto = false;
try {
$MadelineProto = new \danog\MadelineProto\API('MadelineProto_bot.madeline');
} catch (\danog\MadelineProto\Exception $e) {
$MadelineProto = new \danog\MadelineProto\API($settings);
$authorization = $MadelineProto->bot_login(\readline('Enter a bot token: '));
\danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE);
}
if (\file_exists('token.php') && $MadelineProto === false) {
include_once 'token.php';
$MadelineProto = new \danog\MadelineProto\API($settings);
$authorization = $MadelineProto->bot_login($MadelineProto_token);
\danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE);
}
$offset = 0;
$reply_markup = ['inline_keyboard' => [
[ // Row 1
['text' => 'Row 1 c1'],
['text' => 'Row 1 c2'],
['text' => 'Row 1 c3'],
],
[ // Row 2
['text' => 'Row 2 c1'],
['text' => 'Row 2 c2'],
['text' => 'Row 2 c3'],
],
[ // Row 3
['text' => 'Row 3 c1'],
['text' => 'Row 3 c2'],
['text' => 'Row 3 c3'],
],
],
];
$start = 'This bot can create inline text buttons.
To use it, simply type an inline query with the following syntax:
@MadelineProto_bot Text to show in message
Row 1 c1 | Row 1 c2 | Row 1 c3
Row 2 c1 | Row 2 c2 | Row 2 c3
Row 3 c1 | Row 3 c2 | Row 3 c3
This will create a keyboard exactly like the one used in this message (click the buttons ;D) with the phrase "Text to show in message" instead of this help message.
Created by [Daniil Gentili](mention:@danogentili) (@daniilgentili) using the [MadelineProto PHP MTProto client](daniil.it/MadelineProto).';
echo 'Bot started.'.PHP_EOL;
while (true) {
$updates = $MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
foreach ($updates as $update) {
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
switch ($update['update']['_']) {
case 'updateNewMessage':
if (isset($update['update']['message']['out']) && $update['update']['message']['out']) {
continue;
}
try {
if (isset($update['update']['message']['message']) && \preg_match('|/start|', $update['update']['message']['message'])) {
$MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['from_id'], 'message' => $start, 'reply_to_msg_id' => $update['update']['message']['id'], 'parse_mode' => 'markdown', 'reply_markup' => $reply_markup]);
}
} catch (\danog\MadelineProto\RPCErrorException $e) {
//$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
}
break;
case 'updateNewChannelMessage':
if (isset($update['update']['message']['out']) && $update['update']['message']['out']) {
continue;
}
try {
if (\preg_match('|/start|', $update['update']['message']['message'])) {
$MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['to_id'], 'message' => $start, 'reply_to_msg_id' => $update['update']['message']['id'], 'parse_mode' => 'markdown', 'reply_markup' => $reply_markup]);
}
} catch (\danog\MadelineProto\RPCErrorException $e) {
//$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
} catch (\danog\MadelineProto\Exception $e) {
//$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
}
break;
case 'updateBotInlineQuery':
try {
$sswitch = ['_' => 'inlineBotSwitchPM', 'text' => 'FAQ', 'start_param' => 'lel'];
if ($update['update']['query'] === '') {
$MadelineProto->messages->setInlineBotResults(['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'switch_pm' => $sswitch]);
} else {
$toset = ['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'private' => true];
$rows = \explode("\n", $update['update']['query']);
$text = \array_shift($rows);
if (empty($rows)) {
$MadelineProto->messages->setInlineBotResults(['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'switch_pm' => $sswitch]);
} else {
\array_walk($rows, function (&$value, $key) {
$value = \explode('|', $value);
\array_walk($value, function (&$value, $key) {
$value = ['text' => \trim($value), 'url' => 'https://yayponies.eu'];
});
});
$toset['results'] = [['_' => 'inputBotInlineResult', 'id' => (string) \random_int(0, \pow(2, 31) - 1), 'type' => 'article', 'title' => $text, 'description' => 'Your keyboard', 'send_message' => ['_' => 'inputBotInlineMessageText', 'message' => $text, 'reply_markup' => ['inline_keyboard' => $rows]]]];
$MadelineProto->messages->setInlineBotResults($toset);
}
}
} catch (\danog\MadelineProto\RPCErrorException $e) {
$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
try {
$MadelineProto->messages->sendMessage(['peer' => $update['update']['user_id'], 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
} catch (\danog\MadelineProto\RPCErrorException $e) {
} catch (\danog\MadelineProto\Exception $e) {
}
try {
$toset['switch_pm'] = $sswitch;
$MadelineProto->messages->setInlineBotResults($toset);
} catch (\danog\MadelineProto\RPCErrorException $e) {
} catch (\danog\MadelineProto\Exception $e) {
}
} catch (\danog\MadelineProto\Exception $e) {
try {
$MadelineProto->messages->sendMessage(['peer' => $update['update']['user_id'], 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
} catch (\danog\MadelineProto\RPCErrorException $e) {
} catch (\danog\MadelineProto\Exception $e) {
}
try {
$toset['switch_pm'] = $sswitch;
$MadelineProto->messages->setInlineBotResults($toset);
} catch (\danog\MadelineProto\RPCErrorException $e) {
} catch (\danog\MadelineProto\Exception $e) {
}
}
}
}
\danog\MadelineProto\Serialization::serialize('MadelineProto_bot.madeline', $MadelineProto);
}

@ -1 +0,0 @@
Subproject commit 6121026ffc906305083796df8b831c93b79ad819

View File

@ -1,249 +0,0 @@
#!/usr/bin/env php
<?php
/*
Copyright 2016-2019 Daniil Gentili
(https://daniil.it)
This file is part of MadelineProto.
MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Affero General Public License for more details.
You should have received a copy of the GNU General Public License along with MadelineProto.
If not, see <http://www.gnu.org/licenses/>.
*/
if (!\file_exists(__DIR__.'/../vendor/autoload.php')) {
echo 'You did not run composer update, using madeline.php'.PHP_EOL;
if (!\file_exists('madeline.php')) {
\copy('https://phar.madelineproto.xyz/madeline.php', 'madeline.php');
}
include 'madeline.php';
} else {
require_once 'vendor/autoload.php';
}
$settings = [];
$MadelineProto = false;
$uMadelineProto = false;
try {
$MadelineProto = new \danog\MadelineProto\API('pipesbot.madeline');
} catch (\danog\MadelineProto\Exception $e) {
\danog\MadelineProto\Logger::log($e->getMessage());
}
try {
$uMadelineProto = new \danog\MadelineProto\API('pwr.madeline');
} catch (\danog\MadelineProto\Exception $e) {
\danog\MadelineProto\Logger::log($e->getMessage());
}
if (\file_exists('token.php') && $MadelineProto === false) {
include_once 'token.php';
$MadelineProto = new \danog\MadelineProto\API($settings);
$authorization = $MadelineProto->bot_login($pipes_token);
\danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE);
}
if ($uMadelineProto === false) {
echo 'Loading MadelineProto...'.PHP_EOL;
$uMadelineProto = new \danog\MadelineProto\API(\array_merge($settings, ['updates' => ['handle_updates' => false]]));
$sentCode = $uMadelineProto->phone_login(\readline());
\danog\MadelineProto\Logger::log($sentCode, \danog\MadelineProto\Logger::NOTICE);
echo 'Enter the code you received: ';
$code = \fgets(STDIN, (isset($sentCode['type']['length']) ? $sentCode['type']['length'] : 5) + 1);
$authorization = $uMadelineProto->complete_phone_login($code);
\danog\MadelineProto\Logger::log($authorization, \danog\MadelineProto\Logger::NOTICE);
if ($authorization['_'] === 'account.noPassword') {
throw new \danog\MadelineProto\Exception('2FA is enabled but no password is set!');
}
if ($authorization['_'] === 'account.password') {
\danog\MadelineProto\Logger::log('2FA is enabled', \danog\MadelineProto\Logger::NOTICE);
$authorization = $uMadelineProto->complete_2fa_login(\readline('Please enter your password (hint '.$authorization['hint'].'): '));
}
echo 'Serializing MadelineProto to session.madeline...'.PHP_EOL;
echo 'Wrote '.\danog\MadelineProto\Serialization::serialize('session.madeline', $uMadelineProto).' bytes'.PHP_EOL;
}
function inputify(&$stuff)
{
$stuff['_'] = 'input'.\ucfirst($stuff['_']);
return $stuff;
}
function translatetext(&$value)
{
inputify($value);
if (isset($value['entities'])) {
foreach ($value['entities'] as &$entity) {
if ($entity['_'] === 'messageEntityMentionName') {
inputify($entity);
}
}
}
if (isset($value['geo'])) {
$value['geo_point'] = inputify($value['geo']);
}
}
function translate(&$value, $key)
{
switch ($value['_']) {
case 'botInlineResult':
$value['_'] = 'inputBotInlineResult';
translatetext($value['send_message']);
return $value;
case 'botInlineMediaResult':
if (isset($value['game'])) {
throw new \danog\MadelineProto\RPCErrorException('Games are not supported.');
}
if (isset($value['photo'])) {
$value['_'] = 'inputBotInlineResultPhoto';
}
if (isset($value['document'])) {
$value['_'] = 'inputBotInlineResultDocument';
}
translatetext($value['send_message']);
return $value;
}
}
$offset = 0;
$start = "This bot can create a pipeline between inline bots.
To use it, simply type an inline query with the following syntax:
@pipesbot Hey I'm writing this using the leet filter of @filtersbot w/ @lolcatzbot | @filtersbot:eleet | @lolcatzbot \$
This will make an inline query with text \"Hey I'm writing this using the leet filter of @filtersbot w/ @lolcatzbot\" to @filtersbot, take the result that has the word \"eleet\" (regexes are supported. you can specify just the username to select the first result), in the title, if it's a text message (entities will be ignored, if it's a media message you will be redirected here), then it will make an inline query to @lolcatzbot with the text received out of the first bot fetch all results and return them to you.
Note that the query must be terminated by a \$
Created by @danogentili (@daniilgentili) using the daniil.it/MadelineProto PHP MTProto client.";
while (true) {
$updates = $MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
foreach ($updates as $update) {
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
try {
switch ($update['update']['_']) {
case 'updateNewMessage':
if (isset($update['update']['message']['out']) && $update['update']['message']['out']) {
continue;
}
try {
if (\preg_match('|/start|', $update['update']['message']['message'])) {
$MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['from_id'], 'message' => $start, 'reply_to_msg_id' => $update['update']['message']['id']]);
}
} catch (\danog\MadelineProto\RPCErrorException $e) {
$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
}
break;
case 'updateNewChannelMessage':
if (isset($update['update']['message']['out']) && $update['update']['message']['out']) {
continue;
}
try {
if (\preg_match('|/start|', $update['update']['message']['message'])) {
$MadelineProto->messages->sendMessage(['peer' => $update['update']['message']['to_id'], 'message' => $start, 'reply_to_msg_id' => $update['update']['message']['id']]);
}
} catch (\danog\MadelineProto\RPCErrorException $e) {
$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
} catch (\danog\MadelineProto\Exception $e) {
$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
}
break;
case 'updateBotInlineQuery':
try {
$sswitch = ['_' => 'inlineBotSwitchPM', 'text' => 'FAQ', 'start_param' => 'lel'];
if ($update['update']['query'] === '') {
$MadelineProto->messages->setInlineBotResults(['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'switch_pm' => $sswitch]);
} else {
$toset = ['query_id' => $update['update']['query_id'], 'results' => [], 'cache_time' => 0, 'private' => true];
if (\preg_match('|\$\s*$|', $update['update']['query'])) {
$exploded = \explode('|', \preg_replace('/\$\s*$/', '', $update['update']['query']));
\array_walk($exploded, function (&$value, $key) {
$value = \preg_replace(['/^\s+/', '/\s+$/'], '', $value);
});
$query = \array_shift($exploded);
foreach ($exploded as $current => $botq) {
$bot = \preg_replace('|:.*|', '', $botq);
if ($bot === '' || $uMadelineProto->get_info($bot)['bot_api_id'] === $MadelineProto->API->authorization['user']['id']) {
$toset['switch_pm'] = $sswitch;
break;
}
$select = \preg_replace('|'.$bot.':|', '', $botq);
$results = $uMadelineProto->messages->getInlineBotResults(['bot' => $bot, 'peer' => $update['update']['user_id'], 'query' => $query, 'offset' => $offset]);
if (isset($results['switch_pm'])) {
$toset['switch_pm'] = $results['switch_pm'];
break;
}
$toset['gallery'] = $results['gallery'];
$toset['results'] = [];
if (\is_numeric($select)) {
$toset['results'][0] = $results['results'][$select - 1];
} elseif ($select === '') {
$toset['results'] = $results['results'];
} else {
foreach ($results['results'] as $result) {
if (isset($result['send_message']['message']) && \preg_match('|'.$select.'|', $result['send_message']['message'])) {
$toset['results'][0] = $result;
}
}
}
if (!isset($toset['results'][0])) {
$toset['results'] = $results['results'];
}
if (\count($exploded) - 1 === $current || !isset($toset['results'][0]['send_message']['message'])) {
break;
}
$query = $toset['results'][0]['send_message']['message'];
}
}
if (empty($toset['results'])) {
$toset['switch_pm'] = $sswitch;
} else {
\array_walk($toset['results'], 'translate');
}
$MadelineProto->messages->setInlineBotResults($toset);
}
} catch (\danog\MadelineProto\RPCErrorException $e) {
try {
$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
$MadelineProto->messages->sendMessage(['peer' => $update['update']['user_id'], 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
} catch (\danog\MadelineProto\RPCErrorException $e) {
\danog\MadelineProto\Logger::log($e->getMessage());
} catch (\danog\MadelineProto\Exception $e) {
\danog\MadelineProto\Logger::log($e->getMessage());
}
try {
$toset['switch_pm'] = $sswitch;
$MadelineProto->messages->setInlineBotResults($toset);
} catch (\danog\MadelineProto\RPCErrorException $e) {
\danog\MadelineProto\Logger::log($e->getMessage());
} catch (\danog\MadelineProto\Exception $e) {
\danog\MadelineProto\Logger::log($e->getMessage());
}
} catch (\danog\MadelineProto\Exception $e) {
try {
$MadelineProto->messages->sendMessage(['peer' => '@danogentili', 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
$MadelineProto->messages->sendMessage(['peer' => $update['update']['user_id'], 'message' => $e->getCode().': '.$e->getMessage().PHP_EOL.$e->getTraceAsString()]);
} catch (\danog\MadelineProto\RPCErrorException $e) {
\danog\MadelineProto\Logger::log($e->getMessage());
} catch (\danog\MadelineProto\Exception $e) {
\danog\MadelineProto\Logger::log($e->getMessage());
}
try {
$toset['switch_pm'] = $sswitch;
$MadelineProto->messages->setInlineBotResults($toset);
} catch (\danog\MadelineProto\RPCErrorException $e) {
\danog\MadelineProto\Logger::log($e->getMessage());
} catch (\danog\MadelineProto\Exception $e) {
\danog\MadelineProto\Logger::log($e->getMessage());
}
}
}
} catch (\danog\MadelineProto\RPCErrorException $e) {
}
}
\danog\MadelineProto\Serialization::serialize('pipesbot.madeline', $MadelineProto);
\danog\MadelineProto\Serialization::serialize('pwr.madeline', $uMadelineProto);
}