diff options
-rw-r--r-- | CMakeLists.txt | 6 | ||||
-rw-r--r-- | README.md | 7 | ||||
-rw-r--r-- | include/client/web_socket_client.hpp | 3 | ||||
-rw-r--r-- | include/client/websocketpp_client.hpp | 9 | ||||
-rw-r--r-- | include/nostr.hpp | 122 | ||||
-rw-r--r-- | include/nostr_service_base.hpp | 104 | ||||
-rw-r--r-- | include/service/nostr_service_base.hpp | 214 | ||||
-rw-r--r-- | include/signer/noscrypt_signer.hpp | 10 | ||||
-rw-r--r-- | include/signer/signer.hpp | 9 | ||||
-rw-r--r-- | src/client/websocketpp_client.cpp | 4 | ||||
-rw-r--r-- | src/data/event.cpp | 21 | ||||
-rw-r--r-- | src/data/filters.cpp | 12 | ||||
-rw-r--r-- | src/service/nostr_service_base.cpp (renamed from src/nostr_service_base.cpp) | 67 | ||||
-rw-r--r-- | src/signer/noscrypt_signer.cpp | 11 | ||||
-rw-r--r-- | test/nostr_service_base_test.cpp | 39 |
15 files changed, 328 insertions, 310 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 461fbcc..4ae3b1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,7 @@ set_target_properties(noscrypt PROPERTIES CRYPTO_LIB openssl) set(INCLUDE_DIR ./include) set(CLIENT_INCLUDE_DIR ./include/client) set(DATA_INCLUDE_DIR ./include/data) +set(SERVICE_INCLUDE_DIR ./include/service) set(SIGNER_INCLUDE_DIR ./include/signer) include_directories(${INCLUDE_DIR}) include_directories(${CLIENT_INCLUDE_DIR}) @@ -75,10 +76,10 @@ include_directories(${SIGNER_INCLUDE_DIR}) set(HEADERS ${INCLUDE_DIR}/nostr.hpp - ${INCLUDE_DIR}/nostr_service_base.hpp ${CLIENT_INCLUDE_DIR}/web_socket_client.hpp ${CLIENT_INCLUDE_DIR}/websocketpp_client.hpp ${DATA_INCLUDE_DIR}/data.hpp + ${SERVICE_INCLUDE_DIR}/nostr_service_base.hpp ${SIGNER_INCLUDE_DIR}/signer.hpp ${SIGNER_INCLUDE_DIR}/noscrypt_signer.hpp ) @@ -86,12 +87,13 @@ set(HEADERS set(SOURCE_DIR ./src) set(CLIENT_SOURCE_DIR ./src/client) set(DATA_SOURCE_DIR ./src/data) +set(SERVICE_SOURCE_DIR ./src/service) set(SIGNER_SOURCE_DIR ./src/signer) set(SOURCES - ${SOURCE_DIR}/nostr_service_base.cpp ${CLIENT_SOURCE_DIR}/websocketpp_client.cpp ${DATA_SOURCE_DIR}/event.cpp ${DATA_SOURCE_DIR}/filters.cpp + ${SERVICE_SOURCE_DIR}/nostr_service_base.cpp ${SIGNER_SOURCE_DIR}/noscrypt_signer.cpp ) @@ -33,11 +33,12 @@ The SDK aims to support Linux, Windows, and macOS build targets. It currently s To build the SDK on Linux, run the following commands from the project root: ```bash -cmake --build --preset linux +cmake --build --preset="linux" ``` -To run unit tests, use the following command: +To run unit tests, use the following commands: ```bash -ctest --preset linux +cmake --build --preset="linux tests" +ctest --preset="linux" ``` diff --git a/include/client/web_socket_client.hpp b/include/client/web_socket_client.hpp index 19fc949..baaad51 100644 --- a/include/client/web_socket_client.hpp +++ b/include/client/web_socket_client.hpp @@ -3,9 +3,6 @@ #include <functional> #include <string> -#include <websocketpp/client.hpp> -#include <websocketpp/config/asio_client.hpp> - namespace nostr { namespace client diff --git a/include/client/websocketpp_client.hpp b/include/client/websocketpp_client.hpp index becf4fa..27a99b3 100644 --- a/include/client/websocketpp_client.hpp +++ b/include/client/websocketpp_client.hpp @@ -1,6 +1,13 @@ #pragma once -#include "web_socket_client.hpp" +#include <mutex> +#include <unordered_map> +#include <tuple> + +#include <websocketpp/client.hpp> +#include <websocketpp/config/asio_client.hpp> + +#include "client/web_socket_client.hpp" namespace nostr { diff --git a/include/nostr.hpp b/include/nostr.hpp index c555bbe..82c1638 100644 --- a/include/nostr.hpp +++ b/include/nostr.hpp @@ -1,121 +1,11 @@ #pragma once -#include <algorithm> -#include <functional> -#include <mutex> -#include <string> -#include <tuple> -#include <unordered_map> -#include <vector> - -#include <nlohmann/json.hpp> -#include <plog/Init.h> -#include <plog/Log.h> -#include <websocketpp/client.hpp> -#include <websocketpp/config/asio_client.hpp> -#include <uuid_v4.h> - -#include "client/web_socket_client.hpp" #include "data/data.hpp" +#include "client/web_socket_client.hpp" +#include "service/nostr_service_base.hpp" #include "signer/signer.hpp" -namespace nostr -{ -// TODO: Create custom exception types for the nostr namespace. - -class INostrServiceBase -{ -public: - virtual ~INostrServiceBase() = default; - - /** - * @brief Opens connections to the default Nostr relays of the instance, as specified in - * the constructor. - * @return A list of the relay URLs to which connections were successfully opened. - */ - virtual std::vector<std::string> openRelayConnections() = 0; - - /** - * @brief Opens connections to the specified Nostr relays. - * @returns A list of the relay URLs to which connections were successfully opened. - */ - virtual std::vector<std::string> openRelayConnections(std::vector<std::string> relays) = 0; - - /** - * @brief Closes all open relay connections. - */ - virtual void closeRelayConnections() = 0; - - /** - * @brief Closes any open connections to the specified Nostr relays. - */ - virtual void closeRelayConnections(std::vector<std::string> relays) = 0; - - /** - * @brief Publishes a Nostr event to all open relay connections. - * @returns A tuple of `std::vector<std::string>` objects, of the form `<successes, failures>`, indicating - * to which relays the event was published successfully, and to which relays the event failed - * to publish. - */ - virtual std::tuple<std::vector<std::string>, std::vector<std::string>> publishEvent( - std::shared_ptr<data::Event> event) = 0; - - /** - * @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. - * @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. - * @remark Use this method to fetch a batch of events from the relays. A `limit` value must be - * 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( - std::shared_ptr<data::Filters> filters) = 0; - - /** - * @brief Queries all open relay connections for events matching the given set of filters. - * @param filters The filters to use for the query. - * @param eventHandler A callable object that will be invoked each time the client receives - * an event matching the filters. - * @param eoseHandler A callable object that will be invoked when the relay sends an EOSE - * message. - * @param closeHandler A callable object that will be invoked when the relay sends a CLOSE - * message. - * @returns The ID of the subscription created for the query. - * @remark By providing a response handler, the caller assumes responsibility for handling all - * events returned from the relay for the given filters. The service will not store the - * events, and they will not be accessible via `getNewEvents`. - */ - virtual std::string queryRelays( - std::shared_ptr<data::Filters> filters, - std::function<void(const std::string&, std::shared_ptr<data::Event>)> eventHandler, - std::function<void(const std::string&)> eoseHandler, - std::function<void(const std::string&, const std::string&)> closeHandler) = 0; - - /** - * @brief Closes the subscription with the given ID on all open relay connections. - * @returns A tuple of `std::vector<std::string>` objects, of the form `<successes, failures>`, indicating - * to which relays the message was sent successfully, and which relays failed to receive the - * message. - */ - virtual std::tuple<std::vector<std::string>, std::vector<std::string>> closeSubscription( - std::string subscriptionId) = 0; - - /** - * @brief Closes the subscription with the given ID on the given relay. - * @returns True if the relay received the CLOSE message, false otherwise. - * @remark If the subscription does not exist on the given relay, or if the relay is not - * connected, the method will do nothing and return false. - */ - virtual bool closeSubscription(std::string subscriptionId, std::string relay) = 0; - - /** - * @brief Closes all open subscriptions on all open relay connections. - * @returns A list of any subscription IDs that failed to close. - */ - virtual std::vector<std::string> closeSubscriptions() = 0; -}; -} // namespace nostr +// namespace nostr +// { +// // TODO: Create custom exception types for the nostr namespace. +// } // namespace nostr diff --git a/include/nostr_service_base.hpp b/include/nostr_service_base.hpp deleted file mode 100644 index 6abfedc..0000000 --- a/include/nostr_service_base.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#pragma once - -#include "nostr.hpp" - -namespace nostr -{ -class NostrServiceBase : public INostrServiceBase -{ -public: - NostrServiceBase( - std::shared_ptr<plog::IAppender> appender, - std::shared_ptr<client::IWebSocketClient> client); - - NostrServiceBase( - std::shared_ptr<plog::IAppender> appender, - std::shared_ptr<client::IWebSocketClient> client, - std::vector<std::string> relays); - - ~NostrServiceBase() override; - - std::vector<std::string> defaultRelays() const; - - std::vector<std::string> activeRelays() const; - - std::unordered_map<std::string, std::vector<std::string>> subscriptions() const; - - std::vector<std::string> openRelayConnections() override; - - std::vector<std::string> openRelayConnections(std::vector<std::string> relays) override; - - void closeRelayConnections() override; - - void closeRelayConnections(std::vector<std::string> relays) override; - - // TODO: Make this method return a promise. - std::tuple<std::vector<std::string>, std::vector<std::string>> publishEvent( - std::shared_ptr<data::Event> event) override; - - // TODO: Make this method return a promise. - // TODO: Add a timeout to this method to prevent hanging while waiting for the relay. - std::vector<std::shared_ptr<data::Event>> queryRelays( - std::shared_ptr<data::Filters> filters) override; - - std::string queryRelays( - std::shared_ptr<data::Filters> filters, - std::function<void(const std::string&, std::shared_ptr<data::Event>)> eventHandler, - std::function<void(const std::string&)> eoseHandler, - std::function<void(const std::string&, const std::string&)> closeHandler) override; - - std::tuple<std::vector<std::string>, std::vector<std::string>> closeSubscription( - std::string subscriptionId) override; - - bool closeSubscription(std::string subscriptionId, std::string relay) override; - - std::vector<std::string> closeSubscriptions() override; - -private: - ///< The maximum number of events the service will store for each subscription. - const int MAX_EVENTS_PER_SUBSCRIPTION = 128; - - ///< The WebSocket client used to communicate with relays. - std::shared_ptr<client::IWebSocketClient> _client; - - ///< A mutex to protect the instance properties. - std::mutex _propertyMutex; - - ///< The default set of Nostr relays to which the service will attempt to connect. - std::vector<std::string> _defaultRelays; - - ///< The set of Nostr relays to which the service is currently connected. - std::vector<std::string> _activeRelays; - - ///< A map from subscription IDs to the relays on which each subscription is open. - std::unordered_map<std::string, std::vector<std::string>> _subscriptions; - - std::vector<std::string> _getConnectedRelays(std::vector<std::string> relays); - - std::vector<std::string> _getUnconnectedRelays(std::vector<std::string> relays); - - bool _isConnected(std::string relay); - - void _eraseActiveRelay(std::string relay); - - void _connect(std::string relay); - - void _disconnect(std::string relay); - - std::string _generateSubscriptionId(); - - std::string _generateCloseRequest(std::string subscriptionId); - - bool _hasSubscription(std::string subscriptionId); - - bool _hasSubscription(std::string subscriptionId, std::string relay); - - void _onSubscriptionMessage( - std::string message, - std::function<void(const std::string&, std::shared_ptr<data::Event>)> eventHandler, - std::function<void(const std::string&)> eoseHandler, - std::function<void(const std::string&, const std::string&)> closeHandler); - - void _onAcceptance(std::string message, std::function<void(const bool)> acceptanceHandler); -}; -} // namespace nostr diff --git a/include/service/nostr_service_base.hpp b/include/service/nostr_service_base.hpp new file mode 100644 index 0000000..c3f8c99 --- /dev/null +++ b/include/service/nostr_service_base.hpp @@ -0,0 +1,214 @@ +#pragma once + +#include <functional> +#include <memory> +#include <mutex> +#include <string> +#include <tuple> +#include <vector> + +#include <plog/Init.h> +#include <plog/Log.h> + +#include "data/data.hpp" +#include "client/web_socket_client.hpp" + +namespace nostr +{ +namespace service +{ +class INostrServiceBase +{ +public: + virtual ~INostrServiceBase() = default; + + /** + * @brief Opens connections to the default Nostr relays of the instance, as specified in + * the constructor. + * @return A list of the relay URLs to which connections were successfully opened. + */ + virtual std::vector<std::string> openRelayConnections() = 0; + + /** + * @brief Opens connections to the specified Nostr relays. + * @returns A list of the relay URLs to which connections were successfully opened. + */ + virtual std::vector<std::string> openRelayConnections(std::vector<std::string> relays) = 0; + + /** + * @brief Closes all open relay connections. + */ + virtual void closeRelayConnections() = 0; + + /** + * @brief Closes any open connections to the specified Nostr relays. + */ + virtual void closeRelayConnections(std::vector<std::string> relays) = 0; + + /** + * @brief Publishes a Nostr event to all open relay connections. + * @returns A tuple of `std::vector<std::string>` objects, of the form `<successes, failures>`, indicating + * to which relays the event was published successfully, and to which relays the event failed + * to publish. + */ + virtual std::tuple<std::vector<std::string>, std::vector<std::string>> publishEvent( + std::shared_ptr<data::Event> event) = 0; + + /** + * @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. + * @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. + * @remark Use this method to fetch a batch of events from the relays. A `limit` value must be + * 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( + std::shared_ptr<data::Filters> filters) = 0; + + /** + * @brief Queries all open relay connections for events matching the given set of filters. + * @param filters The filters to use for the query. + * @param eventHandler A callable object that will be invoked each time the client receives + * an event matching the filters. + * @param eoseHandler A callable object that will be invoked when the relay sends an EOSE + * message. + * @param closeHandler A callable object that will be invoked when the relay sends a CLOSE + * message. + * @returns The ID of the subscription created for the query. + * @remark By providing a response handler, the caller assumes responsibility for handling all + * events returned from the relay for the given filters. The service will not store the + * events, and they will not be accessible via `getNewEvents`. + */ + virtual std::string queryRelays( + std::shared_ptr<data::Filters> filters, + std::function<void(const std::string&, std::shared_ptr<data::Event>)> eventHandler, + std::function<void(const std::string&)> eoseHandler, + std::function<void(const std::string&, const std::string&)> closeHandler) = 0; + + /** + * @brief Closes the subscription with the given ID on all open relay connections. + * @returns A tuple of `std::vector<std::string>` objects, of the form `<successes, failures>`, indicating + * to which relays the message was sent successfully, and which relays failed to receive the + * message. + */ + virtual std::tuple<std::vector<std::string>, std::vector<std::string>> closeSubscription( + std::string subscriptionId) = 0; + + /** + * @brief Closes the subscription with the given ID on the given relay. + * @returns True if the relay received the CLOSE message, false otherwise. + * @remark If the subscription does not exist on the given relay, or if the relay is not + * connected, the method will do nothing and return false. + */ + virtual bool closeSubscription(std::string subscriptionId, std::string relay) = 0; + + /** + * @brief Closes all open subscriptions on all open relay connections. + * @returns A list of any subscription IDs that failed to close. + */ + virtual std::vector<std::string> closeSubscriptions() = 0; +}; + +class NostrServiceBase : public INostrServiceBase +{ +public: + NostrServiceBase( + std::shared_ptr<plog::IAppender> appender, + std::shared_ptr<client::IWebSocketClient> client); + + NostrServiceBase( + std::shared_ptr<plog::IAppender> appender, + std::shared_ptr<client::IWebSocketClient> client, + std::vector<std::string> relays); + + ~NostrServiceBase() override; + + std::vector<std::string> defaultRelays() const; + + std::vector<std::string> activeRelays() const; + + std::unordered_map<std::string, std::vector<std::string>> subscriptions() const; + + std::vector<std::string> openRelayConnections() override; + + std::vector<std::string> openRelayConnections(std::vector<std::string> relays) override; + + void closeRelayConnections() override; + + void closeRelayConnections(std::vector<std::string> relays) override; + + // TODO: Make this method return a promise. + std::tuple<std::vector<std::string>, std::vector<std::string>> publishEvent( + std::shared_ptr<data::Event> event) override; + + // TODO: Make this method return a promise. + // TODO: Add a timeout to this method to prevent hanging while waiting for the relay. + std::vector<std::shared_ptr<data::Event>> queryRelays( + std::shared_ptr<data::Filters> filters) override; + + std::string queryRelays( + std::shared_ptr<data::Filters> filters, + std::function<void(const std::string&, std::shared_ptr<data::Event>)> eventHandler, + std::function<void(const std::string&)> eoseHandler, + std::function<void(const std::string&, const std::string&)> closeHandler) override; + + std::tuple<std::vector<std::string>, std::vector<std::string>> closeSubscription( + std::string subscriptionId) override; + + bool closeSubscription(std::string subscriptionId, std::string relay) override; + + std::vector<std::string> closeSubscriptions() override; + +private: + ///< The maximum number of events the service will store for each subscription. + const int MAX_EVENTS_PER_SUBSCRIPTION = 128; + + ///< The WebSocket client used to communicate with relays. + std::shared_ptr<client::IWebSocketClient> _client; + + ///< A mutex to protect the instance properties. + std::mutex _propertyMutex; + + ///< The default set of Nostr relays to which the service will attempt to connect. + std::vector<std::string> _defaultRelays; + + ///< The set of Nostr relays to which the service is currently connected. + std::vector<std::string> _activeRelays; + + ///< A map from subscription IDs to the relays on which each subscription is open. + std::unordered_map<std::string, std::vector<std::string>> _subscriptions; + + std::vector<std::string> _getConnectedRelays(std::vector<std::string> relays); + + std::vector<std::string> _getUnconnectedRelays(std::vector<std::string> relays); + + bool _isConnected(std::string relay); + + void _eraseActiveRelay(std::string relay); + + void _connect(std::string relay); + + void _disconnect(std::string relay); + + std::string _generateSubscriptionId(); + + std::string _generateCloseRequest(std::string subscriptionId); + + bool _hasSubscription(std::string subscriptionId); + + bool _hasSubscription(std::string subscriptionId, std::string relay); + + void _onSubscriptionMessage( + std::string message, + std::function<void(const std::string&, std::shared_ptr<data::Event>)> eventHandler, + std::function<void(const std::string&)> eoseHandler, + std::function<void(const std::string&, const std::string&)> closeHandler); + + void _onAcceptance(std::string message, std::function<void(const bool)> acceptanceHandler); +}; +} // namespace service +} // namespace nostr diff --git a/include/signer/noscrypt_signer.hpp b/include/signer/noscrypt_signer.hpp index 1476303..cdee3fd 100644 --- a/include/signer/noscrypt_signer.hpp +++ b/include/signer/noscrypt_signer.hpp @@ -1,11 +1,15 @@ #pragma once +#include <plog/Init.h> +#include <plog/Log.h> + extern "C" { #include <noscrypt.h> } -#include "signer.hpp" +#include "service/nostr_service_base.hpp" +#include "signer/signer.hpp" namespace nostr { @@ -14,7 +18,9 @@ namespace signer class NoscryptSigner : public INostrConnectSigner { public: - NoscryptSigner(std::shared_ptr<plog::IAppender> appender); + NoscryptSigner( + std::shared_ptr<plog::IAppender> appender, + std::shared_ptr<nostr::service::INostrServiceBase> nostrService); ~NoscryptSigner(); diff --git a/include/signer/signer.hpp b/include/signer/signer.hpp index e16aa38..319f739 100644 --- a/include/signer/signer.hpp +++ b/include/signer/signer.hpp @@ -1,12 +1,7 @@ #pragma once -#include <algorithm> -#include <random> -#include <sstream> -#include <tuple> - -#include <plog/Init.h> -#include <plog/Log.h> +#include <memory> +#include <string> #include "data/data.hpp" diff --git a/src/client/websocketpp_client.cpp b/src/client/websocketpp_client.cpp index 3cc6c99..e4f6af6 100644 --- a/src/client/websocketpp_client.cpp +++ b/src/client/websocketpp_client.cpp @@ -1,4 +1,6 @@ -#include "websocketpp_client.hpp" +#include <mutex> + +#include "client/websocketpp_client.hpp" using namespace std; diff --git a/src/data/event.cpp b/src/data/event.cpp index 5f611ff..bd37ee7 100644 --- a/src/data/event.cpp +++ b/src/data/event.cpp @@ -1,13 +1,12 @@ +#include <sstream> +#include <stdexcept> + #include "data/data.hpp" using namespace nlohmann; using namespace std; -namespace nostr -{ -namespace data -{ -string Event::serialize() +string nostr::data::Event::serialize() { try { @@ -31,7 +30,7 @@ string Event::serialize() return j.dump(); }; -Event Event::fromString(string jstr) +nostr::data::Event nostr::data::Event::fromString(string jstr) { json j = json::parse(jstr); Event event; @@ -48,7 +47,7 @@ Event Event::fromString(string jstr) return event; }; -Event Event::fromJson(json j) +nostr::data::Event nostr::data::Event::fromJson(json j) { Event event; @@ -69,7 +68,7 @@ Event Event::fromJson(json j) return event; }; -void Event::validate() +void nostr::data::Event::validate() { bool hasPubkey = this->pubkey.length() > 0; if (!hasPubkey) @@ -90,7 +89,7 @@ void Event::validate() } }; -string Event::generateId(string serializedData) const +string nostr::data::Event::generateId(string serializedData) const { unsigned char hash[SHA256_DIGEST_LENGTH]; EVP_Digest(serializedData.c_str(), serializedData.length(), hash, NULL, EVP_sha256(), NULL); @@ -104,7 +103,7 @@ string Event::generateId(string serializedData) const return ss.str(); }; -bool Event::operator==(const Event& other) const +bool nostr::data::Event::operator==(const Event& other) const { if (this->id.empty()) { @@ -117,5 +116,3 @@ bool Event::operator==(const Event& other) const return this->id == other.id; }; -} // namespace data -} // namespace nostr diff --git a/src/data/filters.cpp b/src/data/filters.cpp index 7e1c744..e345c95 100644 --- a/src/data/filters.cpp +++ b/src/data/filters.cpp @@ -1,13 +1,11 @@ +#include <stdexcept> + #include "data/data.hpp" using namespace nlohmann; using namespace std; -namespace nostr -{ -namespace data -{ -string Filters::serialize(string& subscriptionId) +string nostr::data::Filters::serialize(string& subscriptionId) { try { @@ -40,7 +38,7 @@ string Filters::serialize(string& subscriptionId) return jarr.dump(); }; -void Filters::validate() +void nostr::data::Filters::validate() { bool hasLimit = this->limit > 0; if (!hasLimit) @@ -66,5 +64,3 @@ void Filters::validate() throw invalid_argument("Filters::validate: At least one filter must be set."); } }; -} // namespace data -} // namespace nostr diff --git a/src/nostr_service_base.cpp b/src/service/nostr_service_base.cpp index bce6728..ec847b3 100644 --- a/src/nostr_service_base.cpp +++ b/src/service/nostr_service_base.cpp @@ -1,14 +1,21 @@ -#include "nostr_service_base.hpp" +#include <exception> +#include <future> +#include <stdexcept> +#include <thread> + +#include <uuid_v4.h> + +#include "service/nostr_service_base.hpp" using namespace nlohmann; using namespace std; -nostr::NostrServiceBase::NostrServiceBase( +nostr::service::NostrServiceBase::NostrServiceBase( shared_ptr<plog::IAppender> appender, shared_ptr<client::IWebSocketClient> client) : NostrServiceBase(appender, client, {}) { }; -nostr::NostrServiceBase::NostrServiceBase( +nostr::service::NostrServiceBase::NostrServiceBase( shared_ptr<plog::IAppender> appender, shared_ptr<client::IWebSocketClient> client, vector<string> relays) @@ -18,26 +25,26 @@ nostr::NostrServiceBase::NostrServiceBase( client->start(); }; -nostr::NostrServiceBase::~NostrServiceBase() +nostr::service::NostrServiceBase::~NostrServiceBase() { this->_client->stop(); }; -vector<string> nostr::NostrServiceBase::defaultRelays() const +vector<string> nostr::service::NostrServiceBase::defaultRelays() const { return this->_defaultRelays; }; -vector<string> nostr::NostrServiceBase::activeRelays() const +vector<string> nostr::service::NostrServiceBase::activeRelays() const { return this->_activeRelays; }; -unordered_map<string, vector<string>> nostr::NostrServiceBase::subscriptions() const +unordered_map<string, vector<string>> nostr::service::NostrServiceBase::subscriptions() const { return this->_subscriptions; }; -vector<string> nostr::NostrServiceBase::openRelayConnections() +vector<string> nostr::service::NostrServiceBase::openRelayConnections() { return this->openRelayConnections(this->_defaultRelays); }; -vector<string> nostr::NostrServiceBase::openRelayConnections(vector<string> relays) +vector<string> nostr::service::NostrServiceBase::openRelayConnections(vector<string> relays) { PLOG_INFO << "Attempting to connect to Nostr relays."; vector<string> unconnectedRelays = this->_getUnconnectedRelays(relays); @@ -64,7 +71,7 @@ vector<string> nostr::NostrServiceBase::openRelayConnections(vector<string> rela return this->_activeRelays; }; -void nostr::NostrServiceBase::closeRelayConnections() +void nostr::service::NostrServiceBase::closeRelayConnections() { if (this->_activeRelays.size() == 0) { @@ -75,7 +82,7 @@ void nostr::NostrServiceBase::closeRelayConnections() this->closeRelayConnections(this->_activeRelays); }; -void nostr::NostrServiceBase::closeRelayConnections(vector<string> relays) +void nostr::service::NostrServiceBase::closeRelayConnections(vector<string> relays) { PLOG_INFO << "Disconnecting from Nostr relays."; vector<string> connectedRelays = this->_getConnectedRelays(relays); @@ -100,7 +107,7 @@ void nostr::NostrServiceBase::closeRelayConnections(vector<string> relays) }; // TODO: Make this method return a promise. -tuple<vector<string>, vector<string>> nostr::NostrServiceBase::publishEvent( +tuple<vector<string>, vector<string>> nostr::service::NostrServiceBase::publishEvent( shared_ptr<nostr::data::Event> event) { vector<string> successfulRelays; @@ -181,7 +188,7 @@ tuple<vector<string>, vector<string>> nostr::NostrServiceBase::publishEvent( // 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>> nostr::NostrServiceBase::queryRelays( +vector<shared_ptr<nostr::data::Event>> nostr::service::NostrServiceBase::queryRelays( shared_ptr<nostr::data::Filters> filters) { if (filters->limit > 64 || filters->limit < 1) @@ -276,7 +283,7 @@ vector<shared_ptr<nostr::data::Event>> nostr::NostrServiceBase::queryRelays( return events; }; -string nostr::NostrServiceBase::queryRelays( +string nostr::service::NostrServiceBase::queryRelays( shared_ptr<nostr::data::Filters> filters, function<void(const string&, shared_ptr<nostr::data::Event>)> eventHandler, function<void(const string&)> eoseHandler, @@ -328,7 +335,7 @@ string nostr::NostrServiceBase::queryRelays( return subscriptionId; }; -tuple<vector<string>, vector<string>> nostr::NostrServiceBase::closeSubscription(string subscriptionId) +tuple<vector<string>, vector<string>> nostr::service::NostrServiceBase::closeSubscription(string subscriptionId) { vector<string> successfulRelays; vector<string> failedRelays; @@ -388,7 +395,7 @@ tuple<vector<string>, vector<string>> nostr::NostrServiceBase::closeSubscription return make_tuple(successfulRelays, failedRelays); }; -bool nostr::NostrServiceBase::closeSubscription(string subscriptionId, string relay) +bool nostr::service::NostrServiceBase::closeSubscription(string subscriptionId, string relay) { if (!this->_hasSubscription(subscriptionId, relay)) { @@ -428,7 +435,7 @@ bool nostr::NostrServiceBase::closeSubscription(string subscriptionId, string re return success; }; -vector<string> nostr::NostrServiceBase::closeSubscriptions() +vector<string> nostr::service::NostrServiceBase::closeSubscriptions() { unique_lock<mutex> lock(this->_propertyMutex); vector<string> subscriptionIds; @@ -451,7 +458,7 @@ vector<string> nostr::NostrServiceBase::closeSubscriptions() return remainingSubscriptions; }; -vector<string> nostr::NostrServiceBase::_getConnectedRelays(vector<string> relays) +vector<string> nostr::service::NostrServiceBase::_getConnectedRelays(vector<string> relays) { PLOG_VERBOSE << "Identifying connected relays."; vector<string> connectedRelays; @@ -479,7 +486,7 @@ vector<string> nostr::NostrServiceBase::_getConnectedRelays(vector<string> relay return connectedRelays; }; -vector<string> nostr::NostrServiceBase::_getUnconnectedRelays(vector<string> relays) +vector<string> nostr::service::NostrServiceBase::_getUnconnectedRelays(vector<string> relays) { PLOG_VERBOSE << "Identifying unconnected relays."; vector<string> unconnectedRelays; @@ -510,7 +517,7 @@ vector<string> nostr::NostrServiceBase::_getUnconnectedRelays(vector<string> rel return unconnectedRelays; }; -bool nostr::NostrServiceBase::_isConnected(string relay) +bool nostr::service::NostrServiceBase::_isConnected(string relay) { auto it = find(this->_activeRelays.begin(), this->_activeRelays.end(), relay); if (it != this->_activeRelays.end()) // If the relay is in this->_activeRelays @@ -520,7 +527,7 @@ bool nostr::NostrServiceBase::_isConnected(string relay) return false; }; -void nostr::NostrServiceBase::_eraseActiveRelay(string relay) +void nostr::service::NostrServiceBase::_eraseActiveRelay(string relay) { auto it = find(this->_activeRelays.begin(), this->_activeRelays.end(), relay); if (it != this->_activeRelays.end()) // If the relay is in this->_activeRelays @@ -529,7 +536,7 @@ void nostr::NostrServiceBase::_eraseActiveRelay(string relay) } }; -void nostr::NostrServiceBase::_connect(string relay) +void nostr::service::NostrServiceBase::_connect(string relay) { PLOG_VERBOSE << "Connecting to relay " << relay; this->_client->openConnection(relay); @@ -548,7 +555,7 @@ void nostr::NostrServiceBase::_connect(string relay) } }; -void nostr::NostrServiceBase::_disconnect(string relay) +void nostr::service::NostrServiceBase::_disconnect(string relay) { this->_client->closeConnection(relay); @@ -556,20 +563,20 @@ void nostr::NostrServiceBase::_disconnect(string relay) this->_eraseActiveRelay(relay); }; -string nostr::NostrServiceBase::_generateSubscriptionId() +string nostr::service::NostrServiceBase::_generateSubscriptionId() { UUIDv4::UUIDGenerator<std::mt19937_64> uuidGenerator; UUIDv4::UUID uuid = uuidGenerator.getUUID(); return uuid.str(); }; -string nostr::NostrServiceBase::_generateCloseRequest(string subscriptionId) +string nostr::service::NostrServiceBase::_generateCloseRequest(string subscriptionId) { json jarr = json::array({ "CLOSE", subscriptionId }); return jarr.dump(); }; -bool nostr::NostrServiceBase::_hasSubscription(string subscriptionId) +bool nostr::service::NostrServiceBase::_hasSubscription(string subscriptionId) { lock_guard<mutex> lock(this->_propertyMutex); auto it = this->_subscriptions.find(subscriptionId); @@ -577,7 +584,7 @@ bool nostr::NostrServiceBase::_hasSubscription(string subscriptionId) return it != this->_subscriptions.end(); }; -bool nostr::NostrServiceBase::_hasSubscription(string subscriptionId, string relay) +bool nostr::service::NostrServiceBase::_hasSubscription(string subscriptionId, string relay) { lock_guard<mutex> lock(this->_propertyMutex); auto subscriptionIt = this->_subscriptions.find(subscriptionId); @@ -593,7 +600,7 @@ bool nostr::NostrServiceBase::_hasSubscription(string subscriptionId, string rel return relayIt != relays.end(); }; -void nostr::NostrServiceBase::_onSubscriptionMessage( +void nostr::service::NostrServiceBase::_onSubscriptionMessage( string message, function<void(const string&, shared_ptr<nostr::data::Event>)> eventHandler, function<void(const string&)> eoseHandler, @@ -638,7 +645,9 @@ void nostr::NostrServiceBase::_onSubscriptionMessage( } }; -void nostr::NostrServiceBase::_onAcceptance(string message, function<void(const bool)> acceptanceHandler) +void nostr::service::NostrServiceBase::_onAcceptance( + string message, + function<void(const bool)> acceptanceHandler) { try { diff --git a/src/signer/noscrypt_signer.cpp b/src/signer/noscrypt_signer.cpp index 39bb667..05872c2 100644 --- a/src/signer/noscrypt_signer.cpp +++ b/src/signer/noscrypt_signer.cpp @@ -1,8 +1,15 @@ -#include "noscrypt_signer.hpp" +#include <algorithm> +#include <random> +#include <sstream> +#include <tuple> + +#include "signer/noscrypt_signer.hpp" using namespace std; -nostr::signer::NoscryptSigner::NoscryptSigner(shared_ptr<plog::IAppender> appender) +nostr::signer::NoscryptSigner::NoscryptSigner( + shared_ptr<plog::IAppender> appender, + shared_ptr<nostr::service::INostrServiceBase> nostrService) { plog::init(plog::debug, appender.get()); diff --git a/test/nostr_service_base_test.cpp b/test/nostr_service_base_test.cpp index 9116816..5929d62 100644 --- a/test/nostr_service_base_test.cpp +++ b/test/nostr_service_base_test.cpp @@ -1,4 +1,5 @@ #include <chrono> +#include <future> #include <iostream> #include <gmock/gmock.h> @@ -8,9 +9,7 @@ #include <plog/Formatters/TxtFormatter.h> #include <websocketpp/client.hpp> -#include "nostr.hpp" -#include "nostr_service_base.hpp" -#include "client/web_socket_client.hpp" +#include "service/nostr_service_base.hpp" using namespace nostr; using namespace std; @@ -170,12 +169,12 @@ TEST_F(NostrServiceBaseTest, Constructor_StartsClient) { EXPECT_CALL(*mockClient, start()).Times(1); - auto nostrService = make_unique<nostr::NostrServiceBase>(testAppender, mockClient); + auto nostrService = make_unique<nostr::service::NostrServiceBase>(testAppender, mockClient); }; TEST_F(NostrServiceBaseTest, Constructor_InitializesService_WithNoDefaultRelays) { - auto nostrService = make_unique<nostr::NostrServiceBase>(testAppender, mockClient); + auto nostrService = make_unique<nostr::service::NostrServiceBase>(testAppender, mockClient); auto defaultRelays = nostrService->defaultRelays(); auto activeRelays = nostrService->activeRelays(); @@ -185,7 +184,7 @@ TEST_F(NostrServiceBaseTest, Constructor_InitializesService_WithNoDefaultRelays) TEST_F(NostrServiceBaseTest, Constructor_InitializesService_WithProvidedDefaultRelays) { - auto nostrService = make_unique<nostr::NostrServiceBase>( + auto nostrService = make_unique<nostr::service::NostrServiceBase>( testAppender, mockClient, defaultTestRelays); @@ -204,7 +203,7 @@ TEST_F(NostrServiceBaseTest, Destructor_StopsClient) { EXPECT_CALL(*mockClient, start()).Times(1); - auto nostrService = make_unique<nostr::NostrServiceBase>( + auto nostrService = make_unique<nostr::service::NostrServiceBase>( testAppender, mockClient); }; @@ -231,7 +230,7 @@ TEST_F(NostrServiceBaseTest, OpenRelayConnections_OpensConnections_ToDefaultRela return status; })); - auto nostrService = make_unique<nostr::NostrServiceBase>( + auto nostrService = make_unique<nostr::service::NostrServiceBase>( testAppender, mockClient, defaultTestRelays); @@ -269,7 +268,7 @@ TEST_F(NostrServiceBaseTest, OpenRelayConnections_OpensConnections_ToProvidedRel return status; })); - auto nostrService = make_unique<nostr::NostrServiceBase>( + auto nostrService = make_unique<nostr::service::NostrServiceBase>( testAppender, mockClient, defaultTestRelays); @@ -309,7 +308,7 @@ TEST_F(NostrServiceBaseTest, OpenRelayConnections_AddsOpenConnections_ToActiveRe return status; })); - auto nostrService = make_unique<nostr::NostrServiceBase>( + auto nostrService = make_unique<nostr::service::NostrServiceBase>( testAppender, mockClient, defaultTestRelays); @@ -355,7 +354,7 @@ TEST_F(NostrServiceBaseTest, CloseRelayConnections_ClosesConnections_ToActiveRel return status; })); - auto nostrService = make_unique<nostr::NostrServiceBase>( + auto nostrService = make_unique<nostr::service::NostrServiceBase>( testAppender, mockClient, defaultTestRelays); @@ -393,7 +392,7 @@ TEST_F(NostrServiceBaseTest, CloseRelayConnections_RemovesClosedConnections_From return status; })); - auto nostrService = make_unique<nostr::NostrServiceBase>( + auto nostrService = make_unique<nostr::service::NostrServiceBase>( testAppender, mockClient, allTestRelays); @@ -434,7 +433,7 @@ TEST_F(NostrServiceBaseTest, PublishEvent_CorrectlyIndicates_AllSuccesses) return status; })); - auto nostrService = make_unique<nostr::NostrServiceBase>( + auto nostrService = make_unique<nostr::service::NostrServiceBase>( testAppender, mockClient, defaultTestRelays); @@ -484,7 +483,7 @@ TEST_F(NostrServiceBaseTest, PublishEvent_CorrectlyIndicates_AllFailures) return status; })); - auto nostrService = make_unique<nostr::NostrServiceBase>( + auto nostrService = make_unique<nostr::service::NostrServiceBase>( testAppender, mockClient, defaultTestRelays); @@ -529,7 +528,7 @@ TEST_F(NostrServiceBaseTest, PublishEvent_CorrectlyIndicates_MixedSuccessesAndFa return status; })); - auto nostrService = make_unique<nostr::NostrServiceBase>( + auto nostrService = make_unique<nostr::service::NostrServiceBase>( testAppender, mockClient, defaultTestRelays); @@ -585,7 +584,7 @@ TEST_F(NostrServiceBaseTest, PublishEvent_CorrectlyIndicates_RejectedEvent) return status; })); - auto nostrService = make_unique<nostr::NostrServiceBase>( + auto nostrService = make_unique<nostr::service::NostrServiceBase>( testAppender, mockClient, defaultTestRelays); @@ -634,7 +633,7 @@ TEST_F(NostrServiceBaseTest, PublishEvent_CorrectlyIndicates_EventRejectedBySome return status; })); - auto nostrService = make_unique<nostr::NostrServiceBase>( + auto nostrService = make_unique<nostr::service::NostrServiceBase>( testAppender, mockClient, defaultTestRelays); @@ -696,7 +695,7 @@ TEST_F(NostrServiceBaseTest, QueryRelays_ReturnsEvents_UpToEOSE) return status; })); - auto nostrService = make_unique<nostr::NostrServiceBase>( + auto nostrService = make_unique<nostr::service::NostrServiceBase>( testAppender, mockClient, defaultTestRelays); @@ -788,7 +787,7 @@ TEST_F(NostrServiceBaseTest, QueryRelays_CallsHandler_WithReturnedEvents) return status; })); - auto nostrService = make_unique<nostr::NostrServiceBase>( + auto nostrService = make_unique<nostr::service::NostrServiceBase>( testAppender, mockClient, defaultTestRelays); @@ -904,7 +903,7 @@ TEST_F(NostrServiceBaseTest, Service_MaintainsMultipleSubscriptions_ThenClosesAl return status; })); - auto nostrService = make_unique<nostr::NostrServiceBase>( + auto nostrService = make_unique<nostr::service::NostrServiceBase>( testAppender, mockClient, testRelays); |