Clickable buttons, thread safety (#119)
* I'll just leave this here * Threading fixes * Apply fixes from StyleCI * Composer fixes * Lots of threading fixes, included all RSA keys * Apply fixes from StyleCI * Updated phpseclib * fixes * Apply fixes from StyleCI * final fixes * git add -A * Apply fixes from StyleCI * bugfix * Fixes * Apply fixes from StyleCI * Small fixes * Final fixes * Speed improvements * speed fixes * Apply fixes from StyleCI * This is faster than sanic * Apply fixes from StyleCI * Final speed fixes * Apply fixes from StyleCI * Less logging * Speed+++ * Apply fixes from StyleCI * More fixes * Bug74586Exception * Apply fixes from StyleCI * Fixes * Lemme fix that dumb-ass bug that broke everything * Apply fixes from StyleCI * Updated rollbar token * Fixes for other tcp_* protocols * Apply fixes from StyleCI * No need for phpstruct anymore * Add a conflict (OH NOES pony warfare) * Less logs, beginning of clickable buttons * Apply fixes from StyleCI * Bugfixes, fixed clickable buttons * Apply fixes from StyleCI * Better errors * Apply fixes from StyleCI * You can now click text buttons * Apply fixes from StyleCI
This commit is contained in:
parent
f6208e76cb
commit
915a0cd180
1
.gitignore
vendored
1
.gitignore
vendored
@ -94,3 +94,4 @@ fuzzer.php
|
||||
tests/500mb
|
||||
*.save
|
||||
*.save.1
|
||||
*.save.*
|
||||
|
44
a.php
44
a.php
@ -1,12 +1,38 @@
|
||||
<?php
|
||||
|
||||
$payload = base64_decode('NAAAAAAAAAAAAAAAAAAAAAAAAAC06N5YFAAAAHiXRmAwx9DuB28gQszy/RHjhN2RdLkYdQ==');
|
||||
$socket = fsockopen('tcp://149.154.167.91:443'); // DC 4
|
||||
$socket = fsockopen('tcp://149.154.167.50:443'); // DC 2
|
||||
stream_set_timeout($socket, 5);
|
||||
echo 'Wrote '.fwrite($socket, $payload).' bytes'.PHP_EOL;
|
||||
if (strlen(fread($socket, 100))) {
|
||||
echo 'Read 100 bytes from socket'.PHP_EOL;
|
||||
} else {
|
||||
echo 'No data could be read from socket'.PHP_EOL;
|
||||
$service_port = getservbyname('www', 'tcp');
|
||||
$address = gethostbyname('www.google.com');
|
||||
var_dump(unpack('q', pack('l', 200).chr(0).chr(0).chr(0).chr(0)));
|
||||
class a extends Volatile
|
||||
{
|
||||
public $a = [];
|
||||
|
||||
public function run()
|
||||
{
|
||||
$this->a[1] = new b();
|
||||
$this->a[1]->a['a'] = [];
|
||||
var_dump($this);
|
||||
}
|
||||
}
|
||||
class b extends \Volatile
|
||||
{
|
||||
public $a = [];
|
||||
}
|
||||
class main extends Threaded
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->a = new a();
|
||||
var_dump($this->a);
|
||||
$this->a->run();
|
||||
// One of the OH NOES (b) is printed here
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
// $this->a;
|
||||
}
|
||||
}
|
||||
$a = new main();
|
||||
$pool = new Pool(1);
|
||||
//$pool->submit($a); // One of the OH NOES (a) is printed here
|
||||
|
4
ab.php
Normal file
4
ab.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
|
||||
$packet = file_get_contents('t');
|
||||
var_dump(strrev(hash('crc32b', substr($packet, 0, -4), true)) !== substr($packet, -4));
|
@ -5,12 +5,14 @@
|
||||
"license": "AGPLV3",
|
||||
"homepage": "https://daniil.it/MadelineProto",
|
||||
"keywords": ["telegram", "mtproto", "protocol", "bytes", "messenger", "client", "PHP", "video", "stickers", "audio", "files", "GB"],
|
||||
|
||||
"conflict": {
|
||||
"krakjoe/pthreads-polyfill": "*"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.6.0",
|
||||
"danog/phpstruct": "dev-fast",
|
||||
"danog/primemodule": "dev-master",
|
||||
"phpseclib/phpseclib": "dev-master#12dc23d9",
|
||||
"danog/magicalserializer": "dev-master",
|
||||
"phpseclib/phpseclib": "dev-master#200c2a9",
|
||||
"vlucas/phpdotenv": "^2.4",
|
||||
"erusev/parsedown": "^1.6",
|
||||
"rollbar/rollbar": "dev-master",
|
||||
@ -29,6 +31,10 @@
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"danog\\MadelineProto\\": "src/"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"src/Socket.php",
|
||||
"src/Volatile.php"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,26 @@ description: constructors and methods of type KeyboardButton
|
||||
|
||||
|
||||
|
||||
Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $KeyboardButton->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
### Possible values (constructors):
|
||||
|
||||
[keyboardButton](../constructors/keyboardButton.md)
|
||||
|
@ -7,6 +7,26 @@ description: constructors and methods of type KeyboardButton
|
||||
|
||||
|
||||
|
||||
Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $KeyboardButton->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
### Possible values (constructors):
|
||||
|
||||
[keyboardButton](../constructors/keyboardButton.md)
|
||||
|
@ -7,6 +7,26 @@ description: constructors and methods of type KeyboardButton
|
||||
|
||||
|
||||
|
||||
Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $KeyboardButton->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
### Possible values (constructors):
|
||||
|
||||
[keyboardButton](../constructors/keyboardButton.md)
|
||||
|
@ -7,6 +7,26 @@ description: constructors and methods of type KeyboardButton
|
||||
|
||||
|
||||
|
||||
Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $KeyboardButton->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
### Possible values (constructors):
|
||||
|
||||
[keyboardButton](../constructors/keyboardButton.md)
|
||||
|
@ -7,6 +7,26 @@ description: constructors and methods of type KeyboardButton
|
||||
|
||||
|
||||
|
||||
Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $KeyboardButton->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
### Possible values (constructors):
|
||||
|
||||
[keyboardButton](../constructors/keyboardButton.md)
|
||||
|
@ -7,6 +7,26 @@ description: constructors and methods of type KeyboardButton
|
||||
|
||||
|
||||
|
||||
Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $KeyboardButton->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
### Possible values (constructors):
|
||||
|
||||
[keyboardButton](../constructors/keyboardButton.md)
|
||||
|
@ -7,6 +7,26 @@ description: constructors and methods of type KeyboardButton
|
||||
|
||||
|
||||
|
||||
Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $KeyboardButton->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
### Possible values (constructors):
|
||||
|
||||
[keyboardButton](../constructors/keyboardButton.md)
|
||||
|
@ -7,6 +7,26 @@ description: constructors and methods of type KeyboardButton
|
||||
|
||||
|
||||
|
||||
Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $KeyboardButton->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
### Possible values (constructors):
|
||||
|
||||
[keyboardButton](../constructors/keyboardButton.md)
|
||||
|
@ -7,6 +7,26 @@ description: constructors and methods of type KeyboardButton
|
||||
|
||||
|
||||
|
||||
Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $KeyboardButton->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
### Possible values (constructors):
|
||||
|
||||
[keyboardButton](../constructors/keyboardButton.md)
|
||||
|
@ -7,6 +7,26 @@ description: constructors and methods of type KeyboardButton
|
||||
|
||||
|
||||
|
||||
Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $KeyboardButton->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
### Possible values (constructors):
|
||||
|
||||
[keyboardButton](../constructors/keyboardButton.md)
|
||||
|
@ -7,6 +7,26 @@ description: constructors and methods of type KeyboardButton
|
||||
|
||||
|
||||
|
||||
Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $KeyboardButton->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
### Possible values (constructors):
|
||||
|
||||
[keyboardButton](../constructors/keyboardButton.md)
|
||||
|
@ -7,6 +7,26 @@ description: constructors and methods of type KeyboardButton
|
||||
|
||||
|
||||
|
||||
Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $KeyboardButton->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
### Possible values (constructors):
|
||||
|
||||
[keyboardButton](../constructors/keyboardButton.md)
|
||||
|
@ -7,6 +7,26 @@ description: constructors and methods of type KeyboardButton
|
||||
|
||||
|
||||
|
||||
Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $KeyboardButton->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
### Possible values (constructors):
|
||||
|
||||
[keyboardButton](../constructors/keyboardButton.md)
|
||||
|
@ -7,6 +7,26 @@ description: constructors and methods of type KeyboardButton
|
||||
|
||||
|
||||
|
||||
Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $KeyboardButton->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
### Possible values (constructors):
|
||||
|
||||
[keyboardButton](../constructors/keyboardButton.md)
|
||||
|
@ -7,6 +7,26 @@ description: constructors and methods of type KeyboardButton
|
||||
|
||||
|
||||
|
||||
Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $KeyboardButton->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
### Possible values (constructors):
|
||||
|
||||
[keyboardButton](../constructors/keyboardButton.md)
|
||||
|
@ -7,6 +7,26 @@ description: constructors and methods of type KeyboardButton
|
||||
|
||||
|
||||
|
||||
Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $KeyboardButton->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
### Possible values (constructors):
|
||||
|
||||
[keyboardButton](../constructors/keyboardButton.md)
|
||||
|
@ -10,8 +10,6 @@ You should have received a copy of the GNU General Public License along with Mad
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
if (!extension_loaded('pthreads')) {
|
||||
class Socket
|
||||
{
|
136
src/Volatile.php
Normal file
136
src/Volatile.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
if (!extension_loaded('pthreads')) {
|
||||
class Volatile implements ArrayAccess, Countable, IteratorAggregate
|
||||
{
|
||||
const NOTHING = (0);
|
||||
const STARTED = (1 << 0);
|
||||
const RUNNING = (1 << 1);
|
||||
const JOINED = (1 << 2);
|
||||
const ERROR = (1 << 3);
|
||||
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
$this->__set($offset, $value);
|
||||
}
|
||||
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->{$offset};
|
||||
}
|
||||
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
$this->__unset($offset);
|
||||
}
|
||||
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return isset($this->{$offset});
|
||||
}
|
||||
|
||||
public function count()
|
||||
{
|
||||
return count(get_object_vars($this));
|
||||
}
|
||||
|
||||
public function getIterator()
|
||||
{
|
||||
return new ArrayIterator(get_object_vars($this));
|
||||
}
|
||||
|
||||
public function __set($offset, $value)
|
||||
{
|
||||
if ($offset === null) {
|
||||
$offset = count(get_object_vars($this));
|
||||
}
|
||||
|
||||
if (!$this instanceof self) {
|
||||
if (isset($this->{$offset}) &&
|
||||
$this->{$offset} instanceof Threaded) {
|
||||
throw new \RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->{$offset} = $value;
|
||||
}
|
||||
|
||||
public function __unset($offset)
|
||||
{
|
||||
if (!$this instanceof self) {
|
||||
if (isset($this->{$offset}) && $this->{$offset} instanceof Threaded) {
|
||||
throw new \RuntimeException();
|
||||
}
|
||||
}
|
||||
unset($this->{$offset});
|
||||
}
|
||||
|
||||
public function wait($timeout = 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function notify()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function synchronized(Closure $closure, ...$args)
|
||||
{
|
||||
return $closure(...$args);
|
||||
}
|
||||
|
||||
public function isRunning()
|
||||
{
|
||||
return $this->state & THREAD::RUNNING;
|
||||
}
|
||||
|
||||
public function isTerminated()
|
||||
{
|
||||
return $this->state & THREAD::ERROR;
|
||||
}
|
||||
|
||||
public static function extend($class)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function addRef()
|
||||
{
|
||||
}
|
||||
|
||||
public function delRef()
|
||||
{
|
||||
}
|
||||
|
||||
public function getRefCount()
|
||||
{
|
||||
}
|
||||
|
||||
public function lock()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function unlock()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isWaiting()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
}
|
||||
|
||||
public function isGarbage()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected $state;
|
||||
}
|
||||
}
|
@ -16,11 +16,12 @@ class API extends APIFactory
|
||||
{
|
||||
use \danog\MadelineProto\Wrappers\Login;
|
||||
use \danog\MadelineProto\Wrappers\SettingsManager;
|
||||
use \danog\Serializable;
|
||||
|
||||
public $API;
|
||||
public $namespace = '';
|
||||
|
||||
public function __construct($params = [])
|
||||
public function ___construct($params = [])
|
||||
{
|
||||
set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']);
|
||||
$this->API = new MTProto($params);
|
||||
@ -46,6 +47,9 @@ class API extends APIFactory
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if (\danog\MadelineProto\Logger::$has_thread && is_object(\Thread::getCurrentThread())) {
|
||||
return;
|
||||
}
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
|
@ -12,92 +12,9 @@ If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class APIFactory
|
||||
class APIFactory extends \Volatile
|
||||
{
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
*
|
||||
* @var phone
|
||||
*/
|
||||
public $phone;
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
*
|
||||
* @var payments
|
||||
*/
|
||||
public $payments;
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
*
|
||||
* @var bots
|
||||
*/
|
||||
public $bots;
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
*
|
||||
* @var help
|
||||
*/
|
||||
public $help;
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
*
|
||||
* @var upload
|
||||
*/
|
||||
public $upload;
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
*
|
||||
* @var photos
|
||||
*/
|
||||
public $photos;
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
*
|
||||
* @var updates
|
||||
*/
|
||||
public $updates;
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
*
|
||||
* @var messages
|
||||
*/
|
||||
public $messages;
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
*
|
||||
* @var contacts
|
||||
*/
|
||||
public $contacts;
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
*
|
||||
* @var users
|
||||
*/
|
||||
public $users;
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
*
|
||||
* @var channels
|
||||
*/
|
||||
public $channels;
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
*
|
||||
* @var account
|
||||
*/
|
||||
public $account;
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
*
|
||||
* @var auth
|
||||
*/
|
||||
public $auth;
|
||||
/**
|
||||
* @internal this is a internal property generated by build_docs.php, don't change manually
|
||||
*
|
||||
* @var contest
|
||||
*/
|
||||
public $contest;
|
||||
use Tools;
|
||||
|
||||
public $namespace;
|
||||
public $API;
|
||||
@ -112,6 +29,6 @@ class APIFactory
|
||||
{
|
||||
$this->API->get_config([], ['datacenter' => $this->API->datacenter->curdc]);
|
||||
|
||||
return method_exists($this->API, $this->namespace.$name) ? $this->API->{$this->namespace.$name}(...$arguments) : $this->API->method_call($this->namespace.$name, (isset($arguments[0]) && is_array($arguments[0])) ? $arguments[0] : [], (isset($arguments[1]) && is_array($arguments[1])) ? $arguments[1] : ['datacenter' => $this->API->datacenter->curdc]);
|
||||
return method_exists($this->API, $this->namespace.$name) ? $this->API->{$this->namespace.$name}(...$arguments) : $this->API->method_call($this->namespace.$name, (isset($arguments[0]) && $this->is_array($arguments[0])) ? $arguments[0] : [], (isset($arguments[1]) && $this->is_array($arguments[1])) ? $arguments[1] : ['datacenter' => $this->API->datacenter->curdc]);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ use phpDocumentor\Reflection\DocBlockFactory;
|
||||
class AnnotationsBuilder
|
||||
{
|
||||
use \danog\MadelineProto\TL\TL;
|
||||
use Tools;
|
||||
|
||||
public function __construct($settings)
|
||||
{
|
||||
|
@ -12,6 +12,6 @@ If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class RSASerializable extends VolatileSerializer
|
||||
class Bug74586Exception extends \Exception
|
||||
{
|
||||
}
|
48
src/danog/MadelineProto/Button.php
Normal file
48
src/danog/MadelineProto/Button.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/*
|
||||
Copyright 2016-2017 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class Button extends \Volatile implements \JsonSerializable
|
||||
{
|
||||
use \danog\Serializable;
|
||||
private $info = [];
|
||||
|
||||
public function __construct($API, $message, $button)
|
||||
{
|
||||
foreach ($button as $key => $value) {
|
||||
$this->{$key} = $value;
|
||||
}
|
||||
$this->info['peer'] = $message['to_id'];
|
||||
$this->info['id'] = $message['id'];
|
||||
$this->info['API'] = $API;
|
||||
}
|
||||
|
||||
public function click($donotwait = false)
|
||||
{
|
||||
switch ($this->_) {
|
||||
default: return false;
|
||||
case 'keyboardButtonUrl': return $this->url;
|
||||
case 'keyboardButton': return $this->info['API']->method_call('messages.sendMessage', ['peer' => $this->info['peer'], 'message' => $this->text, 'reply_to_msg_id' => $this->info['id']], ['datacenter' => $this->info['API']->datacenter->curdc]);
|
||||
case 'keyboardButtonCallback': return $this->info['API']->method_call('messages.getBotCallbackAnswer', ['peer' => $this->info['peer'], 'msg_id' => $this->info['id'], 'data' => $this->data], ['noResponse' => $donotwait, 'datacenter' => $this->info['API']->datacenter->curdc]);
|
||||
case 'keyboardButtonGame': return $this->info['API']->method_call('messages.getBotCallbackAnswer', ['peer' => $this->info['peer'], 'msg_id' => $this->info['id'], 'game' => true], ['noResponse' => $donotwait, 'datacenter' => $this->info['API']->datacenter->curdc]);
|
||||
}
|
||||
}
|
||||
|
||||
public function jsonSerialize()
|
||||
{
|
||||
$res = get_object_vars($this);
|
||||
unset($res['info']);
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
@ -15,8 +15,9 @@ namespace danog\MadelineProto;
|
||||
/**
|
||||
* Manages connection to telegram servers.
|
||||
*/
|
||||
class Connection
|
||||
class Connection extends \Volatile
|
||||
{
|
||||
use \danog\Serializable;
|
||||
use \danog\MadelineProto\Tools;
|
||||
public $sock = null;
|
||||
|
||||
@ -24,21 +25,22 @@ class Connection
|
||||
public $ip = null;
|
||||
public $port = null;
|
||||
public $timeout = null;
|
||||
|
||||
// public $parsed = [];
|
||||
public $time_delta = 0;
|
||||
public $temp_auth_key;
|
||||
public $auth_key;
|
||||
public $session_id;
|
||||
public $session_out_seq_no = 0;
|
||||
public $session_in_seq_no = 0;
|
||||
|
||||
public $ipv6 = false;
|
||||
public $incoming_messages = [];
|
||||
public $outgoing_messages = [];
|
||||
public $new_incoming = [];
|
||||
public $new_outgoing = [];
|
||||
|
||||
public function __construct($ip, $port, $protocol, $timeout)
|
||||
public function ___construct($ip, $port, $protocol, $timeout, $ipv6)
|
||||
{
|
||||
|
||||
// Can use:
|
||||
/*
|
||||
- tcp_full
|
||||
@ -50,42 +52,63 @@ class Connection
|
||||
*/
|
||||
$this->protocol = $protocol;
|
||||
$this->timeout = $timeout;
|
||||
$this->ipv6 = $ipv6;
|
||||
$this->ip = $ip;
|
||||
$this->port = $port;
|
||||
switch ($this->protocol) {
|
||||
case 'tcp_abridged':
|
||||
$this->sock = fsockopen('tcp://'.$ip.':'.$port);
|
||||
stream_set_timeout($this->sock, $timeout);
|
||||
if (!(get_resource_type($this->sock) === 'file' || get_resource_type($this->sock) === 'stream')) {
|
||||
$this->sock = new \Socket($ipv6 ? \AF_INET6 : \AF_INET, \SOCK_STREAM, getprotobyname('tcp'));
|
||||
if (!\danog\MadelineProto\Logger::$has_thread) {
|
||||
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
|
||||
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
|
||||
}
|
||||
$this->sock->setBlocking(true);
|
||||
if (!$this->sock->connect($ip, $port)) {
|
||||
throw new Exception("Connection: couldn't connect to socket.");
|
||||
}
|
||||
$this->write(chr(239));
|
||||
break;
|
||||
case 'tcp_intermediate':
|
||||
$this->sock = fsockopen('tcp://'.$ip.':'.$port);
|
||||
stream_set_timeout($this->sock, $timeout);
|
||||
if (!(get_resource_type($this->sock) === 'file' || get_resource_type($this->sock) === 'stream')) {
|
||||
$this->sock = new \Socket($ipv6 ? \AF_INET6 : \AF_INET, \SOCK_STREAM, getprotobyname('tcp'));
|
||||
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
|
||||
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
|
||||
if (!$this->sock->connect($ip, $port)) {
|
||||
throw new Exception("Connection: couldn't connect to socket.");
|
||||
}
|
||||
if (!\danog\MadelineProto\Logger::$has_thread) {
|
||||
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
|
||||
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
|
||||
}
|
||||
$this->sock->setBlocking(true);
|
||||
$this->write(str_repeat(chr(238), 4));
|
||||
break;
|
||||
case 'tcp_full':
|
||||
$this->sock = fsockopen('tcp://'.$ip.':'.$port);
|
||||
stream_set_timeout($this->sock, $timeout);
|
||||
if (!(get_resource_type($this->sock) === 'file' || get_resource_type($this->sock) === 'stream')) {
|
||||
|
||||
$this->sock = new \Socket($ipv6 ? \AF_INET6 : \AF_INET, \SOCK_STREAM, getprotobyname('tcp'));
|
||||
if (!$this->sock->connect($ip, $port)) {
|
||||
throw new Exception("Connection: couldn't connect to socket.");
|
||||
}
|
||||
if (!\danog\MadelineProto\Logger::$has_thread) {
|
||||
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
|
||||
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
|
||||
}
|
||||
$this->sock->setBlocking(true);
|
||||
|
||||
$this->out_seq_no = -1;
|
||||
$this->in_seq_no = -1;
|
||||
break;
|
||||
case 'http':
|
||||
case 'https':
|
||||
$this->parsed = parse_url($ip);
|
||||
$this->sock = fsockopen(($this->protocol === 'https' ? 'tls' : 'tcp').'://'.$this->parsed['host'].':'.$port);
|
||||
stream_set_timeout($this->sock, $timeout);
|
||||
if (!(get_resource_type($this->sock) === 'file' || get_resource_type($this->sock) === 'stream')) {
|
||||
$this->sock = new \Socket($ipv6 ? \AF_INET6 : \AF_INET, \SOCK_STREAM, getprotobyname($this->protocol === 'https' ? 'tls' : 'tcp'));
|
||||
if (!$this->sock->connect($this->parsed['host'], $port)) {
|
||||
throw new Exception("Connection: couldn't connect to socket.");
|
||||
}
|
||||
if (!\danog\MadelineProto\Logger::$has_thread) {
|
||||
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
|
||||
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
|
||||
}
|
||||
$this->sock->setBlocking(true);
|
||||
break;
|
||||
case 'udp':
|
||||
throw new Exception("Connection: This protocol isn't implemented yet.");
|
||||
@ -97,6 +120,9 @@ class Connection
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if (\danog\MadelineProto\Logger::$has_thread && is_object(\Thread::getCurrentThread())) {
|
||||
return;
|
||||
}
|
||||
switch ($this->protocol) {
|
||||
case 'tcp_abridged':
|
||||
case 'tcp_intermediate':
|
||||
@ -104,7 +130,7 @@ class Connection
|
||||
case 'http':
|
||||
case 'https':
|
||||
try {
|
||||
fclose($this->sock);
|
||||
unset($this->sock);
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
}
|
||||
break;
|
||||
@ -119,12 +145,35 @@ class Connection
|
||||
public function close_and_reopen()
|
||||
{
|
||||
$this->__destruct();
|
||||
$this->__construct($this->ip, $this->port, $this->protocol, $this->timeout);
|
||||
$this->__construct($this->ip, $this->port, $this->protocol, $this->timeout, $this->ipv6);
|
||||
}
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
$t = get_object_vars($this);
|
||||
if (isset($t['sock'])) {
|
||||
unset($t['sock']);
|
||||
}
|
||||
|
||||
$keys = array_keys((array) $t);
|
||||
if (count($keys) !== count(array_unique($keys))) {
|
||||
throw new Bug74586Exception();
|
||||
}
|
||||
|
||||
return $keys;
|
||||
}
|
||||
|
||||
public function __wakeup()
|
||||
{
|
||||
$this->__construct($this->ip, $this->port, $this->protocol, $this->timeout);
|
||||
if (\danog\MadelineProto\Logger::$has_thread && is_object(\Thread::getCurrentThread())) {
|
||||
return;
|
||||
}
|
||||
$keys = array_keys((array) get_object_vars($this));
|
||||
if (count($keys) !== count(array_unique($keys))) {
|
||||
throw new Bug74586Exception();
|
||||
}
|
||||
|
||||
//$this->__construct($this->ip, $this->port, $this->protocol, $this->timeout, $this->ipv6);
|
||||
}
|
||||
|
||||
public function write($what, $length = null)
|
||||
@ -138,11 +187,10 @@ class Connection
|
||||
case 'tcp_full':
|
||||
case 'http':
|
||||
case 'https':
|
||||
if (!(get_resource_type($this->sock) === 'file' || get_resource_type($this->sock) === 'stream')) {
|
||||
throw new Exception("Connection: couldn't connect to socket.");
|
||||
}
|
||||
if (($wrote = fwrite($this->sock, $what)) !== strlen($what)) {
|
||||
throw new \danog\MadelineProto\Exception("WARNING: Wrong length was written (should've written ".strlen($what).', wrote '.$wrote.')!');
|
||||
$wrote = 0;
|
||||
$len = strlen($what);
|
||||
if (($wrote += $this->sock->write($what)) !== $len) {
|
||||
while (($wrote += $this->sock->write(substr($what, $wrote))) !== $len);
|
||||
}
|
||||
|
||||
return $wrote;
|
||||
@ -164,15 +212,16 @@ class Connection
|
||||
case 'tcp_full':
|
||||
case 'http':
|
||||
case 'https':
|
||||
if (!(get_resource_type($this->sock) === 'file' || get_resource_type($this->sock) === 'stream')) {
|
||||
throw new Exception("Connection: couldn't connect to socket.");
|
||||
}
|
||||
$packet = stream_get_contents($this->sock, $length);
|
||||
$packet = '';
|
||||
while (strlen($packet) < $length) {
|
||||
$packet .= $this->sock->read($length - strlen($packet));
|
||||
if ($packet === false || strlen($packet) === 0) {
|
||||
throw new \danog\MadelineProto\NothingInTheSocketException('Nothing in the socket!');
|
||||
}
|
||||
if (strlen($packet) != $length) {
|
||||
throw new \danog\MadelineProto\Exception("WARNING: Wrong length was read (should've read ".($length).', read '.strlen($packet).')!');
|
||||
}
|
||||
if (strlen($packet) !== $length) {
|
||||
$this->close_and_reopen();
|
||||
throw new Exception("WARNING: Wrong length was read (should've read ".($length).', read '.strlen($packet).')!');
|
||||
}
|
||||
|
||||
return $packet;
|
||||
@ -189,13 +238,14 @@ class Connection
|
||||
switch ($this->protocol) {
|
||||
case 'tcp_full':
|
||||
$packet_length_data = $this->read(4);
|
||||
$packet_length = \danog\PHP\Struct::unpack('<I', $packet_length_data)[0];
|
||||
$packet_length = unpack('V', $packet_length_data)[1];
|
||||
$packet = $this->read($packet_length - 4);
|
||||
|
||||
if (strrev(hash('crc32b', $packet_length_data.substr($packet, 0, -4), true)) !== substr($packet, -4)) {
|
||||
throw new Exception('CRC32 was not correct!');
|
||||
}
|
||||
$this->in_seq_no++;
|
||||
$in_seq_no = \danog\PHP\Struct::unpack('<I', substr($packet, 0, 4))[0];
|
||||
$in_seq_no = unpack('V', substr($packet, 0, 4))[1];
|
||||
if ($in_seq_no != $this->in_seq_no) {
|
||||
throw new Exception('Incoming seq_no mismatch');
|
||||
}
|
||||
@ -203,7 +253,7 @@ class Connection
|
||||
return substr($packet, 4, $packet_length - 12);
|
||||
case 'tcp_intermediate':
|
||||
$packet_length_data = $this->read(4);
|
||||
$packet_length = \danog\PHP\Struct::unpack('<I', $packet_length_data)[0];
|
||||
$packet_length = unpack('V', $packet_length_data)[1];
|
||||
|
||||
return $this->read($packet_length);
|
||||
case 'tcp_abridged':
|
||||
@ -213,7 +263,7 @@ class Connection
|
||||
$packet_length <<= 2;
|
||||
} else {
|
||||
$packet_length_data = $this->read(3);
|
||||
$packet_length = \danog\PHP\Struct::unpack('<I', $packet_length_data.pack('x'))[0] << 2;
|
||||
$packet_length = unpack('V', $packet_length_data."\0")[1] << 2;
|
||||
}
|
||||
|
||||
return $this->read($packet_length);
|
||||
@ -234,7 +284,7 @@ class Connection
|
||||
throw new Exception('No data in the socket!');
|
||||
}
|
||||
if (preg_match('|^Content-Length: |i', $current_header)) {
|
||||
$length = preg_replace('|Content-Length: |i', '', $current_header);
|
||||
$length = (int) preg_replace('|Content-Length: |i', '', $current_header);
|
||||
}
|
||||
if (preg_match('|^Connection: close|i', $current_header)) {
|
||||
$close = true;
|
||||
@ -260,19 +310,19 @@ class Connection
|
||||
switch ($this->protocol) {
|
||||
case 'tcp_full':
|
||||
$this->out_seq_no++;
|
||||
$step1 = \danog\PHP\Struct::pack('<II', (strlen($message) + 12), $this->out_seq_no).$message;
|
||||
$step1 = pack('VV', (strlen($message) + 12), $this->out_seq_no).$message;
|
||||
$step2 = $step1.strrev(hash('crc32b', $step1, true));
|
||||
$this->write($step2);
|
||||
break;
|
||||
case 'tcp_intermediate':
|
||||
$this->write(\danog\PHP\Struct::pack('<I', strlen($message)).$message);
|
||||
$this->write(pack('V', strlen($message)).$message);
|
||||
break;
|
||||
case 'tcp_abridged':
|
||||
$len = strlen($message) / 4;
|
||||
if ($len < 127) {
|
||||
$step1 = chr($len).$message;
|
||||
} else {
|
||||
$step1 = chr(127).substr(\danog\PHP\Struct::pack('<I', $len), 0, 3).$message;
|
||||
$step1 = chr(127).substr(pack('V', $len), 0, 3).$message;
|
||||
}
|
||||
$this->write($step1);
|
||||
break;
|
||||
|
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
Copyright 2016-2017 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class ConnectionSerializable extends VolatileSerializer
|
||||
{
|
||||
}
|
@ -15,9 +15,10 @@ namespace danog\MadelineProto;
|
||||
/**
|
||||
* Manages datacenters.
|
||||
*/
|
||||
class DataCenter
|
||||
class DataCenter extends \Volatile
|
||||
{
|
||||
use \danog\MadelineProto\Tools;
|
||||
use \danog\Serializable;
|
||||
|
||||
public $sockets = [];
|
||||
public $curdc = 0;
|
||||
@ -29,9 +30,8 @@ class DataCenter
|
||||
return ['sockets', 'curdc', 'dclist', 'settings'];
|
||||
}
|
||||
|
||||
public function __construct($dclist, $settings)
|
||||
public function ___construct($dclist, $settings)
|
||||
{
|
||||
//if ($this->unserialized($dclist)) return true;
|
||||
$this->dclist = $dclist;
|
||||
$this->settings = $settings;
|
||||
foreach ($this->sockets as $socket) {
|
||||
@ -63,7 +63,7 @@ class DataCenter
|
||||
$address = $this->settings[$dc_config_number]['ipv6'] ? '['.$address.']' : $address;
|
||||
$port = $this->dclist[$test][$ipv6][$dc_number]['port'];
|
||||
if ($this->settings[$dc_config_number]['protocol'] === 'https') {
|
||||
$subdomain = $this->dclist['ssl_subdomains'][$dc_config_number];
|
||||
$subdomain = $this->dclist['ssl_subdomains'][$dc_number];
|
||||
$path = $this->settings[$dc_config_number]['test_mode'] ? 'apiw_test1' : 'apiw1';
|
||||
$address = $this->settings[$dc_config_number]['protocol'].'://'.$subdomain.'.web.telegram.org/'.$path;
|
||||
}
|
||||
@ -74,17 +74,17 @@ class DataCenter
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Connecting to DC '.$dc_number.' ('.$test.' server, '.$ipv6.', '.$this->settings[$dc_config_number]['protocol'].')...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
|
||||
$this->sockets[$dc_number] = new Connection($address, $port, $this->settings[$dc_config_number]['protocol'], $this->settings[$dc_config_number]['timeout']);
|
||||
$this->sockets[$dc_number] = new Connection($address, $port, $this->settings[$dc_config_number]['protocol'], $this->settings[$dc_config_number]['timeout'], $this->settings[$dc_config_number]['ipv6']);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_dcs()
|
||||
public function get_dcs($all = true)
|
||||
{
|
||||
$test = $this->settings['all']['test_mode'] ? 'test' : 'main';
|
||||
$ipv6 = $this->settings['all']['ipv6'] ? 'ipv6' : 'ipv4';
|
||||
|
||||
return array_keys($this->dclist[$test][$ipv6]);
|
||||
return $all ? array_keys((array) $this->dclist[$test][$ipv6]) : array_keys((array) $this->sockets);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
Copyright 2016-2017 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class DataCenterSerializable extends VolatileSerializer
|
||||
{
|
||||
}
|
@ -15,6 +15,7 @@ namespace danog\MadelineProto;
|
||||
class DocsBuilder
|
||||
{
|
||||
use \danog\MadelineProto\TL\TL;
|
||||
use Tools;
|
||||
|
||||
public function __construct($settings)
|
||||
{
|
||||
@ -37,7 +38,7 @@ class DocsBuilder
|
||||
public function mk_docs()
|
||||
{
|
||||
$types = [];
|
||||
// $any = '*';
|
||||
$any = '*';
|
||||
\danog\MadelineProto\Logger::log(['Generating documentation index...'], \danog\MadelineProto\Logger::NOTICE);
|
||||
|
||||
file_put_contents($this->index, '---
|
||||
@ -306,7 +307,7 @@ description: List of methods
|
||||
|
||||
'.implode('', $methods));
|
||||
|
||||
foreach (glob('constructors/*') as $unlink) {
|
||||
foreach (glob('constructors/'.$any) as $unlink) {
|
||||
unlink($unlink);
|
||||
}
|
||||
|
||||
@ -588,6 +589,29 @@ $'.$type.' = -147286699; // Numeric chat id returned by request_secret_chat, can
|
||||
```
|
||||
|
||||
|
||||
';
|
||||
}
|
||||
if (in_array($type, ['KeyboardButton'])) {
|
||||
$header .= 'Clicking these buttons:
|
||||
|
||||
To click these buttons simply run the `click` method:
|
||||
|
||||
```
|
||||
$result = $'.$type.'->click();
|
||||
```
|
||||
|
||||
`$result` can be one of the following:
|
||||
|
||||
|
||||
* A string - If the button is a keyboardButtonUrl
|
||||
|
||||
* [Updates](Updates.md) - If the button is a keyboardButton, the message will be sent to the chat, in reply to the message with the keyboard
|
||||
|
||||
* [messages_BotCallbackAnswer](messages_BotCallbackAnswer.md) - If the button is a keyboardButtonCallback or a keyboardButtonGame the button will be pressed and the result will be returned
|
||||
|
||||
* `false` - If the button is an unsupported button, like keyboardButtonRequestPhone, keyboardButtonRequestGeoLocation, keyboardButtonSwitchInlinekeyboardButtonBuy; you will have to parse data from these buttons manually
|
||||
|
||||
|
||||
';
|
||||
}
|
||||
$constructors = '### Possible values (constructors):
|
||||
|
@ -29,7 +29,7 @@ class Exception extends \Exception
|
||||
if (in_array($message, ['Re-executing query...', 'I had to recreate the temporary authorization key', 'This peer is not present in the internal peer database', "Couldn't get response", 'Chat forbidden'])) {
|
||||
return;
|
||||
}
|
||||
if (strpos($message, 'fwrite') !== false || strpos($message, 'Received request to switch to DC ') !== false || strpos($message, 'Re-executing query...') !== false || strpos($message, "Couldn't find peer by provided") !== false) {
|
||||
if (strpos($message, 'socket_write') !== false || strpos($message, 'socket_read') !== false || strpos($message, 'Received request to switch to DC ') !== false || strpos($message, 'Re-executing query...') !== false || strpos($message, "Couldn't find peer by provided") !== false || strpos($message, 'id.pwrtelegram.xyz') !== false) {
|
||||
return;
|
||||
}
|
||||
\Rollbar\Rollbar::log(\Rollbar\Payload\Level::error(), $this, debug_backtrace(0));
|
||||
|
@ -17,11 +17,16 @@ namespace danog\MadelineProto;
|
||||
|
||||
class Logger
|
||||
{
|
||||
public static $storage = [];
|
||||
public static $mode = null;
|
||||
public static $optional = null;
|
||||
public static $constructed = false;
|
||||
public static $prefix = '';
|
||||
public static $level = 3;
|
||||
public static $has_thread = false;
|
||||
public static $BIG_ENDIAN = false;
|
||||
public static $bigint = true;
|
||||
|
||||
const ULTRA_VERBOSE = 5;
|
||||
const VERBOSE = 4;
|
||||
const NOTICE = 3;
|
||||
@ -29,6 +34,13 @@ class Logger
|
||||
const ERROR = 1;
|
||||
const FATAL_ERROR = 0;
|
||||
|
||||
public static function class_exists()
|
||||
{
|
||||
self::$has_thread = class_exists('\Thread') && method_exists('\Thread', 'getCurrentThread');
|
||||
self::$BIG_ENDIAN = (pack('L', 1) === pack('N', 1));
|
||||
self::$bigint = PHP_INT_SIZE < 8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructor function
|
||||
* Accepts various logger modes:
|
||||
@ -47,6 +59,7 @@ class Logger
|
||||
self::$constructed = true;
|
||||
self::$prefix = $prefix === '' ? '' : ', '.$prefix;
|
||||
self::$level = $level;
|
||||
self::class_exists();
|
||||
}
|
||||
|
||||
public static function log($params, $level = self::NOTICE)
|
||||
@ -58,12 +71,12 @@ class Logger
|
||||
return false;
|
||||
}
|
||||
$prefix = self::$prefix;
|
||||
if (class_exists('\Thread') && method_exists('\Thread', 'getCurrentThread') && is_object(\Thread::getCurrentThread())) {
|
||||
if (\danog\MadelineProto\Logger::$has_thread && is_object(\Thread::getCurrentThread())) {
|
||||
$prefix .= ' (t)';
|
||||
}
|
||||
foreach (is_array($params) ? $params : [$params] as $param) {
|
||||
if (!is_string($param)) {
|
||||
$param = var_export($param, true);
|
||||
$param = json_encode($param, JSON_PRETTY_PRINT);
|
||||
}
|
||||
$param = str_pad(basename(debug_backtrace()[0]['file'], '.php').$prefix.': ', 16 + strlen($prefix))."\t".$param;
|
||||
switch (self::$mode) {
|
||||
|
@ -14,11 +14,12 @@ namespace danog\MadelineProto;
|
||||
|
||||
class Lua
|
||||
{
|
||||
use \danog\Serializable;
|
||||
public $MadelineProto;
|
||||
private $Lua;
|
||||
private $script;
|
||||
protected $Lua;
|
||||
protected $script;
|
||||
|
||||
public function __construct($script, $MadelineProto)
|
||||
public function ___construct($script, $MadelineProto)
|
||||
{
|
||||
if (!file_exists($script)) {
|
||||
throw new Exception('Provided script does not exist');
|
||||
|
@ -15,8 +15,9 @@ namespace danog\MadelineProto;
|
||||
/**
|
||||
* Manages all of the mtproto stuff.
|
||||
*/
|
||||
class MTProto
|
||||
class MTProto extends \Volatile
|
||||
{
|
||||
use \danog\Serializable;
|
||||
use \danog\MadelineProto\MTProtoTools\AckHandler;
|
||||
use \danog\MadelineProto\MTProtoTools\AuthKeyHandler;
|
||||
use \danog\MadelineProto\MTProtoTools\CallHandler;
|
||||
@ -51,11 +52,12 @@ class MTProto
|
||||
public $bigint = false;
|
||||
public $run_workers = false;
|
||||
public $threads = false;
|
||||
public $rsa_keys = [];
|
||||
|
||||
public function __construct($settings = [])
|
||||
public function ___construct($settings = [])
|
||||
{
|
||||
//if ($this->unserialized($settings)) return true;
|
||||
$this->bigint = PHP_INT_SIZE < 8;
|
||||
\danog\MadelineProto\Logger::class_exists();
|
||||
// Parse settings
|
||||
$this->parse_settings($settings);
|
||||
|
||||
@ -68,8 +70,10 @@ class MTProto
|
||||
}
|
||||
// Load rsa key
|
||||
\danog\MadelineProto\Logger::log(['Loading RSA key...'], Logger::ULTRA_VERBOSE);
|
||||
$key = new RSA($this->settings['authorization']['rsa_key']);
|
||||
foreach ($this->settings['authorization']['rsa_keys'] as $key) {
|
||||
$key = new RSA($key);
|
||||
$this->rsa_keys[$key->fp] = $key;
|
||||
}
|
||||
|
||||
// Istantiate TL class
|
||||
\danog\MadelineProto\Logger::log(['Translating tl schemas...'], Logger::ULTRA_VERBOSE);
|
||||
@ -89,8 +93,6 @@ class MTProto
|
||||
$this->twoe2047 = new \phpseclib\Math\BigInteger('16158503035655503650357438344334975980222051334857742016065172713762327569433945446598600705761456731844358980460949009747059779575245460547544076193224141560315438683650498045875098875194826053398028819192033784138396109321309878080919047169238085235290822926018152521443787945770532904303776199561965192760957166694834171210342487393282284747428088017663161029038902829665513096354230157075129296432088558362971801859230928678799175576150822952201848806616643615613562842355410104862578550863465661734839271290328348967522998634176499319107762583194718667771801067716614802322659239302476074096777926805529798115328');
|
||||
$this->twoe2048 = new \phpseclib\Math\BigInteger('32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638215525166389437335543602135433229604645318478604952148193555853611059596230656');
|
||||
|
||||
$this->setup_threads();
|
||||
|
||||
$this->connect_to_all_dcs();
|
||||
$this->datacenter->curdc = 2;
|
||||
|
||||
@ -112,23 +114,30 @@ class MTProto
|
||||
public function __sleep()
|
||||
{
|
||||
$t = get_object_vars($this);
|
||||
if (isset($t['reader_pool'])) {
|
||||
unset($t['reader_pool']);
|
||||
}
|
||||
if (isset($t['readers'])) {
|
||||
unset($t['readers']);
|
||||
}
|
||||
|
||||
return array_keys($t);
|
||||
$keys = array_keys((array) $t);
|
||||
if (count($keys) !== count(array_unique($keys))) {
|
||||
throw new Bug74586Exception();
|
||||
}
|
||||
|
||||
return $keys;
|
||||
}
|
||||
|
||||
public function __wakeup()
|
||||
{
|
||||
set_error_handler(['\danog\MadelineProto\Exception', 'ExceptionErrorHandler']);
|
||||
$this->setup_logger();
|
||||
if (class_exists('\Thread') && method_exists('\Thread', 'getCurrentThread') && is_object(\Thread::getCurrentThread())) {
|
||||
if (\danog\MadelineProto\Logger::$has_thread && is_object(\Thread::getCurrentThread())) {
|
||||
return;
|
||||
}
|
||||
$keys = array_keys((array) get_object_vars($this));
|
||||
if (count($keys) !== count(array_unique($keys))) {
|
||||
throw new Bug74586Exception();
|
||||
}
|
||||
|
||||
/*
|
||||
if (method_exists($this->datacenter, 'wakeup')) $this->datacenter = $this->datacenter->wakeup();
|
||||
foreach ($this->rsa_keys as $key => $elem) {
|
||||
@ -139,7 +148,6 @@ class MTProto
|
||||
}
|
||||
*/
|
||||
$this->getting_state = false;
|
||||
$this->bigint = PHP_INT_SIZE < 8;
|
||||
$this->reset_session();
|
||||
if (!isset($this->v) || $this->v !== $this->getV()) {
|
||||
\danog\MadelineProto\Logger::log(['Serialization is out of date, reconstructing object!'], Logger::WARNING);
|
||||
@ -148,6 +156,9 @@ class MTProto
|
||||
$settings['updates']['callback'] = 'get_updates_update_handler';
|
||||
}
|
||||
unset($settings['tl_schema']);
|
||||
if (isset($settings['authorization']['rsa_key'])) {
|
||||
unset($settings['authorization']['rsa_key']);
|
||||
}
|
||||
$this->reset_session(true, true);
|
||||
$this->__construct($settings);
|
||||
}
|
||||
@ -161,12 +172,15 @@ class MTProto
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if (isset($this->reader_pool)) {
|
||||
if (\danog\MadelineProto\Logger::$has_thread && is_object(\Thread::getCurrentThread())) {
|
||||
return;
|
||||
}
|
||||
if (isset(Logger::$storage[spl_object_hash($this)])) {
|
||||
$this->run_workers = false;
|
||||
while ($number = $this->reader_pool->collect()) {
|
||||
while ($number = Logger::$storage[spl_object_hash($this)]->collect()) {
|
||||
\danog\MadelineProto\Logger::log(['Shutting down reader pool, '.$number.' jobs left'], \danog\MadelineProto\Logger::NOTICE);
|
||||
}
|
||||
$this->reader_pool->shutdown();
|
||||
Logger::$storage[spl_object_hash($this)]->shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,28 +194,33 @@ class MTProto
|
||||
|
||||
public function start_threads()
|
||||
{
|
||||
if ($this->threads) {
|
||||
$dcs = $this->datacenter->get_dcs();
|
||||
if (!isset($this->reader_pool)) {
|
||||
$this->reader_pool = new \Pool(count($dcs));
|
||||
if ($this->threads && !is_object(\Thread::getCurrentThread())) {
|
||||
$dcs = $this->datacenter->get_dcs(false);
|
||||
if (!isset(Logger::$storage[spl_object_hash($this)])) {
|
||||
Logger::$storage[spl_object_hash($this)] = new \Pool(count($dcs));
|
||||
}
|
||||
if (!isset($this->readers)) {
|
||||
$this->readers = [];
|
||||
}
|
||||
foreach ($dcs as $dc) {
|
||||
if (!isset($this->readers[$dc])) {
|
||||
Logger::log(['Socket reader on DC '.$dc.': CREATING'], Logger::WARNING);
|
||||
$this->readers[$dc] = new \danog\MadelineProto\Threads\SocketReader($this, $dc);
|
||||
}
|
||||
if (!$this->readers[$dc]->isRunning()) {
|
||||
Logger::log(['Socket reader on DC '.$dc.': SUBMITTING'], Logger::WARNING);
|
||||
$this->readers[$dc]->garbage = false;
|
||||
$this->reader_pool->submit($this->readers[$dc]);
|
||||
Logger::log(['Socket reader on DC '.$dc.': RESTARTED'], Logger::WARNING);
|
||||
Logger::$storage[spl_object_hash($this)]->submit($this->readers[$dc]);
|
||||
Logger::log(['Socket reader on DC '.$dc.': WAITING'], Logger::WARNING);
|
||||
while (!$this->readers[$dc]->ready);
|
||||
Logger::log(['Socket reader on DC '.$dc.': READY'], Logger::WARNING);
|
||||
} else {
|
||||
Logger::log(['Socket reader on DC '.$dc.': WORKING'], Logger::NOTICE);
|
||||
Logger::log(['Socket reader on DC '.$dc.': WORKING'], Logger::ULTRA_VERBOSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function parse_settings($settings)
|
||||
@ -232,14 +251,12 @@ class MTProto
|
||||
$default_settings = [
|
||||
'authorization' => [ // Authorization settings
|
||||
'default_temp_auth_key_expires_in' => 31557600, // validity of temporary keys and the binding of the temporary and permanent keys
|
||||
'rsa_key' => '-----BEGIN RSA PUBLIC KEY-----
|
||||
MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6
|
||||
lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS
|
||||
an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw
|
||||
Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+
|
||||
8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n
|
||||
Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
-----END RSA PUBLIC KEY-----', // RSA public key
|
||||
'rsa_keys' => [
|
||||
"-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6\nlyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS\nan9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw\nEfzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+\n8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n\nSlv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB\n-----END RSA PUBLIC KEY-----",
|
||||
"-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAxq7aeLAqJR20tkQQMfRn+ocfrtMlJsQ2Uksfs7Xcoo77jAid0bRt\nksiVmT2HEIJUlRxfABoPBV8wY9zRTUMaMA654pUX41mhyVN+XoerGxFvrs9dF1Ru\nvCHbI02dM2ppPvyytvvMoefRoL5BTcpAihFgm5xCaakgsJ/tH5oVl74CdhQw8J5L\nxI/K++KJBUyZ26Uba1632cOiq05JBUW0Z2vWIOk4BLysk7+U9z+SxynKiZR3/xdi\nXvFKk01R3BHV+GUKM2RYazpS/P8v7eyKhAbKxOdRcFpHLlVwfjyM1VlDQrEZxsMp\nNTLYXb6Sce1Uov0YtNx5wEowlREH1WOTlwIDAQAB\n-----END RSA PUBLIC KEY-----",
|
||||
"-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAsQZnSWVZNfClk29RcDTJQ76n8zZaiTGuUsi8sUhW8AS4PSbPKDm+\nDyJgdHDWdIF3HBzl7DHeFrILuqTs0vfS7Pa2NW8nUBwiaYQmPtwEa4n7bTmBVGsB\n1700/tz8wQWOLUlL2nMv+BPlDhxq4kmJCyJfgrIrHlX8sGPcPA4Y6Rwo0MSqYn3s\ng1Pu5gOKlaT9HKmE6wn5Sut6IiBjWozrRQ6n5h2RXNtO7O2qCDqjgB2vBxhV7B+z\nhRbLbCmW0tYMDsvPpX5M8fsO05svN+lKtCAuz1leFns8piZpptpSCFn7bWxiA9/f\nx5x17D7pfah3Sy2pA+NDXyzSlGcKdaUmwQIDAQAB\n-----END RSA PUBLIC KEY-----",
|
||||
"-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAwqjFW0pi4reKGbkc9pK83Eunwj/k0G8ZTioMMPbZmW99GivMibwa\nxDM9RDWabEMyUtGoQC2ZcDeLWRK3W8jMP6dnEKAlvLkDLfC4fXYHzFO5KHEqF06i\nqAqBdmI1iBGdQv/OQCBcbXIWCGDY2AsiqLhlGQfPOI7/vvKc188rTriocgUtoTUc\n/n/sIUzkgwTqRyvWYynWARWzQg0I9olLBBC2q5RQJJlnYXZwyTL3y9tdb7zOHkks\nWV9IMQmZmyZh/N7sMbGWQpt4NMchGpPGeJ2e5gHBjDnlIf2p1yZOYeUYrdbwcS0t\nUiggS4UeE8TzIuXFQxw7fzEIlmhIaq3FnwIDAQAB\n-----END RSA PUBLIC KEY-----",
|
||||
], // RSA public keys
|
||||
],
|
||||
'connection' => [ // List of datacenters/subdomains where to connect
|
||||
'ssl_subdomains' => [ // Subdomains of web.telegram.org for https protocol
|
||||
@ -310,7 +327,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
'telegram' => __DIR__.'/TL_telegram_v66.tl', // telegram TL scheme
|
||||
'secret' => __DIR__.'/TL_secret.tl', // secret chats TL scheme
|
||||
'calls' => __DIR__.'/TL_calls.tl', // calls TL scheme
|
||||
'td' => __DIR__.'/TL_td.tl', // telegram-cli TL scheme
|
||||
//'td' => __DIR__.'/TL_td.tl', // telegram-cli TL scheme
|
||||
'botAPI' => __DIR__.'/TL_botAPI.tl', // bot API TL scheme for file ids
|
||||
],
|
||||
],
|
||||
@ -326,6 +343,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
'logger_param' => '/tmp/MadelineProto.log',
|
||||
'logger' => 3, // overwrite previous setting and echo logs
|
||||
'logger_level' => Logger::VERBOSE, // Logging level, available logging levels are: ULTRA_VERBOSE, VERBOSE, NOTICE, WARNING, ERROR, FATAL_ERROR. Can be provided as last parameter to the logging function.
|
||||
'rollbar_token' => 'f9fff6689aea4905b58eec73f66c791d',
|
||||
//'rollbar_token' => 'f9fff6689aea4905b58eec73f66c791d' // You can provide a token for the rollbar log management system
|
||||
],
|
||||
'max_tries' => [
|
||||
@ -384,7 +402,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
|
||||
public function setup_logger()
|
||||
{
|
||||
\Rollbar\Rollbar::init(['environment' => 'production', 'root' => __DIR__, 'access_token' => (isset($this->settings['logger']['rollbar_token']) && !in_array($this->settings['logger']['rollbar_token'], ['f9fff6689aea4905b58eec73f66c791d'])) ? $this->settings['logger']['rollbar_token'] : '300afd7ccef346ea84d0c185ae831718'], false, false);
|
||||
\Rollbar\Rollbar::init(['environment' => 'production', 'root' => __DIR__, 'access_token' => (isset($this->settings['logger']['rollbar_token']) && !in_array($this->settings['logger']['rollbar_token'], ['f9fff6689aea4905b58eec73f66c791d', '300afd7ccef346ea84d0c185ae831718'])) ? $this->settings['logger']['rollbar_token'] : '11a8c2fe4c474328b40a28193f8d63f5'], false, false);
|
||||
\danog\MadelineProto\Logger::constructor($this->settings['logger']['logger'], $this->settings['logger']['logger_param'], isset($this->authorization['user']) ? (isset($this->authorization['user']['username']) ? $this->authorization['user']['username'] : $this->authorization['user']['id']) : '', isset($this->settings['logger']['logger_level']) ? $this->settings['logger']['logger_level'] : Logger::VERBOSE);
|
||||
}
|
||||
|
||||
@ -416,13 +434,14 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
$this->datacenter->dc_connect($new_dc);
|
||||
}
|
||||
}
|
||||
$this->setup_threads();
|
||||
$this->init_authorization();
|
||||
if ($old !== $this->datacenter->get_dcs()) {
|
||||
$this->connect_to_all_dcs();
|
||||
}
|
||||
}
|
||||
|
||||
private $initing_authorization = false;
|
||||
protected $initing_authorization = false;
|
||||
|
||||
// Creates authorization keys
|
||||
public function init_authorization()
|
||||
@ -466,7 +485,8 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
if ($int_dc != $new_dc) {
|
||||
continue;
|
||||
}
|
||||
if (preg_match('|media|', $new_dc)) {
|
||||
\danog\MadelineProto\Logger::log([$int_dc, $new_dc]);
|
||||
if (preg_match('|_|', $new_dc)) {
|
||||
continue;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Copying authorization from dc '.$authorized_dc.' to dc '.$new_dc.'...'], Logger::VERBOSE);
|
||||
@ -538,7 +558,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
|
||||
public function getV()
|
||||
{
|
||||
return 24;
|
||||
return 29;
|
||||
}
|
||||
|
||||
public function get_self()
|
||||
|
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
Copyright 2016-2017 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class MTProtoSerializable extends VolatileSerializer
|
||||
{
|
||||
}
|
@ -37,7 +37,7 @@ trait AckHandler
|
||||
\danog\MadelineProto\Logger::log(["WARNING: Couldn't find message id ".$message_id.' in the array of incomgoing messages. Maybe try to increase its size?'], \danog\MadelineProto\Logger::WARNING);
|
||||
//throw new \danog\MadelineProto\Exception("Couldn't find message id ".$message_id.' in the array of incoming message ids. Maybe try to increase its size?');
|
||||
}
|
||||
if ($this->datacenter->sockets[$datacenter]->temp_auth_key['id'] === null || $this->datacenter->sockets[$datacenter]->temp_auth_key['id'] === str_repeat(chr(0), 8) || (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$message_id]['ack']) && $this->datacenter->sockets[$datacenter]->incoming_messages[$message_id]['ack'])) {
|
||||
if ($this->datacenter->sockets[$datacenter]->temp_auth_key['id'] === null || $this->datacenter->sockets[$datacenter]->temp_auth_key['id'] === "\0\0\0\0\0\0\0\0" || (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$message_id]['ack']) && $this->datacenter->sockets[$datacenter]->incoming_messages[$message_id]['ack'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ trait AuthKeyHandler
|
||||
*/
|
||||
|
||||
foreach ($this->rsa_keys as $fp => $curkey) {
|
||||
if (in_array($fp, $ResPQ['server_public_key_fingerprints'])) {
|
||||
if ($this->in_array($fp, $ResPQ['server_public_key_fingerprints'])) {
|
||||
$key = $curkey;
|
||||
}
|
||||
}
|
||||
@ -546,7 +546,7 @@ trait AuthKeyHandler
|
||||
$message_id = $this->generate_message_id($datacenter);
|
||||
|
||||
$seq_no = 0;
|
||||
$encrypted_data = $this->random(16).$message_id.\danog\PHP\Struct::pack('<II', $seq_no, strlen($message_data)).$message_data;
|
||||
$encrypted_data = $this->random(16).$message_id.pack('VV', $seq_no, strlen($message_data)).$message_data;
|
||||
$message_key = substr(sha1($encrypted_data, true), -16);
|
||||
$padding = $this->random($this->posmod(-strlen($encrypted_data), 16));
|
||||
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->datacenter->sockets[$datacenter]->auth_key['auth_key']);
|
||||
|
@ -34,7 +34,7 @@ trait CallHandler
|
||||
}
|
||||
$args = $this->botAPI_to_MTProto($args);
|
||||
if (isset($args['ping_id']) && is_int($args['ping_id'])) {
|
||||
$args['ping_id'] = \danog\PHP\Struct::pack('<q', $args['ping_id']);
|
||||
$args['ping_id'] = $this->pack_signed_long($args['ping_id']);
|
||||
}
|
||||
if (isset($args['chat_id']) && !isset($args['peer']) && $method !== 'messages.discardEncryption' && (is_object($args['chat_id']) || $args['chat_id'] < 0)) {
|
||||
$res = $this->get_info($args['chat_id']);
|
||||
@ -54,12 +54,12 @@ trait CallHandler
|
||||
try {
|
||||
\danog\MadelineProto\Logger::log(['Calling method (try number '.$count.' for '.$method.')...'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
|
||||
$int_message_id = $this->send_message($serialized, $content_related, $aargs);
|
||||
$message_id = $this->send_message($serialized, $content_related, $aargs);
|
||||
if ($method === 'http_wait' || (isset($aargs['noResponse']) && $aargs['noResponse'])) {
|
||||
return true;
|
||||
}
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$int_message_id]['content'] = ['method' => $method, 'args' => $args];
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->new_outgoing[$int_message_id] = ['msg_id' => $int_message_id, 'method' => $method, 'type' => $type];
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id]['content'] = ['method' => $method, 'args' => $args];
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->new_outgoing[$message_id] = ['msg_id' => $message_id, 'method' => $method, 'type' => $type];
|
||||
$res_count = 0;
|
||||
$server_answer = null;
|
||||
$update_count = 0;
|
||||
@ -68,8 +68,8 @@ trait CallHandler
|
||||
try {
|
||||
\danog\MadelineProto\Logger::log(['Getting response (try number '.$res_count.' for '.$method.')...'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
//sleep(2);
|
||||
//$this->start_threads();
|
||||
if (!isset($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$int_message_id]['response']) || !isset($this->datacenter->sockets[$aargs['datacenter']]->incoming_messages[$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$int_message_id]['response']]['content'])) { // Checks if I have received the response to the called method, if not continue looping
|
||||
$this->start_threads();
|
||||
if (!isset($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id]['response']) || !isset($this->datacenter->sockets[$aargs['datacenter']]->incoming_messages[$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id]['response']]['content'])) { // Checks if I have received the response to the called method, if not continue looping
|
||||
if ($only_updates) {
|
||||
if ($update_count > 50) {
|
||||
$update_count = 0;
|
||||
@ -79,13 +79,18 @@ trait CallHandler
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$server_answer = $this->datacenter->sockets[$aargs['datacenter']]->incoming_messages[$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$int_message_id]['response']]['content'];
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->incoming_messages[$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$int_message_id]['response']]['content'] = [];
|
||||
//var_dump(base64_encode($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id]['response']), $this->datacenter->sockets[$aargs['datacenter']]->incoming_messages[$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id]['response']]);
|
||||
$server_answer = (array) $this->datacenter->sockets[$aargs['datacenter']]->incoming_messages[$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id]['response']]['content'];
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->incoming_messages[$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id]['response']]['content'] = [];
|
||||
break;
|
||||
}
|
||||
if (!$this->threads && !$this->run_workers) {
|
||||
$this->recv_message($aargs['datacenter']); // This method receives data from the socket, and parses stuff
|
||||
$only_updates = $this->handle_messages($aargs['datacenter']); // This method receives data from the socket, and parses stuff
|
||||
} else {
|
||||
$res_count--;
|
||||
//var_dump($this->datacenter->sockets[$aargs['datacenter']]->incoming_messages);
|
||||
sleep(1);
|
||||
}
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
if ($e->getMessage() === 'I had to recreate the temporary authorization key') {
|
||||
@ -122,7 +127,7 @@ trait CallHandler
|
||||
case 16:
|
||||
case 17:
|
||||
\danog\MadelineProto\Logger::log(['Received bad_msg_notification: '.$this->bad_msg_error_codes[$server_answer['error_code']]], \danog\MadelineProto\Logger::WARNING);
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->timedelta = (int) ((new \phpseclib\Math\BigInteger(strrev($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$int_message_id]['response']), 256))->bitwise_rightShift(32)->subtract(new \phpseclib\Math\BigInteger(time()))->toString());
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->timedelta = (int) ((new \phpseclib\Math\BigInteger(strrev($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id]['response']), 256))->bitwise_rightShift(32)->subtract(new \phpseclib\Math\BigInteger(time()))->toString());
|
||||
\danog\MadelineProto\Logger::log(['Set time delta to '.$this->datacenter->sockets[$aargs['datacenter']]->timedelta], \danog\MadelineProto\Logger::WARNING);
|
||||
$this->reset_session();
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key = null;
|
||||
@ -142,7 +147,7 @@ trait CallHandler
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$last_error = $e->getMessage().' in '.basename($e->getFile(), '.php').' on line '.$e->getLine();
|
||||
\danog\MadelineProto\Logger::log(['An error occurred while calling method '.$method.': '.$last_error.'. Recreating connection and retrying to call method...'], \danog\MadelineProto\Logger::WARNING);
|
||||
if (in_array($this->datacenter->sockets[$aargs['datacenter']]->protocol, ['http', 'https']) && $method !== 'http_wait') {
|
||||
if ($this->in_array($this->datacenter->sockets[$aargs['datacenter']]->protocol, ['http', 'https']) && $method !== 'http_wait') {
|
||||
//$this->method_call('http_wait', ['max_wait' => $this->datacenter->sockets[$aargs['datacenter']]->timeout, 'wait_after' => 0, 'max_delay' => 0], ['datacenter' => $aargs['datacenter']]);
|
||||
} else {
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->close_and_reopen();
|
||||
@ -150,14 +155,14 @@ trait CallHandler
|
||||
//sleep(1); // To avoid flooding
|
||||
continue;
|
||||
} finally {
|
||||
if (isset($aargs['heavy']) && $aargs['heavy'] && isset($int_message_id)) {
|
||||
//$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$int_message_id]['args'] = [];
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$int_message_id] = [];
|
||||
unset($this->datacenter->sockets[$aargs['datacenter']]->new_outgoing[$int_message_id]);
|
||||
if (isset($aargs['heavy']) && $aargs['heavy'] && isset($message_id)) {
|
||||
//$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id]['args'] = [];
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id] = [];
|
||||
unset($this->datacenter->sockets[$aargs['datacenter']]->new_outgoing[$message_id]);
|
||||
}
|
||||
if (isset($int_message_id) && $method === 'req_pq') {
|
||||
unset($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$int_message_id]);
|
||||
unset($this->datacenter->sockets[$aargs['datacenter']]->new_outgoing[$int_message_id]);
|
||||
if (isset($message_id) && $method === 'req_pq') {
|
||||
unset($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id]);
|
||||
unset($this->datacenter->sockets[$aargs['datacenter']]->new_outgoing[$message_id]);
|
||||
}
|
||||
if ($canunset) {
|
||||
$this->getting_state = false;
|
||||
@ -166,9 +171,9 @@ trait CallHandler
|
||||
}
|
||||
|
||||
if ($server_answer === null) {
|
||||
if ($last_recv === $this->last_recv && $this->datacenter->sockets[$args['datacenter']]->temp_auth_key !== null) {
|
||||
if ($last_recv === $this->last_recv && $this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key !== null) {
|
||||
\danog\MadelineProto\Logger::log(['WARNING: Resetting auth key...'], \danog\MadelineProto\Logger::WARNING);
|
||||
$this->datacenter->sockets[$args['datacenter']]->temp_auth_key = null;
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key = null;
|
||||
$this->init_authorization();
|
||||
|
||||
return $this->method_call($method, $args, $aargs);
|
||||
@ -176,7 +181,7 @@ trait CallHandler
|
||||
throw new \danog\MadelineProto\Exception('An error occurred while calling method '.$method.' ('.$last_error.').');
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Got response for method '.$method.' @ try '.$count.' (response try '.$res_count.')'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$int_message_id] = [];
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id] = [];
|
||||
if (isset($message_chunks) && count($message_chunks)) {
|
||||
$server_answer = [$server_answer];
|
||||
foreach ($message_chunks as $message) {
|
||||
@ -187,7 +192,9 @@ trait CallHandler
|
||||
|
||||
return $server_answer;
|
||||
}
|
||||
|
||||
if ($method === 'req_pq') {
|
||||
throw new \danog\MadelineProto\RPCErrorException('RPC_CALL_FAIL');
|
||||
}
|
||||
throw new \danog\MadelineProto\Exception('An error occurred while calling method '.$method.' ('.$last_error.').');
|
||||
}
|
||||
|
||||
@ -202,9 +209,9 @@ trait CallHandler
|
||||
for ($count = 1; $count <= $this->settings['max_tries']['query']; $count++) {
|
||||
try {
|
||||
\danog\MadelineProto\Logger::log([$object === 'msgs_ack' ? 'ack '.$args['msg_ids'][0] : 'Sending object (try number '.$count.' for '.$object.')...'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
$int_message_id = $this->send_message($this->serialize_object(['type' => $object], $args), $this->content_related($object), $aargs);
|
||||
$message_id = $this->send_message($this->serialize_object(['type' => $object], $args), $this->content_related($object), $aargs);
|
||||
if ($object !== 'msgs_ack') {
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$int_message_id]['content'] = ['method' => $object, 'args' => $args];
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id]['content'] = ['method' => $object, 'args' => $args];
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
\danog\MadelineProto\Logger::log(['An error occurred while calling object '.$object.': '.$e->getMessage().' in '.$e->getFile().':'.$e->getLine().'. Recreating connection and retrying to call object...'], \danog\MadelineProto\Logger::WARNING);
|
||||
@ -212,7 +219,7 @@ trait CallHandler
|
||||
continue;
|
||||
}
|
||||
|
||||
return $int_message_id;
|
||||
return $message_id;
|
||||
}
|
||||
throw new \danog\MadelineProto\Exception('An error occurred while sending object '.$object.'.');
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ trait Crypt
|
||||
public function ctr_encrypt($message, $key, $iv, $length)
|
||||
{
|
||||
$cipher = new \phpseclib\Crypt\AES(\phpseclib\Crypt\AES::MODE_CTR);
|
||||
$iv .= \danog\PHP\Struct::pack('<i', $length);
|
||||
$iv .= $this->pack_signed_int($length);
|
||||
$cipher->setKey($key);
|
||||
$cipher->setIV($iv);
|
||||
|
||||
|
@ -27,7 +27,7 @@ trait Files
|
||||
}
|
||||
$datacenter = is_null($datacenter) ? $this->datacenter->curdc : $datacenter;
|
||||
$file_size = filesize($file);
|
||||
if ($file_size > 1500 * 1024 * 1024) {
|
||||
if ($file_size > 1610612736) {
|
||||
throw new \danog\MadelineProto\Exception('Given file is too big!');
|
||||
}
|
||||
if ($cb === null) {
|
||||
@ -47,7 +47,7 @@ trait Files
|
||||
$key = $this->random(32);
|
||||
$iv = $this->random(32);
|
||||
$digest = hash('md5', $key.$iv, true);
|
||||
$fingerprint = \danog\PHP\Struct::unpack('<i', substr($digest, 0, 4) ^ substr($digest, 4, 4))[0];
|
||||
$fingerprint = $this->unpack_signed_int(substr($digest, 0, 4) ^ substr($digest, 4, 4));
|
||||
$ige = new \phpseclib\Crypt\AES(\phpseclib\Crypt\AES::MODE_IGE);
|
||||
$ige->setIV($iv);
|
||||
$ige->setKey($key);
|
||||
@ -61,7 +61,7 @@ trait Files
|
||||
$bytes = $ige->encrypt(str_pad($bytes, $part_size, chr(0)));
|
||||
}
|
||||
hash_update($ctx, $bytes);
|
||||
if (!$this->method_call($method, ['file_id' => $file_id, 'file_part' => $part_num++, 'file_total_parts' => $part_total_num, 'bytes' => $bytes], ['heavy' => true, 'datacenter' => $datacenter])) {
|
||||
if (!$this->method_call($method, ['file_id' => $file_id, 'file_part' => $part_num++, 'file_total_parts' => $part_total_num, 'bytes' => $bytes], ['heavy' => true, 'datacenter' => &$datacenter])) {
|
||||
throw new \danog\MadelineProto\Exception('An error occurred while uploading file part '.$part_num);
|
||||
}
|
||||
$cb(ftell($f) * 100 / $file_size);
|
||||
@ -254,7 +254,7 @@ trait Files
|
||||
$datacenter = isset($message_media['InputFileLocation']['dc_id']) ? $message_media['InputFileLocation']['dc_id'] : $this->datacenter->curdc;
|
||||
if (isset($message_media['key'])) {
|
||||
$digest = hash('md5', $message_media['key'].$message_media['iv'], true);
|
||||
$fingerprint = \danog\PHP\Struct::unpack('<i', substr($digest, 0, 4) ^ substr($digest, 4, 4))[0];
|
||||
$fingerprint = $this->unpack_signed_int(substr($digest, 0, 4) ^ substr($digest, 4, 4));
|
||||
if ($fingerprint !== $message_media['key_fingerprint']) {
|
||||
throw new \danog\MadelineProto\Exception('Fingerprint mismatch!');
|
||||
}
|
||||
@ -270,7 +270,7 @@ trait Files
|
||||
$offset -= $start_at;
|
||||
}
|
||||
try {
|
||||
$res = $cdn ? $this->method_call('upload.getCdnFile', ['file_token' => $message_media['file_token'], 'offset' => $offset, 'limit' => $part_size], ['heavy' => true, 'datacenter' => $datacenter]) : $this->method_call('upload.getFile', ['location' => $message_media['InputFileLocation'], 'offset' => $offset, 'limit' => $part_size], ['heavy' => true, 'datacenter' => $datacenter]);
|
||||
$res = $cdn ? $this->method_call('upload.getCdnFile', ['file_token' => $message_media['file_token'], 'offset' => $offset, 'limit' => $part_size], ['heavy' => true, 'datacenter' => $datacenter]) : $this->method_call('upload.getFile', ['location' => $message_media['InputFileLocation'], 'offset' => $offset, 'limit' => $part_size], ['heavy' => true, 'datacenter' => &$datacenter]);
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
if ($e->rpc === 'OFFSET_INVALID') {
|
||||
\Rollbar\Rollbar::log(\Rollbar\Payload\Level::error(), $e->rpc, ['info' => $message_media, 'offset' => $offset]);
|
||||
|
@ -21,7 +21,7 @@ trait MessageHandler
|
||||
* Forming the message frame and sending message to server
|
||||
* :param message: byte string to send.
|
||||
*/
|
||||
private $last_recv = 0;
|
||||
protected $last_recv = 0;
|
||||
|
||||
public function send_message($message_data, $content_related, $aargs = [])
|
||||
{
|
||||
@ -33,22 +33,23 @@ trait MessageHandler
|
||||
if (!is_string($message_id)) {
|
||||
throw new \danog\MadelineProto\Exception("Specified message id isn't a string");
|
||||
}
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages['a'.$message_id] = [];
|
||||
|
||||
if ($this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key['auth_key'] === null || $this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key['server_salt'] === null) {
|
||||
$message = str_repeat(chr(0), 8).$message_id.\danog\PHP\Struct::pack('<I', strlen($message_data)).$message_data;
|
||||
$message = "\0\0\0\0\0\0\0\0".$message_id.$this->pack_unsigned_int(strlen($message_data)).$message_data;
|
||||
} else {
|
||||
$seq_no = $this->generate_out_seq_no($aargs['datacenter'], $content_related);
|
||||
$data2enc = $this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key['server_salt'].$this->datacenter->sockets[$aargs['datacenter']]->session_id.$message_id.\danog\PHP\Struct::pack('<II', $seq_no, strlen($message_data)).$message_data;
|
||||
$data2enc = $this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key['server_salt'].$this->datacenter->sockets[$aargs['datacenter']]->session_id.$message_id.pack('VV', $seq_no, strlen($message_data)).$message_data;
|
||||
$padding = $this->random($this->posmod(-strlen($data2enc), 16));
|
||||
$message_key = substr(sha1($data2enc, true), -16);
|
||||
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key['auth_key']);
|
||||
$message = $this->datacenter->sockets[$aargs['datacenter']]->temp_auth_key['id'].$message_key.$this->ige_encrypt($data2enc.$padding, $aes_key, $aes_iv);
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id]['seq_no'] = $seq_no;
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages['a'.$message_id]['seq_no'] = $seq_no;
|
||||
}
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[$message_id]['response'] = -1;
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages['a'.$message_id]['response'] = -1;
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->send_message($message);
|
||||
|
||||
return $message_id;
|
||||
return 'a'.$message_id;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -58,7 +59,7 @@ trait MessageHandler
|
||||
{
|
||||
$payload = $this->datacenter->sockets[$datacenter]->read_message();
|
||||
if (strlen($payload) === 4) {
|
||||
$error = \danog\PHP\Struct::unpack('<i', $payload)[0];
|
||||
$error = $this->unpack_signed_int($payload);
|
||||
if ($error === -404) {
|
||||
if ($this->datacenter->sockets[$datacenter]->temp_auth_key !== null) {
|
||||
\danog\MadelineProto\Logger::log(['WARNING: Resetting auth key...'], \danog\MadelineProto\Logger::WARNING);
|
||||
@ -70,11 +71,12 @@ trait MessageHandler
|
||||
throw new \danog\MadelineProto\RPCErrorException($error, $error);
|
||||
}
|
||||
$auth_key_id = substr($payload, 0, 8);
|
||||
if ($auth_key_id === str_repeat(chr(0), 8)) {
|
||||
$message_id = substr($payload, 8, 8);
|
||||
if ($auth_key_id === "\0\0\0\0\0\0\0\0") {
|
||||
$message_id = 'a'.substr($payload, 8, 8);
|
||||
$this->check_message_id($message_id, ['outgoing' => false, 'datacenter' => $datacenter, 'container' => false]);
|
||||
$message_length = \danog\PHP\Struct::unpack('<I', substr($payload, 16, 4))[0];
|
||||
$message_length = unpack('V', substr($payload, 16, 4))[1];
|
||||
$message_data = substr($payload, 20, $message_length);
|
||||
$this->datacenter->sockets[$datacenter]->incoming_messages[$message_id] = [];
|
||||
} elseif ($auth_key_id === $this->datacenter->sockets[$datacenter]->temp_auth_key['id']) {
|
||||
$message_key = substr($payload, 8, 16);
|
||||
$encrypted_data = substr($payload, 24);
|
||||
@ -91,13 +93,13 @@ trait MessageHandler
|
||||
throw new \danog\MadelineProto\Exception('Session id mismatch.');
|
||||
}
|
||||
|
||||
$message_id = substr($decrypted_data, 16, 8);
|
||||
$message_id = 'a'.substr($decrypted_data, 16, 8);
|
||||
$this->check_message_id($message_id, ['outgoing' => false, 'datacenter' => $datacenter, 'container' => false]);
|
||||
|
||||
$seq_no = \danog\PHP\Struct::unpack('<I', substr($decrypted_data, 24, 4))[0];
|
||||
$seq_no = unpack('V', substr($decrypted_data, 24, 4))[1];
|
||||
// Dunno how to handle any incorrect sequence numbers
|
||||
|
||||
$message_data_length = \danog\PHP\Struct::unpack('<I', substr($decrypted_data, 28, 4))[0];
|
||||
$message_data_length = unpack('V', substr($decrypted_data, 28, 4))[1];
|
||||
|
||||
if ($message_data_length > strlen($decrypted_data)) {
|
||||
throw new \danog\MadelineProto\SecurityException('message_data_length is too big');
|
||||
@ -119,7 +121,7 @@ trait MessageHandler
|
||||
if ($message_key != substr(sha1(substr($decrypted_data, 0, 32 + $message_data_length), true), -16)) {
|
||||
throw new \danog\MadelineProto\SecurityException('msg_key mismatch');
|
||||
}
|
||||
$this->datacenter->sockets[$datacenter]->incoming_messages[$message_id]['seq_no'] = $seq_no;
|
||||
$this->datacenter->sockets[$datacenter]->incoming_messages[$message_id] = ['seq_no' => $seq_no];
|
||||
} else {
|
||||
throw new \danog\MadelineProto\SecurityException('Got unknown auth_key id');
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ trait MsgIdHandler
|
||||
public function check_message_id($new_message_id, $aargs)
|
||||
{
|
||||
if (!is_object($new_message_id)) {
|
||||
$new_message_id = new \phpseclib\Math\BigInteger(strrev($new_message_id), 256);
|
||||
$new_message_id = new \phpseclib\Math\BigInteger(strrev(substr($new_message_id, 1)), 256);
|
||||
}
|
||||
$min_message_id = (new \phpseclib\Math\BigInteger(time() + $this->datacenter->sockets[$aargs['datacenter']]->time_delta - 300))->bitwise_leftShift(32);
|
||||
if ($min_message_id->compare($new_message_id) > 0) {
|
||||
@ -34,7 +34,6 @@ trait MsgIdHandler
|
||||
if (!$new_message_id->divide($this->four)[1]->equals($this->zero)) {
|
||||
throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is not divisible by 4.');
|
||||
}
|
||||
$keys = array_keys($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages);
|
||||
$key = $this->get_max_id($aargs['datacenter'], false);
|
||||
if ($new_message_id->compare($key) <= 0) {
|
||||
throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is lower than or equal than the current limit ('.$key.').', 1);
|
||||
@ -43,7 +42,7 @@ trait MsgIdHandler
|
||||
reset($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages);
|
||||
unset($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[key($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages)]);
|
||||
}
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages[strrev($new_message_id->toBytes())] = [];
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages['a'.strrev($new_message_id->toBytes())] = [];
|
||||
} else {
|
||||
if (!$new_message_id->divide($this->four)[1]->equals($this->one) && !$new_message_id->divide($this->four)[1]->equals($this->three)) {
|
||||
throw new \danog\MadelineProto\Exception('message id mod 4 != 1 or 3');
|
||||
@ -63,7 +62,7 @@ trait MsgIdHandler
|
||||
reset($this->datacenter->sockets[$aargs['datacenter']]->incoming_messages);
|
||||
unset($this->datacenter->sockets[$aargs['datacenter']]->incoming_messages[key($this->datacenter->sockets[$aargs['datacenter']]->incoming_messages)]);
|
||||
}
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->incoming_messages[strrev($new_message_id->toBytes())] = [];
|
||||
$this->datacenter->sockets[$aargs['datacenter']]->incoming_messages['a'.strrev($new_message_id->toBytes())] = [];
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,12 +80,12 @@ trait MsgIdHandler
|
||||
|
||||
public function get_max_id($datacenter, $incoming)
|
||||
{
|
||||
$keys = array_keys($this->datacenter->sockets[$datacenter]->{$incoming ? 'incoming_messages' : 'outgoing_messages'});
|
||||
$keys = array_keys((array) $this->datacenter->sockets[$datacenter]->{$incoming ? 'incoming_messages' : 'outgoing_messages'});
|
||||
if (empty($keys)) {
|
||||
return $this->zero;
|
||||
}
|
||||
array_walk($keys, function (&$value, $key) {
|
||||
$value = is_int($value) ? new \phpseclib\Math\BigInteger($value) : new \phpseclib\Math\BigInteger(strrev($value), 256);
|
||||
$value = new \phpseclib\Math\BigInteger(strrev(substr($value, 1)), 256);
|
||||
});
|
||||
|
||||
return \phpseclib\Math\BigInteger::max(...$keys);
|
||||
|
@ -200,7 +200,7 @@ trait PeerHandler
|
||||
|
||||
if (is_numeric($id)) {
|
||||
if (is_string($id)) {
|
||||
$id = $this->bigint ? ((float) $id) : ((int) $id);
|
||||
$id = \danog\MadelineProto\Logger::$bigint ? ((float) $id) : ((int) $id);
|
||||
}
|
||||
if (isset($this->chats[$id])) {
|
||||
return $this->gen_all($this->chats[$id]);
|
||||
@ -212,15 +212,15 @@ trait PeerHandler
|
||||
}
|
||||
}
|
||||
if (!isset($this->settings['pwr']['requests']) || $this->settings['pwr']['requests'] === true) {
|
||||
$dbres = json_decode(file_get_contents('https://id.pwrtelegram.xyz/db/getusername?id='.$id, false, stream_context_create(['http'=> [
|
||||
$dbres = json_decode(@file_get_contents('https://id.pwrtelegram.xyz/db/getusername?id='.$id, false, stream_context_create(['http'=> [
|
||||
'timeout' => 2,
|
||||
],
|
||||
])), true);
|
||||
if ($dbres['ok']) {
|
||||
if (isset($dbres['ok']) && $dbres['ok']) {
|
||||
return $this->get_info('@'.$dbres['result']);
|
||||
}
|
||||
}
|
||||
throw new \danog\MadelineProto\Exception("Couldn't find peer by provided chat id ".$id);
|
||||
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
||||
}
|
||||
$id = str_replace('@', '', $id);
|
||||
foreach ($this->chats as $chat) {
|
||||
@ -233,7 +233,7 @@ trait PeerHandler
|
||||
|
||||
return $this->get_info($id, false);
|
||||
}
|
||||
throw new \danog\MadelineProto\Exception("Couldn't find peer by provided username ".$id);
|
||||
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
|
||||
}
|
||||
|
||||
public function gen_all($constructor)
|
||||
|
@ -17,8 +17,8 @@ namespace danog\MadelineProto\MTProtoTools;
|
||||
*/
|
||||
trait ResponseHandler
|
||||
{
|
||||
private $pending_updates = [];
|
||||
private $bad_msg_error_codes = [
|
||||
protected $pending_updates = [];
|
||||
protected $bad_msg_error_codes = [
|
||||
16 => 'msg_id too low (most likely, client time is wrong; it would be worthwhile to synchronize it using msg_id notifications and re-send the original message with the โcorrectโ msg_id or wrap it in a container with a new msg_id if the original message had waited too long on the client to be transmitted)',
|
||||
17 => 'msg_id too high (similar to the previous case, the client time has to be synchronized, and the message re-sent with the correct msg_id)',
|
||||
18 => 'incorrect two lower order msg_id bits (the server expects client message msg_id to be divisible by 4)',
|
||||
@ -31,7 +31,7 @@ trait ResponseHandler
|
||||
48 => 'incorrect server salt (in this case, the bad_server_salt response is received with the correct salt, and the message is to be re-sent with it)',
|
||||
64 => 'invalid container.',
|
||||
];
|
||||
private $msgs_info_flags = [
|
||||
protected $msgs_info_flags = [
|
||||
1 => 'nothing is known about the message (msg_id too low, the other party may have forgotten it)',
|
||||
2 => 'message not received (msg_id falls within the range of stored identifiers; however, the other party has certainly not received a message like that)',
|
||||
3 => 'message not received (msg_id too high; however, the other party has certainly not received it yet)',
|
||||
@ -48,8 +48,8 @@ trait ResponseHandler
|
||||
$info = '';
|
||||
foreach ($msg_ids as $msg_id) {
|
||||
$cur_info = 0;
|
||||
if (!in_array($msg_id, $this->datacenter->sockets[$datacenter]->incoming_messages)) {
|
||||
$msg_id = new \phpseclib\Math\BigInteger(strrev($msg_id), 256);
|
||||
if (!isset($this->datacenter->sockets[$datacenter]->incoming_messages[$msg_id])) {
|
||||
$msg_id = new \phpseclib\Math\BigInteger(strrev(substr($msg_id, 1)), 256);
|
||||
if ((new \phpseclib\Math\BigInteger(time() + $this->datacenter->sockets[$datacenter]->time_delta + 30))->bitwise_leftShift(32)->compare($msg_id) < 0) {
|
||||
$cur_info |= 3;
|
||||
} elseif ((new \phpseclib\Math\BigInteger(time() + $this->datacenter->sockets[$datacenter]->time_delta - 300))->bitwise_leftShift(32)->compare($msg_id) > 0) {
|
||||
@ -68,13 +68,31 @@ trait ResponseHandler
|
||||
$this->datacenter->sockets[$datacenter]->outgoing_messages[$this->object_call('msgs_state_info', ['req_msg_id' => $req_msg_id, 'info' => $info], ['datacenter' => $datacenter])]['response'] = $req_msg_id;
|
||||
}
|
||||
|
||||
public $stop = false;
|
||||
|
||||
public function handle_messages($datacenter)
|
||||
{
|
||||
if ($this->stop) {
|
||||
return;
|
||||
}
|
||||
$only_updates = true;
|
||||
foreach ($this->datacenter->sockets[$datacenter]->new_incoming as $current_msg_id) {
|
||||
$unset = false;
|
||||
\danog\MadelineProto\Logger::log(['Received '.$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_'].'.'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Received '.$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_'].'.'], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
if (\danog\MadelineProto\Logger::$has_thread && is_object(\Thread::getCurrentThread())) {
|
||||
if (!$this->synchronized(function ($zis, $datacenter, $current_msg_id) {
|
||||
if (isset($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['handling'])) {
|
||||
return false;
|
||||
}
|
||||
$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['handling'] = true;
|
||||
|
||||
return true;
|
||||
}, $this, $datacenter, $current_msg_id) || $this->stop) {
|
||||
\danog\MadelineProto\Logger::log([base64_encode($current_msg_id).$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_'].' is already being handled'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
continue;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Handling '.base64_encode($current_msg_id).$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_'].'.'], \danog\MadelineProto\Logger::VERBOSE);
|
||||
}
|
||||
switch ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['_']) {
|
||||
case 'msgs_ack':
|
||||
$this->check_in_seq_no($datacenter, $current_msg_id);
|
||||
@ -88,10 +106,17 @@ trait ResponseHandler
|
||||
case 'rpc_result':
|
||||
$this->ack_incoming_message_id($current_msg_id, $datacenter); // Acknowledge that I received the server's response
|
||||
$this->ack_outgoing_message_id($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['req_msg_id'], $datacenter); // Acknowledge that the server received my request
|
||||
$this->datacenter->sockets[$datacenter]->outgoing_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['req_msg_id']]['response'] = $current_msg_id;
|
||||
unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]);
|
||||
unset($this->datacenter->sockets[$datacenter]->new_outgoing[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['req_msg_id']]);
|
||||
$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content'] = $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['result'];
|
||||
$this->datacenter->sockets[$datacenter]->outgoing_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['req_msg_id']]['response'] = $current_msg_id;
|
||||
//var_dump($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]);
|
||||
$content = (array) $this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['result'];
|
||||
$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content'] = $content;
|
||||
///var_dump($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]);
|
||||
///var_dump($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]);
|
||||
///var_dump($this->datacenter->sockets[$datacenter]->incoming_messages[$this->datacenter->sockets[$datacenter]->outgoing_messages[$this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['req_msg_id']]['response']]['content']);
|
||||
///$this->stop = true;
|
||||
//var_dump(base64_encode($current_msg_id), $this->datacenter->sockets[$datacenter]->incoming_messages);
|
||||
$this->check_in_seq_no($datacenter, $current_msg_id);
|
||||
$only_updates = false;
|
||||
break;
|
||||
@ -200,13 +225,13 @@ trait ResponseHandler
|
||||
unset($this->datacenter->sockets[$datacenter]->new_incoming[$current_msg_id]);
|
||||
|
||||
foreach ($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['msg_ids'] as $key => $msg_id) {
|
||||
$msg_id = new \phpseclib\Math\BigInteger(strrev($msg_id), 256);
|
||||
$msg_id = new \phpseclib\Math\BigInteger(strrev(substr($msg_id, 1)), 256);
|
||||
$status = 'Status for message id '.$msg_id.': ';
|
||||
if (($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['info'][$key] & 4) === 1) {
|
||||
if (($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['info'][$key] & 4) !== 0) {
|
||||
$this->ack_outgoing_message_id($msg_id, $datacenter);
|
||||
}
|
||||
foreach ($this->msgs_info_flags as $flag => $description) {
|
||||
if (($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['info'][$key] & $flag) === 1) {
|
||||
if (($this->datacenter->sockets[$datacenter]->incoming_messages[$current_msg_id]['content']['info'][$key] & $flag) !== 0) {
|
||||
$status .= $description;
|
||||
}
|
||||
}
|
||||
@ -319,6 +344,10 @@ trait ResponseHandler
|
||||
return $only_updates;
|
||||
}
|
||||
|
||||
public function handle_messages_threaded()
|
||||
{
|
||||
}
|
||||
|
||||
public function handle_rpc_error($server_answer, &$datacenter)
|
||||
{
|
||||
switch ($server_answer['error_code']) {
|
||||
@ -342,7 +371,6 @@ trait ResponseHandler
|
||||
$this->init_authorization(); // idk
|
||||
throw new \danog\MadelineProto\RPCErrorException($server_answer['error_message'], $server_answer['error_code']);
|
||||
}
|
||||
|
||||
case 420:
|
||||
$seconds = preg_replace('/[^0-9]+/', '', $server_answer['error_message']);
|
||||
if (is_numeric($seconds) && isset($this->settings['flood_timeout']['wait_if_lt']) && $seconds < $this->settings['flood_timeout']['wait_if_lt']) {
|
||||
@ -352,7 +380,6 @@ trait ResponseHandler
|
||||
}
|
||||
default:
|
||||
throw new \danog\MadelineProto\RPCErrorException($server_answer['error_message'], $server_answer['error_code']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ trait SeqNoHandler
|
||||
|
||||
public function content_related($method)
|
||||
{
|
||||
return isset($method['_']) ? !in_array(
|
||||
return isset($method['_']) ? !$this->in_array(
|
||||
$method['_'],
|
||||
[
|
||||
'rpc_result',
|
||||
|
@ -22,9 +22,9 @@ trait UpdateHandler
|
||||
public $channels_state = [];
|
||||
public $updates = [];
|
||||
public $updates_key = 0;
|
||||
private $getting_state = false;
|
||||
protected $getting_state = false;
|
||||
public $full_chats;
|
||||
private $msg_ids = [];
|
||||
protected $msg_ids = [];
|
||||
|
||||
public function pwr_update_handler($update)
|
||||
{
|
||||
@ -80,7 +80,7 @@ trait UpdateHandler
|
||||
return [];
|
||||
}
|
||||
if ($params['offset'] < 0) {
|
||||
$params['offset'] = array_reverse(array_keys($this->updates))[abs($params['offset']) - 1];
|
||||
$params['offset'] = array_reverse(array_keys((array) $this->updates))[abs($params['offset']) - 1];
|
||||
}
|
||||
$updates = [];
|
||||
ksort($this->updates);
|
||||
@ -158,7 +158,6 @@ trait UpdateHandler
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Got '.$difference['_']], \danog\MadelineProto\Logger::VERBOSE);
|
||||
$this->get_channel_state($channel)['sync_loading'] = false;
|
||||
switch ($difference['_']) {
|
||||
case 'updates.channelDifferenceEmpty':
|
||||
@ -175,6 +174,7 @@ trait UpdateHandler
|
||||
}
|
||||
break;
|
||||
case 'updates.channelDifferenceTooLong':
|
||||
\danog\MadelineProto\Logger::log(['Got '.$difference['_']], \danog\MadelineProto\Logger::VERBOSE);
|
||||
$this->set_channel_state($channel, $difference);
|
||||
$this->handle_update_messages($difference['messages'], $channel);
|
||||
unset($difference);
|
||||
@ -239,7 +239,7 @@ trait UpdateHandler
|
||||
$this->get_update_state()['pending_seq_updates'] = [];
|
||||
}
|
||||
$difference = $this->method_call('updates.getDifference', ['pts' => $this->get_update_state()['pts'], 'date' => $this->get_update_state()['date'], 'qts' => $this->get_update_state()['qts']], ['datacenter' => $this->datacenter->curdc]);
|
||||
\danog\MadelineProto\Logger::log(['Got '.$difference['_']], \danog\MadelineProto\Logger::VERBOSE);
|
||||
\danog\MadelineProto\Logger::log(['Got '.$difference['_']], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
|
||||
$this->get_update_state()['sync_loading'] = false;
|
||||
|
||||
switch ($difference['_']) {
|
||||
@ -312,7 +312,7 @@ trait UpdateHandler
|
||||
} else {
|
||||
$cur_state = &$this->get_channel_state($channel_id, (isset($update['pts']) ? $update['pts'] : 0) - (isset($update['pts_count']) ? $update['pts_count'] : 0));
|
||||
}
|
||||
if ($cur_state['sync_loading'] && in_array($update['_'], ['updateNewMessage', 'updateEditMessage', 'updateNewChannelMessage', 'updateEditChannelMessage'])) {
|
||||
if ($cur_state['sync_loading'] && $this->in_array($update['_'], ['updateNewMessage', 'updateEditMessage', 'updateNewChannelMessage', 'updateEditChannelMessage'])) {
|
||||
\danog\MadelineProto\Logger::log(['Sync loading, not handling update'], \danog\MadelineProto\Logger::NOTICE);
|
||||
|
||||
return false;
|
||||
@ -561,7 +561,7 @@ trait UpdateHandler
|
||||
if ($update['_'] === 'updateEncryption') {
|
||||
switch ($update['chat']['_']) {
|
||||
case 'encryptedChatRequested':
|
||||
if ($this->settings['secret_chats']['accept_chats'] === false || ($this->is_array($this->settings['secret_chats']['accept_chats']) && !in_array($update['chat']['admin_id'], $this->settings['secret_chats']['accept_chats']))) {
|
||||
if ($this->settings['secret_chats']['accept_chats'] === false || ($this->is_array($this->settings['secret_chats']['accept_chats']) && !$this->in_array($update['chat']['admin_id'], $this->settings['secret_chats']['accept_chats']))) {
|
||||
return;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log(['Accepting secret chat '.$update['chat']['id']], \danog\MadelineProto\Logger::NOTICE);
|
||||
|
@ -1,305 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
Copyright 2016-2017 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.
|
||||
The PWRTelegram API 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
/**
|
||||
* Manages connection to telegram servers.
|
||||
*/
|
||||
class NewConnection extends SerializableVolatile
|
||||
{
|
||||
use \danog\MadelineProto\Tools;
|
||||
public $sock = null;
|
||||
|
||||
public $protocol = null;
|
||||
public $ip = null;
|
||||
public $port = null;
|
||||
public $timeout = null;
|
||||
|
||||
public $time_delta = 0;
|
||||
public $temp_auth_key;
|
||||
public $auth_key;
|
||||
public $session_id;
|
||||
public $session_out_seq_no = 0;
|
||||
public $session_in_seq_no = 0;
|
||||
public $ipv6 = false;
|
||||
public $incoming_messages = [];
|
||||
public $outgoing_messages = [];
|
||||
public $new_incoming = [];
|
||||
public $new_outgoing = [];
|
||||
|
||||
public function __construct($ip, $port = null, $protocol = null, $timeout = null, $ipv6 = null)
|
||||
{
|
||||
if ($this->unserialized($ip)) {
|
||||
return true;
|
||||
}
|
||||
// Can use:
|
||||
/*
|
||||
- tcp_full
|
||||
- tcp_abridged
|
||||
- tcp_intermediate
|
||||
- http
|
||||
- https
|
||||
- udp
|
||||
*/
|
||||
$this->protocol = $protocol;
|
||||
$this->timeout = $timeout;
|
||||
$this->ipv6 = $ipv6;
|
||||
$this->ip = $ip;
|
||||
$this->port = $port;
|
||||
$this->sock = new \Volatile();
|
||||
switch ($this->protocol) {
|
||||
case 'tcp_abridged':
|
||||
$this->sock['pony'] = new \Volatile();
|
||||
$this->sock['pony']['socket'] = new Socket($ipv6 ? \AF_INET6 : \AF_INET, \SOCK_STREAM, getprotobyname('tcp'));
|
||||
$this->sock['pony']->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
|
||||
$this->sock['pony']->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
|
||||
if (!$this->sock['pony']->connect($ip, $port)) {
|
||||
throw new Exception("Connection: couldn't connect to socket.");
|
||||
}
|
||||
$this->write(chr(239));
|
||||
break;
|
||||
case 'tcp_intermediate':
|
||||
$this->sock['pony'] = new Socket($ipv6 ? \AF_INET6 : \AF_INET, \SOCK_STREAM, getprotobyname('tcp'));
|
||||
$this->sock['pony']->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
|
||||
$this->sock['pony']->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
|
||||
if (!$this->sock['pony']->connect($ip, $port)) {
|
||||
throw new Exception("Connection: couldn't connect to socket.");
|
||||
}
|
||||
$this->write(str_repeat(chr(238), 4));
|
||||
break;
|
||||
case 'tcp_full':
|
||||
$this->sock['pony'] = new Socket($ipv6 ? \AF_INET6 : \AF_INET, \SOCK_STREAM, getprotobyname('tcp'));
|
||||
//$this->sock["pony"]->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
|
||||
//$this->sock["pony"]->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
|
||||
if (!$this->sock['pony']->connect($ip, $port)) {
|
||||
throw new Exception("Connection: couldn't connect to socket.");
|
||||
}
|
||||
$this->out_seq_no = -1;
|
||||
$this->in_seq_no = -1;
|
||||
break;
|
||||
case 'http':
|
||||
case 'https':
|
||||
$this->parsed = parse_url($ip);
|
||||
$this->sock['pony'] = new Socket($ipv6 ? \AF_INET6 : \AF_INET, \SOCK_STREAM, getprotobyname($this->protocol === 'https' ? 'tls' : 'tcp'));
|
||||
$this->sock['pony']->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
|
||||
$this->sock['pony']->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
|
||||
if (!$this->sock['pony']->connect($this->parsed['host'], $port)) {
|
||||
throw new Exception("Connection: couldn't connect to socket.");
|
||||
}
|
||||
break;
|
||||
case 'udp':
|
||||
throw new Exception("Connection: This protocol isn't implemented yet.");
|
||||
default:
|
||||
throw new Exception('Connection: invalid protocol specified.');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
switch ($this->protocol) {
|
||||
case 'tcp_abridged':
|
||||
case 'tcp_intermediate':
|
||||
case 'tcp_full':
|
||||
case 'http':
|
||||
case 'https':
|
||||
try {
|
||||
unset($this->sock['pony']);
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
}
|
||||
break;
|
||||
case 'udp':
|
||||
throw new Exception("Connection: This protocol wasn't implemented yet.");
|
||||
default:
|
||||
throw new Exception('Connection: invalid protocol specified.');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function close_and_reopen()
|
||||
{
|
||||
$this->__destruct();
|
||||
$this->__construct($this->ip, $this->port, $this->protocol, $this->timeout, $this->ipv6);
|
||||
}
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
$t = get_object_vars($this);
|
||||
if (isset($t['sock'])) {
|
||||
unset($t['sock']);
|
||||
}
|
||||
|
||||
return array_keys($t);
|
||||
}
|
||||
|
||||
public function __wakeup()
|
||||
{
|
||||
$this->__construct($this->ip, $this->port, $this->protocol, $this->timeout, $this->ipv6);
|
||||
}
|
||||
|
||||
public function write($what, $length = null)
|
||||
{
|
||||
if ($length !== null) {
|
||||
$what = substr($what, 0, $length);
|
||||
}
|
||||
switch ($this->protocol) {
|
||||
case 'tcp_abridged':
|
||||
case 'tcp_intermediate':
|
||||
case 'tcp_full':
|
||||
case 'http':
|
||||
case 'https':
|
||||
if (($wrote = $this->sock['pony']->write($what)) !== strlen($what)) {
|
||||
throw new \danog\MadelineProto\Exception("WARNING: Wrong length was written (should've written ".strlen($what).', wrote '.$wrote.')!');
|
||||
}
|
||||
|
||||
return $wrote;
|
||||
break;
|
||||
case 'udp':
|
||||
throw new Exception("Connection: This protocol wasn't implemented yet.");
|
||||
break;
|
||||
default:
|
||||
throw new Exception('Connection: invalid protocol specified.');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function read($length)
|
||||
{
|
||||
switch ($this->protocol) {
|
||||
case 'tcp_abridged':
|
||||
case 'tcp_intermediate':
|
||||
case 'tcp_full':
|
||||
case 'http':
|
||||
case 'https':
|
||||
$packet = $this->sock['pony']->read($length);
|
||||
|
||||
if ($packet === false || strlen($packet) === 0) {
|
||||
throw new \danog\MadelineProto\NothingInTheSocketException('Nothing in the socket!');
|
||||
}
|
||||
if (strlen($packet) != $length) {
|
||||
throw new \danog\MadelineProto\Exception("WARNING: Wrong length was read (should've read ".($length).', read '.strlen($packet).')!');
|
||||
}
|
||||
|
||||
return $packet;
|
||||
case 'udp':
|
||||
throw new Exception("Connection: This protocol wasn't implemented yet.");
|
||||
default:
|
||||
throw new Exception('Connection: invalid protocol specified.');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function read_message()
|
||||
{
|
||||
switch ($this->protocol) {
|
||||
case 'tcp_full':
|
||||
$packet_length_data = $this->read(4);
|
||||
$packet_length = \danog\PHP\Struct::unpack('<I', $packet_length_data)[0];
|
||||
$packet = $this->read($packet_length - 4);
|
||||
if (strrev(hash('crc32b', $packet_length_data.substr($packet, 0, -4), true)) !== substr($packet, -4)) {
|
||||
throw new Exception('CRC32 was not correct!');
|
||||
}
|
||||
$this->in_seq_no++;
|
||||
$in_seq_no = \danog\PHP\Struct::unpack('<I', substr($packet, 0, 4))[0];
|
||||
if ($in_seq_no != $this->in_seq_no) {
|
||||
throw new Exception('Incoming seq_no mismatch');
|
||||
}
|
||||
|
||||
return substr($packet, 4, $packet_length - 12);
|
||||
case 'tcp_intermediate':
|
||||
$packet_length_data = $this->read(4);
|
||||
$packet_length = \danog\PHP\Struct::unpack('<I', $packet_length_data)[0];
|
||||
|
||||
return $this->read($packet_length);
|
||||
case 'tcp_abridged':
|
||||
$packet_length_data = $this->read(1);
|
||||
$packet_length = ord($packet_length_data);
|
||||
if ($packet_length < 127) {
|
||||
$packet_length <<= 2;
|
||||
} else {
|
||||
$packet_length_data = $this->read(3);
|
||||
$packet_length = \danog\PHP\Struct::unpack('<I', $packet_length_data.pack('x'))[0] << 2;
|
||||
}
|
||||
|
||||
return $this->read($packet_length);
|
||||
case 'http':
|
||||
case 'https':
|
||||
$headers = [];
|
||||
$close = false;
|
||||
while (true) {
|
||||
$current_header = '';
|
||||
while (($curchar = $this->read(1)) !== "\n") {
|
||||
$current_header .= $curchar;
|
||||
}
|
||||
$current_header = rtrim($current_header);
|
||||
if ($current_header === '') {
|
||||
break;
|
||||
}
|
||||
if ($current_header === false) {
|
||||
throw new Exception('No data in the socket!');
|
||||
}
|
||||
if (preg_match('|^Content-Length: |i', $current_header)) {
|
||||
$length = preg_replace('|Content-Length: |i', '', $current_header);
|
||||
}
|
||||
if (preg_match('|^Connection: close|i', $current_header)) {
|
||||
$close = true;
|
||||
}
|
||||
$headers[] = $current_header;
|
||||
}
|
||||
$read = $this->read($length);
|
||||
if ($headers[0] !== 'HTTP/1.1 200 OK') {
|
||||
throw new Exception($headers[0]);
|
||||
}
|
||||
if ($close) {
|
||||
$this->close_and_reopen();
|
||||
}
|
||||
|
||||
return $read;
|
||||
case 'udp':
|
||||
throw new Exception("Connection: This protocol wasn't implemented yet.");
|
||||
}
|
||||
}
|
||||
|
||||
public function send_message($message)
|
||||
{
|
||||
switch ($this->protocol) {
|
||||
case 'tcp_full':
|
||||
$this->out_seq_no++;
|
||||
$step1 = \danog\PHP\Struct::pack('<II', (strlen($message) + 12), $this->out_seq_no).$message;
|
||||
$step2 = $step1.strrev(hash('crc32b', $step1, true));
|
||||
$this->write($step2);
|
||||
break;
|
||||
case 'tcp_intermediate':
|
||||
$this->write(\danog\PHP\Struct::pack('<I', strlen($message)).$message);
|
||||
break;
|
||||
case 'tcp_abridged':
|
||||
$len = strlen($message) / 4;
|
||||
if ($len < 127) {
|
||||
$step1 = chr($len).$message;
|
||||
} else {
|
||||
$step1 = chr(127).substr(\danog\PHP\Struct::pack('<I', $len), 0, 3).$message;
|
||||
}
|
||||
$this->write($step1);
|
||||
break;
|
||||
case 'http':
|
||||
case 'https':
|
||||
$this->write('POST '.$this->parsed['path']." HTTP/1.1\r\nHost: ".$this->parsed['host']."\r\nContent-Type: application/x-www-form-urlencoded\r\nConnection: keep-alive\r\nContent-Length: ".strlen($message)."\r\n\r\n".$message);
|
||||
break;
|
||||
|
||||
case 'udp':
|
||||
throw new Exception("Connection: This protocol wasn't implemented yet.");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -12,16 +12,17 @@ If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class RSA
|
||||
class RSA extends \Volatile
|
||||
{
|
||||
use \danog\MadelineProto\TL\TL;
|
||||
use \danog\MadelineProto\Tools;
|
||||
use \danog\Serializable;
|
||||
|
||||
public $e;
|
||||
public $n;
|
||||
public $fp;
|
||||
|
||||
public function __construct($rsa_key)
|
||||
public function ___construct($rsa_key)
|
||||
{
|
||||
//if ($this->unserialized($rsa_key)) return true;
|
||||
\danog\MadelineProto\Logger::log(['Istantiating \phpseclib\Crypt\RSA...'], Logger::ULTRA_VERBOSE);
|
||||
|
@ -19,8 +19,8 @@ namespace danog\MadelineProto\SecretChats;
|
||||
*/
|
||||
trait AuthKeyHandler
|
||||
{
|
||||
private $temp_requested_secret_chats = [];
|
||||
private $secret_chats = [];
|
||||
protected $temp_requested_secret_chats = [];
|
||||
protected $secret_chats = [];
|
||||
|
||||
public function accept_secret_chat($params)
|
||||
{
|
||||
@ -95,7 +95,7 @@ trait AuthKeyHandler
|
||||
$this->method_call('messages.sendEncryptedService', ['peer' => $chat, 'message' => ['_' => 'decryptedMessageService', 'action' => ['_' => 'decryptedMessageActionNotifyLayer', 'layer' => $this->encrypted_layer]]], ['datacenter' => $this->datacenter->curdc]);
|
||||
}
|
||||
|
||||
private $temp_rekeyed_secret_chats = [];
|
||||
protected $temp_rekeyed_secret_chats = [];
|
||||
|
||||
public function rekey($chat)
|
||||
{
|
||||
|
@ -34,7 +34,7 @@ trait MessageHandler
|
||||
}
|
||||
$this->secret_chats[$chat_id]['outgoing'][$this->secret_chats[$chat_id]['out_seq_no']] = $message;
|
||||
$message = $this->serialize_object(['type' => $this->secret_chats[$chat_id]['layer'] === 8 ? 'DecryptedMessage' : 'DecryptedMessageLayer'], $message, $this->secret_chats[$chat_id]['layer']);
|
||||
$message = \danog\PHP\Struct::pack('<I', strlen($message)).$message;
|
||||
$message = $this->pack_unsigned_int(strlen($message)).$message;
|
||||
|
||||
$message_key = substr(sha1($message, true), -16);
|
||||
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->secret_chats[$chat_id]['key']['auth_key'], 'to server');
|
||||
@ -70,7 +70,7 @@ trait MessageHandler
|
||||
$encrypted_data = substr($message['message']['bytes'], 24);
|
||||
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, $this->secret_chats[$message['message']['chat_id']][$old ? 'old_key' : 'key']['auth_key'], 'to server');
|
||||
$decrypted_data = $this->ige_decrypt($encrypted_data, $aes_key, $aes_iv);
|
||||
$message_data_length = \danog\PHP\Struct::unpack('<I', substr($decrypted_data, 0, 4))[0];
|
||||
$message_data_length = unpack('V', substr($decrypted_data, 0, 4))[1];
|
||||
if ($message_data_length > strlen($decrypted_data)) {
|
||||
throw new \danog\MadelineProto\SecurityException('message_data_length is too big');
|
||||
}
|
||||
|
@ -1,32 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
Copyright 2016-2017 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/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
abstract class SerializableVolatile
|
||||
{
|
||||
public function unserialized($data)
|
||||
{
|
||||
if (!isset($data['_']) || $data['_'] !== 'pony') {
|
||||
return false;
|
||||
}
|
||||
unset($data['_']);
|
||||
foreach ($data as $key => $data) {
|
||||
$this->{$key} = $data;
|
||||
}
|
||||
if (method_exists($this, '__wakeup')) {
|
||||
$this->__wakeup();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -31,7 +31,7 @@ class Serialization
|
||||
if ($instance->API->should_serialize || !(file_exists($filename) && !empty(file_get_contents($filename))) || $force) {
|
||||
$instance->API->should_serialize = false;
|
||||
|
||||
return file_put_contents($filename, serialize($instance), LOCK_EX);
|
||||
return file_put_contents($filename, \danog\MadelineProto\Logger::$has_thread ? \danog\Serialization::serialize($instance) : serialize($instance), LOCK_EX);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -54,16 +54,16 @@ class Serialization
|
||||
$file = fopen($filename, 'r+');
|
||||
flock($file, LOCK_SH);
|
||||
$unserialized = stream_get_contents($file);
|
||||
/*
|
||||
foreach (['MTProto', 'DataCenter', 'Connection', 'RSA'] as $class) {
|
||||
$oclass = "danog\\MadelineProto\\".$class;
|
||||
$nclass = $oclass.'Serializable';
|
||||
$unserialized = str_replace('O:'.strlen($oclass).':"'.$oclass.'":', 'O:'.strlen($nclass).':"'.$nclass.'":', $unserialized);
|
||||
}
|
||||
*/
|
||||
flock($file, LOCK_UN);
|
||||
fclose($file);
|
||||
$unserialized = unserialize($unserialized);
|
||||
foreach (['RSA', 'TL\TLMethod', 'TL\TLConstructor', 'MTProto', 'API', 'DataCenter', 'Connection'] as $class) {
|
||||
class_exists('\danog\MadelineProto\\'.$class);
|
||||
}
|
||||
try {
|
||||
$unserialized = \danog\MadelineProto\Logger::$has_thread ? \danog\Serialization::unserialize($unserialized) : unserialize($unserialized);
|
||||
} catch (Bug74586Exception $e) {
|
||||
$unserialized = \danog\Serialization::unserialize($unserialized);
|
||||
}
|
||||
} else {
|
||||
throw new Exception('File does not exist');
|
||||
}
|
||||
|
@ -407,7 +407,7 @@ trait Extension
|
||||
public function get_extension_from_mime($mime)
|
||||
{
|
||||
foreach ($this->all_mimes as $key => $value) {
|
||||
if (array_search($mime, $value) !== false) {
|
||||
if (array_search($mime, (array) $value) !== false) {
|
||||
return '.'.$key;
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace danog\MadelineProto\TL\Conversion;
|
||||
|
||||
trait TD
|
||||
{
|
||||
private $td_params_conversion = [
|
||||
protected $td_params_conversion = [
|
||||
'updateNewMessage' => [
|
||||
'_' => 'updateNewMessage',
|
||||
'disable_notification' => ['message', 'silent'],
|
||||
@ -51,10 +51,10 @@ trait TD
|
||||
],
|
||||
|
||||
];
|
||||
private $reverse = [
|
||||
protected $reverse = [
|
||||
'sendMessage'=> 'messages.sendMessage',
|
||||
];
|
||||
private $ignore = ['updateMessageID'];
|
||||
protected $ignore = ['updateMessageID'];
|
||||
|
||||
public function tdcli_to_td(&$params, $key = null)
|
||||
{
|
||||
@ -126,7 +126,7 @@ trait TD
|
||||
return $params;
|
||||
}
|
||||
$newparams = ['_' => $params['_']];
|
||||
if (in_array($params['_'], $this->ignore)) {
|
||||
if ($this->in_array($params['_'], $this->ignore)) {
|
||||
return $params;
|
||||
}
|
||||
foreach ($this->td_params_conversion[$params['_']] as $td => $mtproto) {
|
||||
|
@ -132,7 +132,7 @@ trait TL
|
||||
$dparams = [];
|
||||
}
|
||||
$TL_dict[$type][$key][$type === 'constructors' ? 'predicate' : 'method'] = $name;
|
||||
$TL_dict[$type][$key]['id'] = \danog\PHP\Struct::unpack('<i', pack('V', hexdec($id)))[0];
|
||||
$TL_dict[$type][$key]['id'] = strrev(hex2bin($id));
|
||||
$TL_dict[$type][$key]['params'] = [];
|
||||
$TL_dict[$type][$key]['type'] = preg_replace(['/.+\s/', '/;/'], '', $line);
|
||||
if ($layer !== null) {
|
||||
@ -150,6 +150,13 @@ trait TL
|
||||
}
|
||||
$key++;
|
||||
}
|
||||
} else {
|
||||
foreach ($TL_dict['constructors'] as $key => $value) {
|
||||
$TL_dict['constructors'][$key]['id'] = $this->pack_signed_int($TL_dict['constructors'][$key]['id']);
|
||||
}
|
||||
foreach ($TL_dict['methods'] as $key => $value) {
|
||||
$TL_dict['methods'][$key]['id'] = $this->pack_signed_int($TL_dict['methods'][$key]['id']);
|
||||
}
|
||||
}
|
||||
if (empty($TL_dict) || empty($TL_dict['constructors']) || !isset($TL_dict['methods'])) {
|
||||
throw new Exception('Invalid source file was provided: '.$file);
|
||||
@ -210,12 +217,11 @@ trait TL
|
||||
|
||||
public function serialize_bool($bool)
|
||||
{
|
||||
return \danog\PHP\Struct::pack('<i', $this->constructors->find_by_predicate('bool'.($bool ? 'True' : 'False'))['id']);
|
||||
return $this->constructors->find_by_predicate($bool ? 'boolTrue' : 'boolFalse')['id'];
|
||||
}
|
||||
|
||||
public function deserialize_bool($data)
|
||||
public function deserialize_bool($id)
|
||||
{
|
||||
$id = \danog\PHP\Struct::unpack('<i', $data)[0];
|
||||
$tl_elem = $this->constructors->find_by_id($id);
|
||||
if ($tl_elem === false) {
|
||||
throw new Exception('Could not extract boolean');
|
||||
@ -232,13 +238,13 @@ trait TL
|
||||
throw new Exception('given value ('.$object.") isn't numeric");
|
||||
}
|
||||
|
||||
return \danog\PHP\Struct::pack('<i', $object);
|
||||
return $this->pack_signed_int($object);
|
||||
case '#':
|
||||
if (!is_numeric($object)) {
|
||||
throw new Exception('given value ('.$object.") isn't numeric");
|
||||
}
|
||||
|
||||
return pack('V', $object);
|
||||
return $this->pack_unsigned_int($object);
|
||||
case 'long':
|
||||
if (is_object($object)) {
|
||||
return str_pad(strrev($object->toBytes()), 8, chr(0));
|
||||
@ -247,11 +253,14 @@ trait TL
|
||||
if (is_string($object) && strlen($object) === 8) {
|
||||
return $object;
|
||||
}
|
||||
if (is_string($object) && strlen($object) === 9 && $object[0] === 'a') {
|
||||
return substr($object, 1);
|
||||
}
|
||||
if (!is_numeric($object)) {
|
||||
throw new Exception('given value ('.$object.") isn't numeric");
|
||||
}
|
||||
|
||||
return \danog\PHP\Struct::pack('<q', $object);
|
||||
return $this->pack_signed_long($object);
|
||||
case 'int128':
|
||||
if (strlen($object) !== 16) {
|
||||
throw new Exception('Given value is not 16 bytes long');
|
||||
@ -271,7 +280,7 @@ trait TL
|
||||
|
||||
return (string) $object;
|
||||
case 'double':
|
||||
return \danog\PHP\Struct::pack('<d', $object);
|
||||
return $this->pack_double($object);
|
||||
case 'string':
|
||||
$object = pack('C*', ...unpack('C*', $object));
|
||||
case 'bytes':
|
||||
@ -283,7 +292,7 @@ trait TL
|
||||
$concat .= pack('@'.$this->posmod((-$l - 1), 4));
|
||||
} else {
|
||||
$concat .= chr(254);
|
||||
$concat .= substr(\danog\PHP\Struct::pack('<i', $l), 0, 3);
|
||||
$concat .= substr($this->pack_signed_int($l), 0, 3);
|
||||
$concat .= $object;
|
||||
$concat .= pack('@'.$this->posmod(-$l, 4));
|
||||
}
|
||||
@ -299,8 +308,8 @@ trait TL
|
||||
if (!$this->is_array($object)) {
|
||||
throw new Exception("You didn't provide a valid array");
|
||||
}
|
||||
$concat = \danog\PHP\Struct::pack('<i', $this->constructors->find_by_predicate('vector')['id']);
|
||||
$concat .= \danog\PHP\Struct::pack('<i', count($object));
|
||||
$concat = $this->constructors->find_by_predicate('vector')['id'];
|
||||
$concat .= $this->pack_unsigned_int(count($object));
|
||||
foreach ($object as $current_object) {
|
||||
$concat .= $this->serialize_object(['type' => $type['subtype']], $current_object);
|
||||
}
|
||||
@ -346,7 +355,7 @@ trait TL
|
||||
$constructorData = $this->constructors->find_by_predicate('inputMessageEntityMentionName');
|
||||
}
|
||||
if (!$bare) {
|
||||
$concat .= \danog\PHP\Struct::pack('<i', $constructorData['id']);
|
||||
$concat .= $constructorData['id'];
|
||||
}
|
||||
|
||||
return $concat.$this->serialize_params($constructorData, $object, $layer);
|
||||
@ -359,7 +368,7 @@ trait TL
|
||||
throw new Exception('Could not find method: '.$method);
|
||||
}
|
||||
|
||||
return \danog\PHP\Struct::pack('<i', $tl['id']).$this->serialize_params($tl, $arguments);
|
||||
return $tl['id'].$this->serialize_params($tl, $arguments);
|
||||
}
|
||||
|
||||
public function serialize_params($tl, $arguments, $layer = -1)
|
||||
@ -413,8 +422,8 @@ trait TL
|
||||
continue 2;
|
||||
case 'Vector t':
|
||||
if (isset($arguments['id'])) {
|
||||
$serialized .= \danog\PHP\Struct::pack('<i', $this->constructors->find_by_predicate('vector')['id']);
|
||||
$serialized .= \danog\PHP\Struct::pack('<i', count($arguments['id']));
|
||||
$serialized .= $this->constructors->find_by_predicate('vector')['id'];
|
||||
$serialized .= $this->pack_unsigned_int(count($arguments['id']));
|
||||
$serialized .= $this->random(8 * count($arguments['id']));
|
||||
continue 2;
|
||||
}
|
||||
@ -464,17 +473,22 @@ trait TL
|
||||
} elseif (!is_resource($bytes_io)) {
|
||||
throw new Exception('An invalid bytes_io handle was provided.');
|
||||
}
|
||||
|
||||
switch ($type['type']) {
|
||||
case 'Bool':
|
||||
return $this->deserialize_bool(stream_get_contents($bytes_io, 4));
|
||||
case 'int':
|
||||
return \danog\PHP\Struct::unpack('<i', stream_get_contents($bytes_io, 4))[0];
|
||||
return $this->unpack_signed_int(stream_get_contents($bytes_io, 4));
|
||||
case '#':
|
||||
return unpack('V', stream_get_contents($bytes_io, 4))[1];
|
||||
case 'long':
|
||||
return $this->bigint || isset($type['strlong']) ? stream_get_contents($bytes_io, 8) : \danog\PHP\Struct::unpack('<q', stream_get_contents($bytes_io, 8))[0];
|
||||
if (isset($type['idstrlong'])) {
|
||||
return 'a'.stream_get_contents($bytes_io, 8);
|
||||
}
|
||||
|
||||
return \danog\MadelineProto\Logger::$bigint || isset($type['strlong']) ? stream_get_contents($bytes_io, 8) : $this->unpack_signed_long(stream_get_contents($bytes_io, 8));
|
||||
case 'double':
|
||||
return \danog\PHP\Struct::unpack('<d', stream_get_contents($bytes_io, 8))[0];
|
||||
return $this->unpack_double(stream_get_contents($bytes_io, 8));
|
||||
case 'int128':
|
||||
return stream_get_contents($bytes_io, 16);
|
||||
case 'int256':
|
||||
@ -509,7 +523,7 @@ trait TL
|
||||
case 'true':
|
||||
return true;
|
||||
case 'Vector t':
|
||||
$id = \danog\PHP\Struct::unpack('<i', stream_get_contents($bytes_io, 4))[0];
|
||||
$id = stream_get_contents($bytes_io, 4);
|
||||
$constructorData = $this->constructors->find_by_id($id);
|
||||
if ($constructorData === false) {
|
||||
throw new Exception('Could not extract type: '.$type['type'].' with id '.$id);
|
||||
@ -524,7 +538,7 @@ trait TL
|
||||
throw new Exception('Invalid vector constructor: '.$constructorData['predicate']);
|
||||
}
|
||||
case 'vector':
|
||||
$count = \danog\PHP\Struct::unpack('<i', stream_get_contents($bytes_io, 4))[0];
|
||||
$count = unpack('V', stream_get_contents($bytes_io, 4))[1];
|
||||
$result = [];
|
||||
$type['type'] = $type['subtype'];
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
@ -542,7 +556,7 @@ trait TL
|
||||
} else {
|
||||
$constructorData = $this->constructors->find_by_predicate($type['type']);
|
||||
if ($constructorData === false) {
|
||||
$id = \danog\PHP\Struct::unpack('<i', stream_get_contents($bytes_io, 4))[0];
|
||||
$id = stream_get_contents($bytes_io, 4);
|
||||
$constructorData = $this->constructors->find_by_id($id);
|
||||
if ($constructorData === false) {
|
||||
throw new Exception('Could not extract type: '.$type['type'].' with id '.$id);
|
||||
@ -585,7 +599,10 @@ trait TL
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($this->in_array($arg['name'], ['msg_ids', 'msg_id', 'bad_msg_id', 'req_msg_id', 'answer_msg_id', 'first_msg_id', 'key_fingerprint', 'server_salt', 'new_server_salt', 'server_public_key_fingerprints', 'ping_id', 'exchange_id'])) {
|
||||
if ($this->in_array($arg['name'], ['msg_ids', 'msg_id', 'bad_msg_id', 'req_msg_id', 'answer_msg_id', 'first_msg_id'])) {
|
||||
$arg['idstrlong'] = true;
|
||||
}
|
||||
if ($this->in_array($arg['name'], ['key_fingerprint', 'server_salt', 'new_server_salt', 'server_public_key_fingerprints', 'ping_id', 'exchange_id'])) {
|
||||
$arg['strlong'] = true;
|
||||
}
|
||||
|
||||
@ -612,6 +629,14 @@ trait TL
|
||||
return json_decode($x['data'], true);
|
||||
}
|
||||
|
||||
if ($x['_'] === 'message' && isset($x['reply_markup']['rows'])) {
|
||||
foreach ($x['reply_markup']['rows'] as $key => $row) {
|
||||
foreach ($row['buttons'] as $bkey => $button) {
|
||||
$x['reply_markup']['rows'][$key]['buttons'][$bkey] = new \danog\MadelineProto\Button($this, $x, $button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $x;
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,12 @@ If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace danog\MadelineProto\TL;
|
||||
|
||||
class TLConstructor extends TLParams
|
||||
class TLConstructor extends \Volatile
|
||||
{
|
||||
use \danog\Serializable;
|
||||
use \danog\MadelineProto\Tools;
|
||||
use TLParams;
|
||||
|
||||
public $id = [];
|
||||
public $predicate = [];
|
||||
public $type = [];
|
||||
@ -23,7 +27,7 @@ class TLConstructor extends TLParams
|
||||
|
||||
public function add($json_dict, $scheme_type)
|
||||
{
|
||||
$this->id[$this->key] = (int) $json_dict['id'];
|
||||
$this->id[$this->key] = $json_dict['id'];
|
||||
$this->predicate[$this->key] = (string) ((($scheme_type === 'mtproto' && $json_dict['predicate'] === 'message') ? 'MT' : '').$json_dict['predicate']);
|
||||
$this->type[$this->key] = (($scheme_type === 'mtproto' && $json_dict['type'] === 'Message') ? 'MT' : '').$json_dict['type'];
|
||||
$this->params[$this->key] = $json_dict['params'];
|
||||
@ -36,13 +40,13 @@ class TLConstructor extends TLParams
|
||||
|
||||
public function find_by_type($type)
|
||||
{
|
||||
$key = array_search($type, $this->type);
|
||||
$key = array_search($type, (array) $this->type);
|
||||
|
||||
return ($key === false) ? false : [
|
||||
'id' => $this->id[$key],
|
||||
'predicate' => $this->predicate[$key],
|
||||
'type' => $this->type[$key],
|
||||
'params' => $this->params[$key],
|
||||
'params' => $this->array_cast_recursive($this->params[$key]),
|
||||
];
|
||||
}
|
||||
|
||||
@ -50,7 +54,7 @@ class TLConstructor extends TLParams
|
||||
{
|
||||
if ($layer !== -1) {
|
||||
$newlayer = -1;
|
||||
$keys = array_keys($this->predicate, $predicate);
|
||||
$keys = array_keys((array) $this->predicate, $predicate);
|
||||
foreach ($keys as $k) {
|
||||
if ($this->layer[$k] <= $layer && $this->layer[$k] > $newlayer) {
|
||||
$key = $k;
|
||||
@ -61,26 +65,26 @@ class TLConstructor extends TLParams
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$key = array_search($predicate, $this->predicate);
|
||||
$key = array_search($predicate, (array) $this->predicate);
|
||||
}
|
||||
|
||||
return ($key === false) ? false : [
|
||||
'id' => $this->id[$key],
|
||||
'predicate' => $this->predicate[$key],
|
||||
'type' => $this->type[$key],
|
||||
'params' => $this->params[$key],
|
||||
'params' => $this->array_cast_recursive($this->params[$key]),
|
||||
];
|
||||
}
|
||||
|
||||
public function find_by_id($id)
|
||||
{
|
||||
$key = array_search($id, $this->id);
|
||||
$key = array_search($id, (array) $this->id);
|
||||
|
||||
return ($key === false) ? false : [
|
||||
'id' => $this->id[$key],
|
||||
'predicate' => $this->predicate[$key],
|
||||
'type' => $this->type[$key],
|
||||
'params' => $this->params[$key],
|
||||
'params' => $this->array_cast_recursive($this->params[$key]),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,11 @@ If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace danog\MadelineProto\TL;
|
||||
|
||||
class TLMethod extends TLParams
|
||||
class TLMethod extends \Volatile
|
||||
{
|
||||
use \danog\Serializable;
|
||||
use \danog\MadelineProto\Tools;
|
||||
use TLParams;
|
||||
public $id = [];
|
||||
public $method = [];
|
||||
public $type = [];
|
||||
@ -23,7 +26,7 @@ class TLMethod extends TLParams
|
||||
|
||||
public function add($json_dict)
|
||||
{
|
||||
$this->id[$this->key] = (int) $json_dict['id'];
|
||||
$this->id[$this->key] = $json_dict['id'];
|
||||
$this->method[$this->key] = $json_dict['method'];
|
||||
$this->type[$this->key] = $json_dict['type'];
|
||||
$this->params[$this->key] = $json_dict['params'];
|
||||
@ -38,25 +41,25 @@ class TLMethod extends TLParams
|
||||
|
||||
public function find_by_method($method)
|
||||
{
|
||||
$key = array_search($method, $this->method);
|
||||
$key = array_search($method, (array) $this->method);
|
||||
|
||||
return ($key === false) ? false : [
|
||||
'id' => $this->id[$key],
|
||||
'method' => $this->method[$key],
|
||||
'type' => $this->type[$key],
|
||||
'params' => $this->params[$key],
|
||||
'params' => $this->array_cast_recursive($this->params[$key]),
|
||||
];
|
||||
}
|
||||
|
||||
public function find_by_id($id)
|
||||
{
|
||||
$key = array_search($id, $this->id);
|
||||
$key = array_search($id, (array) $this->id);
|
||||
|
||||
return ($key === false) ? false : [
|
||||
'id' => $this->id[$key],
|
||||
'method' => $this->method[$key],
|
||||
'type' => $this->type[$key],
|
||||
'params' => $this->params[$key],
|
||||
'params' => $this->array_cast_recursive($this->params[$key]),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace danog\MadelineProto\TL;
|
||||
|
||||
class TLParams
|
||||
trait TLParams
|
||||
{
|
||||
public function parse_params($key, $mtproto = false)
|
||||
{
|
||||
|
@ -28,18 +28,12 @@ class SocketHandler extends \Threaded implements \Collectable
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
require_once __DIR__.'/../SecurityException.php';
|
||||
require_once __DIR__.'/../RPCErrorException.php';
|
||||
require_once __DIR__.'/../ResponseException.php';
|
||||
require_once __DIR__.'/../TL/Conversion/Exception.php';
|
||||
require_once __DIR__.'/../TL/Exception.php';
|
||||
require_once __DIR__.'/../NothingInTheSocketException.php';
|
||||
require_once __DIR__.'/../Exception.php';
|
||||
$this->API->handle_messages($current);
|
||||
require __DIR__.'/../../../../vendor/autoload.php';
|
||||
$this->API->handle_messages($this->current);
|
||||
$this->setGarbage();
|
||||
}
|
||||
|
||||
private $garbage = false;
|
||||
protected $garbage = false;
|
||||
|
||||
public function setGarbage():void
|
||||
{
|
||||
|
@ -21,11 +21,8 @@ class SocketReader extends \Threaded implements \Collectable
|
||||
|
||||
public function __construct($me, $current)
|
||||
{
|
||||
return;
|
||||
$this->API = $me;
|
||||
$this->current = $current;
|
||||
|
||||
var_dump('OK');
|
||||
}
|
||||
|
||||
public function __sleep()
|
||||
@ -43,27 +40,23 @@ class SocketReader extends \Threaded implements \Collectable
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
var_dump('BLOCK');
|
||||
while (true);
|
||||
require_once __DIR__.'/../SecurityException.php';
|
||||
require_once __DIR__.'/../RPCErrorException.php';
|
||||
require_once __DIR__.'/../ResponseException.php';
|
||||
require_once __DIR__.'/../TL/Conversion/Exception.php';
|
||||
require_once __DIR__.'/../TL/Exception.php';
|
||||
require_once __DIR__.'/../NothingInTheSocketException.php';
|
||||
require_once __DIR__.'/../Exception.php';
|
||||
require __DIR__.'/../../../../vendor/autoload.php';
|
||||
|
||||
$handler_pool = new \Pool($this->API->settings['threading']['handler_workers']);
|
||||
|
||||
$this->ready = true;
|
||||
|
||||
//while ($this->API->run_workers) {
|
||||
//try {
|
||||
//var_dump('READING');
|
||||
// $this->API->recv_message($this->current);
|
||||
// $handler_pool->submit(new SocketHandler($this->API, $this->current));
|
||||
//} catch (\danog\MadelineProto\NothingInTheSocketException $e) { \danog\MadelineProto\Logger::log(['Nothing in the socket for dc '.$this->current], \danog\MadelineProto\Logger::VERBOSE); }
|
||||
//}
|
||||
while ($this->API->run_workers) {
|
||||
try {
|
||||
$this->API->datacenter->sockets[$this->current]->reading = true;
|
||||
$this->API->recv_message($this->current);
|
||||
var_dump('NOW HANDLE');
|
||||
$handler_pool->submit(new SocketHandler($this->API, $this->current));
|
||||
$this->API->datacenter->sockets[$this->current]->reading = false;
|
||||
} catch (\danog\MadelineProto\NothingInTheSocketException $e) {
|
||||
\danog\MadelineProto\Logger::log(['Nothing in the socket for dc '.$this->current], \danog\MadelineProto\Logger::VERBOSE);
|
||||
}
|
||||
}
|
||||
while ($number = $handler_pool->collect()) {
|
||||
\danog\MadelineProto\Logger::log(['Shutting down handler pool for dc '.$this->current.', '.$number.' jobs left'], \danog\MadelineProto\Logger::NOTICE);
|
||||
}
|
||||
|
@ -19,11 +19,7 @@ trait Tools
|
||||
{
|
||||
public function random($length)
|
||||
{
|
||||
if ($length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return \phpseclib\Crypt\Random::string($length);
|
||||
return $length === 0 ? '' : \phpseclib\Crypt\Random::string($length);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33,18 +29,15 @@ trait Tools
|
||||
public function posmod($a, $b)
|
||||
{
|
||||
$resto = $a % $b;
|
||||
if ($resto < 0) {
|
||||
$resto += abs($b);
|
||||
}
|
||||
|
||||
return $resto;
|
||||
return $resto < 0 ? ($resto + abs($b)) : $resto;
|
||||
}
|
||||
|
||||
public function utf8ize($d)
|
||||
{
|
||||
if (is_array($d)) {
|
||||
if ($this->is_array($d)) {
|
||||
foreach ($d as $k => $v) {
|
||||
if ($k === 'bytes') {
|
||||
if ($k === 'bytes' || $this->is_array($v)) {
|
||||
$d[$k] = $this->utf8ize($v);
|
||||
}
|
||||
}
|
||||
@ -62,11 +55,14 @@ trait Tools
|
||||
|
||||
public function __call($method, $params)
|
||||
{
|
||||
return $method(...$this->array_cast_recursive($params));
|
||||
return \danog\MadelineProto\Logger::$has_thread ? $method(...$this->array_cast_recursive($params)) : $method(...$params);
|
||||
}
|
||||
|
||||
public function array_cast_recursive($array)
|
||||
{
|
||||
if (!\danog\MadelineProto\Logger::$has_thread) {
|
||||
return $array;
|
||||
}
|
||||
if ($this->is_array($array)) {
|
||||
if (!is_array($array)) {
|
||||
$array = (array) $array;
|
||||
@ -78,4 +74,79 @@ trait Tools
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function unpack_signed_int($value)
|
||||
{
|
||||
if (strlen($value) !== 4) {
|
||||
throw new TL\Exception('Length is not equal to 4');
|
||||
}
|
||||
|
||||
return unpack('l', \danog\MadelineProto\Logger::$BIG_ENDIAN ? strrev($value) : $value)[1];
|
||||
}
|
||||
|
||||
public function unpack_signed_long($value)
|
||||
{
|
||||
if (strlen($value) !== 8) {
|
||||
throw new TL\Exception('Length is not equal to 8');
|
||||
}
|
||||
|
||||
return unpack('q', \danog\MadelineProto\Logger::$BIG_ENDIAN ? strrev($value) : $value)[1];
|
||||
}
|
||||
|
||||
public function pack_signed_int($value)
|
||||
{
|
||||
if ($value > 2147483647) {
|
||||
throw new TL\Exception('Provided value '.$value.' is bigger than 2147483647');
|
||||
}
|
||||
if ($value < -2147483648) {
|
||||
throw new TL\Exception('Provided value '.$value.' is smaller than -2147483648');
|
||||
}
|
||||
$res = pack('l', $value);
|
||||
|
||||
return \danog\MadelineProto\Logger::$BIG_ENDIAN ? strrev($res) : $res;
|
||||
}
|
||||
|
||||
public function pack_signed_long($value)
|
||||
{
|
||||
if ($value > 9223372036854775807) {
|
||||
throw new TL\Exception('Provided value '.$value.' is bigger than 9223372036854775807');
|
||||
}
|
||||
if ($value < -9223372036854775808) {
|
||||
throw new TL\Exception('Provided value '.$value.' is smaller than -9223372036854775808');
|
||||
}
|
||||
$res = \danog\MadelineProto\Logger::$bigint ? ($this->pack_signed_int($value)."\0\0\0\0") : (\danog\MadelineProto\Logger::$BIG_ENDIAN ? strrev(pack('q', $value)) : pack('q', $value));
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function pack_unsigned_int($value)
|
||||
{
|
||||
if ($value > 4294967295) {
|
||||
throw new TL\Exception('Provided value '.$value.' is bigger than 4294967296');
|
||||
}
|
||||
if ($value < 0) {
|
||||
throw new TL\Exception('Provided value '.$value.' is smaller than 0');
|
||||
}
|
||||
|
||||
return pack('V', $value);
|
||||
}
|
||||
|
||||
public function pack_signed_double($value)
|
||||
{
|
||||
$res = pack('d', $value);
|
||||
if (strlen($res) !== 8) {
|
||||
throw new TL\Exception('Could not properly encode double');
|
||||
}
|
||||
|
||||
return \danog\MadelineProto\Logger::$BIG_ENDIAN ? strrev($res) : $res;
|
||||
}
|
||||
|
||||
public function unpack_double($value)
|
||||
{
|
||||
if (strlen($value) !== 8) {
|
||||
throw new TL\Exception('Length is not equal to 8');
|
||||
}
|
||||
|
||||
return unpack('d', \danog\MadelineProto\Logger::$BIG_ENDIAN ? strrev($value) : $value)[1];
|
||||
}
|
||||
}
|
||||
|
@ -20,12 +20,12 @@ namespace danog\MadelineProto\VoIP;
|
||||
*/
|
||||
trait AuthKeyHandler
|
||||
{
|
||||
private $calls = [];
|
||||
protected $calls = [];
|
||||
public $REQUESTED = 0;
|
||||
public $ACCEPTED = 1;
|
||||
public $CONFIRMED = 2;
|
||||
public $READY = 3;
|
||||
private $emojis = ['๐', '๐', '๐', '๐ญ', '๐ฑ', '๐ก', '๐', '๐ด', '๐ต', '๐', '๐ฌ', '๐', '๐', '๐ฎ', '๐ท', '๐', '๐ถ', '๐จ', '๐ฉ', '๐ด', '๐ต', '๐ป', '๐ฝ', '๐', '๐บ', '๐', '๐', '๐', '๐', '๐ฝ', '๐ฉ', '๐ฅ', '๐ฅ', '๐ค', '๐', '๐', '๐', '๐
', '๐', '๐', '๐', '๐', '๐', 'โ', 'โ', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐ช', '๐ถ', '๐', '๐', '๐ซ', '๐ช', '๐ฌ', '๐ญ', '๐
', '๐ฉ', '๐', '๐', '๐', '๐', '๐ ', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐ถ', '๐บ', '๐ฑ', '๐ญ', '๐น', '๐ฐ', '๐ธ', '๐ฏ', '๐จ', '๐ป', '๐ท', '๐ฎ', '๐', '๐ด', '๐', '๐', '๐ผ', '๐ง', '๐ฅ', '๐', '๐', '๐ข', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐ฌ', '๐', '๐', '๐', '๐ซ', '๐', '๐น', '๐ป', '๐', '๐พ', '๐', '๐ต', '๐ด', '๐ณ', '๐', '๐', '๐', '๐', '๐', 'โก', 'โ', 'โ', 'โ', '๐', '๐', '๐', '๐', '๐', '๐', '๐ป', '๐
', '๐', '๐', '๐', '๐ฎ', '๐ฅ', '๐ท', '๐ฟ', '๐ป', 'โ', '๐ก', '๐บ', '๐ป', '๐', '๐', 'โณ', 'โฐ', 'โ', '๐', '๐', '๐', '๐ก', '๐ฆ', '๐', '๐', '๐ฟ', '๐ฝ', '๐ง', '๐จ', '๐ช', '๐ฌ', '๐ฃ', '๐ซ', '๐ช', '๐', '๐', '๐ฐ', '๐ต', '๐ณ', 'โ', '๐ซ', '๐ฆ', '๐
', '๐', 'โ', '๐', '๐', 'โ', 'โ', '๐', '๐', '๐ฌ', '๐ญ', '๐จ', '๐ฌ', '๐ค', '๐ง', '๐ต', '๐น', '๐ป', '๐บ', '๐ธ', '๐พ', '๐ฎ', '๐', '๐ฒ', '๐ฏ', '๐', '๐', 'โฝ', 'โพ', '๐พ', '๐ฑ', '๐', '๐ณ', '๐', '๐', '๐', '๐', '๐', 'โ', '๐ผ', '๐บ', '๐ท', '๐ด', '๐', '๐', '๐', '๐', '๐ฑ', '๐', '๐', '๐ก', '๐ณ', '๐', '๐ฉ', '๐ฆ', '๐', '๐ฐ', '๐ช', '๐ซ', '๐ญ', '๐ฏ', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐
', '๐ฝ', '๐ก', '๐ฅ', '๐ฆ', 'โช', '๐ฐ', 'โบ', '๐ญ', '๐ป', '๐ฝ', '๐ ', '๐ก', 'โฒ', '๐ข', '๐ข', '๐ค', 'โ', '๐', 'โ', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐จ', '๐', '๐', '๐', '๐ฒ', '๐ ', '๐', '๐ฆ', 'โ ', '๐ง', 'โฝ', '๐ฐ', '๐ฟ', '๐ช', '๐ญ', '๐ฏ๐ต', '๐ฐ๐ท', '๐ฉ๐ช', '๐จ๐ณ', '๐บ๐ธ', '๐ซ๐ท', '๐ช๐ธ', '๐ฎ๐น', '๐ท๐บ', '๐ฌ๐ง', '1โฃ', '2โฃ', '3โฃ', '4โฃ', '5โฃ', '6โฃ', '7โฃ', '8โฃ', '9โฃ', '0โฃ', '๐', 'โ', 'โ', 'โฅ', 'โฆ', '๐ฏ', '๐', '๐ฑ', '๐ด', '๐ต', '๐ถ', '๐ท'];
|
||||
protected $emojis = ['๐', '๐', '๐', '๐ญ', '๐ฑ', '๐ก', '๐', '๐ด', '๐ต', '๐', '๐ฌ', '๐', '๐', '๐ฎ', '๐ท', '๐', '๐ถ', '๐จ', '๐ฉ', '๐ด', '๐ต', '๐ป', '๐ฝ', '๐', '๐บ', '๐', '๐', '๐', '๐', '๐ฝ', '๐ฉ', '๐ฅ', '๐ฅ', '๐ค', '๐', '๐', '๐', '๐
', '๐', '๐', '๐', '๐', '๐', 'โ', 'โ', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐ช', '๐ถ', '๐', '๐', '๐ซ', '๐ช', '๐ฌ', '๐ญ', '๐
', '๐ฉ', '๐', '๐', '๐', '๐', '๐ ', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐ถ', '๐บ', '๐ฑ', '๐ญ', '๐น', '๐ฐ', '๐ธ', '๐ฏ', '๐จ', '๐ป', '๐ท', '๐ฎ', '๐', '๐ด', '๐', '๐', '๐ผ', '๐ง', '๐ฅ', '๐', '๐', '๐ข', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐ฌ', '๐', '๐', '๐', '๐ซ', '๐', '๐น', '๐ป', '๐', '๐พ', '๐', '๐ต', '๐ด', '๐ณ', '๐', '๐', '๐', '๐', '๐', 'โก', 'โ', 'โ', 'โ', '๐', '๐', '๐', '๐', '๐', '๐', '๐ป', '๐
', '๐', '๐', '๐', '๐ฎ', '๐ฅ', '๐ท', '๐ฟ', '๐ป', 'โ', '๐ก', '๐บ', '๐ป', '๐', '๐', 'โณ', 'โฐ', 'โ', '๐', '๐', '๐', '๐ก', '๐ฆ', '๐', '๐', '๐ฟ', '๐ฝ', '๐ง', '๐จ', '๐ช', '๐ฌ', '๐ฃ', '๐ซ', '๐ช', '๐', '๐', '๐ฐ', '๐ต', '๐ณ', 'โ', '๐ซ', '๐ฆ', '๐
', '๐', 'โ', '๐', '๐', 'โ', 'โ', '๐', '๐', '๐ฌ', '๐ญ', '๐จ', '๐ฌ', '๐ค', '๐ง', '๐ต', '๐น', '๐ป', '๐บ', '๐ธ', '๐พ', '๐ฎ', '๐', '๐ฒ', '๐ฏ', '๐', '๐', 'โฝ', 'โพ', '๐พ', '๐ฑ', '๐', '๐ณ', '๐', '๐', '๐', '๐', '๐', 'โ', '๐ผ', '๐บ', '๐ท', '๐ด', '๐', '๐', '๐', '๐', '๐ฑ', '๐', '๐', '๐ก', '๐ณ', '๐', '๐ฉ', '๐ฆ', '๐', '๐ฐ', '๐ช', '๐ซ', '๐ญ', '๐ฏ', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐
', '๐ฝ', '๐ก', '๐ฅ', '๐ฆ', 'โช', '๐ฐ', 'โบ', '๐ญ', '๐ป', '๐ฝ', '๐ ', '๐ก', 'โฒ', '๐ข', '๐ข', '๐ค', 'โ', '๐', 'โ', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐', '๐จ', '๐', '๐', '๐', '๐ฒ', '๐ ', '๐', '๐ฆ', 'โ ', '๐ง', 'โฝ', '๐ฐ', '๐ฟ', '๐ช', '๐ญ', '๐ฏ๐ต', '๐ฐ๐ท', '๐ฉ๐ช', '๐จ๐ณ', '๐บ๐ธ', '๐ซ๐ท', '๐ช๐ธ', '๐ฎ๐น', '๐ท๐บ', '๐ฌ๐ง', '1โฃ', '2โฃ', '3โฃ', '4โฃ', '5โฃ', '6โฃ', '7โฃ', '8โฃ', '9โฃ', '0โฃ', '๐', 'โ', 'โ', 'โฅ', 'โฆ', '๐ฏ', '๐', '๐ฑ', '๐ด', '๐ต', '๐ถ', '๐ท'];
|
||||
|
||||
public function request_call($user)
|
||||
{
|
||||
@ -55,7 +55,7 @@ trait AuthKeyHandler
|
||||
if ($this->settings['calls']['accept_calls'] === false) {
|
||||
return false;
|
||||
}
|
||||
if (is_array($this->settings['calls']['accept_calls']) && !in_array($this->settings['calls']['accept_calls'])) {
|
||||
if ($this->is_array($this->settings['calls']['accept_calls']) && !$this->in_array($this->settings['calls']['accept_calls'])) {
|
||||
return false;
|
||||
}
|
||||
if ($params['protocol']['udp_p2p'] && !$this->settings['calls']['allow_p2p']) {
|
||||
|
@ -1,25 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
Copyright 2016-2017 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 the MadelineProto.
|
||||
If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
class VolatileSerializer
|
||||
{
|
||||
public function wakeup()
|
||||
{
|
||||
$elements = $this;
|
||||
$elements['_'] = 'pony';
|
||||
$class = '\\'.str_replace('Serializable', '', get_class($this));
|
||||
|
||||
return new $class($elements);
|
||||
}
|
||||
}
|
@ -41,6 +41,7 @@ if ($MadelineProto === false) {
|
||||
'phone_number' => getenv('MTPROTO_NUMBER'),
|
||||
]
|
||||
);
|
||||
|
||||
\danog\MadelineProto\Logger::log([$checkedPhone], \danog\MadelineProto\Logger::NOTICE);
|
||||
$sentCode = $MadelineProto->phone_login(getenv('MTPROTO_NUMBER'));
|
||||
\danog\MadelineProto\Logger::log([$sentCode], \danog\MadelineProto\Logger::NOTICE);
|
||||
|
Loadingโฆ
Reference in New Issue
Block a user