Skip to content

Commit

Permalink
[EN-7314] Implement the DXPublisher (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
AnatolyKalin authored Aug 25, 2023
1 parent e401e3b commit 6fc79f8
Show file tree
Hide file tree
Showing 95 changed files with 3,551 additions and 836 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@
build/
cmake-build-*/
.idea/
/doc/html/
/doc/latex/
/docs/html/
/docs/latex/
/docs/*.log

.PVS-Studio/
*.PVS-Studio.*
Expand Down
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ option(DXFCXX_INSTALL_LIB "Prepare install the libraries" ON)
option(DXFCXX_INSTALL_SAMPLES "Prepare install the samples" ${DXFCXX_IS_ROOT_PROJECT})
option(DXFCXX_INSTALL_TOOLS "Prepare install the tools" ${DXFCXX_IS_ROOT_PROJECT})
option(DXFCXX_USE_DXFEED_GRAAL_NATIVE_SDK_JFROG "" ON)
set(DXFEED_GRAAL_NATIVE_SDK_VERSION "1.0.0" CACHE STRING "")
set(DXFEED_GRAAL_NATIVE_SDK_VERSION "1.0.1" CACHE STRING "")
set(DXFEED_GRAAL_NATIVE_SDK_JFROG_BASE_URL "https://dxfeed.jfrog.io/artifactory/maven-open/com/dxfeed/graal-native-sdk/" CACHE STRING "")

include(FetchContent)
Expand Down Expand Up @@ -105,6 +105,7 @@ set(dxFeedNativeAPIAPISources
src/api/DXEndpoint.cpp
src/api/DXFeed.cpp
src/api/DXFeedSubscription.cpp
src/api/DXPublisher.cpp
)

set(dxFeedNativeAPIAPIOsubSources
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -455,20 +455,20 @@ be downloaded from [Release](https://github.com/dxFeed/dxfeed-graal-cxx-api/rele
- [STREAM_FEED](https://docs.dxfeed.com/dxfeed/api/com/dxfeed/api/DXEndpoint.Role.html#STREAM_FEED) is similar to
FEED and also connects to the remote data feed provider but is designed for bulk data parsing from files
- [ ] dxFeed Graal C API
- [ ] dxFeed Graal C++ API
- [x] dxFeed Graal C++ API
- [LOCAL_HUB](https://docs.dxfeed.com/dxfeed/api/com/dxfeed/api/DXEndpoint.Role.html#LOCAL_HUB) is a local hub
without the ability to establish network connections. Events published via publisher are delivered to local feed only.
- [ ] dxFeed Graal C API
- [ ] dxFeed Graal C++ API
- [x] dxFeed Graal C++ API
- [PUBLISHER](https://docs.dxfeed.com/dxfeed/api/com/dxfeed/api/DXEndpoint.Role.html#PUBLISHER) connects to the
remote publisher hub (also known as multiplexor) or creates a publisher on the local
host ([Java API sample](https://github.com/devexperts/QD/blob/master/dxfeed-samples/src/main/java/com/dxfeed/sample/_simple_/WriteTapeFile.java))
- [ ] dxFeed Graal C API
- [ ] dxFeed Graal C++ API
- [x] dxFeed Graal C++ API
- [STREAM_PUBLISHER](https://docs.dxfeed.com/dxfeed/api/com/dxfeed/api/DXEndpoint.Role.html#STREAM_PUBLISHER) is
similar to PUBLISHER and also connects to the remote publisher hub, but is designed for bulk data publishing
- [ ] dxFeed Graal C API
- [ ] dxFeed Graal C++ API
- [x] dxFeed Graal C++ API
- [ON_DEMAND_FEED](https://docs.dxfeed.com/dxfeed/api/com/dxfeed/api/DXEndpoint.Role.html#ON_DEMAND_FEED) is similar
to FEED, but it is designed to be used with OnDemandService for historical data replay only
- [ ] dxFeed Graal C API
Expand Down
8 changes: 4 additions & 4 deletions docs/Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# The default value is: My Project.

PROJECT_NAME = "dxFeed Graal Native CXX API"
PROJECT_NAME = "dxFeed Graal CXX API"

# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
Expand Down Expand Up @@ -209,7 +209,7 @@ SHORT_NAMES = NO
# description.)
# The default value is: NO.

JAVADOC_AUTOBRIEF = NO
JAVADOC_AUTOBRIEF = YES

# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
# such as
Expand Down Expand Up @@ -905,7 +905,7 @@ WARN_LINE_FORMAT = "at line $line of file $file"
# specified the warning and error messages are written to standard output
# (stdout).

WARN_LOGFILE =
WARN_LOGFILE = doxygen_warns.log

#---------------------------------------------------------------------------
# Configuration options related to the input files
Expand Down Expand Up @@ -1775,7 +1775,7 @@ FORMULA_MACROFILE =
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.

USE_MATHJAX = NO
USE_MATHJAX = YES

# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
# Note that the different versions of MathJax have different requirements with
Expand Down
1 change: 1 addition & 0 deletions include/dxfeed_graal_cpp_api/api/ApiModule.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@
#include "DXEndpoint.hpp"
#include "DXFeed.hpp"
#include "DXFeedSubscription.hpp"
#include "DXPublisher.hpp"
#include "FilteredSubscriptionSymbol.hpp"
120 changes: 57 additions & 63 deletions include/dxfeed_graal_cpp_api/api/DXEndpoint.hpp

Large diffs are not rendered by default.

193 changes: 189 additions & 4 deletions include/dxfeed_graal_cpp_api/api/DXFeed.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,85 @@ class EventTypeEnum;

/**
* Main entry class for dxFeed API (<b>read it first</b>).
*
* <h3>Sample usage</h3>
*
* This section gives sample usage scenarios.
*
* <h4>Default singleton instance</h4>
*
* There is a singleton instance of the feed that is returned by DXFeed::getInstance() method.
* It is created on the first use with default configuration properties that are explained in detail in
* documentation for DXEndpoint class in the "Default properties" section.
*
* <p>In particular,
* you can provide a default address to connect and credentials using
* "@ref DXEndpoint::DXFEED_ADDRESS_PROPERTY "dxfeed.address"",
* "@ref DXEndpoint::DXFEED_USER_PROPERTY "dxfeed.user"", and
* "@ref DXEndpoint::DXFEED_PASSWORD_PROPERTY "dxfeed.password""
* system properties or by putting them into
* "@ref DXEndpoint::DXFEED_PROPERTIES_PROPERTY "dxfeed.properties""
* file in the same directory. dxFeed API samples come with a ready-to-use "<b>dxfeed.properties</b>"
* file that contains an address of dxFeed demo feed at "<b>demo.dxfeed.com:7300</b>" and
* demo access credentials.
*
* <h4>Subscribe for single event type</h4>
*
* The following code creates listener that prints mid price for each quote
* and subscribes for quotes on SPDR S&P 500 ETF symbol:
* <pre><tt>
* auto sub = @ref DXFeed "DXFeed"::@ref DXFeed::getInstance() "getInstance"()->@ref DXFeed::createSubscription() "createSubscription"(Quote::TYPE);
*
* sub->@ref DXFeedSubscription::addEventListener() "addEventListener"<Quote>([](const auto& quotes) {
* for (const auto& quote : quotes) {
* std::cout << "Mid = " + (quote->@ref Quote::getBidPrice() "getBidPrice"() + quote->@ref Quote::getAskPrice() "getAskPrice"()) / 2) << std::endl;
* }
* });
*
* sub->@ref DXFeedSubscription::addSymbols() "addSymbols"("SPY");</tt></pre>
*
* Note, that order of calls is important here. By attaching listeners first and then setting
* subscription we ensure that the current quote gets received by the listener. See DXFeedSubscription::addSymbols() for details.
* If a set of symbols is changed first, then @ref DXFeedSubscription::addEventListener() "sub->addEventListener"
* raises an IllegalStateException in JVM to protected from hard-to-catch bugs with potentially missed events.
*
* <h4>Subscribe for multiple event types</h4>
*
* The following code creates listener that prints each received event and
* subscribes for quotes and trades on SPDR S&P 500 ETF symbol:
* <pre><tt>
* auto sub = @ref DXFeed "DXFeed"::@ref DXFeed::getInstance() "getInstance"()->@ref DXFeed::createSubscription() "createSubscription"({Quote::TYPE, Trade::TYPE});
*
* sub->@ref DXFeedSubscription::addEventListener() "addEventListener"([](auto&& events) {
* for (const auto& event : events) {
* std::cout << event << std::endl;
* }
* });
*
* sub->@ref DXFeedSubscription::addSymbols() "addSymbols"("SPY");</tt></pre>
*
* <h4>Subscribe for event and query periodically its last value</h4>
*
* The following code subscribes for trades on SPDR S&P 500 ETF symbol and
* prints last trade every second.
*
* <pre><tt>
* using namespace std::chrono_literals;
*
* auto sub = @ref DXFeed "DXFeed"::@ref DXFeed::getInstance() "getInstance"()->@ref DXFeed::createSubscription() "createSubscription"({Trade::TYPE});
*
* sub->@ref DXFeedSubscription::addSymbols() "addSymbols"("SPY");
*
* auto feed = @ref DXFeed "DXFeed"::@ref DXFeed::getInstance() "getInstance"();
*
* while (true) {
* std::cout << System.out.println(feed->@ref DXFeed::getLastEvent() "getLastEvent"(Trade::create("SPY")));
* std::this_thread::sleep_for(1000ms);
* }</tt></pre>
*
* <h3>Threads and locks</h3>
*
* This class is thread-safe and can be used concurrently from multiple threads without external synchronization.
*/
struct DXFCPP_EXPORT DXFeed : SharedEntity {
friend struct DXEndpoint;
Expand All @@ -43,7 +122,7 @@ struct DXFCPP_EXPORT DXFeed : SharedEntity {
}

public:
virtual ~DXFeed() noexcept {
~DXFeed() noexcept override {
if constexpr (Debugger::isDebug) {
Debugger::debug("DXFeed{" + handler_.toString() + "}::~DXFeed()");
}
Expand All @@ -59,14 +138,92 @@ struct DXFCPP_EXPORT DXFeed : SharedEntity {
*/
static std::shared_ptr<DXFeed> getInstance() noexcept;

/**
* Attaches the given subscription to this feed. This method does nothing if the
* corresponding subscription is already attached to this feed.
*
* <p> This feed publishes data to the attached subscription.
* Application can attach event listener via DXFeedSubscription::addEventListener to get notified about data changes
* and can change its data subscription via DXFeedSubscription methods.
*
* <h3>Implementation notes</h3>
*
* This method adds a non-serializable ObservableSubscriptionChangeListener for the given subscription
* via DXFeedSubscription::addChangeListener method.
*
* @param subscription The subscription.
* @see DXFeedSubscription
*/
void attachSubscription(std::shared_ptr<DXFeedSubscription> subscription) noexcept;

/**
* Detaches the given subscription from this feed. This method does nothing if the
* corresponding subscription is not attached to this feed.
*
* <h3>Implementation notes</h3>
*
* This method removes ObservableSubscriptionChangeListener from the given subscription
* via DXFeedSubscription::removeChangeListener method.
*
* @param subscription The subscription.
* @see DXFeedSubscription
*/
void detachSubscription(std::shared_ptr<DXFeedSubscription> subscription) noexcept;

/**
* Detaches the given subscription from this feed and clears data delivered to this subscription
* by publishing empty events. This method does nothing if the
* corresponding subscription is not attached to this feed.
*
* @param subscription The subscription.
* @see DXFeed::detachSubscription()
*/
void detachSubscriptionAndClear(std::shared_ptr<DXFeedSubscription> subscription) noexcept;

/**
* Creates new subscription for a single event type that is <i>attached</i> to this feed.
* This method creates new DXFeedSubscription and invokes @link DXFeed::attachSubscription.
*
* Example:
* ```cpp
* auto sub = dxfcpp::DXFeed::getInstance()->createSubscription(dxfcpp::Quote::TYPE);
* ```
*
* @param eventType The type of event
* @return The new subscription
*/
std::shared_ptr<DXFeedSubscription> createSubscription(const EventTypeEnum &eventType) noexcept;

/**
* Creates new subscription for multiple event types that is <i>attached</i> to this feed.
* This method creates new DXFeedSubscription and invokes @link DXFeed::attachSubscription.
*
* Example:
* ```cpp
* auto eventTypes = {dxfcpp::Quote::TYPE, dxfcpp::TimeAndSale::TYPE};
*
* auto sub = dxfcpp::DXFeed::getInstance()->createSubscription(eventTypes.begin(), eventTypes.end());
* ```
*
* ```cpp
* std::vector types{dxfcpp::Quote::TYPE, dxfcpp::Trade::TYPE, dxfcpp::Summary::TYPE};
*
* auto sub = dxfcpp::DXFeedSubscription::create(types.begin(), types.end());
* ```
*
* ```cpp
* std::set types{dxfcpp::Quote::TYPE, dxfcpp::Trade::TYPE, dxfcpp::Summary::TYPE};
* auto endpoint = dxfcpp::DXEndpoint::newBuilder()->withRole(dxfcpp::DXEndpoint::Role::FEED)->build();
* auto sub = endpoint->getFeed()->createSubscription(eventTypes.begin(), eventTypes.end());
*
* endpoint->connect("demo.dxfeed.com:7300");
* ```
*
* @tparam EventTypeIt The iterator type of the collection of event types
* @param begin The start iterator
* @param end The end iterator
* @return The new subscription
*/
template <typename EventTypeIt>
std::shared_ptr<DXFeedSubscription> createSubscription(EventTypeIt begin, EventTypeIt end) noexcept {
if constexpr (Debugger::isDebug) {
Expand All @@ -80,13 +237,41 @@ struct DXFCPP_EXPORT DXFeed : SharedEntity {
return sub;
}

/**
* Creates new subscription for multiple event types that is <i>attached</i> to this feed.
* This method creates new DXFeedSubscription and invokes @link DXFeed::attachSubscription.
*
* Example:
* ```cpp
* auto sub = dxfcpp::DXFeed::getInstance()->createSubscription({dxfcpp::Quote::TYPE, dxfcpp::TimeAndSale::TYPE});
* ```
*
* @param eventTypes The initializer list of event types
* @return The new subscription
*/
std::shared_ptr<DXFeedSubscription> createSubscription(std::initializer_list<EventTypeEnum> eventTypes) noexcept;

/**
* Creates new subscription for multiple event types that is <i>attached</i> to this feed.
* This method creates new DXFeedSubscription and invokes @link DXFeed::attachSubscription.
*
* Example:
* ```cpp
* auto sub = dxfcpp::DXFeed::getInstance()->createSubscription(std::unordered_set{dxfcpp::Quote::TYPE,
* dxfcpp::TimeAndSale::TYPE});
* ```
*
* ```cpp
* std::vector types = {dxfcpp::Quote::TYPE, dxfcpp::TimeAndSale::TYPE};
* auto sub = dxfcpp::DXFeed::getInstance()->createSubscription(types);
* ```
*
* @tparam EventTypesCollection The class of the collection of event types
* @param eventTypes The collection of event types
* @return The new subscription
*/
template <typename EventTypesCollection>
std::shared_ptr<DXFeedSubscription> createSubscription(EventTypesCollection &&eventTypes) noexcept
#if __cpp_concepts
requires ElementTypeIs<EventTypesCollection, EventTypeEnum>
#endif
{
if constexpr (Debugger::isDebug) {
Debugger::debug(toString() + "::createSubscription(eventTypes = " +
Expand Down
Loading

0 comments on commit 6fc79f8

Please sign in to comment.