ollie/kde/gui/plumber.h

101 lines
3.5 KiB
C++

/*
* 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 <QObject>
#include <QString>
#include <QQmlEngine>
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