contents/ui/controllers/IdentifiedTokensController.qml
import QtQuick
import org.kde.plasma.plasma5support as Plasma5Support
import "../CommandLedger.js" as CommandLedger
import "../IdentifiedTokens.js" as IdentifiedTokens
Item {
id: controller
property string commandPath: ""
property bool collectionEnabled: false
property string sshHost: ""
property int historyDays: 30
readonly property bool loading: CommandLedger.hasKind(lifecycle.commands, "identified")
readonly property var snapshot: lifecycle.snapshot
readonly property string errorKind: lifecycle.errorKind
readonly property bool sshAvailable: IdentifiedTokens.validHost(sshHost)
function request(includeRemote) {
if (!collectionEnabled) return false;
if (includeRemote === true && !sshAvailable) return false;
var plan = IdentifiedTokens.requestPlan(commandPath, historyDays, Date.now(), includeRemote === true ? sshHost : "");
lifecycle.clear();
if (plan.outcome !== "ready") {
lifecycle.errorKind = plan.outcome;
return false;
}
lifecycle.runSerial++;
var source = CommandLedger.withRunNonce(plan.command, lifecycle.runSerial, Date.now() + "-" + Math.random());
var descriptor = CommandLedger.descriptor("identified", "codex", Date.now(), IdentifiedTokens.requestDeadlineMs);
descriptor.plan = plan;
descriptor.context = lifecycle.context;
lifecycle.commands = CommandLedger.opened(lifecycle.commands, source, descriptor);
dataSource.connectSource(source);
return true;
}
Component.onDestruction: lifecycle.retireRequests()
Item {
id: lifecycle
objectName: "identifiedTokensLifecycle"
property int runSerial: 0
property var commands: ({})
property var snapshot: null
property string errorKind: ""
readonly property string context: JSON.stringify([controller.commandPath, controller.collectionEnabled,
controller.sshHost, controller.historyDays])
onContextChanged: clear()
function finishRequest(source) {
commands = CommandLedger.closed(commands, source);
dataSource.disconnectSource(source);
}
function retireRequests() {
var sources = CommandLedger.sourcesOfKind(commands, "identified");
for (var i = 0; i < sources.length; i++) finishRequest(sources[i]);
}
function clear() {
retireRequests();
snapshot = null;
errorKind = "";
}
function expireRequests(nowMs) {
var expired = CommandLedger.expired(commands, nowMs);
for (var i = 0; i < expired.length; i++) {
finishRequest(expired[i].sourceName);
errorKind = "timeout";
}
}
function acceptReply(source, stdoutText, exitCode) {
var descriptor = CommandLedger.find(commands, source);
if (!descriptor) return;
finishRequest(source);
if (!controller.collectionEnabled || descriptor.context !== context) return;
var result = IdentifiedTokens.decode(stdoutText, exitCode, descriptor.plan);
snapshot = result.outcome === "data" ? result.snapshot : null;
errorKind = result.outcome === "data" ? "" : result.outcome;
}
}
Plasma5Support.DataSource {
id: dataSource
engine: "executable"
interval: 0
onNewData: function(sourceName, data) {
lifecycle.acceptReply(sourceName, data ? data["stdout"] : "", data ? data["exit code"] : null);
}
}
Timer {
interval: 1000
repeat: true
running: controller.loading
onTriggered: lifecycle.expireRequests(Date.now())
}
}