chore: complete update
This commit is contained in:
45
src/Framework/Http/Responses/AdaptiveStreamResponse.php
Normal file
45
src/Framework/Http/Responses/AdaptiveStreamResponse.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Http\Responses;
|
||||
|
||||
use App\Framework\Http\HeaderKey;
|
||||
use App\Framework\Http\Response;
|
||||
use App\Framework\Http\Status;
|
||||
use App\Framework\Http\Headers;
|
||||
use App\Framework\Http\Streaming\AdaptivePlaylist;
|
||||
use App\Framework\Http\Streaming\StreamingFormat;
|
||||
|
||||
final readonly class AdaptiveStreamResponse implements Response, Streamable
|
||||
{
|
||||
public string $body;
|
||||
|
||||
public Headers $headers;
|
||||
|
||||
public function __construct(
|
||||
public AdaptivePlaylist $playlist,
|
||||
public Status $status = Status::OK,
|
||||
Headers $headers = new Headers(),
|
||||
|
||||
public StreamingFormat $format = StreamingFormat::HLS
|
||||
) {
|
||||
$this->body = $this->playlist->generate($this->format);
|
||||
|
||||
$this->headers = $headers
|
||||
->with(HeaderKey::CACHE_CONTROL, 'max-age=60', )
|
||||
->with(HeaderKey::ACCESS_CONTROL_ALLOW_ORIGIN, '*' )
|
||||
->with(HeaderKey::ACCESS_CONTROL_ALLOW_METHODS, 'GET, HEAD, OPTIONS')
|
||||
->with(HeaderKey::ACCESS_CONTROL_ALLOW_HEADERS, 'RANGE' );
|
||||
|
||||
// Format-spezifische Header setzen
|
||||
#$this->headers = $this->headers->with('Content-Type', $this->format->getContentType());
|
||||
|
||||
// Standard Streaming-Header
|
||||
#$this->headers = $this->headers
|
||||
# ->with('Cache-Control', 'max-age=60')
|
||||
# ->with('Access-Control-Allow-Origin', '*')
|
||||
# ->with('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS')
|
||||
# ->with('Access-Control-Allow-Headers', 'Range');
|
||||
}
|
||||
}
|
||||
22
src/Framework/Http/Responses/JsonResponse.php
Normal file
22
src/Framework/Http/Responses/JsonResponse.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Http\Responses;
|
||||
|
||||
use App\Framework\Http\Headers;
|
||||
use App\Framework\Http\Response;
|
||||
use App\Framework\Http\Status;
|
||||
|
||||
final readonly class JsonResponse implements Response
|
||||
{
|
||||
public Headers $headers;
|
||||
|
||||
public string $body;
|
||||
public function __construct(
|
||||
array $body = [],
|
||||
public Status $status = Status::OK,
|
||||
) {
|
||||
$this->headers = new Headers()->with('Content-Type', 'application/json');
|
||||
$this->body = json_encode($body);
|
||||
}
|
||||
}
|
||||
21
src/Framework/Http/Responses/MediaType.php
Normal file
21
src/Framework/Http/Responses/MediaType.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Http\Responses;
|
||||
|
||||
enum MediaType: string
|
||||
{
|
||||
case VIDEO = 'video';
|
||||
case AUDIO = 'audio';
|
||||
case UNKNOWN = 'unknown';
|
||||
|
||||
|
||||
public static function fromMimeType(string $mimeType): self
|
||||
{
|
||||
return match (true) {
|
||||
str_starts_with($mimeType, 'video/') => self::VIDEO,
|
||||
str_starts_with($mimeType, 'audio/') => self::AUDIO,
|
||||
default => self::UNKNOWN
|
||||
};
|
||||
}
|
||||
}
|
||||
20
src/Framework/Http/Responses/NotFound.php
Normal file
20
src/Framework/Http/Responses/NotFound.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\Http\Responses;
|
||||
|
||||
use App\Framework\Http\Headers;
|
||||
use App\Framework\Http\Response;
|
||||
use App\Framework\Http\Status;
|
||||
|
||||
final readonly class NotFound implements Response
|
||||
{
|
||||
public Status $status;
|
||||
public Headers $headers;
|
||||
|
||||
public function __construct(
|
||||
public string $body = 'Not Found',
|
||||
) {
|
||||
$this->status = Status::NOT_FOUND;
|
||||
$this->headers = new Headers();
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\Http\Responses;
|
||||
|
||||
use App\Framework\Http\Headers;
|
||||
use App\Framework\Http\Response;
|
||||
use App\Framework\Http\Status;
|
||||
|
||||
class Redirect implements Response
|
||||
{
|
||||
public private(set) string $body = '';
|
||||
public private(set) Status $status = Status::FOUND;
|
||||
public \App\Framework\Http\Headers $headers {
|
||||
get {
|
||||
return new Headers()->with('Location', $this->body);
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/Framework/Http/Responses/RedirectResponse.php
Normal file
24
src/Framework/Http/Responses/RedirectResponse.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\Http\Responses;
|
||||
|
||||
use App\Framework\Http\HeaderKey;
|
||||
use App\Framework\Http\Headers;
|
||||
use App\Framework\Http\Response;
|
||||
use App\Framework\Http\Status;
|
||||
use App\Framework\Http\Uri;
|
||||
|
||||
final readonly class RedirectResponse implements Response
|
||||
{
|
||||
public Headers $headers;
|
||||
public string $body;
|
||||
public Status $status;
|
||||
|
||||
public function __construct(
|
||||
public Uri $location = new Uri('/'),
|
||||
) {
|
||||
$this->status = Status::FOUND;
|
||||
$this->body = '';
|
||||
$this->headers = new Headers()->with(HeaderKey::LOCATION, (string)$this->location);
|
||||
}
|
||||
}
|
||||
71
src/Framework/Http/Responses/SseResponse.php
Normal file
71
src/Framework/Http/Responses/SseResponse.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Http\Responses;
|
||||
|
||||
use App\Framework\Http\Headers;
|
||||
use App\Framework\Http\Response;
|
||||
use App\Framework\Http\Status;
|
||||
use App\Framework\Router\Result\SseEvent;
|
||||
use App\Framework\Router\Result\SseResult;
|
||||
use App\Framework\Router\Result\SseResultWithCallback;
|
||||
use Closure;
|
||||
|
||||
/**
|
||||
* Response-Klasse für Server-Sent Events
|
||||
*/
|
||||
final class SseResponse implements Response, Streamable
|
||||
{
|
||||
public readonly Status $status;
|
||||
public readonly Headers $headers;
|
||||
public readonly string $body;
|
||||
|
||||
public array $initialEvents = [];
|
||||
|
||||
/**
|
||||
* @var int Maximale Streaming-Dauer in Sekunden (0 = unbegrenzt)
|
||||
*/
|
||||
public readonly int $maxDuration;
|
||||
|
||||
/**
|
||||
* @var int Intervall für Heartbeats in Sekunden
|
||||
*/
|
||||
public readonly int $heartbeatInterval;
|
||||
|
||||
/**
|
||||
* @param SseResult $sseResult Das SseResult, aus dem die Response erstellt wird
|
||||
* @param Closure|null $streamCallback
|
||||
*/
|
||||
public function __construct(SseResult $sseResult, public readonly ?Closure $streamCallback = null)
|
||||
{
|
||||
$this->status = $sseResult->status;
|
||||
|
||||
$this->body = '';
|
||||
|
||||
// Standard SSE-Header
|
||||
$headerData = [
|
||||
'Content-Type' => 'text/event-stream',
|
||||
'Cache-Control' => 'no-cache',
|
||||
'Connection' => 'keep-alive',
|
||||
'X-Accel-Buffering' => 'no', // Nginx buffering deaktivieren
|
||||
];
|
||||
|
||||
// Benutzerdefinierte Header hinzufügen
|
||||
foreach ($sseResult->headers as $name => $value) {
|
||||
$headerData[$name] = $value;
|
||||
}
|
||||
|
||||
$this->headers = new Headers($headerData);
|
||||
|
||||
// Initiale Events aus dem SseResult speichern
|
||||
$this->initialEvents = $sseResult->getInitialEvents();
|
||||
|
||||
// Globales Retry-Interval setzen, falls definiert
|
||||
if ($sseResult->retryInterval !== null) {
|
||||
$this->initialEvents[] = new SseEvent('', null, null, $sseResult->retryInterval);
|
||||
}
|
||||
|
||||
$this->maxDuration = $sseResult->maxDuration;
|
||||
$this->heartbeatInterval = $sseResult->heartbeatInterval;;
|
||||
}
|
||||
}
|
||||
29
src/Framework/Http/Responses/StreamResponse.php
Normal file
29
src/Framework/Http/Responses/StreamResponse.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Http\Responses;
|
||||
|
||||
use App\Framework\Http\Headers;
|
||||
use App\Framework\Http\Range;
|
||||
use App\Framework\Http\Response;
|
||||
use App\Framework\Http\Status;
|
||||
|
||||
final readonly class StreamResponse implements Response, Streamable
|
||||
{
|
||||
|
||||
public string $body;
|
||||
|
||||
public function __construct(
|
||||
public Status $status = Status::OK,
|
||||
public Headers $headers = new Headers(),
|
||||
#public mixed $fileContent,
|
||||
|
||||
public string $filePath = '',
|
||||
public int $fileSize = 0,
|
||||
public string $mimeType = 'application/octet-stream',
|
||||
public ?Range $range = null,
|
||||
public MediaType $mediaType = MediaType::UNKNOWN,
|
||||
) {
|
||||
$this->body = '';
|
||||
}
|
||||
}
|
||||
8
src/Framework/Http/Responses/Streamable.php
Normal file
8
src/Framework/Http/Responses/Streamable.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\Http\Responses;
|
||||
|
||||
interface Streamable
|
||||
{
|
||||
|
||||
}
|
||||
59
src/Framework/Http/Responses/WebSocketResponse.php
Normal file
59
src/Framework/Http/Responses/WebSocketResponse.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Http\Responses;
|
||||
|
||||
use App\Framework\Http\Headers;
|
||||
use App\Framework\Http\Response;
|
||||
use App\Framework\Http\Status;
|
||||
use App\Framework\Router\Result\WebSocketResult;
|
||||
|
||||
/**
|
||||
* Response-Klasse für WebSocket-Upgrade
|
||||
*/
|
||||
final readonly class WebSocketResponse implements Response, Streamable
|
||||
{
|
||||
public Status $status;
|
||||
public Headers $headers;
|
||||
public string $body;
|
||||
|
||||
public function __construct(
|
||||
private WebSocketResult $webSocketResult,
|
||||
private string $websocketKey
|
||||
) {
|
||||
$this->status = $webSocketResult->status;
|
||||
|
||||
// WebSocket-Upgrade-Header
|
||||
$headerData = [
|
||||
'Upgrade' => 'websocket',
|
||||
'Connection' => 'Upgrade',
|
||||
'Sec-WebSocket-Accept' => $this->generateAcceptKey($this->websocketKey),
|
||||
];
|
||||
|
||||
// Subprotokoll hinzufügen, falls unterstützt
|
||||
$subprotocols = $webSocketResult->getSubprotocols();
|
||||
if (!empty($subprotocols)) {
|
||||
$headerData['Sec-WebSocket-Protocol'] = implode(', ', $subprotocols);
|
||||
}
|
||||
|
||||
// Benutzerdefinierte Header hinzufügen
|
||||
foreach ($webSocketResult->headers as $name => $value) {
|
||||
$headerData[$name] = $value;
|
||||
}
|
||||
|
||||
$this->headers = new Headers($headerData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generiert den Accept-Key für WebSocket-Handshake
|
||||
*/
|
||||
private function generateAcceptKey(string $key): string
|
||||
{
|
||||
return base64_encode(hash('sha1', $key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
|
||||
}
|
||||
|
||||
public function getWebSocketResult(): WebSocketResult
|
||||
{
|
||||
return $this->webSocketResult;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user