Implement socket interface
This commit is contained in:
parent
c218517673
commit
e9dc0ba6f6
|
@ -55,7 +55,7 @@ if (!is_object($Lua)) {
|
|||
}
|
||||
$offset = 0;
|
||||
while (true) {
|
||||
$updates = $Lua->MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
$updates = $Lua->MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
foreach ($updates as $update) {
|
||||
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
|
||||
$Lua->madeline_update_callback($update['update']);
|
||||
|
|
|
@ -56,7 +56,7 @@ if (!is_object($Lua)) {
|
|||
|
||||
$offset = 0;
|
||||
while (true) {
|
||||
$updates = $Lua->MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
$updates = $Lua->MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
foreach ($updates as $update) {
|
||||
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
|
||||
$Lua->tdcli_update_callback($update['update']);
|
||||
|
|
|
@ -107,7 +107,7 @@ if (stripos(readline('Do you want to handle incoming calls? (y/n): '), 'y') !==
|
|||
$howmany = readline('How many calls would you like me to handle? ');
|
||||
$offset = 0;
|
||||
while ($howmany > 0) {
|
||||
$updates = $MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
$updates = $MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
foreach ($updates as $update) {
|
||||
\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
|
||||
|
@ -135,7 +135,7 @@ if (stripos(readline('Do you want to make the secret chat tests? (y/n): '), 'y')
|
|||
\danog\MadelineProto\Logger::log($sentMessage, \danog\MadelineProto\Logger::NOTICE);
|
||||
/*
|
||||
while (true) {
|
||||
$updates = $MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
$updates = $MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
//\danog\MadelineProto\Logger::log($updates);
|
||||
foreach ($updates as $update) {
|
||||
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
<?php
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
$handler = new \danog\MadelineProto\Server(['type' => AF_INET, 'protocol' => 0, 'address' => 'localhost', 'port' => 8005]);
|
||||
$handler->start();
|
||||
|
|
|
@ -120,13 +120,13 @@ If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
if (!extension_loaded('pthreads')) {
|
||||
if (extension_loaded('sockets')) {
|
||||
class Socket
|
||||
class SocketBase
|
||||
{
|
||||
private $sock;
|
||||
|
||||
public function __construct(int $domain, int $type, int $protocol)
|
||||
public function __construct($sock)
|
||||
{
|
||||
$this->sock = socket_create($domain, $type, $protocol);
|
||||
$this->sock = $sock;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
|
@ -170,7 +170,11 @@ if (!extension_loaded('pthreads')) {
|
|||
|
||||
public function accept()
|
||||
{
|
||||
return socket_accept($this->sock);
|
||||
if ($socket = socket_accept($this->sock)) {
|
||||
return new SocketBase($socket);
|
||||
} else {
|
||||
return $socket;
|
||||
}
|
||||
}
|
||||
|
||||
public function connect(string $address, int $port = 0)
|
||||
|
@ -222,6 +226,13 @@ if (!extension_loaded('pthreads')) {
|
|||
return $port ? ['host' => $address, 'port' => $port] : ['host' => $address];
|
||||
}
|
||||
}
|
||||
class Socket extends SocketBase
|
||||
{
|
||||
public function __construct(int $domain, int $type, int $protocol)
|
||||
{
|
||||
parent::__construct(socket_create($domain, $type, $protocol));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
define('AF_INET', 0);
|
||||
define('AF_INET6', 1);
|
||||
|
|
|
@ -22,7 +22,6 @@ class API extends APIFactory
|
|||
public function __magic_construct($params = [])
|
||||
{
|
||||
set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
||||
set_exception_handler(['\\danog\\MadelineProto\\Serialization', 'serialize_all']);
|
||||
if (is_string($params)) {
|
||||
$realpaths = Serialization::realpaths($params);
|
||||
if (file_exists($realpaths['file'])) {
|
||||
|
|
|
@ -236,13 +236,10 @@ class Connection
|
|||
}
|
||||
|
||||
return $wrote;
|
||||
break;
|
||||
case 'udp':
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['protocol_not_implemented']);
|
||||
break;
|
||||
default:
|
||||
throw new Exception(\danog\MadelineProto\Lang::$current_lang['protocol_invalid']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,9 @@ class Server
|
|||
|
||||
public function __construct($settings)
|
||||
{
|
||||
set_error_handler(['\\danog\\MadelineProto\\Exception', 'ExceptionErrorHandler']);
|
||||
$this->settings = $settings;
|
||||
$this->main = getmypid();
|
||||
}
|
||||
|
||||
public function start()
|
||||
|
@ -32,15 +34,24 @@ class Server
|
|||
pcntl_signal(SIGINT, [$this, 'sig_handler']);
|
||||
pcntl_signal(SIGCHLD, [$this, 'sig_handler']);
|
||||
|
||||
$this->sock = new Socket($this->settings['type'], SOCK_STREAM, $this->settings['protocol']);
|
||||
$this->sock = new \Socket($this->settings['type'], SOCK_STREAM, $this->settings['protocol']);
|
||||
$this->sock->bind($this->settings['address'], $this->settings['port']);
|
||||
$this->sock->listen();
|
||||
$this->sock->setBlocking(true);
|
||||
|
||||
$timeout = 2;
|
||||
$this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout);
|
||||
$this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout);
|
||||
while (true) {
|
||||
$this->handle($this->sock->accept());
|
||||
pcntl_signal_dispatch();
|
||||
try {
|
||||
if ($sock = $this->sock->accept()) {
|
||||
$this->handle($sock);
|
||||
}
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function handle($socket)
|
||||
{
|
||||
$pid = pcntl_fork();
|
||||
|
@ -49,16 +60,21 @@ class Server
|
|||
} elseif ($pid) {
|
||||
return $this->pids[] = $pid;
|
||||
}
|
||||
$handler = new \danog\MadelineProto\Server\Handler($socket);
|
||||
$handler = new \danog\MadelineProto\Server\Handler($socket, 'tcp_abridged', null, null, null, null, null);
|
||||
$handler->loop();
|
||||
die;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
foreach ($this->pid as $pid) {
|
||||
pcntl_wait($pid);
|
||||
if (!\danog\MadelineProto\Logger::$is_fork) {
|
||||
\danog\MadelineProto\Logger::log('Shutting main process down');
|
||||
foreach ($this->pids as $pid) {
|
||||
pcntl_wait($pid);
|
||||
}
|
||||
return;
|
||||
}
|
||||
\danog\MadelineProto\Logger::log('Shutting fork '.getmypid().' down');
|
||||
}
|
||||
|
||||
public function sig_handler($sig)
|
||||
|
@ -66,6 +82,7 @@ class Server
|
|||
switch ($sig) {
|
||||
case SIGTERM:
|
||||
case SIGINT:
|
||||
Logger::log('Got SIGTERM/SIGINT in '.getmypid());
|
||||
exit();
|
||||
|
||||
case SIGCHLD:
|
||||
|
|
|
@ -16,24 +16,123 @@ namespace danog\MadelineProto\Server;
|
|||
/*
|
||||
* Socket handler for server
|
||||
*/
|
||||
class Handler
|
||||
class Handler extends \danog\MadelineProto\Connection
|
||||
{
|
||||
private $socket;
|
||||
use \danog\MadelineProto\TL\TL;
|
||||
use \danog\MadelineProto\Tools;
|
||||
private $madeline;
|
||||
|
||||
public function __construct($socket)
|
||||
public function __magic_construct($socket, $extra, $ip, $port, $protocol, $timeout, $ipv6)
|
||||
{
|
||||
$this->socket = $socket;
|
||||
$this->sock = $socket;
|
||||
$this->sock->setBlocking(true);
|
||||
$this->protocol = $protocol;
|
||||
$this->construct_TL(['socket' => __DIR__.'/../TL_socket.tl']);
|
||||
}
|
||||
public function __destruct() {
|
||||
unset($this->sock);
|
||||
$this->destruct_madeline();
|
||||
exit();
|
||||
}
|
||||
public function destruct_madeline() {
|
||||
if ($this->madeline !== null) {
|
||||
$this->madeline->settings['logger'] = ['logger' => 0];
|
||||
$this->madeline->serialize();
|
||||
unset($this->madeline);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function loop()
|
||||
{
|
||||
}
|
||||
while (true) {
|
||||
$request_id = 0;
|
||||
try {
|
||||
$message = $this->read_message();
|
||||
} catch (\danog\MadelineProto\NothingInTheSocketException $e) {
|
||||
continue;
|
||||
}
|
||||
if ($message === null) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$message = $this->deserialize($message, ['type' => '', 'datacenter' => '']);
|
||||
if ($message['_'] !== 'socketMessageRequest') {
|
||||
throw new \danog\MadelineProto\Exception('Invalid object received');
|
||||
}
|
||||
$request_id = $message['request_id'];
|
||||
$this->send_response($request_id, $this->on_request($request_id, $message['method'], $message['args']));
|
||||
} catch (\danog\MadelineProto\TL\Exception $e) {
|
||||
$this->send_exception($request_id, $e);
|
||||
continue;
|
||||
} catch (\danog\MadelineProto\Exception $e) {
|
||||
$this->send_exception($request_id, $e);
|
||||
continue;
|
||||
} catch (\danog\MadelineProto\RPCErrorException $e) {
|
||||
$this->send_exception($request_id, $e);
|
||||
continue;
|
||||
} catch (\DOMException $e) {
|
||||
$this->send_exception($request_id, $e);
|
||||
continue;
|
||||
}
|
||||
|
||||
public function read_payload()
|
||||
{
|
||||
}
|
||||
}
|
||||
public function on_request($method, $args) {
|
||||
if (count($method) === 0 || count($method) > 2) {
|
||||
throw new \danog\MadelineProto\Exception('Invalid method called');
|
||||
}
|
||||
if ($method[0] === '__construct') {
|
||||
if (count($args) === 1 && is_array($args[0])) {
|
||||
$args[0]['logger'] = ['logger' => 4, 'logger_param' => [$this, 'logger']];
|
||||
$args[0]['updates']['callback'] = [$this, 'update_handler'];
|
||||
} else if (count($args) === 2 && is_array($args[1])) {
|
||||
$args[1]['logger'] = ['logger' => 4, 'logger_param' => [$this, 'logger']];
|
||||
$args[1]['updates']['callback'] = [$this, 'update_handler'];
|
||||
}
|
||||
$this->madeline = new \danog\MadelineProto\API(...$args);
|
||||
return true;
|
||||
}
|
||||
if ($method[0] === '__destruct') {
|
||||
return $this->destruct_madeline();
|
||||
}
|
||||
if ($this->madeline === null) {
|
||||
throw new \danog\MadelineProto\Exception('__construct was not called');
|
||||
}
|
||||
foreach ($args as &$arg) {
|
||||
if (is_array($arg) && isset($arg['_'])){
|
||||
if ($arg['_'] === 'callback' && isset($arg['callback']) && !method_exists($this, $arg['callback'])) {
|
||||
$arg = [$this, $arg['callback']];
|
||||
}
|
||||
if ($arg['_'] === 'stream' && isset($arg['stream_id'])) {
|
||||
$arg = fopen('madelineSocket://', 'r+b', false, Handler::getContext($this, $arg['stream_id']));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($method) === 1) {
|
||||
return $this->madeline->{$method[0]}(...$args);
|
||||
}
|
||||
if (count($method) === 2) {
|
||||
return $this->madeline->{$method[0]}->{$method[1]}(...$args);
|
||||
}
|
||||
}
|
||||
public function send_exception($request_id, $e) {
|
||||
echo $e;
|
||||
//$this->send_message($this->serialize_object(['type' => 'socketMessageException'], ['request_id' => $request_id, 'exception' => $e]));
|
||||
}
|
||||
public function send_response($request_id, $response) {
|
||||
$this->send_message($this->serialize_object(['type' => 'socketMessageResponse'], ['request_id' => $request_id, 'data' => $response]));
|
||||
}
|
||||
public function send_data($stream_id, $data) {
|
||||
$this->send_message($this->serialize_object(['type' => 'socketMessageRawData'], ['stream_id' => $stream_id, 'data' => $data]));
|
||||
}
|
||||
public function logger($message, $level) {
|
||||
|
||||
public function write_payload($payload)
|
||||
{
|
||||
}
|
||||
public function update_handler($update) {
|
||||
$this->send_message($this->serialize_object(['type' => 'socketMessageUpdate'], ['data' => $update]));
|
||||
}
|
||||
public function __call($method, $args) {
|
||||
$this->send_message($this->serialize_object(['type' => 'socketMessageRequest'], ['request_id' => 0, 'method' => $method, 'args' => $args]));
|
||||
}
|
||||
}
|
||||
|
|
57
src/danog/MadelineProto/Server/Stream.php
Normal file
57
src/danog/MadelineProto/Server/Stream.php
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
Copyright 2016-2018 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\Server;
|
||||
|
||||
|
||||
class Stream
|
||||
{
|
||||
const WRAPPER_NAME = 'madelineSocket';
|
||||
|
||||
public $context;
|
||||
private $_handler;
|
||||
private $_stream_id;
|
||||
|
||||
private static $_isRegistered = false;
|
||||
|
||||
public static function getContext($handler, $stream_id)
|
||||
{
|
||||
if (!self::$_isRegistered) {
|
||||
stream_wrapper_register(self::WRAPPER_NAME, get_class());
|
||||
self::$_isRegistered = true;
|
||||
}
|
||||
return stream_context_create(array(self::WRAPPER_NAME => ['handler' => $handler, $stream_id]));
|
||||
}
|
||||
|
||||
public function stream_open($path, $mode, $options, &$opened_path)
|
||||
{
|
||||
$opt = stream_context_get_options($this->context);
|
||||
if (!is_array($opt[self::WRAPPER_NAME]) ||
|
||||
!isset($opt[self::WRAPPER_NAME]['handler']) ||
|
||||
!($opt[self::WRAPPER_NAME]['handler'] instanceof Handler)
|
||||
!isset($opt[self::WRAPPER_NAME]['stream_id']) ||
|
||||
!is_integer($opt[self::WRAPPER_NAME]['stream_id'])) return false;
|
||||
$this->_handler = $opt[self::WRAPPER_NAME]['handler'];
|
||||
$this->_stream_id = $opt[self::WRAPPER_NAME]['stream_id'];
|
||||
return true;
|
||||
}
|
||||
|
||||
public function stream_write($data)
|
||||
{
|
||||
$this->handler->send_data($this->_stream_id, $data);
|
||||
}
|
||||
|
||||
public function stream_lock($mode) {
|
||||
|
||||
}
|
||||
}
|
18
src/danog/MadelineProto/TL_socket.tl
Normal file
18
src/danog/MadelineProto/TL_socket.tl
Normal file
|
@ -0,0 +1,18 @@
|
|||
|
||||
dataJSON#7d748d04 data:string = DataJSON;
|
||||
|
||||
socketMessageRequest request_id:int method:vector<string> args:vector<%DataJSON> = SocketMessage;
|
||||
socketMessageResponse request_id:int data:%DataJSON = SocketMessage;
|
||||
socketMessageException request_id:int exception:SocketException = SocketMessage;
|
||||
socketMessageUpdate data:%DataJSON = SocketMessage;
|
||||
socketMessageLog flags:# thread:flags.0?true process:flags.1?true additional:flags.2?string file:flags.3?string level:int data:string = SocketMessage;
|
||||
socketMessageRawData stream_id:int data:bytes = SocketMessage;
|
||||
|
||||
socketException message:string code:int trace:%SocketTLTrace = SocketException;
|
||||
socketRPCErrorException flags:# rpc_message:flags.0?string message:flags.1?string code:int trace:%SocketTLTrace = SocketException;
|
||||
socketTLException message:string code:int trace:%SocketTLTrace = SocketException;
|
||||
socketDOMException message:string code:int trace:%SocketTLTrace = SocketException;
|
||||
|
||||
socketTLTrace frames:vector<%SocketTLFrame> = SocketTLTrace;
|
||||
|
||||
socketTLFrame flags:# file:flags.0?string line:flags.1?string function:flags.2?string args:flags.3?string tl_param:flags.4?string = SocketTLFrame;
|
|
@ -113,7 +113,7 @@ if (stripos(readline('Do you want to handle incoming calls? (y/n): '), 'y') !==
|
|||
$howmany = readline('How many calls would you like me to handle? ');
|
||||
$offset = 0;
|
||||
while ($howmany > 0) {
|
||||
$updates = $MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
$updates = $MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
foreach ($updates as $update) {
|
||||
\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
|
||||
|
@ -141,7 +141,7 @@ if (stripos(readline('Do you want to make the secret chat tests? (y/n): '), 'y')
|
|||
\danog\MadelineProto\Logger::log($sentMessage, \danog\MadelineProto\Logger::NOTICE);
|
||||
/*
|
||||
while (true) {
|
||||
$updates = $MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
$updates = $MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
//\danog\MadelineProto\Logger::log($updates);
|
||||
foreach ($updates as $update) {
|
||||
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
|
||||
|
|
|
@ -64,7 +64,7 @@ Created by [Daniil Gentili](mention:@danogentili) (@daniilgentili) using the [Ma
|
|||
echo 'Bot started.'.PHP_EOL;
|
||||
|
||||
while (true) {
|
||||
$updates = $MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
$updates = $MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
foreach ($updates as $update) {
|
||||
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
|
||||
switch ($update['update']['_']) {
|
||||
|
|
|
@ -107,7 +107,7 @@ Note that the query must be terminated by a \$
|
|||
|
||||
Created by @danogentili (@daniilgentili) using the daniil.it/MadelineProto PHP MTProto client.";
|
||||
while (true) {
|
||||
$updates = $MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
$updates = $MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
foreach ($updates as $update) {
|
||||
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
|
||||
try {
|
||||
|
|
|
@ -109,7 +109,7 @@ function recurse($array, $prefix = '')
|
|||
}
|
||||
$offset = 0;
|
||||
while (true) {
|
||||
$updates = $MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
$updates = $MadelineProto->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); // Just like in the bot API, you can specify an offset, a limit and a timeout
|
||||
foreach ($updates as $update) {
|
||||
$offset = $update['update_id'] + 1; // Just like in the bot API, the offset must be set to the last update_id
|
||||
switch ($update['update']['_']) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user