Refactor public API: full encapsulation and strict typing

This commit is contained in:
Daniil Gentili 2019-12-28 16:07:09 +01:00
parent 9899d34b11
commit 894470a147
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
25 changed files with 1157 additions and 782 deletions

View File

@ -21,6 +21,7 @@ namespace danog\MadelineProto;
use Amp\Promise;
use danog\MadelineProto\TL\TL;
use danog\MadelineProto\TL\TLCallback;
use phpDocumentor\Reflection\DocBlockFactory;
class AnnotationsBuilder
@ -78,9 +79,11 @@ class AnnotationsBuilder
}
/**
* Create file InternalDoc with all interfaces.
* Create internalDoc.
*
* @return void
*/
private function createInternalClasses()
private function createInternalClasses(): void
{
\danog\MadelineProto\Logger::log('Creating internal classes...', \danog\MadelineProto\Logger::NOTICE);
$handle = \fopen($this->output, 'w');
@ -92,6 +95,13 @@ class AnnotationsBuilder
foreach ($methods as $method) {
$ignoreMethods[$method->getName()] = $method->getName();
}
$class = new \ReflectionClass(TLCallback::class);
$methods = $class->getMethods(\ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC);
foreach ($methods as $method) {
$ignoreMethods[$method->getName()] = $method->getName();
}
\fclose($handle);
$handle = \fopen($this->output, 'w');
@ -169,6 +179,9 @@ class AnnotationsBuilder
if (isset($ignoreMethods[$name])) {
continue;
}
if (\strpos($method->getDocComment() ?? '', '@internal') !== false) {
continue;
}
if ($name == 'methodCallAsyncRead') {
$name = 'methodCall';
@ -249,6 +262,13 @@ class AnnotationsBuilder
$doc .= " $ret \$this->__call(__FUNCTION__, $paramList);\n";
$doc .= "}\n";
if (!$method->getDocComment()) {
Logger::log("$name has no PHPDOC!", Logger::FATAL_ERROR);
}
if (!$type) {
Logger::log("$name has no return type!", Logger::FATAL_ERROR);
}
$internalDoc['InternalDoc'][$name]['method'] = $method->getDocComment() ?? '';
$internalDoc['InternalDoc'][$name]['method'] .= "\n ".\implode("\n ", \explode("\n", $doc));
}

View File

@ -635,7 +635,6 @@ class Lang
public static function addToLang(string $key, string $value = '', bool $force = false)
{
if (!isset(\danog\MadelineProto\Lang::$lang['en'][$key]) || $force) {
\var_dump("Adding $key");
\danog\MadelineProto\Lang::$lang['en'][$key] = $value;
\file_put_contents(__DIR__.'/Lang.php', \sprintf(self::$template, \var_export(\danog\MadelineProto\Lang::$lang, true), \var_export(\danog\MadelineProto\Lang::$lang['en'], true)));
}

File diff suppressed because it is too large Load Diff

View File

@ -257,10 +257,10 @@ class Logger
*
* @return void
*/
public function logger($param, int $level = self::NOTICE, string $file = '')
public function logger($param, int $level = self::NOTICE, string $file = ''): void
{
if ($level > $this->level || $this->mode === 0) {
return false;
return;
}
if (!self::$printed) {
self::$printed = true;
@ -274,7 +274,8 @@ class Logger
$this->colors[self::NOTICE] = \implode(';', [self::FOREGROUND['yellow'], self::SET['bold']]);
}
if ($this->mode === 4) {
return \call_user_func_array($this->optional, [$param, $level]);
\call_user_func_array($this->optional, [$param, $level]);
return;
}
$prefix = $this->prefix;
if (\danog\MadelineProto\Magic::$has_thread && \is_object(\Thread::getCurrentThread())) {

View File

@ -581,9 +581,9 @@ class MTProto extends AsyncConstruct implements TLCallback
/**
* Cleanup memory and session file.
*
* @return void
* @return self
*/
public function cleanup()
public function cleanup(): self
{
$this->referenceDatabase = new ReferenceDatabase($this);
$callbacks = [$this, $this->referenceDatabase];
@ -603,13 +603,13 @@ class MTProto extends AsyncConstruct implements TLCallback
*
* @return void
*/
public function logger($param, int $level = Logger::NOTICE, string $file = '')
public function logger($param, int $level = Logger::NOTICE, string $file = ''): void
{
if ($file === null) {
$file = \basename(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php');
}
return isset($this->logger) ? $this->logger->logger($param, $level, $file) : Logger::$default->logger($param, $level, $file);
isset($this->logger) ? $this->logger->logger($param, $level, $file) : Logger::$default->logger($param, $level, $file);
}
/**
@ -767,6 +767,8 @@ class MTProto extends AsyncConstruct implements TLCallback
/**
* Clean up properties from previous versions of MadelineProto.
*
* @internal
*
* @return void
*/
private function cleanupProperties()
@ -1358,7 +1360,7 @@ class MTProto extends AsyncConstruct implements TLCallback
*
* @return void
*/
public function parseSettings(array $settings)
private function parseSettings(array $settings): void
{
$settings = self::getSettings($settings, $this->settings);
if ($settings['app_info'] === null) {
@ -1377,7 +1379,7 @@ class MTProto extends AsyncConstruct implements TLCallback
*
* @return void
*/
public function setupLogger()
public function setupLogger(): void
{
$this->logger = Logger::getLoggerFromSettings($this->settings, isset($this->authorization['user']) ? isset($this->authorization['user']['username']) ? $this->authorization['user']['username'] : $this->authorization['user']['id'] : '');
}
@ -1388,9 +1390,11 @@ class MTProto extends AsyncConstruct implements TLCallback
* @param boolean $de Whether to reset the session ID
* @param boolean $auth_key Whether to reset the auth key
*
* @internal
*
* @return void
*/
public function resetMTProtoSession(bool $de = true, bool $auth_key = false)
public function resetMTProtoSession(bool $de = true, bool $auth_key = false): void
{
if (!\is_object($this->datacenter)) {
throw new Exception(Lang::$current_lang['session_corrupted']);
@ -1440,6 +1444,8 @@ class MTProto extends AsyncConstruct implements TLCallback
/**
* Whether we're initing authorization.
*
* @internal
*
* @return boolean
*/
public function isInitingAuthorization()
@ -1493,7 +1499,7 @@ class MTProto extends AsyncConstruct implements TLCallback
*
* @return void
*/
public function resetSession()
public function resetSession(): void
{
if (isset($this->seqUpdater)) {
$this->seqUpdater->signal(true);
@ -1539,7 +1545,7 @@ class MTProto extends AsyncConstruct implements TLCallback
*
* @return void
*/
public function resetUpdateState()
public function resetUpdateState(): void
{
if (isset($this->seqUpdater)) {
$this->seqUpdater->signal(true);
@ -1571,9 +1577,11 @@ class MTProto extends AsyncConstruct implements TLCallback
*
* @param boolean $anyway Force start update system?
*
* @internal
*
* @return void
*/
public function startUpdateSystem($anyway = false)
public function startUpdateSystem($anyway = false): void
{
if ($this->asyncInitPromise && !$anyway) {
$this->logger("Not starting update system");
@ -1617,9 +1625,11 @@ class MTProto extends AsyncConstruct implements TLCallback
*
* @param mixed $watcherId Watcher ID
*
* @return void
* @internal
*
* @return \Generator<void>
*/
public function getPhoneConfig($watcherId = null)
public function getPhoneConfig($watcherId = null): \Generator
{
if ($this->authorized === self::LOGGED_IN && \class_exists(VoIPServerConfigInternal::class) && !$this->authorization['user']['bot'] && $this->datacenter->getDataCenterConnection($this->settings['connection_settings']['default_dc'])->hasTempAuthKey()) {
$this->logger->logger('Fetching phone config...');
@ -1747,16 +1757,35 @@ class MTProto extends AsyncConstruct implements TLCallback
return $this->authorization['user'];
}
/**
* Called right before serialization of method starts.
*
* Pass the method name
*
* @return array
*/
public function getMethodCallbacks(): array
{
return [];
}
/**
* Called right before serialization of method starts.
*
* Pass the method name
*
* @return array
*/
public function getMethodBeforeCallbacks(): array
{
return [];
}
/**
* Called right after deserialization of object, passing the final object.
*
* @return array
*/
public function getConstructorCallbacks(): array
{
return \array_merge(
@ -1766,16 +1795,38 @@ class MTProto extends AsyncConstruct implements TLCallback
);
}
/**
* Called right before deserialization of object.
*
* Pass only the constructor name
*
* @return array
*/
public function getConstructorBeforeCallbacks(): array
{
return [];
}
/**
* Called right before serialization of constructor.
*
* Passed the object, will return a modified version.
*
* @return array
*/
public function getConstructorSerializeCallbacks(): array
{
return [];
}
/**
* Called if objects of the specified type cannot be serialized.
*
* Passed the unserializable object,
* will try to convert it to an object of the proper type.
*
* @return array
*/
public function getTypeMismatchCallbacks(): array
{
return \array_merge(

View File

@ -56,7 +56,7 @@ trait Files
* @param callable $cb Callback (DEPRECATED, use FileCallbackInterface)
* @param boolean $encrypted Whether to encrypt file for secret chats
*
* @return array
* @return \Generator<array>
*/
public function upload($file, string $file_name = '', $cb = null, bool $encrypted = false): \Generator
{
@ -229,9 +229,9 @@ trait Files
* @param boolean $seekable Whether chunks can be fetched out of order
* @param boolean $encrypted Whether to encrypt file for secret chats
*
* @return array
* @return \Generator<array>
*/
public function uploadFromCallable($callable, int $size, string $mime, string $file_name = '', $cb = null, bool $seekable = true, bool $encrypted = false)
public function uploadFromCallable($callable, int $size, string $mime, string $file_name = '', $cb = null, bool $seekable = true, bool $encrypted = false): \Generator
{
if (\is_object($callable) && $callable instanceof FileCallbackInterface) {
$cb = $callable;
@ -360,9 +360,9 @@ trait Files
* @param string $file_name File name
* @param callable $cb Callback (DEPRECATED, use FileCallbackInterface)
*
* @return array
* @return \Generator<array>
*/
public function uploadEncrypted($file, string $file_name = '', $cb = null)
public function uploadEncrypted($file, string $file_name = '', $cb = null): \Generator
{
return $this->upload($file, $file_name, $cb, true);
}
@ -374,9 +374,9 @@ trait Files
* @param callable $cb Callback (DEPRECATED, use FileCallbackInterface)
* @param boolean $encrypted Whether to encrypt file for secret chats
*
* @return array
* @return \Generator<array>
*/
public function uploadFromTgfile($media, $cb = null, bool $encrypted = false)
public function uploadFromTgfile($media, $cb = null, bool $encrypted = false): \Generator
{
if (\is_object($media) && $media instanceof FileCallbackInterface) {
$cb = $media;
@ -447,7 +447,7 @@ trait Files
return $res;
}
public function genAllFile($media)
private function genAllFile($media)
{
$res = [$this->TL->getConstructors()->findByPredicate($media['_'])['type'] => $media];
switch ($media['_']) {
@ -540,7 +540,14 @@ trait Files
return $res;
}
public function getFileInfo($constructor)
/**
* Get info about file.
*
* @param mixed $constructor File ID
*
* @return \Generator<array>
*/
public function getFileInfo($constructor): \Generator
{
if (\is_string($constructor)) {
$constructor = $this->unpackFileId($constructor)['MessageMedia'];
@ -932,6 +939,15 @@ trait Files
header('Content-Length: '.$info['size']);
header('Content-Type: '.$info['mime']);
}*/
/**
* Extract photo size.
*
* @param mixed $photo Photo
*
* @internal
*
* @return void
*/
public function extractPhotosize($photo)
{
}
@ -1224,7 +1240,7 @@ trait Files
];
}
$x = 0;
//$x = 0;
while (true) {
try {
$res = yield $this->methodCallAsyncRead(
@ -1241,7 +1257,7 @@ trait Files
break;
} catch (\danog\MadelineProto\RPCErrorException $e) {
if (\strpos($e->rpc, 'FLOOD_WAIT_') === 0) {
if ($x++ === 5) {
/*if ($x++ === 5) {
if (isset($message_media['MessageMedia']) && !$this->authorization['user']['bot'] && $this->settings['download']['report_broken_media']) {
try {
yield $this->methodCallAsyncRead('messages.sendMedia', ['peer' => 'support', 'media' => $message_media['MessageMedia'], 'message' => "I can't download this file, could you please help?"], ['datacenter' => $this->datacenter->curdc]);
@ -1253,7 +1269,7 @@ trait Files
}
throw new \danog\MadelineProto\Exception('The media server where this file is hosted is offline/overloaded, please try again later. Send the media to the telegram devs or to @danogentili to fix this.');
}
}*/
yield Tools::sleep(1);
continue;
}

View File

@ -51,7 +51,7 @@ trait PeerHandler
*
* @return int
*/
public static function fromSupergroup($id)
public static function fromSupergroup($id): int
{
return -$id - \pow(10, (int) \floor(\log(-$id, 10)));
}
@ -70,12 +70,28 @@ trait PeerHandler
return ($log - \intval($log)) * 1000 < 10;
}
public function addSupport($support)
/**
* Set support info.
*
* @param array $support Support info
*
* @internal
*
* @return void
*/
public function addSupport(array $support): void
{
$this->supportUser = $support['user']['id'];
}
public function addUser($user)
/**
* Add user info.
*
* @param array $user User info
*
* @return void
*/
public function addUser(array $user): void
{
if (!isset($user['access_hash']) && !($user['min'] ?? false)) {
if (isset($this->chats[$user['id']]['access_hash']) && $this->chats[$user['id']]['access_hash']) {
@ -117,11 +133,19 @@ trait PeerHandler
break;
default:
throw new \danog\MadelineProto\Exception('Invalid user provided', $user);
break;
}
}
public function addChat($chat)
/**
* Add chat to database.
*
* @param array $chat Chat
*
* @internal
*
* @return void
*/
public function addChat($chat): \Generator
{
switch ($chat['_']) {
case 'chat':
@ -182,7 +206,7 @@ trait PeerHandler
}
}
public function cachePwrChat($id, $full_fetch, $send)
private function cachePwrChat($id, $full_fetch, $send)
{
\danog\MadelineProto\Tools::callFork((function () use ($id, $full_fetch, $send) {
try {
@ -220,7 +244,16 @@ trait PeerHandler
}
}
public function entitiesPeerIsset($entities): \Generator
/**
* Check if all peer entities are in db.
*
* @param array $entities Entity list
*
* @internal
*
* @return \Generator<bool>
*/
public function entitiesPeerIsset(array $entities): \Generator
{
try {
foreach ($entities as $entity) {
@ -237,7 +270,16 @@ trait PeerHandler
return true;
}
public function fwdPeerIsset($fwd): \Generator
/**
* Check if fwd peer is set.
*
* @param array $fwd Forward info
*
* @internal
*
* @return \Generator
*/
public function fwdPeerIsset(array $fwd): \Generator
{
try {
if (isset($fwd['user_id']) && !yield $this->peerIsset($fwd['user_id'])) {
@ -260,7 +302,7 @@ trait PeerHandler
*
* @return ?int
*/
public function getFolderId($id)
public function getFolderId($id): ?int
{
if (!\is_array($id)) {
return null;
@ -593,7 +635,7 @@ trait PeerHandler
throw new \danog\MadelineProto\Exception('This peer is not present in the internal peer database');
}
public function genAll($constructor, $folder_id = null)
private function genAll($constructor, $folder_id = null)
{
$res = [$this->TL->getConstructors()->findByPredicate($constructor['_'])['type'] => $constructor];
switch ($constructor['_']) {
@ -655,7 +697,14 @@ trait PeerHandler
return $res;
}
public function fullChatLastUpdated($id)
/**
* When were full info for this chat last cached.
*
* @param mixed $id Chat ID
*
* @return integer
*/
public function fullChatLastUpdated($id): int
{
return isset($this->full_chats[$id]['last_update']) ? $this->full_chats[$id]['last_update'] : 0;
}
@ -845,7 +894,7 @@ trait PeerHandler
return $res;
}
public function recurseAlphabetSearchParticipants($channel, $filter, $q, $total_count, &$res)
private function recurseAlphabetSearchParticipants($channel, $filter, $q, $total_count, &$res)
{
if (!yield $this->fetchParticipants($channel, $filter, $q, $total_count, $res)) {
return false;
@ -856,7 +905,7 @@ trait PeerHandler
}
}
public function fetchParticipants($channel, $filter, $q, $total_count, &$res)
private function fetchParticipants($channel, $filter, $q, $total_count, &$res)
{
$offset = 0;
$limit = 200;
@ -942,12 +991,12 @@ trait PeerHandler
return $has_more;
}
public function fetchParticipantsCache($channel, $filter, $q, $offset, $limit)
private function fetchParticipantsCache($channel, $filter, $q, $offset, $limit)
{
return $this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit];
}
public function storeParticipantsCache($gres, $channel, $filter, $q, $offset, $limit)
private function storeParticipantsCache($gres, $channel, $filter, $q, $offset, $limit)
{
//return;
unset($gres['users']);
@ -960,12 +1009,12 @@ trait PeerHandler
$this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit] = $gres;
}
public function getParticipantsHash($channel, $filter, $q, $offset, $limit)
private function getParticipantsHash($channel, $filter, $q, $offset, $limit)
{
return isset($this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit]) ? $this->channel_participants[$channel['channel_id']][$filter][$q][$offset][$limit]['hash'] : 0;
}
public function storeDb($res, $force = false)
private function storeDb($res, $force = false)
{
$settings = isset($this->settings['connection_settings'][$this->datacenter->curdc]) ? $this->settings['connection_settings'][$this->datacenter->curdc] : $this->settings['connection_settings']['all'];
if (!isset($this->settings['pwr']) || $this->settings['pwr']['pwr'] === false || $settings['test_mode']) {
@ -1007,7 +1056,14 @@ trait PeerHandler
}
}
public function resolveUsername($username)
/**
* Resolve username (use getInfo instead).
*
* @param string $username Username
*
* @return \Generator
*/
public function resolveUsername(string $username): \Generator
{
try {
$this->caching_simple_username[$username] = true;

View File

@ -35,6 +35,15 @@ trait UpdateHandler
public $updates = [];
public $updates_key = 0;
/**
* PWR update handler.
*
* @param array $update Update
*
* @internal
*
* @return void
*/
public function pwrUpdateHandler($update)
{
if (isset($this->settings['pwr']['updateHandler'])) {
@ -48,7 +57,16 @@ trait UpdateHandler
}
}
public function getUpdatesUpdateHandler($update)
/**
* Getupdates update handler.
*
* @param array $update Update
*
* @internal
*
* @return void
*/
public function getUpdatesUpdateHandler(array $update): void
{
if (!$this->settings['updates']['handle_updates']) {
return;
@ -56,7 +74,16 @@ trait UpdateHandler
$this->updates[$this->updates_key++] = $update;
}
public function getUpdates($params = [])
/**
* Get updates.
*
* @param array $params Params
*
* @internal
*
* @return \Generator<array>
*/
public function getUpdates($params = []): \Generator
{
if (!$this->settings['updates']['handle_updates']) {
$this->settings['updates']['handle_updates'] = true;
@ -98,7 +125,14 @@ trait UpdateHandler
public $update_resolved = false;
public $update_deferred;
public function waitUpdate()
/**
* Wait for update.
*
* @internal
*
* @return \Generator
*/
public function waitUpdate(): \Generator
{
if (!$this->update_deferred) {
$this->update_deferred = new Deferred();
@ -108,7 +142,14 @@ trait UpdateHandler
$this->update_deferred = new Deferred();
}
public function signalUpdate()
/**
* Signal update.
*
* @internal
*
* @return void
*/
public function signalUpdate(): void
{
if (!$this->update_deferred) {
$this->update_deferred = new Deferred();
@ -121,7 +162,17 @@ trait UpdateHandler
});
}
public function checkMsgId($message)
/**
* Check message ID.
*
* @param array $message Message
*
* @internal
*
* @return boolean
*/
public function checkMsgId(array $message): bool
{
if (!isset($message['to_id'])) {
return true;
@ -144,6 +195,13 @@ trait UpdateHandler
return false;
}
/**
* Get channel state.
*
* @internal
*
* @return UpdatesState|UpdatesState[]
*/
public function loadUpdateState()
{
if (!$this->got_state) {
@ -154,17 +212,41 @@ trait UpdateHandler
return $this->channels_state->get(false);
}
/**
* Load channel state.
*
* @param ?int $channelId Channel ID
* @param array $init Init
*
* @internal
*
* @return UpdatesState|UpdatesState[]
*/
public function loadChannelState($channelId = null, $init = [])
{
return $this->channels_state->get($channelId, $init);
}
/**
* Get channel states.
*
* @internal
*
* @return CombinedUpdatesState
*/
public function getChannelStates()
{
return $this->channels_state;
}
public function getUpdatesState()
/**
* Get update state.
*
* @internal
*
* @return \Generator
*/
public function getUpdatesState(): \Generator
{
$data = yield $this->methodCallAsyncRead('updates.getState', [], ['datacenter' => $this->settings['connection_settings']['default_dc']]);
yield $this->getCdnConfig($this->settings['connection_settings']['default_dc']);
@ -173,7 +255,17 @@ trait UpdateHandler
}
public function handleUpdates($updates, $actual_updates = null)
/**
* Undocumented function.
*
* @param array $updates Updates
* @param array $actual_updates Actual updates for deferred
*
* @internal
*
* @return \Generator
*/
public function handleUpdates($updates, $actual_updates = null): \Generator
{
if (!$this->settings['updates']['handle_updates']) {
return;
@ -252,7 +344,16 @@ trait UpdateHandler
break;
}
}
public function saveUpdate($update)
/**
* Save update.
*
* @param array $update Update to save
*
* @internal
*
* @return \Generator
*/
public function saveUpdate(array $update): \Generator
{
if ($update['_'] === 'updateConfig') {
$this->config['expires'] = 0;
@ -388,14 +489,21 @@ trait UpdateHandler
}
}
public function pwrWebhook($update)
/**
* Send update to webhook.
*
* @param array $update Update
*
* @return void
*/
private function pwrWebhook(array $update): void
{
$payload = \json_encode($update);
//$this->logger->logger($update, $payload, json_last_error());
if ($payload === '') {
$this->logger->logger('EMPTY UPDATE');
return false;
return;
}
\danog\MadelineProto\Tools::callFork((function () use ($payload) {
$request = new Request($this->hook_url, 'POST');

View File

@ -24,7 +24,17 @@ namespace danog\MadelineProto\SecretChats;
*/
trait MessageHandler
{
public function encryptSecretMessage($chat_id, $message)
/**
* Encrypt secret chat message.
*
* @param integer $chat_id Chat ID
* @param array $message Message to encrypt
*
* @internal
*
* @return \Generator
*/
public function encryptSecretMessage(int $chat_id, array $message): \Generator
{
if (!isset($this->secret_chats[$chat_id])) {
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $chat_id));
@ -61,7 +71,7 @@ trait MessageHandler
return $message;
}
public function handleEncryptedUpdate($message, $test = false)
private function handleEncryptedUpdate(array $message): \Generator
{
if (!isset($this->secret_chats[$message['message']['chat_id']])) {
$this->logger->logger(\sprintf(\danog\MadelineProto\Lang::$current_lang['secret_chat_skipping'], $message['message']['chat_id']));
@ -122,7 +132,7 @@ trait MessageHandler
yield $this->handleDecryptedUpdate($message);
}
public function tryMTProtoV1Decrypt($message_key, $chat_id, $old, $encrypted_data)
private function tryMTProtoV1Decrypt($message_key, $chat_id, $old, $encrypted_data)
{
list($aes_key, $aes_iv) = $this->oldAesCalculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], true);
$decrypted_data = $this->igeDecrypt($encrypted_data, $aes_key, $aes_iv);
@ -144,7 +154,7 @@ trait MessageHandler
return $message_data;
}
public function tryMTProtoV2Decrypt($message_key, $chat_id, $old, $encrypted_data)
private function tryMTProtoV2Decrypt($message_key, $chat_id, $old, $encrypted_data)
{
list($aes_key, $aes_iv) = $this->aesCalculate($message_key, $this->secret_chats[$chat_id][$old ? 'old_key' : 'key']['auth_key'], !$this->secret_chats[$chat_id]['admin']);
$decrypted_data = $this->igeDecrypt($encrypted_data, $aes_key, $aes_iv);

View File

@ -24,7 +24,7 @@ namespace danog\MadelineProto\SecretChats;
*/
trait ResponseHandler
{
public function handleDecryptedUpdate($update)
private function handleDecryptedUpdate($update)
{
/*if (isset($update['message']['decrypted_message']['random_bytes']) && strlen($update['message']['decrypted_message']['random_bytes']) < 15) {
throw new \danog\MadelineProto\ResponseException(\danog\MadelineProto\Lang::$current_lang['rand_bytes_too_short']);

View File

@ -24,7 +24,7 @@ namespace danog\MadelineProto\SecretChats;
*/
trait SeqNoHandler
{
public function checkSecretInSeqNo($chat_id, $seqno)
private function checkSecretInSeqNo($chat_id, $seqno)
{
$seqno = ($seqno - $this->secret_chats[$chat_id]['out_seq_no_x']) / 2;
$last = 0;
@ -47,7 +47,7 @@ trait SeqNoHandler
return true;
}
public function checkSecretOutSeqNo($chat_id, $seqno)
private function checkSecretOutSeqNo($chat_id, $seqno)
{
$seqno = ($seqno - $this->secret_chats[$chat_id]['in_seq_no_x']) / 2;
$C = 0;
@ -78,12 +78,12 @@ trait SeqNoHandler
return true;
}
public function generateSecretInSeqNo($chat)
private function generateSecretInSeqNo($chat)
{
return $this->secret_chats[$chat]['layer'] > 8 ? $this->secret_chats[$chat]['in_seq_no'] * 2 + $this->secret_chats[$chat]['in_seq_no_x'] : -1;
}
public function generateSecretOutSeqNo($chat)
private function generateSecretOutSeqNo($chat)
{
return $this->secret_chats[$chat]['layer'] > 8 ? $this->secret_chats[$chat]['out_seq_no'] * 2 + $this->secret_chats[$chat]['out_seq_no_x'] : -1;
}

View File

@ -23,12 +23,19 @@ use danog\MadelineProto\Logger;
trait BotAPI
{
public function htmlEntityDecode($stuff)
private function htmlEntityDecode($stuff)
{
return \html_entity_decode(\preg_replace('#< *br */? *>#', "\n", $stuff));
}
public function mbStrlen($text)
/**
* Get Telegram UTF-8 length of string.
*
* @param string $text Text
*
* @return int
*/
public function mbStrlen(string $text): int
{
$length = 0;
$textlength = \strlen($text);
@ -42,7 +49,16 @@ trait BotAPI
return $length;
}
public function mbSubstr($text, $offset, $length = null)
/**
* Telegram UTF-8 multibyte substring.
*
* @param string $text Text to substring
* @param integer $offset Offset
* @param ?int $length Length
*
* @return string
*/
public function mbSubstr(string $text, int $offset, $length = null): string
{
$mb_text_length = $this->mbStrlen($text);
if ($offset < 0) {
@ -75,7 +91,15 @@ trait BotAPI
return $new_text;
}
public function mbStrSplit($text, $length)
/**
* Telegram UTF-8 multibyte split.
*
* @param string $text Text
* @param integer $length Length
*
* @return string
*/
public function mbStrSplit(string $text, int $length): string
{
$tlength = \mb_strlen($text, 'UTF-8');
$result = [];
@ -86,7 +110,7 @@ trait BotAPI
return $result;
}
public function parseButtons($rows)
private function parseButtons($rows)
{
$newrows = [];
$key = 0;
@ -125,7 +149,7 @@ trait BotAPI
return $newrows;
}
public function parseReplyMarkup($markup)
private function parseReplyMarkup($markup)
{
if (isset($markup['force_reply']) && $markup['force_reply']) {
$markup['_'] = 'replyKeyboardForceReply';
@ -157,7 +181,15 @@ trait BotAPI
return $markup;
}
public function MTProtoToBotAPI($data, $sent_arguments = [])
/**
* Convert MTProto parameters to bot API parameters.
*
* @param array $data Data
* @param array $sent_arguments Sent arguments
*
* @return \Generator<array>
*/
public function MTProtoToBotAPI(array $data, array $sent_arguments = []): \Generator
{
$newd = [];
if (!isset($data['_'])) {
@ -382,7 +414,14 @@ trait BotAPI
}
}
public function botAPIToMTProto($arguments)
/**
* Convert bot API parameters to MTProto parameters.
*
* @param array $arguments Arguments
*
* @return \Generator<array>
*/
public function botAPIToMTProto(array $arguments): \Generator
{
foreach (self::BOTAPI_PARAMS_CONVERSION as $bot => $mtproto) {
if (isset($arguments[$bot]) && !isset($arguments[$mtproto])) {
@ -400,7 +439,7 @@ trait BotAPI
return $arguments;
}
public function parseNode($node, &$entities, &$new_message, &$offset)
private function parseNode($node, &$entities, &$new_message, &$offset)
{
switch ($node->nodeName) {
case 'br':
@ -518,7 +557,7 @@ trait BotAPI
}
}
public function parseMode($arguments)
private function parseMode($arguments)
{
if ($arguments['message'] === '' || !isset($arguments['message']) || !isset($arguments['parse_mode'])) {
return $arguments;
@ -555,7 +594,7 @@ trait BotAPI
return $arguments;
}
public function splitToChunks($args)
private function splitToChunks($args)
{
$args = yield $this->parseMode($args);
if (!isset($args['entities'])) {
@ -665,7 +704,7 @@ trait BotAPI
return $multiple_args;
}
public function multipleExplodeKeepDelimiters($delimiters, $string)
private function multipleExplodeKeepDelimiters($delimiters, $string)
{
$initialArray = \explode(\chr(1), \str_replace($delimiters, \chr(1), $string));
$finalArray = [];
@ -681,7 +720,7 @@ trait BotAPI
return $finalArray;
}
public function htmlFixtags($text)
private function htmlFixtags($text)
{
$diff = 0;
\preg_match_all('#(.*?)(<(\bu\b|\bs\b|\ba\b|\bb\b|\bstrong\b|\bblockquote\b|\bstrike\b|\bdel\b|\bem\b|i|\bcode\b|\bpre\b)[^>]*>)(.*?)([<]\s*/\s*\3[>])#is', $text, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
@ -724,7 +763,7 @@ trait BotAPI
return \htmlentities($text);
}
public function buildRows($button_list)
private function buildRows($button_list)
{
$end = false;
$rows = [];

View File

@ -21,7 +21,7 @@ namespace danog\MadelineProto\TL\Conversion;
trait BotAPIFiles
{
public function photosizeToBotAPI($photoSize, $photo, $thumbnail = false)
private function photosizeToBotAPI($photoSize, $photo, $thumbnail = false)
{
$ext = '.jpg';//$this->getExtensionFromLocation(['_' => 'inputFileLocation', 'volume_id' => $photoSize['location']['volume_id'], 'local_id' => $photoSize['location']['local_id'], 'secret' => $photoSize['location']['secret'], 'dc_id' => $photoSize['location']['dc_id']], '.jpg');
$photoSize['location']['access_hash'] = $photo['access_hash'] ?? 0;
@ -41,7 +41,14 @@ trait BotAPIFiles
];
}
public function unpackFileId($file_id)
/**
* Unpack bot API file ID.
*
* @param string $file_id Bot API file ID
*
* @return array Unpacked file ID
*/
public function unpackFileId(string $file_id): array
{
$file_id = \danog\MadelineProto\Tools::rleDecode(\danog\MadelineProto\Tools::base64urlDecode($file_id));
if ($file_id[\strlen($file_id) - 1] !== \chr(2)) {

View File

@ -14,22 +14,39 @@ If not, see <http://www.gnu.org/licenses/>.
namespace danog\MadelineProto\TL\Conversion;
use danog\MadelineProto\MTProto;
/**
* Manages generation of extensions for files.
*/
trait Extension
{
public function getMimeFromExtension($extension, $default)
/**
* Get mime type from file extension.
*
* @param string $extension File extension
* @param string $default Default mime type
*
* @return string
*/
public function getMimeFromExtension(string $extension, string $default): string
{
$ext = \ltrim($extension, '.');
if (isset(self::ALL_MIMES[$ext])) {
return self::ALL_MIMES[$ext][0];
if (isset(MTProto::ALL_MIMES[$ext])) {
return MTProto::ALL_MIMES[$ext][0];
}
return $default;
}
public function getExtensionFromMime($mime)
/**
* Get extension from mime type.
*
* @param string $mime MIME type
*
* @return string
*/
public function getExtensionFromMime(string $mime): string
{
foreach (self::ALL_MIMES as $key => $value) {
if (\array_search($mime, $value) !== false) {
@ -40,7 +57,15 @@ trait Extension
return '';
}
public function getExtensionFromLocation($location, $default)
/**
* Get extension from file location.
*
* @param mixed $location File location
* @param string $default Default extension
*
* @return string
*/
public function getExtensionFromLocation($location, string $default): string
{
return $default;
//('upload.getFile', ['location' => $location, 'offset' => 0, 'limit' => 2], ['heavy' => true, 'datacenter' => $location['dc_id']]);
@ -69,14 +94,28 @@ trait Extension
}
}
public function getMimeFromFile($file)
/**
* Get mime type of file.
*
* @param string $file File
*
* @return string
*/
public function getMimeFromFile(string $file): string
{
$finfo = new \finfo(FILEINFO_MIME_TYPE);
return $finfo->file($file);
}
public function getMimeFromBuffer($buffer)
/**
* Get mime type from buffer.
*
* @param string $buffer Buffer
*
* @return string
*/
public function getMimeFromBuffer(string $buffer): string
{
$finfo = new \finfo(FILEINFO_MIME_TYPE);

View File

@ -21,7 +21,15 @@ namespace danog\MadelineProto\TL\Conversion;
trait TD
{
public function tdcliToTd(&$params, $key = null)
/**
* Convert tdcli parameters to tdcli.
*
* @param array $params Params
* @param array $key Key
*
* @return array
*/
public function tdcliToTd(&$params, $key = null): array
{
if (!\is_array($params)) {
return $params;
@ -44,7 +52,14 @@ trait TD
return $params;
}
public function tdToMTProto($params)
/**
* Convert TD to MTProto parameters.
*
* @param array $params Parameters
*
* @return \Generator<array>
*/
public function tdToMTProto(array $params): \Generator
{
$newparams = ['_' => self::REVERSE[$params['_']]];
foreach (self::TD_PARAMS_CONVERSION[$newparams['_']] as $td => $mtproto) {
@ -75,12 +90,26 @@ trait TD
return $newparams;
}
public function MTProtoToTdcli($params)
/**
* MTProto to TDCLI params.
*
* @param mixed $params Params
*
* @return \Generator
*/
public function MTProtoToTdcli($params): \Generator
{
return $this->tdToTdcli(yield $this->MTProtoToTd($params));
}
public function MTProtoToTd(&$params)
/**
* MTProto to TD params.
*
* @param mixed $params Params
*
* @return \Generator
*/
public function MTProtoToTd(&$params): \Generator
{
if (!\is_array($params)) {
return $params;
@ -163,6 +192,13 @@ trait TD
return $newparams;
}
/**
* Convert TD parameters to tdcli.
*
* @param mixed $params Parameters
*
* @return mixed
*/
public function tdToTdcli($params)
{
if (!\is_array($params)) {

View File

@ -45,7 +45,7 @@ interface TLCallback
*
* Pass the method name and arguments
*
* @var array
* @return array
*/
public function getMethodCallbacks(): array;
@ -54,14 +54,14 @@ interface TLCallback
*
* Pass the method name
*
* @var array
* @return array
*/
public function getMethodBeforeCallbacks(): array;
/**
* Called right after deserialization of object, passing the final object.
*
* @var array
* @return array
*/
public function getConstructorCallbacks(): array;
@ -70,7 +70,7 @@ interface TLCallback
*
* Pass only the constructor name
*
* @var array
* @return array
*/
public function getConstructorBeforeCallbacks(): array;
@ -79,7 +79,7 @@ interface TLCallback
*
* Passed the object, will return a modified version.
*
* @var array
* @return array
*/
public function getConstructorSerializeCallbacks(): array;
@ -89,7 +89,7 @@ interface TLCallback
* Passed the unserializable object,
* will try to convert it to an object of the proper type.
*
* @var array
* @return array
*/
public function getTypeMismatchCallbacks(): array;
}

View File

@ -480,7 +480,7 @@ trait Tools
*
* @return void
*/
public static function callForkDefer($promise)
public static function callForkDefer($promise): void
{
Loop::defer([__CLASS__, 'callFork'], $promise);
}
@ -493,7 +493,7 @@ trait Tools
*
* @return void
*/
public static function rethrow(\Throwable $e, $file = '')
public static function rethrow(\Throwable $e, $file = ''): void
{
$zis = isset($this) ? $this : null;
$logger = isset($zis->logger) ? $zis->logger : Logger::$default;
@ -593,6 +593,8 @@ trait Tools
* @param integer $operation Locking mode
* @param float $polling Polling interval
*
* @internal Generator function
*
* @return \Generator
*/
public static function flockGenerator(string $file, int $operation, float $polling): \Generator
@ -646,6 +648,8 @@ trait Tools
*
* @param string $prompt Prompt
*
* @internal Generator function
*
* @return \Generator
*/
public static function readLineGenerator(string $prompt = ''): \Generator

View File

@ -29,22 +29,57 @@ trait AuthKeyHandler
{
private $calls = [];
/**
* Request call (synchronous).
*
* @param mixed $user User info
*
* @internal
*
* @return \danog\MadelineProto\VoIPController
*/
public function requestCall($user)
{
return \danog\MadelineProto\Tools::wait($this->requestCallAsync($user));
}
public function acceptCall($user)
/**
* Accept call (synchronous).
*
* @param mixed $user Accept call
*
* @internal
*
* @return bool
*/
public function acceptCall($user): bool
{
return \danog\MadelineProto\Tools::wait($this->acceptCallAsync($user));
}
public function discardCall($call, $reason, $rating = [], $need_debug = true)
/**
* Discard call (synchronous).
*
* @param array $call Call
* @param string $reason Discard reason
* @param array $rating Rating
* @param boolean $need_debug Need debug?
*
* @return array
*/
public function discardCall($call, $reason, $rating = [], $need_debug = true): void
{
return \danog\MadelineProto\Tools::wait($this->discardCallAsync($call, $reason, $rating, $need_debug));
\danog\MadelineProto\Tools::wait($this->discardCallAsync($call, $reason, $rating, $need_debug));
}
public function requestCallAsync($user)
/**
* Request VoIP call.
*
* @param mixed $user User
*
* @return void
*/
public function requestCallAsync($user): \Generator
{
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
throw \danog\MadelineProto\Exception::extension('libtgvoip');
@ -71,7 +106,14 @@ trait AuthKeyHandler
return $controller;
}
public function acceptCallAsync($call)
/**
* Accept call.
*
* @param array $call Call
*
* @return \Generator
*/
public function acceptCallAsync($call): \Generator
{
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
throw new \danog\MadelineProto\Exception();
@ -111,7 +153,14 @@ trait AuthKeyHandler
return true;
}
public function confirmCall($params)
/**
* Confirm call.
*
* @param array $params Params
*
* @return \Generator
*/
public function confirmCall($params): \Generator
{
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
throw \danog\MadelineProto\Exception::extension('libtgvoip');
@ -160,7 +209,14 @@ trait AuthKeyHandler
return $res;
}
public function completeCall($params)
/**
* Complete call handshake.
*
* @param array $params Params
*
* @return \Generator
*/
public function completeCall($params): \Generator
{
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
throw \danog\MadelineProto\Exception::extension('libtgvoip');
@ -195,7 +251,14 @@ trait AuthKeyHandler
return $this->calls[$params['id']]->startTheMagic();
}
public function callStatus($id)
/**
* Get call status.
*
* @param array $id Call ID
*
* @return integer
*/
public function callStatus($id): int
{
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
throw \danog\MadelineProto\Exception::extension('libtgvoip');
@ -207,7 +270,14 @@ trait AuthKeyHandler
return \danog\MadelineProto\VoIP::CALL_STATE_NONE;
}
public function getCall($call)
/**
* Get call info.
*
* @param mixed $call Call ID
*
* @return array
*/
public function getCall($call): array
{
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
throw \danog\MadelineProto\Exception::extension('libtgvoip');
@ -216,7 +286,17 @@ trait AuthKeyHandler
return $this->calls[$call];
}
public function discardCallAsync($call, $reason, $rating = [], $need_debug = true)
/**
* Discard call.
*
* @param array $call Call
* @param string $reason Discard reason
* @param array $rating Rating
* @param boolean $need_debug Need debug?
*
* @return \Generator
*/
public function discardCallAsync($call, $reason, $rating = [], $need_debug = true): \Generator
{
if (!\class_exists('\\danog\\MadelineProto\\VoIP')) {
throw \danog\MadelineProto\Exception::extension('libtgvoip');
@ -249,7 +329,12 @@ trait AuthKeyHandler
}
unset($this->calls[$call['id']]);
}
public function checkCalls()
/**
* Check state of calls.
*
* @return void
*/
public function checkCalls(): void
{
\array_walk($this->calls, function ($controller, $id) {
if ($controller->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_ENDED) {

View File

@ -108,7 +108,7 @@ Note that you can also provide the API parameters directly in the code using the
exit;
}
public function webAPIPhoneLogin($settings)
private function webAPIPhoneLogin($settings)
{
try {
$this->my_telegram_org_wrapper = new \danog\MadelineProto\MyTelegramOrgWrapper($settings);
@ -119,7 +119,7 @@ Note that you can also provide the API parameters directly in the code using the
}
}
public function webAPICompleteLogin()
private function webAPICompleteLogin()
{
try {
yield $this->my_telegram_org_wrapper->completeLogin($_POST['code']);
@ -130,7 +130,7 @@ Note that you can also provide the API parameters directly in the code using the
}
}
public function webAPICreateApp()
private function webAPICreateApp()
{
try {
$params = $_POST;

View File

@ -38,22 +38,32 @@ trait ApiTemplates
</body>
</html>';
public function webAPIEchoTemplate($message, $form)
private function webAPIEchoTemplate($message, $form)
{
return \sprintf($this->web_api_template, $message, $form);
}
public function getWebAPITemplate()
/**
* Get web API login HTML template string.
*
* @return string
*/
public function getWebAPITemplate(): string
{
return $this->web_template;
}
public function setWebAPITemplate($template)
/**
* Set web API login HTML template string.
*
* @return string
*/
public function setWebAPITemplate(string $template)
{
$this->web_template = $template;
}
public function webAPIEcho($message = '')
private function webAPIEcho(string $message = '')
{
$stdout = getOutputBufferStream();
if (!isset($this->my_telegram_org_wrapper)) {

View File

@ -52,7 +52,7 @@ trait Events
*
* @return void
*/
public function setEventHandler($event_handler)
public function setEventHandler($event_handler): void
{
if (!\class_exists($event_handler) || !\is_subclass_of($event_handler, '\danog\MadelineProto\EventHandler')) {
throw new \danog\MadelineProto\Exception('Wrong event handler was defined');

View File

@ -27,7 +27,13 @@ use danog\MadelineProto\MTProtoTools\PasswordCalculator;
*/
trait Login
{
public function logout()
/**
* Log out currently logged in user.
*
* @return \Generator
*/
public function logout(): \Generator
{
yield $this->methodCallAsyncRead('auth.logOut', [], ['datacenter' => $this->datacenter->curdc]);
$this->resetSession();
@ -37,7 +43,14 @@ trait Login
return true;
}
public function botLogin($token)
/**
* Login as bot.
*
* @param string $token Bot token
*
* @return \Generator
*/
public function botLogin(string $token): \Generator
{
if ($this->authorized === self::LOGGED_IN) {
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['already_loggedIn'], \danog\MadelineProto\Logger::NOTICE);
@ -61,7 +74,15 @@ trait Login
return $this->authorization;
}
public function phoneLogin($number, $sms_type = 5)
/**
* Login as user.
*
* @param string $number Phone number
* @param integer $sms_type SMS type
*
* @return \Generator
*/
public function phoneLogin($number, $sms_type = 5): \Generator
{
if ($this->authorized === self::LOGGED_IN) {
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['already_loggedIn'], \danog\MadelineProto\Logger::NOTICE);
@ -80,7 +101,14 @@ trait Login
return $this->authorization;
}
public function completePhoneLogin($code)
/**
* Complet user login using login code.
*
* @param string $code Login code
*
* @return \Generator
*/
public function completePhoneLogin($code): \Generator
{
if ($this->authorized !== self::WAITING_CODE) {
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['login_code_uncalled']);
@ -131,7 +159,14 @@ trait Login
return $this->authorization;
}
public function importAuthorization($authorization)
/**
* Import authorization.
*
* @param mixed $authorization Authorization info
*
* @return \Generator
*/
public function importAuthorization($authorization): \Generator
{
if ($this->authorized === self::LOGGED_IN) {
$this->logger->logger(\danog\MadelineProto\Lang::$current_lang['already_loggedIn'], \danog\MadelineProto\Logger::NOTICE);
@ -166,7 +201,12 @@ trait Login
return $res;
}
public function exportAuthorization()
/**
* Export authorization.
*
* @return \Generator<array>
*/
public function exportAuthorization(): \Generator
{
if ($this->authorized !== self::LOGGED_IN) {
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['not_loggedIn']);
@ -177,7 +217,15 @@ trait Login
return [$this->datacenter->curdc, $this->datacenter->getDataCenterConnection($this->datacenter->curdc)->getPermAuthKey()->getAuthKey()];
}
public function completeSignup($first_name, $last_name)
/**
* Complete signup to Telegram.
*
* @param string $first_name First name
* @param string $last_name Last name
*
* @return \Generator
*/
public function completeSignup(string $first_name, string $last_name = ''): \Generator
{
if ($this->authorized !== self::WAITING_SIGNUP) {
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['signup_uncalled']);
@ -196,7 +244,14 @@ trait Login
return $this->authorization;
}
public function complete2faLogin($password)
/**
* Complete 2FA login.
*
* @param string $password Password
*
* @return \Generator
*/
public function complete2faLogin(string $password): \Generator
{
if ($this->authorized !== self::WAITING_PASSWORD) {
throw new \danog\MadelineProto\Exception(\danog\MadelineProto\Lang::$current_lang['2fa_uncalled']);
@ -222,9 +277,10 @@ trait Login
* The params array can contain password, new_password, email and hint params.
*
* @param array $params The params
* @return void
*
* @return \Generator
*/
public function update2fa(array $params)
public function update2fa(array $params): \Generator
{
$hasher = new PasswordCalculator($this->logger);
$hasher->addInfo(yield $this->methodCallAsyncRead('account.getPassword', [], ['datacenter' => $this->datacenter->curdc]));

View File

@ -88,7 +88,7 @@ trait Start
exit;
}
public function webPhoneLogin()
private function webPhoneLogin()
{
try {
yield $this->phoneLogin($_POST['phone_number']);
@ -100,7 +100,7 @@ trait Start
}
}
public function webCompletePhoneLogin()
private function webCompletePhoneLogin()
{
try {
yield $this->completePhoneLogin($_POST['phone_code']);
@ -112,7 +112,7 @@ trait Start
}
}
public function webComplete2faLogin()
private function webComplete2faLogin()
{
try {
yield $this->complete2faLogin($_POST['password']);
@ -124,7 +124,7 @@ trait Start
}
}
public function webCompleteSignup()
private function webCompleteSignup()
{
try {
yield $this->completeSignup($_POST['first_name'], isset($_POST['last_name']) ? $_POST['last_name'] : '');
@ -136,7 +136,7 @@ trait Start
}
}
public function webBotLogin()
private function webBotLogin()
{
try {
yield $this->botLogin($_POST['token']);

View File

@ -23,7 +23,7 @@ use function Amp\ByteStream\getOutputBufferStream;
trait Templates
{
public function webEcho(string $message = '')
private function webEcho(string $message = '')
{
$stdout = getOutputBufferStream();
switch ($this->authorized) {
@ -68,7 +68,7 @@ trait Templates
</body>
</html>';
public function webEchoTemplate($message, $form): string
private function webEchoTemplate($message, $form): string
{
return \sprintf($this->web_template, $form, $message);
}

View File

@ -64,218 +64,221 @@ $settings = \json_decode(\getenv('MTPROTO_SETTINGS'), true) ?: [];
*/
echo 'Loading MadelineProto...'.PHP_EOL;
$MadelineProto = new \danog\MadelineProto\API(\getcwd().'/testing.madeline', $settings);
$MadelineProto->fileGetContents('https://google.com');
$MadelineProto->start();
$MadelineProto->async(false);
$MadelineProto->async(true);
$MadelineProto->loop(function () use ($MadelineProto) {
yield $MadelineProto->fileGetContents('https://google.com');
yield $MadelineProto->start();
try {
$MadelineProto->getSelf();
} catch (\danog\MadelineProto\Exception $e) {
if ($e->getMessage() === 'TOS action required, check the logs') {
$MadelineProto->acceptTos();
try {
yield $MadelineProto->getSelf();
} catch (\danog\MadelineProto\Exception $e) {
if ($e->getMessage() === 'TOS action required, check the logs') {
yield $MadelineProto->acceptTos();
}
}
}
//var_dump(count($MadelineProto->getPwrChat('@madelineproto')['participants']));
//var_dump(count($MadelineProto->getPwrChat('@madelineproto')['participants']));
/*
* Test logging
*/
\danog\MadelineProto\Logger::log('hey', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
\danog\MadelineProto\Logger::log('hey', \danog\MadelineProto\Logger::VERBOSE);
\danog\MadelineProto\Logger::log('hey', \danog\MadelineProto\Logger::NOTICE);
\danog\MadelineProto\Logger::log('hey', \danog\MadelineProto\Logger::WARNING);
\danog\MadelineProto\Logger::log('hey', \danog\MadelineProto\Logger::ERROR);
\danog\MadelineProto\Logger::log('hey', \danog\MadelineProto\Logger::FATAL_ERROR);
/*
* Test logging
*/
$MadelineProto->logger('hey', \danog\MadelineProto\Logger::ULTRA_VERBOSE);
$MadelineProto->logger('hey', \danog\MadelineProto\Logger::VERBOSE);
$MadelineProto->logger('hey', \danog\MadelineProto\Logger::NOTICE);
$MadelineProto->logger('hey', \danog\MadelineProto\Logger::WARNING);
$MadelineProto->logger('hey', \danog\MadelineProto\Logger::ERROR);
$MadelineProto->logger('hey', \danog\MadelineProto\Logger::FATAL_ERROR);
/**
* A small example message to use for tests.
*/
$message = (\getenv('TRAVIS_COMMIT') == '') ? 'I iz works always (io laborare sembre) (yo lavorar siempre) (mi labori ĉiam) (я всегда работать) (Ik werkuh altijd) (Ngimbonga ngaso sonke isikhathi ukusebenza)' : ('Travis ci tests in progress: commit '.\getenv('TRAVIS_COMMIT').', job '.\getenv('TRAVIS_JOB_NUMBER').', PHP version: '.\getenv('TRAVIS_PHP_VERSION'));
/**
* A small example message to use for tests.
*/
$message = (\getenv('TRAVIS_COMMIT') == '') ? 'I iz works always (io laborare sembre) (yo lavorar siempre) (mi labori ĉiam) (я всегда работать) (Ik werkuh altijd) (Ngimbonga ngaso sonke isikhathi ukusebenza)' : ('Travis ci tests in progress: commit '.\getenv('TRAVIS_COMMIT').', job '.\getenv('TRAVIS_JOB_NUMBER').', PHP version: '.\getenv('TRAVIS_PHP_VERSION'));
/*
* Try making a phone call
*/
if (!\getenv('TRAVIS_COMMIT') && \stripos($MadelineProto->readline('Do you want to make a call? (y/n): '), 'y') !== false) {
$controller = $MadelineProto->requestCall(\getenv('TEST_SECRET_CHAT'))->play('input.raw')->then('input.raw')->playOnHold(['input.raw'])->setOutputFile('output.raw');
while ($controller->getCallState() < \danog\MadelineProto\VoIP::CALL_STATE_READY) {
$MadelineProto->getUpdates();
/*
* Try making a phone call
*/
if (!\getenv('TRAVIS_COMMIT') && \stripos(yield $MadelineProto->readline('Do you want to make a call? (y/n): '), 'y') !== false) {
$controller = yield $MadelineProto->requestCall(\getenv('TEST_SECRET_CHAT'))->play('input.raw')->then('input.raw')->playOnHold(['input.raw'])->setOutputFile('output.raw');
while ($controller->getCallState() < \danog\MadelineProto\VoIP::CALL_STATE_READY) {
yield $MadelineProto->getUpdates();
}
$MadelineProto->logger($controller->configuration);
while ($controller->getCallState() < \danog\MadelineProto\VoIP::CALL_STATE_ENDED) {
yield $MadelineProto->getUpdates();
}
}
\danog\MadelineProto\Logger::log($controller->configuration);
while ($controller->getCallState() < \danog\MadelineProto\VoIP::CALL_STATE_ENDED) {
$MadelineProto->getUpdates();
}
}
/*
* Try receiving a phone call
*/
if (!\getenv('TRAVIS_COMMIT') && \stripos($MadelineProto->readline('Do you want to handle incoming calls? (y/n): '), 'y') !== false) {
$howmany = $MadelineProto->readline('How many calls would you like me to handle? ');
$offset = 0;
while ($howmany > 0) {
$updates = $MadelineProto->getUpdates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
foreach ($updates as $update) {
\danog\MadelineProto\Logger::log($update);
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
switch ($update['update']['_']) {
/*
* Try receiving a phone call
*/
if (!\getenv('TRAVIS_COMMIT') && \stripos(yield $MadelineProto->readline('Do you want to handle incoming calls? (y/n): '), 'y') !== false) {
$howmany = yield $MadelineProto->readline('How many calls would you like me to handle? ');
$offset = 0;
while ($howmany > 0) {
$updates = yield $MadelineProto->getUpdates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
foreach ($updates as $update) {
$MadelineProto->logger($update);
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
switch ($update['update']['_']) {
case 'updatePhoneCall':
if (\is_object($update['update']['phone_call']) && $update['update']['phone_call']->getCallState() === \danog\MadelineProto\VoIP::CALL_STATE_INCOMING) {
$update['update']['phone_call']->accept()->play('input.raw')->then('input.raw')->playOnHold(['input.raw'])->setOutputFile('output.raw');
$howmany--;
}
}
}
}
}
}
/*
* Secret chat usage
*/
if (!\getenv('TRAVIS_COMMIT') && \stripos($MadelineProto->readline('Do you want to make the secret chat tests? (y/n): '), 'y') !== false) {
/**
* Request a secret chat.
*/
$secret_chat_id = $MadelineProto->requestSecretChat(\getenv('TEST_SECRET_CHAT'));
echo 'Waiting for '.\getenv('TEST_SECRET_CHAT').' (secret chat id '.$secret_chat_id.') to accept the secret chat...'.PHP_EOL;
/*
* Wait until the other party accepts it
* Secret chat usage
*/
while ($MadelineProto->secretChatStatus($secret_chat_id) !== 2) {
$MadelineProto->getUpdates();
}
if (!\getenv('TRAVIS_COMMIT') && \stripos(yield $MadelineProto->readline('Do you want to make the secret chat tests? (y/n): '), 'y') !== false) {
/**
* Request a secret chat.
*/
$secret_chat_id = yield $MadelineProto->requestSecretChat(\getenv('TEST_SECRET_CHAT'));
echo 'Waiting for '.\getenv('TEST_SECRET_CHAT').' (secret chat id '.$secret_chat_id.') to accept the secret chat...'.PHP_EOL;
/**
* Send a markdown-formatted text message with expiration after 10 seconds.
*/
$sentMessage = $MadelineProto->messages->sendEncrypted([
'peer' => $secret_chat_id,
'message' => [
'_' => 'decryptedMessage',
'media' => ['_' => 'decryptedMessageMediaEmpty'], // No media
'ttl' => 10, // This message self-destructs 10 seconds after reception
'message' => '```'.$message.'```', // Code Markdown
'parse_mode' => 'Markdown',
],
]);
\danog\MadelineProto\Logger::log($sentMessage, \danog\MadelineProto\Logger::NOTICE);
/*
* Wait until the other party accepts it
*/
while (yield $MadelineProto->secretChatStatus($secret_chat_id) !== 2) {
yield $MadelineProto->getUpdates();
}
/**
* Send secret media.
*/
$secret_media = [];
/**
* Send a markdown-formatted text message with expiration after 10 seconds.
*/
$sentMessage = yield $MadelineProto->messages->sendEncrypted([
'peer' => $secret_chat_id,
'message' => [
'_' => 'decryptedMessage',
'media' => ['_' => 'decryptedMessageMediaEmpty'], // No media
'ttl' => 10, // This message self-destructs 10 seconds after reception
'message' => '```'.$message.'```', // Code Markdown
'parse_mode' => 'Markdown',
],
]);
$MadelineProto->logger($sentMessage, \danog\MadelineProto\Logger::NOTICE);
// Photo uploaded as document, secret chat
$secret_media['document_photo'] = [
'peer' => $secret_chat_id,
'file' => 'tests/faust.jpg', // The file to send
'message' => [
'_' => 'decryptedMessage',
'ttl' => 0, // This message does not self-destruct
'message' => '', // No text message, only media
'media' => [
'_' => 'decryptedMessageMediaDocument',
'thumb' => \file_get_contents('tests/faust.preview.jpg'), // The thumbnail must be generated manually, it must be in jpg format, 90x90
'thumb_w' => 90,
'thumb_h' => 90,
'mime_type' => \mime_content_type('tests/faust.jpg'), // The file's mime type
'caption' => 'This file was uploaded using @MadelineProto', // The caption
'file_name' => 'faust.jpg', // The file's name
'size' => \filesize('tests/faust.jpg'), // The file's size
'attributes' => [
['_' => 'documentAttributeImageSize', 'w' => 1280, 'h' => 914], // Image's resolution
/**
* Send secret media.
*/
$secret_media = [];
// Photo uploaded as document, secret chat
$secret_media['document_photo'] = [
'peer' => $secret_chat_id,
'file' => 'tests/faust.jpg', // The file to send
'message' => [
'_' => 'decryptedMessage',
'ttl' => 0, // This message does not self-destruct
'message' => '', // No text message, only media
'media' => [
'_' => 'decryptedMessageMediaDocument',
'thumb' => \file_get_contents('tests/faust.preview.jpg'), // The thumbnail must be generated manually, it must be in jpg format, 90x90
'thumb_w' => 90,
'thumb_h' => 90,
'mime_type' => \mime_content_type('tests/faust.jpg'), // The file's mime type
'caption' => 'This file was uploaded using @MadelineProto', // The caption
'file_name' => 'faust.jpg', // The file's name
'size' => \filesize('tests/faust.jpg'), // The file's size
'attributes' => [
['_' => 'documentAttributeImageSize', 'w' => 1280, 'h' => 914], // Image's resolution
],
],
],
],
];
];
// Photo, secret chat
$secret_media['photo'] = [
'peer' => $secret_chat_id,
'file' => 'tests/faust.jpg',
'message' => [
'_' => 'decryptedMessage',
'ttl' => 0,
'message' => '',
'media' => [
'_' => 'decryptedMessageMediaPhoto',
'thumb' => \file_get_contents('tests/faust.preview.jpg'),
'thumb_w' => 90,
'thumb_h' => 90,
'caption' => 'This file was uploaded using @MadelineProto',
'size' => \filesize('tests/faust.jpg'),
'w' => 1280,
'h' => 914,
// Photo, secret chat
$secret_media['photo'] = [
'peer' => $secret_chat_id,
'file' => 'tests/faust.jpg',
'message' => [
'_' => 'decryptedMessage',
'ttl' => 0,
'message' => '',
'media' => [
'_' => 'decryptedMessageMediaPhoto',
'thumb' => \file_get_contents('tests/faust.preview.jpg'),
'thumb_w' => 90,
'thumb_h' => 90,
'caption' => 'This file was uploaded using @MadelineProto',
'size' => \filesize('tests/faust.jpg'),
'w' => 1280,
'h' => 914,
],
],
],
];
];
// GIF, secret chat
$secret_media['gif'] = ['peer' => $secret_chat_id, 'file' => 'tests/pony.mp4', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/pony.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => \mime_content_type('tests/pony.mp4'), 'caption' => 'test', 'file_name' => 'pony.mp4', 'size' => \filesize('tests/faust.jpg'), 'attributes' => [['_' => 'documentAttributeAnimated']]]]];
// GIF, secret chat
$secret_media['gif'] = ['peer' => $secret_chat_id, 'file' => 'tests/pony.mp4', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/pony.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => \mime_content_type('tests/pony.mp4'), 'caption' => 'test', 'file_name' => 'pony.mp4', 'size' => \filesize('tests/faust.jpg'), 'attributes' => [['_' => 'documentAttributeAnimated']]]]];
// Sticker, secret chat
$secret_media['sticker'] = ['peer' => $secret_chat_id, 'file' => 'tests/lel.webp', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/lel.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => \mime_content_type('tests/lel.webp'), 'caption' => 'test', 'file_name' => 'lel.webp', 'size' => \filesize('tests/lel.webp'), 'attributes' => [['_' => 'documentAttributeSticker', 'alt' => 'LEL', 'stickerset' => ['_' => 'inputStickerSetEmpty']]]]]];
// Sticker, secret chat
$secret_media['sticker'] = ['peer' => $secret_chat_id, 'file' => 'tests/lel.webp', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/lel.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => \mime_content_type('tests/lel.webp'), 'caption' => 'test', 'file_name' => 'lel.webp', 'size' => \filesize('tests/lel.webp'), 'attributes' => [['_' => 'documentAttributeSticker', 'alt' => 'LEL', 'stickerset' => ['_' => 'inputStickerSetEmpty']]]]]];
// Document, secret chat
$secret_media['document'] = ['peer' => $secret_chat_id, 'file' => 'tests/60', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => 'magic/magic', 'caption' => 'test', 'file_name' => 'magic.magic', 'size' => \filesize('tests/60'), 'attributes' => [['_' => 'documentAttributeFilename', 'file_name' => 'fairy']]]]];
// Document, secret chat
$secret_media['document'] = ['peer' => $secret_chat_id, 'file' => 'tests/60', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => 'magic/magic', 'caption' => 'test', 'file_name' => 'magic.magic', 'size' => \filesize('tests/60'), 'attributes' => [['_' => 'documentAttributeFilename', 'file_name' => 'fairy']]]]];
// Video, secret chat
$secret_media['video'] = ['peer' => $secret_chat_id, 'file' => 'tests/swing.mp4', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/swing.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => \mime_content_type('tests/swing.mp4'), 'caption' => 'test', 'file_name' => 'swing.mp4', 'size' => \filesize('tests/swing.mp4'), 'attributes' => [['_' => 'documentAttributeVideo']]]]];
// Video, secret chat
$secret_media['video'] = ['peer' => $secret_chat_id, 'file' => 'tests/swing.mp4', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/swing.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => \mime_content_type('tests/swing.mp4'), 'caption' => 'test', 'file_name' => 'swing.mp4', 'size' => \filesize('tests/swing.mp4'), 'attributes' => [['_' => 'documentAttributeVideo']]]]];
// audio, secret chat
$secret_media['audio'] = ['peer' => $secret_chat_id, 'file' => 'tests/mosconi.mp3', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => \mime_content_type('tests/mosconi.mp3'), 'caption' => 'test', 'file_name' => 'mosconi.mp3', 'size' => \filesize('tests/mosconi.mp3'), 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => false, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]]]];
$secret_media['voice'] = ['peer' => $secret_chat_id, 'file' => 'tests/mosconi.mp3', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => \mime_content_type('tests/mosconi.mp3'), 'caption' => 'test', 'file_name' => 'mosconi.mp3', 'size' => \filesize('tests/mosconi.mp3'), 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => true, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]]]];
// audio, secret chat
$secret_media['audio'] = ['peer' => $secret_chat_id, 'file' => 'tests/mosconi.mp3', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => \mime_content_type('tests/mosconi.mp3'), 'caption' => 'test', 'file_name' => 'mosconi.mp3', 'size' => \filesize('tests/mosconi.mp3'), 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => false, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]]]];
$secret_media['voice'] = ['peer' => $secret_chat_id, 'file' => 'tests/mosconi.mp3', 'message' => ['_' => 'decryptedMessage', 'ttl' => 0, 'message' => '', 'media' => ['_' => 'decryptedMessageMediaDocument', 'thumb' => \file_get_contents('tests/faust.preview.jpg'), 'thumb_w' => 90, 'thumb_h' => 90, 'mime_type' => \mime_content_type('tests/mosconi.mp3'), 'caption' => 'test', 'file_name' => 'mosconi.mp3', 'size' => \filesize('tests/mosconi.mp3'), 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => true, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]]]];
foreach ($secret_media as $type => $smessage) {
\danog\MadelineProto\Logger::log("Encrypting and uploading $type...");
$type = $MadelineProto->messages->sendEncryptedFile($smessage);
foreach ($secret_media as $type => $smessage) {
$MadelineProto->logger("Encrypting and uploading $type...");
$type = yield $MadelineProto->messages->sendEncryptedFile($smessage);
}
}
}
$mention = $MadelineProto->getInfo(\getenv('TEST_USERNAME')); // Returns an array with all of the constructors that can be extracted from a username or an id
$mention = $mention['user_id']; // Selects only the numeric user id
$media = [];
$mention = yield $MadelineProto->getInfo(\getenv('TEST_USERNAME')); // Returns an array with all of the constructors that can be extracted from a username or an id
$mention = $mention['user_id']; // Selects only the numeric user id
$media = [];
// Image
$media['photo'] = ['_' => 'inputMediaUploadedPhoto', 'file' => 'tests/faust.jpg'];
// Image
$media['photo'] = ['_' => 'inputMediaUploadedPhoto', 'file' => 'tests/faust.jpg'];
// Sticker
$media['sticker'] = ['_' => 'inputMediaUploadedDocument', 'file' => 'tests/lel.webp', 'attributes' => [['_' => 'documentAttributeSticker', 'alt' => 'LEL']]];
// Sticker
$media['sticker'] = ['_' => 'inputMediaUploadedDocument', 'file' => 'tests/lel.webp', 'attributes' => [['_' => 'documentAttributeSticker', 'alt' => 'LEL']]];
// Video
$media['video'] = ['_' => 'inputMediaUploadedDocument', 'file' => 'tests/swing.mp4', 'attributes' => [['_' => 'documentAttributeVideo']]];
// Video
$media['video'] = ['_' => 'inputMediaUploadedDocument', 'file' => 'tests/swing.mp4', 'attributes' => [['_' => 'documentAttributeVideo']]];
// audio
$media['audio'] = ['_' => 'inputMediaUploadedDocument', 'file' => 'tests/mosconi.mp3', 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => false, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]];
// audio
$media['audio'] = ['_' => 'inputMediaUploadedDocument', 'file' => 'tests/mosconi.mp3', 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => false, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]];
// voice
$media['voice'] = ['_' => 'inputMediaUploadedDocument', 'file' => 'tests/mosconi.mp3', 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => true, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]];
// voice
$media['voice'] = ['_' => 'inputMediaUploadedDocument', 'file' => 'tests/mosconi.mp3', 'attributes' => [['_' => 'documentAttributeAudio', 'voice' => true, 'title' => 'AH NON LO SO IO', 'performer' => 'IL DIO GERMANO MOSCONI']]];
// Document
$media['document'] = ['_' => 'inputMediaUploadedDocument', 'file' => 'tests/60', 'mime_type' => 'magic/magic', 'attributes' => [['_' => 'documentAttributeFilename', 'file_name' => 'magic.magic']]];
// Document
$media['document'] = ['_' => 'inputMediaUploadedDocument', 'file' => 'tests/60', 'mime_type' => 'magic/magic', 'attributes' => [['_' => 'documentAttributeFilename', 'file_name' => 'magic.magic']]];
$message = 'yay '.\PHP_VERSION_ID;
$mention = $MadelineProto->getInfo(\getenv('TEST_USERNAME')); // Returns an array with all of the constructors that can be extracted from a username or an id
$mention = $mention['user_id']; // Selects only the numeric user id
$message = 'yay '.\PHP_VERSION_ID;
$mention = yield $MadelineProto->getInfo(\getenv('TEST_USERNAME')); // Returns an array with all of the constructors that can be extracted from a username or an id
$mention = $mention['user_id']; // Selects only the numeric user id
/*
$t = time();
$MadelineProto->upload('big');
yield $MadelineProto->upload('big');
var_dump(time()-$t);
*/
foreach (\json_decode(\getenv('TEST_DESTINATION_GROUPS'), true) as $peer) {
$sentMessage = $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message, 'entities' => [['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => \mb_strlen($message), 'user_id' => $mention]]]);
\danog\MadelineProto\Logger::log($sentMessage, \danog\MadelineProto\Logger::NOTICE);
foreach (\json_decode(\getenv('TEST_DESTINATION_GROUPS'), true) as $peer) {
$sentMessage = yield $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message, 'entities' => [['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => \mb_strlen($message), 'user_id' => $mention]]]);
$MadelineProto->logger($sentMessage, \danog\MadelineProto\Logger::NOTICE);
foreach ($media as $type => $inputMedia) {
\danog\MadelineProto\Logger::log("Sending $type");
$type = $MadelineProto->messages->sendMedia(['peer' => $peer, 'media' => $inputMedia, 'message' => '['.$message.'](mention:'.$mention.')', 'parse_mode' => 'markdown']);
foreach ($media as $type => $inputMedia) {
$MadelineProto->logger("Sending $type");
$type = yield $MadelineProto->messages->sendMedia(['peer' => $peer, 'media' => $inputMedia, 'message' => '['.$message.'](mention:'.$mention.')', 'parse_mode' => 'markdown']);
yield $MadelineProto->downloadToDir(yield $MadelineProto->messages->uploadMedia(['peer' => '@me', 'media' => $inputMedia]), '/tmp');
}
}
}
foreach (\json_decode(\getenv('TEST_DESTINATION_GROUPS'), true) as $peer) {
$sentMessage = $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message, 'entities' => [['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => \mb_strlen($message), 'user_id' => $mention]]]);
\danog\MadelineProto\Logger::log($sentMessage, \danog\MadelineProto\Logger::NOTICE);
}
foreach (\json_decode(\getenv('TEST_DESTINATION_GROUPS'), true) as $peer) {
$sentMessage = yield $MadelineProto->messages->sendMessage(['peer' => $peer, 'message' => $message, 'entities' => [['_' => 'inputMessageEntityMentionName', 'offset' => 0, 'length' => \mb_strlen($message), 'user_id' => $mention]]]);
$MadelineProto->logger($sentMessage, \danog\MadelineProto\Logger::NOTICE);
}
});