/* * SPDX-License-Identifier: GPL-3.0-or-later * * Plumber — ollie-gui's bridge to the plan9port plumbing system. * * Full plumb client: * - SEND: send() opens the "send" port on the plumber and writes a packed * plumb message; the plumber's rules resolve it (file:line -> edit port, * url -> web port, etc.). The source is "ollie" and the destination is * left empty so the rules decide. * - RECEIVE: dedicated reader threads open ports and block on reads. * The "ollie" port receives ollie-specific messages (ollie:// URLs). * Messages are emitted via signals on the GUI thread. * * The namespace socket is $NAMESPACE/plumb, or /tmp/ns.$USER.$DISPLAY/plumb * when $NAMESPACE is unset — the same resolution plan9's getns() performs. * * URL scheme for ollie plumb messages: * ollie://session/agent#block - navigate to block in chat * ollie://session/agent - switch to agent * ollie://session - switch to session */ #ifndef PLUMBER_H #define PLUMBER_H #include #include #include class PlumbReader; // reader living on its own thread // Plumber wraps plan9port plumbing for context-aware actions. // B3-click on text → plumber routes to appropriate handler (editor, browser, etc.) class Plumber : public QObject { Q_OBJECT QML_ELEMENT QML_SINGLETON public: explicit Plumber(QObject *parent = nullptr); ~Plumber() override; /*! Resolve the plumb socket path ($NAMESPACE/plumb or display fallback). */ static QString socketPath(); /*! * Build and send a plumb message carrying \a data (a token, path or URL) * with working directory \a wdir. Returns true if the plumber accepted the * write. On failure errorString() explains why. */ Q_INVOKABLE bool send(const QString &data, const QString &wdir = QString()); /*! Plumb text to a specific destination port. */ Q_INVOKABLE bool sendTo(const QString &data, const QString &dst, const QString &wdir = QString()); /*! Last send() error. */ Q_INVOKABLE QString errorString() const { return m_error; } /*! Check if plumber namespace is available. */ Q_INVOKABLE bool available() const; // Legacy compatibility aliases Q_INVOKABLE void plumb(const QString &text, const QString &wdir = QString()) { send(text, wdir); } Q_INVOKABLE void plumbTo(const QString &text, const QString &dst, const QString &wdir = QString()) { sendTo(text, dst, wdir); } /*! * Start the edit-port reader thread. Safe to call once; further calls are * no-ops. Reader failures are reported via readerError(). */ Q_INVOKABLE void startReader(); Q_SIGNALS: /*! * A plumb message arrived on the edit port: open \a file and, if \a addr is * non-empty, jump to it. Emitted on the GUI (Plumber's) thread. */ void edit(const QString &file, const QString &addr, const QString &wdir); /*! * A plumb message arrived on the ollie port. The \a url is an ollie:// URL: * ollie://session/agent#block - navigate to chat block * ollie://session/agent - switch to agent * ollie://session - switch to session */ void ollieMessage(const QString &url); /*! The reader stopped with an error (e.g. plumber not running). */ void readerError(const QString &message); /*! Send failed. */ void plumbError(const QString &error); private: PlumbReader *m_reader = nullptr; PlumbReader *m_ollieReader = nullptr; QString m_error; }; #endif // PLUMBER_H