aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar buttercat1791 <mjjurkoic@gmail.com>2024-08-08 08:53:20 -0500
committerLibravatar buttercat1791 <mjjurkoic@gmail.com>2024-08-08 08:53:20 -0500
commit5f2ac101fa951b55af699fb661866026d0998fef (patch)
tree0494f02864f270876f6f41cedfbb978a7008de7a
parentb69876b1786f5e99448266a3b74ca4404d7118fd (diff)
parent43b61ff06e18a79a3e16e38445e92b0ad678bd9f (diff)
Merge and resolve conflicting changes from master
-rw-r--r--CMakeLists.txt11
-rw-r--r--include/service/nostr_service_base.hpp5
-rw-r--r--src/data/filters.cpp2
-rw-r--r--src/service/nostr_service_base.cpp168
-rw-r--r--test/nostr_service_base_test.cpp12
5 files changed, 105 insertions, 93 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6b933d9..da52a2c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,9 +1,10 @@
cmake_minimum_required(VERSION 3.19)
-project(aedile VERSION 0.0.3)
-if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24")
- cmake_policy(SET CMP0135 NEW)
+if(CMAKE_VERSION VERSION_GREATER "3.24.0")
+ # FIXME this policy isn't compatible with versions prior to 3.24
+ cmake_policy(SET CMP0135 NEW)
endif()
+project(aedile VERSION 0.0.3)
include(ExternalProject)
include(FetchContent)
@@ -43,6 +44,7 @@ find_package(plog CONFIG REQUIRED)
find_package(websocketpp CONFIG REQUIRED)
#======== Configure uuid_v4 ========#
+
FetchContent_Declare(
uuid_v4
GIT_REPOSITORY git@github.com:crashoz/uuid_v4.git
@@ -100,7 +102,7 @@ set(SOURCES
${SIGNER_SOURCE_DIR}/noscrypt_signer.cpp
)
-add_library(aedile ${SOURCES} ${HEADERS})
+add_library(aedile ${SOURCES})
target_link_libraries(aedile PRIVATE
nlohmann_json::nlohmann_json
OpenSSL::SSL
@@ -109,6 +111,7 @@ target_link_libraries(aedile PRIVATE
websocketpp::websocketpp
noscrypt
)
+target_include_directories(aedile PUBLIC ${INCLUDE_DIR})
set_target_properties(aedile PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS YES)
#======== Build the tests ========#
diff --git a/include/service/nostr_service_base.hpp b/include/service/nostr_service_base.hpp
index c3f8c99..f1b91d1 100644
--- a/include/service/nostr_service_base.hpp
+++ b/include/service/nostr_service_base.hpp
@@ -58,7 +58,8 @@ public:
* @brief Queries all open relay connections for events matching the given set of filters, and
* returns all stored matching events returned by the relays.
* @param filters The filters to use for the query.
- * @returns A vector of all events matching the filters from all open relay connections.
+ * @returns A std::future that will eventually hold a vector of all events matching the filters
+ * from all open relay connections.
* @remark This method runs until the relays send an EOSE message, indicating they have no more
* stored events matching the given filters. When the EOSE message is received, the method
* will close the subscription for each relay and return the received events.
@@ -66,7 +67,7 @@ public:
* set on the filters in the range 1-64, inclusive. If no valid limit is given, it will be
* defaulted to 16.
*/
- virtual std::vector<std::shared_ptr<data::Event>> queryRelays(
+ virtual std::future<std::vector<std::shared_ptr<data::Event>>> queryRelays(
std::shared_ptr<data::Filters> filters) = 0;
/**
diff --git a/src/data/filters.cpp b/src/data/filters.cpp
index a8e3343..b725002 100644
--- a/src/data/filters.cpp
+++ b/src/data/filters.cpp
@@ -11,7 +11,7 @@ string Filters::serialize(string& subscriptionId)
try
{
this->validate();
- }
+ }
catch (const invalid_argument& e)
{
throw e;
diff --git a/src/service/nostr_service_base.cpp b/src/service/nostr_service_base.cpp
index 7f3d92c..26748e0 100644
--- a/src/service/nostr_service_base.cpp
+++ b/src/service/nostr_service_base.cpp
@@ -187,101 +187,109 @@ tuple<vector<string>, vector<string>> NostrServiceBase::publishEvent(
return make_tuple(successfulRelays, failedRelays);
};
-// TODO: Make this method return a promise.
// TODO: Add a timeout to this method to prevent hanging while waiting for the relay.
-vector<shared_ptr<nostr::data::Event>> NostrServiceBase::queryRelays(
+future<vector<shared_ptr<nostr::data::Event>>> NostrServiceBase::queryRelays(
shared_ptr<nostr::data::Filters> filters)
{
- if (filters->limit > 64 || filters->limit < 1)
- {
- PLOG_WARNING << "Filters limit must be between 1 and 64, inclusive. Setting limit to 16.";
- filters->limit = 16;
- }
-
- vector<shared_ptr<nostr::data::Event>> events;
-
- string subscriptionId = this->_generateSubscriptionId();
- string request;
-
- try
- {
- request = filters->serialize(subscriptionId);
- }
- catch (const invalid_argument& e)
- {
- PLOG_ERROR << "Failed to serialize filters - invalid object: " << e.what();
- throw e;
- }
- catch (const json::exception& je)
+ return async(launch::async, [this, filters]() -> vector<shared_ptr<Event>>
{
- PLOG_ERROR << "Failed to serialize filters - JSON exception: " << je.what();
- throw je;
- }
+ if (filters->limit > 64 || filters->limit < 1)
+ {
+ PLOG_WARNING << "Filters limit must be between 1 and 64, inclusive. Setting limit to 16.";
+ filters->limit = 16;
+ }
- vector<future<tuple<string, bool>>> requestFutures;
+ vector<shared_ptr<Event>> events;
- // Send the same query to each relay. As events trickle in from each relay, they will be added
- // to the events vector. Multiple copies of an event may be received if the same event is
- // stored on multiple relays. The function will block until all of the relays send an EOSE or
- // CLOSE message.
- for (const string relay : this->_activeRelays)
- {
- promise<tuple<string, bool>> eosePromise;
- requestFutures.push_back(move(eosePromise.get_future()));
+ string subscriptionId = this->generateSubscriptionId();
+ string request;
- auto [uri, success] = this->_client->send(
- request,
- relay,
- [this, &relay, &events, &eosePromise](string payload)
- {
- this->_onSubscriptionMessage(
- payload,
- [&events](const string&, shared_ptr<nostr::data::Event> event)
- {
- events.push_back(event);
- },
- [relay, &eosePromise](const string&)
- {
- eosePromise.set_value(make_tuple(relay, true));
- },
- [relay, &eosePromise](const string&, const string&)
- {
- eosePromise.set_value(make_tuple(relay, false));
- });
- });
-
- if (success)
+ try
{
- PLOG_INFO << "Sent query to relay " << relay;
- lock_guard<mutex> lock(this->_propertyMutex);
- this->_subscriptions[subscriptionId].push_back(relay);
+ request = filters->serialize(subscriptionId);
}
- else
+ catch (const invalid_argument& e)
{
- PLOG_WARNING << "Failed to send query to relay " << relay;
- eosePromise.set_value(make_tuple(uri, false));
+ PLOG_ERROR << "Failed to serialize filters - invalid object: " << e.what();
+ throw e;
}
- }
-
- // Close open subscriptions and disconnect from relays after events are received.
- for (auto& publishFuture : requestFutures)
- {
- auto [relay, isEose] = publishFuture.get();
- if (isEose)
+ catch (const json::exception& je)
{
- PLOG_INFO << "Received EOSE message from relay " << relay;
+ PLOG_ERROR << "Failed to serialize filters - JSON exception: " << je.what();
+ throw je;
}
- else
+
+ vector<future<tuple<string, bool>>> requestFutures;
+
+ unordered_set<string> uniqueEventIds;
+
+ // Send the same query to each relay. As events trickle in from each relay, they will be added
+ // to the events vector. Duplicate copies of the same event will be ignored, as events are
+ // stored on multiple relays. The function will block until all of the relays send an EOSE or
+ // CLOSE message.
+ for (const string relay : this->_activeRelays)
{
- PLOG_WARNING << "Received CLOSE message from relay " << relay;
- this->closeRelayConnections({ relay });
+ promise<tuple<string, bool>> eosePromise;
+ requestFutures.push_back(move(eosePromise.get_future()));
+
+ auto [uri, success] = this->_client->send(
+ request,
+ relay,
+ [this, &relay, &events, &eosePromise, &uniqueEventIds](string payload)
+ {
+ this->onSubscriptionMessage(
+ payload,
+ [&events, &uniqueEventIds](const string&, shared_ptr<Event> event)
+ {
+ // Check if the event is unique before adding.
+ if (uniqueEventIds.insert(event->id).second)
+ {
+ events.push_back(event);
+ }
+ },
+ [relay, &eosePromise](const string&)
+ {
+ eosePromise.set_value(make_tuple(relay, true));
+ },
+ [relay, &eosePromise](const string&, const string&)
+ {
+ eosePromise.set_value(make_tuple(relay, false));
+ });
+ });
+
+ if (success)
+ {
+ PLOG_INFO << "Sent query to relay " << relay;
+ lock_guard<mutex> lock(this->_propertyMutex);
+ this->_subscriptions[subscriptionId].push_back(relay);
+ }
+ else
+ {
+ PLOG_WARNING << "Failed to send query to relay " << relay;
+ eosePromise.set_value(make_tuple(uri, false));
+ }
}
- }
- this->closeSubscription(subscriptionId);
- // TODO: De-duplicate events in the vector before returning.
- return events;
+ // Close open subscriptions and disconnect from relays after events are received.
+
+ for (auto& publishFuture : requestFutures)
+ {
+ auto [relay, isEose] = publishFuture.get();
+ if (isEose)
+ {
+ PLOG_INFO << "Received EOSE message from relay " << relay;
+ }
+ else
+ {
+ PLOG_WARNING << "Received CLOSE message from relay " << relay;
+ this->closeRelayConnections({ relay });
+ }
+ }
+ this->closeSubscription(subscriptionId);
+
+ return events;
+ });
};
string NostrServiceBase::queryRelays(
@@ -357,13 +365,13 @@ tuple<vector<string>, vector<string>> NostrServiceBase::closeSubscription(string
PLOG_WARNING << "Subscription " << subscriptionId << " not found.";
return make_tuple(successfulRelays, failedRelays);
}
-
+
for (const string relay : subscriptionRelays)
{
future<tuple<string, bool>> closeFuture = async([this, subscriptionId, relay]()
{
bool success = this->closeSubscription(subscriptionId, relay);
-
+
return make_tuple(relay, success);
});
closeFutures.push_back(move(closeFuture));
diff --git a/test/nostr_service_base_test.cpp b/test/nostr_service_base_test.cpp
index 5929d62..944b1e8 100644
--- a/test/nostr_service_base_test.cpp
+++ b/test/nostr_service_base_test.cpp
@@ -64,7 +64,7 @@ public:
nostr::data::Event event1;
event1.pubkey = "13tn5ccv2guflxgffq4aj0hw5x39pz70zcdrfd6vym887gry38zys28dask";
event1.kind = 1;
- event1.tags =
+ event1.tags =
{
{ "e", "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36", "wss://nostr.example.com" },
{ "p", "f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca" },
@@ -130,7 +130,7 @@ public:
{
nostr::data::Filters filters;
filters.authors = {
- "13tn5ccv2guflxgffq4aj0hw5x39pz70zcdrfd6vym887gry38zys28dask",
+ "13tn5ccv2guflxgffq4aj0hw5x39pz70zcdrfd6vym887gry38zys28dask",
"1l9d9jh67rkwayalrxcy686aujyz5pper5kzjv8jvg8pu9v9ns4ls0xvq42",
"187ujhtmnv82ftg03h4heetwk3dd9mlfkf8th3fvmrk20nxk9mansuzuyla"
};
@@ -144,7 +144,7 @@ public:
{
nostr::data::Filters filters;
filters.authors = {
- "13tn5ccv2guflxgffq4aj0hw5x39pz70zcdrfd6vym887gry38zys28dask",
+ "13tn5ccv2guflxgffq4aj0hw5x39pz70zcdrfd6vym887gry38zys28dask",
"1l9d9jh67rkwayalrxcy686aujyz5pper5kzjv8jvg8pu9v9ns4ls0xvq42",
"187ujhtmnv82ftg03h4heetwk3dd9mlfkf8th3fvmrk20nxk9mansuzuyla"
};
@@ -745,7 +745,7 @@ TEST_F(NostrServiceBaseTest, QueryRelays_ReturnsEvents_UpToEOSE)
}));
auto filters = make_shared<nostr::data::Filters>(getKind0And1TestFilters());
- auto results = nostrService->queryRelays(filters);
+ auto results = nostrService->queryRelays(filters).get();
// TODO: Check results size when the queryRelays method deduplicates results before returning.
// ASSERT_EQ(results.size(), testEvents.size());
@@ -859,7 +859,7 @@ TEST_F(NostrServiceBaseTest, QueryRelays_CallsHandler_WithReturnedEvents)
}
},
[](const string&, const string&) {});
-
+
eoseReceivedFuture.wait();
// Check that the service is keeping track of its active subscriptions.
@@ -1018,7 +1018,7 @@ TEST_F(NostrServiceBaseTest, Service_MaintainsMultipleSubscriptions_ThenClosesAl
longFormPromise.set_value();
},
[](const string&, const string&) {});
-
+
shortFormFuture.wait();
longFormFuture.wait();