2019-05-29 15:17:14 +02:00
< ? php
2020-01-31 19:29:43 +01:00
2019-05-29 15:17:14 +02:00
/**
* Update loop .
*
* This file is part of MadelineProto .
* MadelineProto is free software : you can redistribute it and / or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation , either version 3 of the License , or ( at your option ) any later version .
* MadelineProto is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
* See the GNU Affero General Public License for more details .
* You should have received a copy of the GNU General Public License along with MadelineProto .
* If not , see < http :// www . gnu . org / licenses />.
*
* @ author Daniil Gentili < daniil @ daniil . it >
2020-02-17 14:13:46 +01:00
* @ copyright 2016 - 2020 Daniil Gentili < daniil @ daniil . it >
2019-05-29 15:17:14 +02:00
* @ license https :// opensource . org / licenses / AGPL - 3.0 AGPLv3
*
2019-10-31 15:07:35 +01:00
* @ link https :// docs . madelineproto . xyz MadelineProto documentation
2019-05-29 15:17:14 +02:00
*/
namespace danog\MadelineProto\Loop\Update ;
2019-05-30 15:39:51 +02:00
use Amp\Loop ;
2019-06-21 17:57:13 +02:00
use danog\MadelineProto\Exception ;
2019-06-04 14:55:58 +02:00
use danog\MadelineProto\Loop\Impl\ResumableSignalLoop ;
2019-05-31 17:43:49 +02:00
use danog\MadelineProto\RPCErrorException ;
2019-05-29 15:17:14 +02:00
/**
* Update loop .
*
* @ author Daniil Gentili < daniil @ daniil . it >
*/
class UpdateLoop extends ResumableSignalLoop
{
private $toPts ;
private $channelId ;
private $feeder ;
public function __construct ( $API , $channelId )
{
$this -> API = $API ;
$this -> channelId = $channelId ;
}
2020-01-31 19:29:43 +01:00
public function loop () : \Generator
2019-05-29 15:17:14 +02:00
{
$API = $this -> API ;
2019-05-29 18:28:43 +02:00
$feeder = $this -> feeder = $API -> feeders [ $this -> channelId ];
2019-10-29 22:51:14 +01:00
while ( ! $API -> settings [ 'updates' ][ 'handle_updates' ] || ! $API -> hasAllAuth ()) {
2019-05-29 15:17:14 +02:00
if ( yield $this -> waitSignal ( $this -> pause ())) {
2020-01-31 19:29:43 +01:00
$API -> logger -> logger ( " Exiting { $this } due to signal " );
2019-05-29 15:17:14 +02:00
return ;
}
}
2020-01-31 19:49:58 +01:00
$this -> state = $state = $this -> channelId === false ? yield from $API -> loadUpdateState () : $API -> loadChannelState ( $this -> channelId );
2019-05-29 15:17:14 +02:00
$timeout = $API -> settings [ 'updates' ][ 'getdifference_interval' ];
2019-06-07 02:48:25 +02:00
$first = true ;
2019-05-29 15:17:14 +02:00
while ( true ) {
2019-10-29 22:51:14 +01:00
while ( ! $API -> settings [ 'updates' ][ 'handle_updates' ] || ! $API -> hasAllAuth ()) {
2019-05-29 15:17:14 +02:00
if ( yield $this -> waitSignal ( $this -> pause ())) {
2020-01-31 19:29:43 +01:00
$API -> logger -> logger ( " Exiting { $this } due to signal " );
2019-05-29 15:17:14 +02:00
return ;
}
}
2019-05-30 13:28:50 +02:00
$result = [];
2019-05-29 17:19:42 +02:00
$toPts = $this -> toPts ;
$this -> toPts = null ;
while ( true ) {
if ( $this -> channelId ) {
2020-04-05 22:22:47 +02:00
$API -> logger -> logger ( 'Resumed and fetching ' . $this -> channelId . ' difference...' , \danog\MadelineProto\Logger :: ULTRA_VERBOSE );
2019-05-29 17:19:42 +02:00
if ( $state -> pts () <= 1 ) {
$limit = 10 ;
2019-06-04 14:55:58 +02:00
} elseif ( $API -> authorization [ 'user' ][ 'bot' ]) {
2019-05-29 17:19:42 +02:00
$limit = 100000 ;
2019-05-29 15:17:14 +02:00
} else {
2019-05-29 17:19:42 +02:00
$limit = 100 ;
}
2019-05-30 15:17:26 +02:00
$request_pts = $state -> pts ();
2019-05-31 17:43:49 +02:00
try {
2020-04-05 22:22:47 +02:00
$difference = yield from $API -> methodCallAsyncRead ( 'updates.getChannelDifference' , [ 'channel' => 'channel#' . $this -> channelId , 'filter' => [ '_' => 'channelMessagesFilterEmpty' ], 'pts' => $request_pts , 'limit' => $limit , 'force' => true ], [ 'datacenter' => $API -> datacenter -> curdc , 'postpone' => $first ]);
2019-05-31 17:43:49 +02:00
} catch ( RPCErrorException $e ) {
2019-09-13 21:40:33 +02:00
if ( \in_array ( $e -> rpc , [ 'CHANNEL_PRIVATE' , 'CHAT_FORBIDDEN' , 'CHANNEL_INVALID' ])) {
2019-05-31 17:43:49 +02:00
$feeder -> signal ( true );
2019-09-02 17:08:36 +02:00
unset ( $API -> updaters [ $this -> channelId ], $API -> feeders [ $this -> channelId ]);
2019-06-07 02:48:25 +02:00
$API -> getChannelStates () -> remove ( $this -> channelId );
2020-01-31 19:29:43 +01:00
$API -> logger -> logger ( " Channel private, exiting { $this } " );
2019-06-06 16:22:52 +02:00
return true ;
}
2019-06-08 02:21:38 +02:00
throw $e ;
2019-06-06 16:22:52 +02:00
} catch ( Exception $e ) {
2019-09-02 17:08:36 +02:00
if ( \in_array ( $e -> getMessage (), [ 'This peer is not present in the internal peer database' ])) {
2019-06-06 16:22:52 +02:00
$feeder -> signal ( true );
2019-06-08 02:21:38 +02:00
$API -> getChannelStates () -> remove ( $this -> channelId );
2019-09-02 17:08:36 +02:00
unset ( $API -> updaters [ $this -> channelId ], $API -> feeders [ $this -> channelId ]);
2020-01-31 19:29:43 +01:00
$API -> logger -> logger ( " Channel private, exiting { $this } " );
2019-05-31 17:43:49 +02:00
return true ;
}
2019-06-04 14:55:58 +02:00
throw $e ;
2019-05-31 17:43:49 +02:00
}
2019-05-29 17:19:42 +02:00
if ( isset ( $difference [ 'timeout' ])) {
$timeout = $difference [ 'timeout' ];
}
2020-04-05 22:22:47 +02:00
$API -> logger -> logger ( 'Got ' . $difference [ '_' ], \danog\MadelineProto\Logger :: VERBOSE );
2019-05-29 17:19:42 +02:00
switch ( $difference [ '_' ]) {
case 'updates.channelDifferenceEmpty' :
$state -> update ( $difference );
unset ( $difference );
break 2 ;
case 'updates.channelDifference' :
2019-05-30 15:17:26 +02:00
if ( $request_pts >= $difference [ 'pts' ] && $request_pts > 1 ) {
2020-04-05 22:22:47 +02:00
$API -> logger -> logger ( " The PTS ( { $difference [ 'pts' ] } ) I got with getDifference is smaller than the PTS I requested " . $state -> pts () . ', using ' . ( $state -> pts () + 1 ), \danog\MadelineProto\Logger :: VERBOSE );
2019-05-30 15:17:26 +02:00
$difference [ 'pts' ] = $request_pts + 1 ;
2019-05-29 17:19:42 +02:00
}
2020-01-31 19:49:58 +01:00
$result += ( yield from $feeder -> feed ( $difference [ 'other_updates' ]));
2019-06-18 12:31:44 +02:00
$state -> update ( $difference );
2019-05-29 22:00:51 +02:00
$feeder -> saveMessages ( $difference [ 'new_messages' ]);
2019-05-29 17:19:42 +02:00
if ( ! $difference [ 'final' ]) {
if ( $difference [ 'pts' ] >= $toPts ) {
2019-05-29 15:17:14 +02:00
unset ( $difference );
break 2 ;
}
unset ( $difference );
break ;
2019-05-29 17:19:42 +02:00
}
unset ( $difference );
break 2 ;
case 'updates.channelDifferenceTooLong' :
2019-06-22 18:22:38 +02:00
if ( isset ( $difference [ 'dialog' ][ 'pts' ])) {
$difference [ 'pts' ] = $difference [ 'dialog' ][ 'pts' ];
}
2019-05-29 17:19:42 +02:00
$state -> update ( $difference );
2019-05-29 22:00:51 +02:00
$feeder -> saveMessages ( $difference [ 'messages' ]);
2019-05-29 17:19:42 +02:00
unset ( $difference );
break ;
default :
2020-04-05 22:22:47 +02:00
throw new \danog\MadelineProto\Exception ( 'Unrecognized update difference received: ' . \var_export ( $difference , true ));
2019-05-29 17:19:42 +02:00
}
} else {
2019-06-07 02:48:25 +02:00
$API -> logger -> logger ( 'Resumed and fetching normal difference...' , \danog\MadelineProto\Logger :: ULTRA_VERBOSE );
2020-02-05 17:37:01 +01:00
$difference = yield from $API -> methodCallAsyncRead ( 'updates.getDifference' , [ 'pts' => $state -> pts (), 'date' => $state -> date (), 'qts' => $state -> qts ()], [ 'datacenter' => $API -> settings [ 'connection_settings' ][ 'default_dc' ]]);
2020-04-05 22:22:47 +02:00
$API -> logger -> logger ( 'Got ' . $difference [ '_' ], \danog\MadelineProto\Logger :: ULTRA_VERBOSE );
2019-05-29 17:19:42 +02:00
switch ( $difference [ '_' ]) {
case 'updates.differenceEmpty' :
$state -> update ( $difference );
unset ( $difference );
break 2 ;
case 'updates.difference' :
2019-06-21 17:57:13 +02:00
$state -> qts ( $difference [ 'state' ][ 'qts' ]);
2019-05-29 17:19:42 +02:00
foreach ( $difference [ 'new_encrypted_messages' ] as & $encrypted ) {
$encrypted = [ '_' => 'updateNewEncryptedMessage' , 'message' => $encrypted ];
}
2020-01-31 19:49:58 +01:00
$result += ( yield from $feeder -> feed ( $difference [ 'other_updates' ]));
$result += ( yield from $feeder -> feed ( $difference [ 'new_encrypted_messages' ]));
2019-05-29 17:19:42 +02:00
$state -> update ( $difference [ 'state' ]);
2019-06-18 12:31:44 +02:00
$feeder -> saveMessages ( $difference [ 'new_messages' ]);
2019-05-29 17:19:42 +02:00
unset ( $difference );
break 2 ;
case 'updates.differenceSlice' :
2019-06-21 21:20:44 +02:00
$state -> qts ( $difference [ 'intermediate_state' ][ 'qts' ]);
2019-05-29 17:19:42 +02:00
foreach ( $difference [ 'new_encrypted_messages' ] as & $encrypted ) {
$encrypted = [ '_' => 'updateNewEncryptedMessage' , 'message' => $encrypted ];
}
2020-01-31 19:49:58 +01:00
$result += ( yield from $feeder -> feed ( $difference [ 'other_updates' ]));
$result += ( yield from $feeder -> feed ( $difference [ 'new_encrypted_messages' ]));
2019-05-29 17:19:42 +02:00
$state -> update ( $difference [ 'intermediate_state' ]);
2019-06-18 12:31:44 +02:00
$feeder -> saveMessages ( $difference [ 'new_messages' ]);
2019-05-29 17:19:42 +02:00
if ( $difference [ 'intermediate_state' ][ 'pts' ] >= $toPts ) {
unset ( $difference );
break 2 ;
}
unset ( $difference );
break ;
2019-05-31 17:43:49 +02:00
case 'updates.differenceTooLong' :
$state -> update ( $difference );
unset ( $difference );
break ;
2019-05-29 17:19:42 +02:00
default :
2020-04-05 22:22:47 +02:00
throw new \danog\MadelineProto\Exception ( 'Unrecognized update difference received: ' . \var_export ( $difference , true ));
2019-05-29 15:17:14 +02:00
}
}
}
2020-01-31 19:29:43 +01:00
$API -> logger -> logger ( " Finished parsing updates in { $this } , now resuming feeders " );
2019-05-30 14:09:15 +02:00
foreach ( $result as $channelId => $boh ) {
2019-06-07 02:48:25 +02:00
$API -> feeders [ $channelId ] -> resumeDefer ();
2019-05-30 13:28:50 +02:00
}
2020-01-31 19:29:43 +01:00
$API -> logger -> logger ( " Finished resuming feeders in { $this } , signaling updates " );
2019-06-07 02:48:25 +02:00
$API -> signalUpdate ();
2020-01-31 19:29:43 +01:00
$API -> logger -> logger ( " Finished signaling updates in { $this } , pausing " );
2019-06-07 02:48:25 +02:00
$first = false ;
2019-05-29 17:19:42 +02:00
if ( yield $this -> waitSignal ( $this -> pause ( $timeout ))) {
2020-01-31 19:29:43 +01:00
$API -> logger -> logger ( " Exiting { $this } due to signal " );
2019-05-29 15:17:14 +02:00
return ;
}
}
}
public function setLimit ( $toPts )
{
$this -> toPts = $toPts ;
}
2019-05-30 14:09:15 +02:00
public function __toString () : string
{
2019-06-04 14:55:58 +02:00
return ! $this -> channelId ? 'getUpdate loop generic' : " getUpdate loop channel { $this -> channelId } " ;
2019-05-30 14:09:15 +02:00
}
2019-05-29 15:17:14 +02:00
}