mirror of
https://github.com/logos-co/logos-protocol.git
synced 2026-08-31 14:01:14 +00:00
fix(protocol): report the failures that happen AFTER acquire, on both twins
#40 made lp_invoke_async able to report a failure, but only for the two conditions produced ABOVE the transport: acquire failure and the unauthorized sentinel. Everything the transport learns while the call is in flight was still discarded — PlainLogosObject answered a bare QVariant() for a timeout and for `ResultMessage.ok == false` alike, and LogosAPIConsumer hard-coded an empty CallError next to it. Two ordinary failures therefore still reported success on both entry points: a TIMEOUT, and MODULE NOT LOADED against a host that is up (which is not an acquire failure on the plain wire — requestObject hands back a handle for any name over an open connection). The information already exists: ResultMessage carries err/errCode, the futures know they expired, QtRO knows its pending call never finished. It had nowhere to go because LogosObject's callMethod returns a lone QVariant and its callMethodAsync callback takes a lone QVariant. Widening those virtuals would append a vtable slot to an installed, subclassed interface, so instead this adds LogosObjectErrorChannel — a SIBLING interface reached by dynamic_cast. LogosObject's size, layout and vtable are unchanged (verified: a subclass compiled against the old and new headers emits the same 14-entry vtable with identical slot indices), and a transport that does not implement it keeps today's behaviour. logos_protocol.cpp needs no change: lp_invoke and lp_invoke_async already render this CallError, so both twins gain the coverage together. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a1f3c7e3a0
commit
ef7539efbe
@@ -141,6 +141,16 @@ QVariant LogosAPIConsumer::invokeRemoteMethod(const QString& authToken, const QS
|
||||
qDebug() << "[LogosObject] LogosAPIConsumer: calling via LogosObject::callMethod" << methodName;
|
||||
// No release() here: the handle stays cached for the next call. Released in
|
||||
// clearObjectCache() (destructor / reconnect) or evicted when stale.
|
||||
//
|
||||
// Prefer the error channel when the transport implements it (see
|
||||
// LogosObjectErrorChannel in logos_object.h). Without it, `err` could only
|
||||
// ever describe an ACQUIRE failure — everything that went wrong after the
|
||||
// handle existed (the deadline elapsing, the connection dropping, the peer
|
||||
// answering "not published") came back as a bare QVariant() with a clean
|
||||
// err, i.e. reported as a method that returned null.
|
||||
if (auto* channel = dynamic_cast<LogosObjectErrorChannel*>(plugin))
|
||||
return channel->callMethodWithError(authToken, methodName, args,
|
||||
timeout.ms, err);
|
||||
return plugin->callMethod(authToken, methodName, args, timeout.ms);
|
||||
}
|
||||
|
||||
@@ -216,6 +226,23 @@ void LogosAPIConsumer::invokeRemoteMethodAsync(const QString& authToken, const Q
|
||||
// before the transport callback fires, the callback is silently dropped and
|
||||
// the handle is released by the destructor's clearObjectCache(), not here.
|
||||
QPointer<LogosAPIConsumer> self(this);
|
||||
|
||||
// Prefer the error channel when the transport implements it. The lambda
|
||||
// below used to take only `QVariant result` and hand the caller a
|
||||
// hard-coded empty logos::CallError — so once acquire had succeeded, every
|
||||
// async outcome was reported as a success, whatever actually happened.
|
||||
if (auto* channel = dynamic_cast<LogosObjectErrorChannel*>(plugin)) {
|
||||
channel->callMethodAsyncWithError(authToken, methodName, args, timeout.ms,
|
||||
[callback, self](QVariant result, const logos::CallError& err) {
|
||||
if (!self)
|
||||
return;
|
||||
callback(std::move(result), err);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Transport without an error channel (the mock): unchanged behaviour —
|
||||
// the value, and no diagnosis to give.
|
||||
plugin->callMethodAsync(authToken, methodName, args, timeout.ms,
|
||||
[callback, self](QVariant result) {
|
||||
if (!self)
|
||||
|
||||
Reference in New Issue
Block a user