fix: replace retained report sessions when re-adding queue items

This commit is contained in:
2026-10-22 17:20:19 +02:00
parent b132bab393
commit 3ff498720b
6 changed files with 96 additions and 16 deletions
+3 -2
View File
@@ -40,8 +40,9 @@ Player *player_create(void);
// Opt-in reporting must be initialized before opening media. Creates a new 0600
// file exclusively; errors never change playback state. Error buffers hold 512 bytes.
bool player_set_progress_file(Player *player, const char *path, char *error);
// Register immutable queue destinations without changing current playback. Each path is new;
// revisits append only to the original owned inode. Conflicting identities/paths are rejected.
// Register queue destinations without changing playback. Each path is new and stays reserved.
// A fresh path replaces an identity's previous session after draining its writer; callers
// reject identities still queued. Revisits append only to the registered session's owned inode.
// Atomic batch: all registrations succeed or none do. Strings are copied before returning.
bool player_register_progress_files(Player *player, const char *const *identities,
const char *const *paths, int count, char *error);
+17 -3
View File
@@ -305,20 +305,34 @@ void ProgressReports::registerFile(const std::string &identity, const std::strin
void ProgressReports::registerFiles(const char *const *identities, const char *const *destinations, int count) {
std::lock_guard lock(mutex);
if (!identities || !destinations || count < 1 || count > 4096 ||
entries.size() + count > 4096)
paths.size() + count > 4096)
throw std::runtime_error("Queue reports exceed the 4096 retained registration limit");
std::map<std::string, Entry> additions;
std::set<std::string> newPaths;
for (int index = 0; index < count; ++index) {
const auto *identity = identities[index], *path = destinations[index];
if (!identity || !path || !ProgressReporter::validMediaIdentity(identity) ||
!*path || *path != '/' || singleIdentity == identity || entries.contains(identity) || additions.contains(identity))
!*path || *path != '/' || additions.contains(identity))
throw std::runtime_error("Invalid or conflicting queue progress identity");
if (singlePath == path || paths.contains(path) || !newPaths.insert(path).second)
throw std::runtime_error("Conflicting queue progress report path");
additions.emplace(identity, Entry{path, nullptr});
}
// Node merges allocate nothing: failed validation cannot partially register a batch.
// Validate and allocate the whole batch before retiring any previous sessions.
auto retire = [this](ProgressReporter *reporter) {
if (!reporter) return;
reporter->finish();
if (active == reporter) active = nullptr;
try { if (failure.empty()) failure = reporter->error(); } catch (...) {}
};
for (auto &[identity, entry] : additions) {
if (singleIdentity == identity) retire(single.get());
if (auto found = entries.find(identity); found != entries.end()) {
retire(found->second.reporter.get());
std::swap(found->second, entry);
}
}
// Node merges allocate nothing; replaced nodes remain in additions for destruction.
entries.merge(additions);
paths.merge(newPaths);
}