. * * @author Daniil Gentili * @copyright 2016-2020 Daniil Gentili * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 * * @link https://docs.madelineproto.xyz MadelineProto documentation */ namespace danog\MadelineProto\Ipc; use Amp\Ipc\Sync\ChannelledSocket; use Amp\Promise; use danog\MadelineProto\API; use danog\MadelineProto\Exception; use danog\MadelineProto\FileCallbackInterface; use danog\MadelineProto\Logger; use danog\MadelineProto\MTProtoTools\FilesLogic; use danog\MadelineProto\SessionPaths; use danog\MadelineProto\Tools; /** * IPC client. */ class Client extends ClientAbstract { use \danog\MadelineProto\Wrappers\Start; use \danog\MadelineProto\Wrappers\Templates; use FilesLogic; /** * Session. */ protected SessionPaths $session; /** * Constructor function. * * @param ChannelledSocket $socket IPC client socket * @param SessionPaths $session Session paths * @param Logger $logger Logger */ public function __construct(ChannelledSocket $server, SessionPaths $session, Logger $logger) { $this->logger = $logger; $this->server = $server; $this->session = $session; Tools::callFork($this->loopInternal()); } /** * Run the provided async callable. * * @param callable $callback Async callable to run * * @return \Generator */ public function loop(callable $callback): \Generator { return yield $callback(); } /** * Unreference. * * @return void */ public function unreference(): void { Tools::wait($this->disconnect()); } /** * Stop IPC server instance. * * @internal */ public function stopIpcServer(): Promise { $this->run = false; return $this->server->send(Server::SHUTDOWN); } /** * Restart IPC server instance. * * @internal */ public function restartIpcServer(): Promise { return $this->server->send(Server::SHUTDOWN); } /** * Whether we're an IPC client instance. * * @return boolean */ public function isIpc(): bool { return true; } /** * Upload file from URL. * * @param string|FileCallbackInterface $url URL of file * @param integer $size Size of file * @param string $fileName File name * @param callable $cb Callback (DEPRECATED, use FileCallbackInterface) * @param boolean $encrypted Whether to encrypt file for secret chats * * @return \Generator */ public function uploadFromUrl($url, int $size = 0, string $fileName = '', $cb = null, bool $encrypted = false): \Generator { if (\is_object($url) && $url instanceof FileCallbackInterface) { $cb = $url; $url = $url->getFile(); } $params = [$url, $size, $fileName, &$cb, $encrypted]; $wrapper = yield from Wrapper::create($params, $this->session, $this->logger); $wrapper->wrap($cb, false); return yield from $this->__call('uploadFromUrl', $wrapper); } /** * Upload file from callable. * * The callable must accept two parameters: int $offset, int $size * The callable must return a string with the contest of the file at the specified offset and size. * * @param mixed $callable Callable * @param integer $size File size * @param string $mime Mime type * @param string $fileName File name * @param callable $cb Callback (DEPRECATED, use FileCallbackInterface) * @param boolean $seekable Whether chunks can be fetched out of order * @param boolean $encrypted Whether to encrypt file for secret chats * * @return \Generator * * @psalm-return \Generator|Promise, mixed, mixed> */ public function uploadFromCallable(callable $callable, int $size, string $mime, string $fileName = '', $cb = null, bool $seekable = true, bool $encrypted = false): \Generator { if (\is_object($callable) && $callable instanceof FileCallbackInterface) { $cb = $callable; $callable = $callable->getFile(); } $params = [&$callable, $size, $mime, $fileName, &$cb, $seekable, $encrypted]; $wrapper = yield from Wrapper::create($params, $this->session, $this->logger); $wrapper->wrap($cb, false); $wrapper->wrap($callable, false); return yield from $this->__call('uploadFromCallable', $wrapper); } /** * Reupload telegram file. * * @param mixed $media Telegram file * @param callable $cb Callback (DEPRECATED, use FileCallbackInterface) * @param boolean $encrypted Whether to encrypt file for secret chats * * @return \Generator * * @psalm-return \Generator|Promise, mixed, mixed> */ public function uploadFromTgfile($media, $cb = null, bool $encrypted = false): \Generator { if (\is_object($media) && $media instanceof FileCallbackInterface) { $cb = $media; $media = $media->getFile(); } $params = [$media, &$cb, $encrypted]; $wrapper = yield from Wrapper::create($params, $this->session, $this->logger); $wrapper->wrap($cb, false); return yield from $this->__call('uploadFromTgfile', $wrapper); } /** * Download file to directory. * * @param mixed $messageMedia File to download * @param string|FileCallbackInterface $dir Directory where to download the file * @param callable $cb Callback (DEPRECATED, use FileCallbackInterface) * * @return \Generator Downloaded file path * * @psalm-return \Generator|Promise, mixed, mixed> */ public function downloadToDir($messageMedia, $dir, $cb = null): \Generator { if (\is_object($dir) && $dir instanceof FileCallbackInterface) { $cb = $dir; $dir = $dir->getFile(); } $params = [$messageMedia, $dir, &$cb]; $wrapper = yield from Wrapper::create($params, $this->session, $this->logger); $wrapper->wrap($cb, false); return yield from $this->__call('downloadToDir', $wrapper); } /** * Download file. * * @param mixed $messageMedia File to download * @param string|FileCallbackInterface $file Downloaded file path * @param callable $cb Callback (DEPRECATED, use FileCallbackInterface) * * @return \Generator Downloaded file path * * @psalm-return \Generator|Promise, mixed, mixed> */ public function downloadToFile($messageMedia, $file, $cb = null): \Generator { if (\is_object($file) && $file instanceof FileCallbackInterface) { $cb = $file; $file = $file->getFile(); } $params = [$messageMedia, $file, &$cb]; $wrapper = yield from Wrapper::create($params, $this->session, $this->logger); $wrapper->wrap($cb, false); return yield from $this->__call('downloadToFile', $wrapper); } /** * Download file to callable. * The callable must accept two parameters: string $payload, int $offset * The callable will be called (possibly out of order, depending on the value of $seekable). * The callable should return the number of written bytes. * * @param mixed $messageMedia File to download * @param callable|FileCallbackInterface $callable Chunk callback * @param callable $cb Status callback (DEPRECATED, use FileCallbackInterface) * @param bool $seekable Whether the callable can be called out of order * @param int $offset Offset where to start downloading * @param int $end Offset where to stop downloading (inclusive) * @param int $part_size Size of each chunk * * @return \Generator * * @psalm-return \Generator|Promise, mixed, mixed> */ public function downloadToCallable($messageMedia, callable $callable, $cb = null, bool $seekable = true, int $offset = 0, int $end = -1, int $part_size = null): \Generator { $messageMedia = (yield from $this->getDownloadInfo($messageMedia)); if (\is_object($callable) && $callable instanceof FileCallbackInterface) { $cb = $callable; $callable = $callable->getFile(); } $params = [$messageMedia, &$callable, &$cb, $seekable, $offset, $end, $part_size, ]; $wrapper = yield from Wrapper::create($params, $this->session, $this->logger); $wrapper->wrap($callable, false); $wrapper->wrap($cb, false); return yield from $this->__call('downloadToCallable', $wrapper); } /** * Placeholder. * * @param mixed ...$params Params * * @return void */ public function setEventHandler(...$params): void { throw new Exception("Can't use ".__FUNCTION__." in an IPC client instance, please use a full ".API::class." instance, instead!"); } /** * Placeholder. * * @param mixed ...$params Params * * @return void */ public function getEventHandler(...$params): void { throw new Exception("Can't use ".__FUNCTION__." in an IPC client instance, please use a full ".API::class." instance, instead!"); } }