96inline void sweep_stale(
const std::filesystem::path &agent_dir,
97 std::string_view keep_digest,
const std::string &name,
98 const std::string &ext) {
99 namespace fs = std::filesystem;
102 for (fs::directory_iterator it(agent_dir, ec), end; !ec && it != end;
104 if (it->path().filename() == keep_digest)
106 std::error_code rm_ec;
107 fs::remove_all(it->path(), rm_ec);
113 const fs::path root = agent_dir.parent_path();
114 std::error_code legacy_ec;
115 fs::remove(root / (name +
".plugin"), legacy_ec);
117 fs::remove(root / (name +
"." + ext), legacy_ec);
135 const std::string &ext,
136 const std::string &bytes) {
137 namespace fs = std::filesystem;
141 const fs::path dir = agent_dir / digest;
142 const fs::path target = dir / (name +
"." + ext);
149 if (fs::exists(target, ec) && fs::file_size(target, ec) == bytes.size()) {
154 fs::create_directories(dir, ec);
155 if (!fs::is_directory(dir, ec)) {
156 throw std::runtime_error(
157 "Failed to create attachment cache directory " + dir.string() +
158 (ec ?
": " + ec.message() : std::string{}));
164 static std::atomic<uint64_t> seq{0};
166 const auto pid =
static_cast<long long>(_getpid());
168 const auto pid =
static_cast<long long>(getpid());
170 const fs::path staged =
171 dir / (
"." + name +
"." + std::to_string(pid) +
"." +
172 std::to_string(seq.fetch_add(1)) +
".tmp");
175 std::ofstream ofs(staged, std::ios::out | std::ios::binary);
177 throw std::runtime_error(
"Failed to open " + staged.string() +
178 " for writing the attachment from the broker");
180 ofs.write(bytes.data(),
static_cast<std::streamsize
>(bytes.size()));
183 std::error_code rm_ec;
184 fs::remove(staged, rm_ec);
185 throw std::runtime_error(
186 "Failed to write the attachment from the broker to " +
194 fs::rename(staged, target, ec);
200 std::error_code check_ec;
201 const bool usable = fs::exists(target, check_ec) &&
202 fs::file_size(target, check_ec) == bytes.size();
203 std::error_code rm_ec;
204 fs::remove(staged, rm_ec);
206 throw std::runtime_error(
"Failed to install the attachment at " +
207 target.string() +
": " + ec.message());
std::filesystem::path store_attachment(const std::string &name, const std::string &ext, const std::string &bytes)
Persist a broker-served attachment under its content digest and return the path to load it from.