#ifndef MPVHTTPSTREAMRELAY_H #define MPVHTTPSTREAMRELAY_H #include #include #include #include class QNetworkAccessManager; class QNetworkReply; class QTimer; class QTcpServer; class QTcpSocket; class MpvHttpStreamRelay : public QObject { Q_OBJECT public: explicit MpvHttpStreamRelay(QObject *parent = nullptr); ~MpvHttpStreamRelay() override; QUrl prepare(const QUrl &targetUrl, const QString &serverId, const QNetworkProxy &proxy); void stop(); Q_SIGNALS: void upstreamSpeedChanged(qint64 bytesPerSecond); private: struct ConnectionState { QByteArray buffer; QNetworkReply *reply = nullptr; QString routeToken; QUrl targetUrl; QString serverId; bool headersSent = false; bool headOnly = false; bool upstreamFinished = false; }; struct RouteState { QUrl targetUrl; QString serverId; QNetworkProxy proxy; }; void onNewConnection(); void onSocketReadyRead(QTcpSocket *socket); void onSocketDisconnected(QTcpSocket *socket); void processRequest(QTcpSocket *socket, const QByteArray &requestData); void sendReplyHeaders(QTcpSocket *socket); void pumpReplyToSocket(QTcpSocket *socket); void writeError(QTcpSocket *socket, int statusCode, const QByteArray &message); void closeConnection(QTcpSocket *socket); void recordRelayedBytes(qint64 bytes); void cleanupUnusedRoutes(); static QByteArray reasonPhrase(int statusCode); static bool isHopByHopHeader(QByteArray name); QTcpServer *m_server = nullptr; QNetworkAccessManager *m_network = nullptr; QTimer *m_speedTimer = nullptr; QHash m_connections; QHash m_routes; QUrl m_targetUrl; QString m_serverId; QString m_streamToken; qint64 m_bytesRelayedSinceLastTick = 0; }; #endif