diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index f16c91d4..d751c31a 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -160,6 +160,26 @@ namespace graphene { namespace app { return result; } + void database_api::unsubscribe_from_accounts( const vector& names_or_ids ) + { + for (const std::string& account_name_or_id : names_or_ids) + { + const account_object* account = nullptr; + if (std::isdigit(account_name_or_id[0])) + account = _db.find(fc::variant(account_name_or_id).as()); + else + { + const auto& idx = _db.get_index_type().indices().get(); + auto itr = idx.find(account_name_or_id); + if (itr != idx.end()) + account = &*itr; + } + if (account == nullptr) + continue; + + _account_subscriptions.erase(account->id); + } + } std::map database_api::get_full_accounts(std::function callback, const vector& names_or_ids) @@ -690,29 +710,59 @@ namespace graphene { namespace app { } } - _broadcast_removed_complete = fc::async([=](){ - for( const auto& item : broadcast_queue ) - { - auto sub = _account_subscriptions.find(item.first); - if( sub != _account_subscriptions.end() ) - sub->second( fc::variant(item.second ) ); - } - }); + if( broadcast_queue.size() ) + { + _broadcast_removed_complete = fc::async([=](){ + for( const auto& item : broadcast_queue ) + { + auto sub = _account_subscriptions.find(item.first); + if( sub != _account_subscriptions.end() ) + sub->second( fc::variant(item.second ) ); + } + }); + } + } + if( _market_subscriptions.size() ) + { + map< pair, vector > broadcast_queue; + for( const auto& obj : objs ) + { + const limit_order_object* order = dynamic_cast(obj); + if( order ) + { + auto sub = _market_subscriptions.find( order->get_market() ); + if( sub != _market_subscriptions.end() ) + broadcast_queue[order->get_market()].emplace_back( order->id ); + } + } + if( broadcast_queue.size() ) + { + _broadcast_removed_complete = fc::async([=](){ + for( const auto& item : broadcast_queue ) + { + auto sub = _market_subscriptions.find(item.first); + if( sub != _market_subscriptions.end() ) + sub->second( fc::variant(item.second ) ); + } + }); + } } } void database_api::on_objects_changed(const vector& ids) { - vector my_objects; - map > broadcast_queue; + vector my_objects; + map > broadcast_queue; + map< pair, vector > market_broadcast_queue; for(auto id : ids) { if(_subscriptions.find(id) != _subscriptions.end()) my_objects.push_back(id); + const object* obj = nullptr; if( _account_subscriptions.size() ) { - const object* obj = _db.find_object( id ); + obj = _db.find_object( id ); if( obj ) { vector relevant = get_relevant_accounts( obj ); @@ -724,6 +774,21 @@ namespace graphene { namespace app { } } } + + if( _market_subscriptions.size() ) + { + if( !_account_subscriptions.size() ) obj = _db.find_object( id ); + if( obj ) + { + const limit_order_object* order = dynamic_cast(obj); + if( order ) + { + auto sub = _market_subscriptions.find( order->get_market() ); + if( sub != _market_subscriptions.end() ) + market_broadcast_queue[order->get_market()].emplace_back( order->id ); + } + } + } } @@ -738,6 +803,12 @@ namespace graphene { namespace app { if( sub != _account_subscriptions.end() ) sub->second( fc::variant(item.second ) ); } + for( const auto& item : market_broadcast_queue ) + { + auto sub = _market_subscriptions.find(item.first); + if( sub != _market_subscriptions.end() ) + sub->second( fc::variant(item.second ) ); + } for(auto id : my_objects) { // just incase _usbscriptions changed between filter and broadcast @@ -766,6 +837,7 @@ namespace graphene { namespace app { if(_market_subscriptions.size() == 0) return; + const auto& ops = _db.get_applied_operations(); map< std::pair, vector> > subscribed_markets_ops; for(const auto& op : ops) @@ -773,9 +845,11 @@ namespace graphene { namespace app { std::pair market; switch(op.op.which()) { + /* This is sent via the object_changed callback case operation::tag::value: market = op.op.get().get_market(); break; + */ case operation::tag::value: market = op.op.get().get_market(); break; diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index 42be161c..be457af2 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -149,11 +149,15 @@ namespace graphene { namespace app { * accounts. If any of the strings in @ref names_or_ids cannot be tied to an account, that input will be * ignored. All other accounts will be retrieved and subscribed. * - * TODO: Describe the return value and argument to callback in detail */ std::map get_full_accounts(std::function callback, const vector& names_or_ids); + /** + * Stop receiving updates generated by get_full_accounts() + */ + void unsubscribe_from_accounts( const vector& names_or_ids ); + /** * @brief Get limit orders in a given market * @param a ID of asset being sold @@ -498,6 +502,7 @@ FC_API(graphene::app::database_api, (get_account_count) (lookup_accounts) (get_full_accounts) + (unsubscribe_from_accounts) (get_account_balances) (get_named_account_balances) (lookup_asset_symbols) diff --git a/libraries/chain/include/graphene/chain/market_evaluator.hpp b/libraries/chain/include/graphene/chain/market_evaluator.hpp index cd316491..48f4d5f6 100644 --- a/libraries/chain/include/graphene/chain/market_evaluator.hpp +++ b/libraries/chain/include/graphene/chain/market_evaluator.hpp @@ -27,6 +27,13 @@ namespace graphene { namespace chain { share_type for_sale; ///< asset id is sell_price.base.asset_id price sell_price; + pair get_market()const + { + auto tmp = std::make_pair( sell_price.base.asset_id, sell_price.quote.asset_id ); + if( tmp.first > tmp.second ) std::swap( tmp.first, tmp.second ); + return tmp; + } + asset amount_for_sale()const { return asset( for_sale, sell_price.base.asset_id ); } asset amount_to_receive()const { return amount_for_sale() * sell_price; } };