Prove every ext-state write by reading the key back, so no guard is constant-true
SetProjExtState's return describes the whole extname. The persist and the instrument's publish now re-read their key; both refusals can finally fire.
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "shell/instrument/reaper_bridge.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "core/instrument/map/bridge_marshal.h"
|
||||
@@ -112,7 +114,9 @@ std::optional<std::string> ReaperBridge::readReasamplerExtState(const std::strin
|
||||
|
||||
bool ReaperBridge::writeGuarded(const std::string& key, const std::string& value,
|
||||
const char* requiredPrefix) {
|
||||
if (!setProjExtState_ || !hostApp_) return false;
|
||||
// getProjExtState_ is required too: without it the write could not be proven, and an
|
||||
// unprovable write may not be reported as a landed one.
|
||||
if (!setProjExtState_ || !getProjExtState_ || !hostApp_) return false;
|
||||
// Read-only-BANK guard: this module writes the two sanctioned per-instance prefixes
|
||||
// and nothing else. Any other key is refused rather than widening the instrument's
|
||||
// write surface (banks/view/tail/assign stay extension-owned).
|
||||
@@ -121,14 +125,20 @@ bool ReaperBridge::writeGuarded(const std::string& key, const std::string& value
|
||||
|
||||
auto* reaper = static_cast<Steinberg::IReaperHostApplication*>(hostApp_);
|
||||
void* proj = reaper->getReaperParent(3); // null = current project (same as reads)
|
||||
// SetProjExtState returns the size of the extname's state — after storing a
|
||||
// non-empty value that's necessarily > 0, so <= 0 means the write did not land (the
|
||||
// publish path retries next reload tick; a silent drop would leave holds unprotected).
|
||||
// A deliberate CLEAR (empty value) shrinks the state and can legitimately return 0,
|
||||
// so it is reported as landed.
|
||||
const int rv =
|
||||
setProjExtState_(proj, kProjExtNamespace(), key.c_str(), value.c_str());
|
||||
return value.empty() ? true : rv > 0;
|
||||
// The return is DELIBERATELY discarded: it describes the whole extname's state, not
|
||||
// this key, so testing it was a guard that could not fire for the bake publish
|
||||
// (wire::extStateWriteLanded owns the reasoning). The read-back below is the proof.
|
||||
setProjExtState_(proj, kProjExtNamespace(), key.c_str(), value.c_str());
|
||||
|
||||
const auto back = wire::readProjExtStateGrowing([&](char* buf, int cap) {
|
||||
return getProjExtState_(proj, kProjExtNamespace(), key.c_str(), buf, cap);
|
||||
});
|
||||
if (back.status == wire::GrowingExtStateRead::Status::Overflow)
|
||||
return false; // could not check -> report unconfirmed, never a claimed success
|
||||
return wire::extStateWriteLanded(
|
||||
value, back.status == wire::GrowingExtStateRead::Status::Complete
|
||||
? std::optional<std::string>(back.value)
|
||||
: std::nullopt);
|
||||
}
|
||||
|
||||
bool ReaperBridge::writeUsageExtState(const std::string& usageKey,
|
||||
|
||||
Reference in New Issue
Block a user