From c6ae9a925552c59e62cb856e2e840fe7bbedd77a Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Wed, 21 Mar 2018 11:59:56 +0100 Subject: [PATCH] Update PrimeModule dependency and finish writing socket interface --- composer.json | 2 +- socket.php | 2 +- src/danog/MadelineProto/Server.php | 2 +- src/danog/MadelineProto/Server/Handler.php | 85 +++++++++++++++++++++- src/danog/MadelineProto/TL_socket.tl | 2 +- 5 files changed, 85 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 5f4b41c96..ab0413723 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ }, "require": { "php": ">=5.6.0", - "danog/primemodule": "^1.0.2", + "danog/primemodule": "^1.0.3", "danog/magicalserializer": "^1.0", "phpseclib/phpseclib": "dev-master#27370df", "vlucas/phpdotenv": "^2.4", diff --git a/socket.php b/socket.php index 8c7c265f9..d2c5da4cb 100644 --- a/socket.php +++ b/socket.php @@ -2,5 +2,5 @@ require 'vendor/autoload.php'; -$handler = new \danog\MadelineProto\Server(['type' => AF_INET, 'protocol' => 0, 'address' => 'localhost', 'port' => 8000, 'transport_protocol' => 'tcp_abridged']); +$handler = new \danog\MadelineProto\Server(['type' => AF_INET, 'protocol' => 0, 'address' => 'localhost', 'port' => 8002]); $handler->start(); diff --git a/src/danog/MadelineProto/Server.php b/src/danog/MadelineProto/Server.php index 4b40f8c5f..bee2841de 100644 --- a/src/danog/MadelineProto/Server.php +++ b/src/danog/MadelineProto/Server.php @@ -63,7 +63,7 @@ class Server } elseif ($pid) { return $this->pids[] = $pid; } - $handler = new \danog\MadelineProto\Server\Handler($socket, $this->settings['transport_protocol'], null, null, null, null, null); + $handler = new \danog\MadelineProto\Server\Handler($socket, null, null, null, null, null, null); $handler->loop(); die; } diff --git a/src/danog/MadelineProto/Server/Handler.php b/src/danog/MadelineProto/Server/Handler.php index f63de4c3b..389ab1c15 100644 --- a/src/danog/MadelineProto/Server/Handler.php +++ b/src/danog/MadelineProto/Server/Handler.php @@ -29,7 +29,6 @@ class Handler extends \danog\MadelineProto\Connection $timeout = 2; $this->sock->setOption(\SOL_SOCKET, \SO_RCVTIMEO, $timeout); $this->sock->setOption(\SOL_SOCKET, \SO_SNDTIMEO, $timeout); - $this->protocol = $extra; $this->construct_TL(['socket' => __DIR__.'/../TL_socket.tl']); } @@ -56,13 +55,46 @@ class Handler extends \danog\MadelineProto\Connection public function loop() { + $buffer = ''; + + $first_byte = $this->sock->read(1); + if ($first_byte === chr(239)) { + $this->protocol = 'tcp_abridged'; + } else { + $first_byte .= $this->sock->read(3); + if ($first_byte === str_repeat(chr(238), 4)) { + $this->protocol = 'tcp_intermediate'; + } else { + $this->protocol = 'tcp_full'; + + $packet_length = unpack('V', $first_byte)[1]; + $packet = $this->read($packet_length - 4); + if (strrev(hash('crc32b', $first_byte.substr($packet, 0, -4), true)) !== substr($packet, -4)) { + throw new Exception('CRC32 was not correct!'); + } + $this->in_seq_no++; + $in_seq_no = unpack('V', substr($packet, 0, 4))[1]; + if ($in_seq_no != $this->in_seq_no) { + throw new Exception('Incoming seq_no mismatch'); + } + + $buffer = substr($packet, 4, $packet_length - 12); + } + } while (true) { pcntl_signal_dispatch(); $request_id = 0; try { - $message = $this->read_message(); + if ($buffer) { + $message = $buffer; + $buffer = ''; + var_dump("using buffer"); + } else { + $message = $this->read_message(); + } } catch (\danog\MadelineProto\NothingInTheSocketException $e) { + var_dump("nothing in the socket"); continue; } @@ -71,6 +103,7 @@ class Handler extends \danog\MadelineProto\Connection if ($message['_'] !== 'socketMessageRequest') { throw new \danog\MadelineProto\Exception('Invalid object received'); } + var_dump($message); $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) { @@ -132,8 +165,50 @@ class Handler extends \danog\MadelineProto\Connection public function send_exception($request_id, $e) { - echo $e; - //$this->send_message($this->serialize_object(['type' => 'socketMessageException'], ['request_id' => $request_id, 'exception' => $e])); + if ($e instanceof \danog\MadelineProto\RPCErrorException) { + $exception = ['_' => 'socketRPCErrorException']; + if ($e->getMessage() === $e->rpc) { + $exception['rpc_message'] = $e->rpc; + } else { + $exception['rpc_message'] = $e->rpc; + $exception['message'] = $e->getMessage(); + } + } else if ($e instanceof \danog\MadelineProto\TL\Exception) { + $exception = ['_' => 'socketTLException', 'message' => $e->getMessage()]; + } else if ($e instanceof \DOMException) { + $exception = ['_' => 'socketDOMException', 'message' => $e->getMessage()]; + } else { + $exception = ['_' => 'socketException', 'message' => $e->getMessage()]; + } + $exception['code'] = $e->getCode(); + $exception['trace'] = ['_' => 'socketTLTrace', 'frames' => []]; + $tl = false; + foreach (array_reverse($e->getTrace()) as $k => $frame) { + $tl_frame = ['_' => 'socketTLFrame']; + if (isset($frame['function']) && in_array($frame['function'], ['serialize_params', 'serialize_object'])) { + if ($frame['args'][2] !== '') { + $tl_frame['tl_param'] = $frame['args'][2]; + $tl = true; + } + } else { + if (isset($frame['function']) && ($frame['function'] === 'handle_rpc_error' && $k === count($this->getTrace()) - 1) || $frame['function'] === 'unserialize') { + continue; + } + if (isset($frame['file'])) { + $tl_frame['file'] = $frame['file']; + $tl_frame['line'] = $frame['line']; + } + if (isset($frame['function'])) { + $tl_frame['function'] = $frame['function']; + } + if (isset($frame['args'])) { + $tl_frame['args'] = json_encode($frame['args']); + } + $tl = false; + } + $exception['trace']['frames'][] = $tl_frame; + } + $this->send_message($this->serialize_object(['type' => 'socketMessageException'], ['request_id' => $request_id, 'exception' => $exception])); } public function send_response($request_id, $response) @@ -148,6 +223,8 @@ class Handler extends \danog\MadelineProto\Connection public function logger($message, $level) { + $message = ['_' => 'socketMessageLog', 'data' => $message, 'level' => $level, 'thread' => \danog\MadelineProto\Logger::$has_thread && is_object(\Thread::getCurrentThread()), 'process' => \danog\MadelineProto\Logger::is_fork(), 'file' => basename(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file'], '.php')]; + $this->send_message($this->serialize_object(['type' => 'socketMessageLog'], $message)); } public function update_handler($update) diff --git a/src/danog/MadelineProto/TL_socket.tl b/src/danog/MadelineProto/TL_socket.tl index ad975cd4d..b59ec8568 100644 --- a/src/danog/MadelineProto/TL_socket.tl +++ b/src/danog/MadelineProto/TL_socket.tl @@ -5,7 +5,7 @@ socketMessageRequest request_id:int method:vector args:vector<%DataJSON> 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; +socketMessageLog flags:# thread:flags.0?true process:flags.1?true file:flags.2?string level:int data:string = SocketMessage; socketMessageRawData stream_id:int data:bytes = SocketMessage; socketException message:string code:int trace:%SocketTLTrace = SocketException;