gui: RPC client, download table model, and a live main window
First vertical slice of velox-gui, built entirely against tools/mockd (no daemon dependency): - rpc/: RpcConnection runs a QLocalSocket on a worker thread with newline-delimited JSON-RPC framing, drives the session.hello / session.subscribe handshake, and reconnects with exponential backoff (250 ms -> 8 s). RpcClient is the main-thread face: marshals calls onto the worker, delivers replies as main-thread callbacks, re-emits server notifications as typed Qt signals, and issues the one-shot download.list on reaching Connected. - models/DownloadTableModel: QAbstractTableModel over TaskSummary. A progress batch is a row patch with a narrow dataChanged over the value columns only; beginResetModel() is reserved for the initial load and a reconnect resync. - widgets/ProgressDelegate: in-cell progress bar for the Status column. - mainwindow/MainWindow: the table, a status-bar connection dot, an offline banner instead of a modal, dialog-free pause/resume/stop actions, and QSettings column/geometry persistence. - gui/CMakeLists.txt links velox::proto (never velox::core, ADR 0009) and self-guards on the veloxproto target so main keeps configuring if it is ever absent again. - i18n from the first commit: every string via tr(), plus an Arabic .ts stub for the RTL check. - tests/: headless QTest for the model — proves the progress patch is a narrow dataChanged and never resets the model. Verified end-to-end against `mockd --tasks 300`: handshake, initial list, live progress batches applied to the model, and a clean Reconnecting -> Connected recovery when mockd is bounced mid-run. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_016Ne28kx4VreeBWZv82Nksd
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
// Shared RPC vocabulary for the GUI client. Lane GUI.
|
||||
//
|
||||
// The wire is JSON-RPC 2.0 over the Unix socket, newline-delimited (one object per line) —
|
||||
// exactly what tools/mockd and the real veloxd speak on the UDS transport. This header
|
||||
// carries only the small enums and structs the rpc/ layer passes around; the payload
|
||||
// *types* live in libveloxproto and are parsed at the model boundary.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QMetaType>
|
||||
#include <QString>
|
||||
|
||||
namespace velox::gui::rpc {
|
||||
|
||||
/// Where the connection is, for the status-bar dot and the offline banner. Anything other
|
||||
/// than Connected means the table is stale and toolbar actions should be disabled.
|
||||
enum class ConnectionState {
|
||||
Disconnected, ///< start() not called yet, or stop() was called
|
||||
Connecting, ///< TCP/UDS connect in flight
|
||||
Handshaking, ///< socket up; session.hello / session.subscribe in flight
|
||||
Connected, ///< handshake done, events flowing
|
||||
Reconnecting, ///< lost the socket, backing off before the next attempt
|
||||
};
|
||||
|
||||
/// Bare label for the status bar. Not tr()'d here — callers wrap it.
|
||||
inline const char *toString(ConnectionState s) noexcept {
|
||||
switch (s) {
|
||||
case ConnectionState::Disconnected:
|
||||
return "Disconnected";
|
||||
case ConnectionState::Connecting:
|
||||
return "Connecting";
|
||||
case ConnectionState::Handshaking:
|
||||
return "Connecting";
|
||||
case ConnectionState::Connected:
|
||||
return "Connected";
|
||||
case ConnectionState::Reconnecting:
|
||||
return "Reconnecting";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
/// A JSON-RPC error object, or the absence of one (code == 0).
|
||||
struct RpcError {
|
||||
int code = 0;
|
||||
QString message;
|
||||
QJsonValue data;
|
||||
|
||||
bool isError() const noexcept { return code != 0; }
|
||||
};
|
||||
|
||||
/// The outcome of one call: exactly one of result / error is meaningful.
|
||||
struct RpcReply {
|
||||
QJsonValue result;
|
||||
RpcError error;
|
||||
|
||||
bool ok() const noexcept { return !error.isError(); }
|
||||
};
|
||||
|
||||
// --- method names ---------------------------------------------------------------------
|
||||
namespace method {
|
||||
inline constexpr auto kSessionHello = "session.hello";
|
||||
inline constexpr auto kSessionSubscribe = "session.subscribe";
|
||||
inline constexpr auto kDownloadList = "download.list";
|
||||
inline constexpr auto kDownloadGet = "download.get";
|
||||
inline constexpr auto kDownloadStart = "download.start";
|
||||
inline constexpr auto kDownloadPause = "download.pause";
|
||||
inline constexpr auto kDownloadResume = "download.resume";
|
||||
inline constexpr auto kDownloadCancel = "download.cancel";
|
||||
inline constexpr auto kDownloadRemove = "download.remove";
|
||||
} // namespace method
|
||||
|
||||
// --- event names ---------------------------------------------------------------------
|
||||
namespace event {
|
||||
inline constexpr auto kTaskAdded = "event.task.added";
|
||||
inline constexpr auto kTaskRemoved = "event.task.removed";
|
||||
inline constexpr auto kTaskState = "event.task.state";
|
||||
inline constexpr auto kTaskProgress = "event.task.progress";
|
||||
inline constexpr auto kSpeedGlobal = "event.speed.global";
|
||||
inline constexpr auto kNotify = "event.notify";
|
||||
} // namespace event
|
||||
|
||||
} // namespace velox::gui::rpc
|
||||
|
||||
Q_DECLARE_METATYPE(velox::gui::rpc::RpcReply)
|
||||
Q_DECLARE_METATYPE(velox::gui::rpc::ConnectionState)
|
||||
Reference in New Issue
Block a user