diff options
-rw-r--r-- | include/client/web_socket_client.hpp | 6 | ||||
-rw-r--r-- | include/nostr.hpp | 44 | ||||
-rw-r--r-- | src/nostr_service.cpp | 26 | ||||
-rw-r--r-- | test/nostr_service_test.cpp | 2 |
4 files changed, 65 insertions, 13 deletions
diff --git a/include/client/web_socket_client.hpp b/include/client/web_socket_client.hpp index 4e6cb8b..f676e59 100644 --- a/include/client/web_socket_client.hpp +++ b/include/client/web_socket_client.hpp @@ -45,10 +45,10 @@ public: /** * @brief Sets up a message handler for the given server. * @param uri The URI of the server to which the message handler should be attached. - * @param messageHandler A callable object that will be invoked when the client receives a - * message from the server. + * @param messageHandler A callable object that will be invoked with the subscription ID and + * the message contents when the client receives a message from the server. */ - virtual void receive(std::string uri, std::function<void(const std::string&)> messageHandler) = 0; + virtual void receive(std::string uri, std::function<void(const std::string&, const std::string&)> messageHandler) = 0; /** * @brief Closes the connection to the given server. diff --git a/include/nostr.hpp b/include/nostr.hpp index 8a9d4c9..448ad64 100644 --- a/include/nostr.hpp +++ b/include/nostr.hpp @@ -1,5 +1,6 @@ #pragma once +#include <functional> #include <mutex> #include <string> #include <tuple> @@ -144,13 +145,33 @@ public: /** * @brief Queries all open relay connections for events matching the given set of filters. - * @returns A tuple of `RelayList` objects, of the form `<successes, failures>`, indicating - * to which relays the request was successfully sent, and which relays did not successfully - * receive the request. + * @param filters The filters to use for the query. + * @returns The ID of the subscription created for the query. + */ + std::string queryRelays(Filters filters); + + /** + * @brief Queries all open relay connections for events matching the given set of filters. + * @param filters The filters to use for the query. + * @param responseHandler A callable object that will be invoked each time the client receives + * an event matching the filters. + * @returns The ID of the subscription created for the query. + */ + std::string queryRelays(Filters filters, std::function<void(std::string, Event)> responseHandler); + + /** + * @brief Get any new events received since the last call to this method, across all + * subscriptions. + * @returns A pointer to a vector of new events. */ - std::tuple<RelayList, RelayList> queryRelays(Filters filters); + std::unique_ptr<std::vector<Event>> getNewEvents(); - // TODO: Write a method that receives events for an active subscription. + /** + * @brief Get any new events received since the last call to this method, for the given + * subscription. + * @returns A pointer to a vector of new events. + */ + std::unique_ptr<std::vector<Event>> getNewEvents(std::string subscriptionId); /** * @brief Closes the subscription with the given ID on all open relay connections. @@ -177,11 +198,13 @@ public: std::tuple<RelayList, RelayList> closeSubscriptions(RelayList relays); private: + client::IWebSocketClient* _client; std::mutex _propertyMutex; RelayList _defaultRelays; RelayList _activeRelays; std::unordered_map<std::string, std::vector<std::string>> _subscriptions; - client::IWebSocketClient* _client; + std::unordered_map<std::string, std::vector<Event>> _events; + std::unordered_map<std::string, std::vector<Event>::iterator> _eventIterators; /** * @brief Determines which of the given relays are currently connected. @@ -234,5 +257,14 @@ private: * @returns True if the relay has the subscription, false otherwise. */ bool hasSubscription(std::string relay, std::string subscriptionId); + + /** + * @brief A default message handler for events returned from relay queries. + * @param subscriptionId The ID of the subscription for which the event was received. + * @param event The event received from the relay. + * @remark By default, new events are stored in a map of subscription IDs to vectors of events. + * Events are retrieved by calling `getNewEvents` or `getNewEvents(subscriptionId)`. + */ + void onEvent(std::string subscriptionId, Event event); }; } // namespace nostr diff --git a/src/nostr_service.cpp b/src/nostr_service.cpp index 3ac5177..13d5ff5 100644 --- a/src/nostr_service.cpp +++ b/src/nostr_service.cpp @@ -15,6 +15,7 @@ using boost::uuids::to_string; using boost::uuids::uuid; using nlohmann::json; using std::async; +using std::function; using std::future; using std::lock_guard; using std::make_tuple; @@ -147,15 +148,22 @@ tuple<RelayList, RelayList> NostrService::publishEvent(Event event) return make_tuple(successfulRelays, failedRelays); }; -tuple<RelayList, RelayList> NostrService::queryRelays(Filters filters) +string NostrService::queryRelays(Filters filters) +{ + return this->queryRelays(filters, [this](string subscriptionId, Event event) { + this->onEvent(subscriptionId, event); + }); +}; + +string NostrService::queryRelays(Filters filters, function<void(string, Event)> responseHandler) { RelayList successfulRelays; RelayList failedRelays; + string subscriptionId = this->generateSubscriptionId(); vector<future<tuple<string, bool>>> requestFutures; for (const string relay : this->_activeRelays) { - string subscriptionId = this->generateSubscriptionId(); this->_subscriptions[relay].push_back(subscriptionId); string request = filters.serialize(subscriptionId); @@ -163,6 +171,12 @@ tuple<RelayList, RelayList> NostrService::queryRelays(Filters filters) return this->_client->send(request, relay); }); requestFutures.push_back(move(requestFuture)); + + this->_client->receive(relay, [responseHandler](string subscriptionId, string message) { + Event event; + event.deserialize(message); + responseHandler(subscriptionId, event); + }); } for (auto& publishFuture : requestFutures) @@ -182,7 +196,7 @@ tuple<RelayList, RelayList> NostrService::queryRelays(Filters filters) size_t successfulCount = successfulRelays.size(); PLOG_INFO << "Sent query to " << successfulCount << "/" << targetCount << " open relay connections."; - return make_tuple(successfulRelays, failedRelays); + return subscriptionId; }; tuple<RelayList, RelayList> NostrService::closeSubscription(string subscriptionId) @@ -394,4 +408,10 @@ bool NostrService::hasSubscription(string relay, string subscriptionId) } return false; }; + +void NostrService::onEvent(string subscriptionId, Event event) +{ + _events[subscriptionId].push_back(event); + PLOG_INFO << "Received event for subscription: " << subscriptionId; +}; } // namespace nostr diff --git a/test/nostr_service_test.cpp b/test/nostr_service_test.cpp index d4fc71b..2dd34d2 100644 --- a/test/nostr_service_test.cpp +++ b/test/nostr_service_test.cpp @@ -28,7 +28,7 @@ public: MOCK_METHOD(void, openConnection, (string uri), (override)); MOCK_METHOD(bool, isConnected, (string uri), (override)); MOCK_METHOD((tuple<string, bool>), send, (string message, string uri), (override)); - MOCK_METHOD(void, receive, (string uri, function<void(const string&)> messageHandler), (override)); + MOCK_METHOD(void, receive, (string uri, function<void(const string&, const string&)> messageHandler), (override)); MOCK_METHOD(void, closeConnection, (string uri), (override)); }; |