downloadToCallable for media.

This commit is contained in:
Alexander Pankratov 2020-01-20 03:13:15 +03:00
parent a42356592e
commit 6ef127e9a8
2 changed files with 79 additions and 44 deletions

View File

@ -3,7 +3,6 @@
namespace TelegramApiServer\Controllers;
use Amp\ByteStream\ResourceInputStream;
use Amp\Coroutine;
use Amp\Http\Server\Request;
use Amp\Http\Server\RequestHandler\CallableRequestHandler;
use Amp\Http\Server\Response;
@ -21,8 +20,10 @@ abstract class AbstractApiController
public const JSON_HEADER = ['Content-Type'=>'application/json;charset=utf-8'];
protected Client $client;
protected Request $request;
protected $extensionClass;
public array $page = [
'headers' => self::JSON_HEADER,
'success' => false,
@ -40,8 +41,8 @@ abstract class AbstractApiController
{
return new CallableRequestHandler(
static function (Request $request) use($client, $extensionClass) {
$requestCallback = new static($client, $extensionClass);
$response = yield from $requestCallback->process($request);
$requestCallback = new static($client, $request, $extensionClass);
$response = yield from $requestCallback->process();
return new Response(
$requestCallback->page['code'],
@ -52,9 +53,10 @@ abstract class AbstractApiController
);
}
public function __construct(Client $client, $extensionClass)
public function __construct(Client $client, Request $request, $extensionClass = null)
{
$this->client = $client;
$this->request = $request;
$this->extensionClass = $extensionClass;
}
@ -63,33 +65,31 @@ abstract class AbstractApiController
* @return ResourceInputStream|string
* @throws \Throwable
*/
public function process(Request $request)
public function process()
{
$body = '';
while ($chunk = yield $request->getBody()->read()) {
$body .= $chunk;
}
$this->resolvePath($request->getAttribute(Router::class));
$this->resolveRequest($request->getUri()->getQuery(), $body, $request->getHeader('Content-Type'));
$this->resolvePath($this->request->getAttribute(Router::class));
yield from $this->resolveRequest($this->request);
yield from $this->generateResponse();
return $this->getResponse();
}
/**
* Получаем параметры из GET и POST
*
* @param string $query
* @param string|null $body
* @param string|null $contentType
* @param Request $request
*
* @return AbstractApiController
*/
private function resolveRequest(string $query, $body, $contentType)
private function resolveRequest(Request $request)
{
$query = $request->getUri()->getQuery();
$body = '';
while ($chunk = yield $request->getBody()->read()) {
$body .= $chunk;
}
$contentType = $request->getHeader('Content-Type');
parse_str($query, $get);
switch ($contentType) {
@ -144,9 +144,9 @@ abstract class AbstractApiController
protected function callApiCommon($madelineProto)
{
$pathCount = count($this->api);
if ($pathCount === 1 && is_callable([$this->extensionClass,$this->api[0]])) {
if ($pathCount === 1 && $this->extensionClass && is_callable([$this->extensionClass,$this->api[0]])) {
/** @var ApiExtensions|SystemApiExtensions $madelineProtoExtensions */
$madelineProtoExtensions = new $this->extensionClass($madelineProto);
$madelineProtoExtensions = new $this->extensionClass($madelineProto, $this->request);
$result = $madelineProtoExtensions->{$this->api[0]}(...$this->parameters);
} else {
//Проверяем нет ли в MadilineProto такого метода.
@ -204,7 +204,7 @@ abstract class AbstractApiController
}
if (isset($this->page['response']['stream'])) {
$this->page['headers'] = $this->page['response']['headers'];
return new ResourceInputStream($this->page['response']['stream']);
return $this->page['response']['stream'];
}
$data = [

View File

@ -4,6 +4,9 @@
namespace TelegramApiServer\MadelineProtoExtensions;
use Amp\ByteStream\IteratorStream;
use Amp\Http\Server\Request;
use Amp\Producer;
use Amp\Promise;
use danog\MadelineProto\TL\Conversion\BotAPI;
use OutOfRangeException;
@ -16,10 +19,12 @@ class ApiExtensions
use BotAPI;
private MadelineProto\Api $madelineProto;
private Request $request;
public function __construct(MadelineProto\Api $madelineProto)
public function __construct(MadelineProto\Api $madelineProto, Request $request)
{
$this->madelineProto = $madelineProto;
$this->request = $request;
}
/**
@ -325,17 +330,7 @@ class ApiExtensions
);
}
$stream = fopen('php://memory', 'rwb');
yield $this->madelineProto->downloadToStream($info, $stream);
rewind($stream);
return [
'headers' => [
'Content-Length' => $info['size'],
'Content-Type' => $info['mime'],
],
'stream' => $stream,
];
return $this->downloadToResponse($info);
}
);
}
@ -399,17 +394,7 @@ class ApiExtensions
$info = $infoFull;
}
$stream = fopen('php://memory', 'rwb');
yield $this->madelineProto->downloadToStream($info, $stream);
rewind($stream);
return [
'headers' => [
'Content-Length' => $info['size'],
'Content-Type' => $info['mime'],
],
'stream' => $stream,
];
return $this->downloadToResponse($info);
}
);
}
@ -440,4 +425,54 @@ class ApiExtensions
);
}
private function getByteRange(?string $header) {
$matches = [
'start' => 0,
'end' => -1
];
if ($header) {
preg_match("~bytes=(?'start'\d+)-(?'end'\d*)~", $header, $matches);
}
return [
'start' => (int) $matches['start'],
'end' => (int) $matches['end'] ?: -1
];
}
private function downloadToResponse(array $info) {
$range = $this->getByteRange($this->request->getHeader('Range'));
if ($range['end'] === -1) {
$range['end'] = $info['size'] - 1;
} else {
$range['end'] = min($range['end'], $info['size'] - 1);
}
$stream = new IteratorStream(new Producer(function (callable $emit) use($info, $range) {
yield $this->madelineProto->downloadToCallable($info, static function($payload) use($emit) {
yield $emit($payload);
return strlen($payload);
}, null, false, $range['start'], $range['end'] + 1);
}));
$headers = [
'Content-Type' => $info['mime'],
// 'Accept-Ranges' => 'bytes',
// 'Content-Transfer-Encoding'=> 'Binary',
];
if ($range['start'] > 0 || $range['end'] < $info['size'] - 1) {
$headers['Content-Length'] = ($range['end'] - $range['start'] + 1);
$headers['Content-Range'] = "bytes {$range['start']}-{$range['end']}/{$info['size']}";
} else {
$headers['Content-Length'] = $info['size'];
}
return [
'headers' => $headers,
'stream' => $stream,
];
}
}