Skip to content

Commit

Permalink
implement deletion of dns entries and REST api for it
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexander Busse authored and wirew0rm committed Feb 28, 2024
1 parent ac69eaf commit 48e9305
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 6 deletions.
8 changes: 6 additions & 2 deletions src/services/include/services/dns.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ class DnsHandler {
public:
void operator()(majordomo::RequestContext &rawCtx, const Context &ctx, const FlatEntryList &in, [[maybe_unused]] Context &replyContext, FlatEntryList &response) {
if (rawCtx.request.command == mdp::Command::Set) {
auto out = datastorage.addEntries(in.toEntries());
response = out;
if (ctx.doDelete) {
response = datastorage.deleteEntries(in.toEntries<QueryEntry>());
} else {
auto out = datastorage.addEntries(in.toEntries());
response = out;
}
} else if (rawCtx.request.command == mdp::Command::Get) {
auto result = datastorage.queryEntries(ctx);
response = { result };
Expand Down
28 changes: 28 additions & 0 deletions src/services/include/services/dns_client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,28 @@ struct DnsClient {
std::move(buf));
}

void unregisterSignalsAsync(std::function<void(std::vector<Entry>)> callback, const std::vector<Entry> &filter = {}) {
auto uri = URI<>::factory(_endpoint);
Context ctx;
ctx.doDelete = true;
uri = std::move(uri).setQuery(query::serialise(ctx));

IoBuffer buf;
FlatEntryList entrylist{ filter };
opencmw::serialise<YaS>(buf, entrylist);

_clientContext.set(
uri.build(), [callback = std::move(callback)](auto &msg) {
FlatEntryList resp;
IoBuffer buf{ msg.data };
if (!buf.empty()) {
deserialise<YaS, ProtocolCheck::ALWAYS>(buf, resp);
}
callback(resp.toEntries());
},
std::move(buf));
}

template<typename ReturnType>
auto _doSync(auto function, auto parameter, std::chrono::seconds timeout) {
std::atomic_bool received{ false };
Expand All @@ -90,12 +112,18 @@ struct DnsClient {
std::vector<Entry> registerSignals(const std::vector<Entry> &entries, std::chrono::seconds timeout = 20s) {
return _doSync<std::vector<Entry>>(&DnsClient::registerSignalsAsync, entries, timeout);
}
std::vector<Entry> unregisterSignals(const std::vector<Entry> &entries, std::chrono::seconds timeout = 20s) {
return _doSync<std::vector<Entry>>(&DnsClient::unregisterSignalsAsync, entries, timeout);
}
Entry registerSignal(const Entry &entry) {
auto s = registerSignals({ entry });
if (s.size() > 0)
return s[0];
return {};
}
std::vector<Entry> unregisterSignal(const Entry &entry) {
return unregisterSignals({ entry });
}
};

} // namespace opencmw::service::dns
Expand Down
24 changes: 24 additions & 0 deletions src/services/include/services/dns_storage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,30 @@ class DataStorage {
return result;
}

template<class ReturnEntryType = EntryType, class FilterT = EntryType>
std::vector<ReturnEntryType> deleteEntries(const std::vector<FilterT> entries) {
std::vector<ReturnEntryType> deletedEntries;
std::ranges::for_each(entries, [this, &deletedEntries](auto &e) {
auto d = deleteEntries(e);
std::ranges::move(d, std::back_inserter(deletedEntries));
});
return deletedEntries;
}

template<class ReturnEntryType = EntryType, class FilterT = FilterType>
std::vector<ReturnEntryType> deleteEntries(const FilterT &filter = {}) {
std::vector<ReturnEntryType> deletedEntries;
std::erase_if(_entries,
[&filter, &deletedEntries](const StorageEntryType &entry) {
if (filter == entry) {
deletedEntries.push_back(entry);
return true; // Remove the entry
}
return false; // Keep the entry
});
return deletedEntries;
}

const std::vector<StorageEntryType> &getEntries() const {
return _entries;
}
Expand Down
10 changes: 6 additions & 4 deletions src/services/include/services/dns_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ struct QueryEntry : Entry {

struct Context : QueryEntry {
[[maybe_unused]] MIME::MimeType contextType{ MIME::BINARY };
bool doDelete{ false };
};

struct FlatEntryList {
Expand Down Expand Up @@ -76,7 +77,8 @@ struct FlatEntryList {
#undef insert_into
}

[[nodiscard]] std::vector<Entry> toEntries() const {
template<typename EntryType = Entry>
[[nodiscard]] std::vector<EntryType> toEntries() const {
const std::size_t size = protocol.size();
assert(hostname.size() == size
&& port.size() == size
Expand All @@ -87,11 +89,11 @@ struct FlatEntryList {
&& signal_rate.size() == size
&& signal_type.size() == size);

std::vector<Entry> res;
std::vector<EntryType> res;
res.reserve(size);

for (std::size_t i = 0; i < size; ++i) {
res.emplace_back(Entry{ protocol[i],
res.emplace_back(EntryType{ protocol[i],
hostname[i],
port[i],
service_name[i],
Expand All @@ -110,7 +112,7 @@ struct FlatEntryList {
#define ENTRY_FIELDS protocol, hostname, port, service_name, service_type, signal_name, signal_unit, signal_rate, signal_type
ENABLE_REFLECTION_FOR(opencmw::service::dns::Entry, ENTRY_FIELDS)
ENABLE_REFLECTION_FOR(opencmw::service::dns::QueryEntry, ENTRY_FIELDS)
ENABLE_REFLECTION_FOR(opencmw::service::dns::Context, contextType, ENTRY_FIELDS)
ENABLE_REFLECTION_FOR(opencmw::service::dns::Context, contextType, doDelete, ENTRY_FIELDS)
ENABLE_REFLECTION_FOR(opencmw::service::dns::FlatEntryList, ENTRY_FIELDS) // everything is a vector<T> here
#undef ENTRY_FIELDS

Expand Down
66 changes: 66 additions & 0 deletions src/services/test/dns_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,23 @@ TEST_CASE("data storage - Renewing Entries") {
REQUIRE(e->ttl > now);
}

TEST_CASE("data storage - Deleting Entries") {
TestDataStorage ds;
ds.addEntry(entry_a);
ds.addEntry(entry_b);
ds.deleteEntries(entry_a);

REQUIRE(ds.getActiveEntriesCount() == 1);

auto entries = ds.entries();
REQUIRE(entries.size() == 1);
auto e = std::find(entries.begin(), entries.end(), entry_a);
REQUIRE(e == entries.end());

ds.addEntry(entry_a);
ds.addEntry(entry_c);
}

#ifndef __EMSCRIPTEN__

TEST_CASE("run services", "[DNS]") {
Expand Down Expand Up @@ -287,6 +304,55 @@ TEST_CASE("query", "[DNS]") {
REQUIRE(services[0] == entry_c);
}
}

TEST_CASE("client unregister entries", "[DNS]") {
FileDeleter fd;
majordomo::Broker<> broker{ "/Broker", {} };
auto fs = cmrc::assets::get_filesystem();
majordomo::RestBackend<majordomo::PLAIN_HTTP, decltype(fs)> rest_backend{ broker, fs };
DnsWorkerType dnsWorker{ broker, DnsHandler{} };

RunInThread restThread(rest_backend);
RunInThread brokerThread(broker);
RunInThread dnsThread(dnsWorker);

REQUIRE(waitUntilWorkerServiceAvailable(broker.context, dnsWorker));

std::vector<std::unique_ptr<opencmw::client::ClientBase>> clients;
clients.emplace_back(std::make_unique<client::MDClientCtx>(broker.context, 20ms, "dnsTestClient"));
clients.emplace_back(std::make_unique<client::RestClient>(opencmw::client::DefaultContentTypeHeader(MIME::BINARY)));
client::ClientContext clientContext{ std::move(clients) };
DnsClient restClient{ clientContext, URI<>{ "http://localhost:8080/dns" } };
restClient.registerSignals({ entry_a, entry_b, entry_c });

SECTION("unregister") {
auto deleted = restClient.unregisterSignal(entry_a);
REQUIRE(deleted.size() == 1);
REQUIRE(deleted.at(0) == entry_a);
auto remaining = restClient.querySignals();
REQUIRE(remaining.size() == 2);
REQUIRE(std::ranges::none_of(remaining, [](auto &e) { return e == entry_a; }));
}
SECTION("unregister entries") {
auto res = restClient.unregisterSignals({ entry_a, entry_b });
REQUIRE(res.size() == 2);

auto rem = restClient.querySignals();
REQUIRE(rem.size() == 1);
REQUIRE(rem.at(0) == entry_c);
}
SECTION("unregister group") {
REQUIRE(restClient.querySignals().size() == 3);
QueryEntry e;
e.service_name = "group a";
auto res = restClient.unregisterSignal(e);
REQUIRE(res.size() == 2);
auto remaining = restClient.querySignals();
REQUIRE(remaining.size() == 1);
REQUIRE(remaining.at(0) == entry_c);
}
}

#endif // __EMSCRIPTEN__

TEST_CASE("registering", "[DNS]") {
Expand Down

0 comments on commit 48e9305

Please sign in to comment.