#pragma once #include #include #include class QNetworkAccessManager; class QNetworkReply; class QTimer; class QQmlEngine; class QJSEngine; namespace PhpQml::Bridge { /// Owns the backend lifecycle and exposes its health to QML. /// /// Phase 1 implements **dev mode**: reads `BRIDGE_URL` and `BRIDGE_TOKEN` /// from env, periodically probes `/healthz`, and reports the result /// as `connectionState`. Bundled mode (spawning FrankenPHP as a child) /// arrives in Phase 4. See PLAN.md §3 (Run modes), §7 (BackendConnection). class BackendConnection : public QObject { Q_OBJECT QML_ELEMENT QML_SINGLETON Q_PROPERTY(Mode mode READ mode CONSTANT) Q_PROPERTY(QString url READ url CONSTANT) Q_PROPERTY(QString token READ token NOTIFY tokenChanged) Q_PROPERTY(ConnectionState connectionState READ connectionState NOTIFY connectionStateChanged) Q_PROPERTY(QString error READ error NOTIFY errorChanged) public: enum class Mode { Dev, Bundled, // Phase 4 }; Q_ENUM(Mode) /// Phase 1 surfaces only Connecting / Online / Error. The full enum /// (Reconnecting, Offline) lands with the Update Semantics layer in /// Phase 2 (PLAN.md §5). enum class ConnectionState { Connecting, Online, Error, }; Q_ENUM(ConnectionState) explicit BackendConnection(QObject* parent = nullptr); ~BackendConnection() override; static BackendConnection* create(QQmlEngine* engine, QJSEngine*); Mode mode() const noexcept { return m_mode; } QString url() const { return m_url; } QString token() const { return m_token; } ConnectionState connectionState() const noexcept { return m_state; } QString error() const { return m_error; } Q_INVOKABLE void restart(); signals: void tokenChanged(); void connectionStateChanged(); void errorChanged(); /// Forward-compatible signal for §3 *Edge cases — Per-session secret /// rotation*. In Phase 1 dev mode it is never emitted; bundled mode /// in Phase 4 will fire it on child restart. void tokenRotated(const QString& newToken); private slots: void probe(); void onProbeFinished(); private: void setState(ConnectionState s); void setError(const QString& msg); Mode m_mode = Mode::Dev; QString m_url; QString m_token; ConnectionState m_state = ConnectionState::Connecting; QString m_error; QNetworkAccessManager* m_nam = nullptr; QNetworkReply* m_pendingReply = nullptr; QTimer* m_retryTimer = nullptr; }; } // namespace PhpQml::Bridge