diff --git a/libraries/plugins/affiliate_stats/affiliate_stats_api.cpp b/libraries/plugins/affiliate_stats/affiliate_stats_api.cpp index 0b072cca..5fcbe0d6 100644 --- a/libraries/plugins/affiliate_stats/affiliate_stats_api.cpp +++ b/libraries/plugins/affiliate_stats/affiliate_stats_api.cpp @@ -37,7 +37,6 @@ #include #include -#include namespace graphene { namespace affiliate_stats { @@ -48,6 +47,28 @@ class affiliate_stats_api_impl public: affiliate_stats_api_impl(graphene::app::application& _app); + std::vector list_top_referred_accounts( asset_id_type asset, uint16_t limit )const + { + std::vector result; + result.reserve( limit ); + auto& idx = app.chain_database()->get_index_type().indices().get(); + auto itr = idx.find( asset ); + while( itr != idx.end() && itr->get_asset_id() == asset && limit-- > 0 ) + result.push_back( *itr ); + return result; + } + + std::vector list_top_rewards_per_app( asset_id_type asset, uint16_t limit )const + { + std::vector result; + result.reserve( limit ); + auto& idx = app.chain_database()->get_index_type().indices().get(); + auto itr = idx.find( asset ); + while( itr != idx.end() && itr->get_asset_id() == asset && limit-- > 0 ) + result.push_back( *itr ); + return result; + } + graphene::app::application& app; }; @@ -56,9 +77,36 @@ affiliate_stats_api_impl::affiliate_stats_api_impl(graphene::app::application& _ } // detail +top_referred_account::top_referred_account() {} + +top_referred_account::top_referred_account( const referral_reward_object& rro ) + : referral( rro.referral ), total_payout( rro.total_payout ) {} + +top_app::top_app() {} + +top_app::top_app( const app_reward_object& aro ) + : app( aro.app ), total_payout( aro.total_payout ) {} + affiliate_stats_api::affiliate_stats_api(graphene::app::application& app) : my(std::make_shared(app)) {} +std::vector affiliate_stats_api::list_top_referred_accounts( asset_id_type asset, uint16_t limit )const +{ + FC_ASSERT( limit <= 100 ); + return my->list_top_referred_accounts( asset, limit ); +} + +std::vector affiliate_stats_api::list_top_rewards_per_app( asset_id_type asset, uint16_t limit )const +{ + FC_ASSERT( limit <= 100 ); + return my->list_top_rewards_per_app( asset, limit ); +} + +std::vector affiliate_stats_api::list_historic_referral_rewards( account_id_type affiliate )const +{ + FC_ASSERT( false, "Not implemented!" ); +} + } } // graphene::affiliate_stats diff --git a/libraries/plugins/affiliate_stats/affiliate_stats_plugin.cpp b/libraries/plugins/affiliate_stats/affiliate_stats_plugin.cpp index ee4f7df5..3099b331 100644 --- a/libraries/plugins/affiliate_stats/affiliate_stats_plugin.cpp +++ b/libraries/plugins/affiliate_stats/affiliate_stats_plugin.cpp @@ -23,6 +23,7 @@ */ #include +#include #include @@ -45,11 +46,9 @@ class affiliate_stats_plugin_impl { public: affiliate_stats_plugin_impl(affiliate_stats_plugin& _plugin) - : _self( _plugin ) - { } + : _self( _plugin ) { } virtual ~affiliate_stats_plugin_impl(); - /** this method is called as a callback after a block is applied * and will process/index all operations that were applied in the block. */ @@ -60,23 +59,67 @@ class affiliate_stats_plugin_impl return _self.database(); } + typedef void result_type; + template + void operator()( const Operation& op ) {} + affiliate_stats_plugin& _self; + app_reward_index* _ar_index; + referral_reward_index* _rr_index; private: }; affiliate_stats_plugin_impl::~affiliate_stats_plugin_impl() {} +template<> +void affiliate_stats_plugin_impl::operator()( const affiliate_payout_operation& op ) +{ + auto& by_app = _ar_index->indices().get(); + auto itr = by_app.find( boost::make_tuple( op.tag, op.payout.asset_id ) ); + if( itr == by_app.end() ) + { + database().create( [&op]( app_reward_object& aro ) { + aro.app = op.tag; + aro.total_payout = op.payout; + }); + } + else + { + database().modify( *itr, [&op]( app_reward_object& aro ) { + aro.total_payout += op.payout; + }); + } +} + +template<> +void affiliate_stats_plugin_impl::operator()( const affiliate_referral_payout_operation& op ) +{ + auto& by_referral = _rr_index->indices().get(); + auto itr = by_referral.find( boost::make_tuple( op.player, op.payout.asset_id ) ); + if( itr == by_referral.end() ) + { + database().create( [&op]( referral_reward_object& rro ) { + rro.referral = op.player; + rro.total_payout = op.payout; + }); + } + else + { + database().modify( *itr, [&op]( referral_reward_object& rro ) { + rro.total_payout += op.payout; + }); + } +} + void affiliate_stats_plugin_impl::update_affiliate_stats( const signed_block& b ) { - graphene::chain::database& db = database(); - vector >& hist = db.get_applied_operations(); + vector >& hist = database().get_applied_operations(); for( optional< operation_history_object >& o_op : hist ) { if( !o_op.valid() ) continue; - const operation_history_object& op = *o_op; - + o_op->op.visit( *this ); } } @@ -107,9 +150,9 @@ void affiliate_stats_plugin::plugin_initialize(const boost::program_options::var { database().applied_block.connect( [this]( const signed_block& b){ my->update_affiliate_stats(b); } ); - // FIXME // my->_oho_index = database().add_index< primary_index< simple_index< operation_history_object > > >(); - // database().add_index< primary_index< account_transaction_history_index > >(); + my->_ar_index = database().add_index< primary_index< app_reward_index > >(); + my->_rr_index = database().add_index< primary_index< referral_reward_index > >(); } void affiliate_stats_plugin::plugin_startup() {} diff --git a/libraries/plugins/affiliate_stats/include/graphene/affiliate_stats/affiliate_stats_api.hpp b/libraries/plugins/affiliate_stats/include/graphene/affiliate_stats/affiliate_stats_api.hpp index b3a27475..d41e6d44 100644 --- a/libraries/plugins/affiliate_stats/include/graphene/affiliate_stats/affiliate_stats_api.hpp +++ b/libraries/plugins/affiliate_stats/include/graphene/affiliate_stats/affiliate_stats_api.hpp @@ -31,6 +31,8 @@ #include #include +#include + using namespace graphene::chain; namespace graphene { namespace app { @@ -43,19 +45,51 @@ namespace detail { class affiliate_stats_api_impl; } +class referral_payment { +public: + +}; + +class top_referred_account { +public: + top_referred_account(); + top_referred_account( const referral_reward_object& rro ); + + account_id_type referral; + asset total_payout; +}; + +class top_app { +public: + top_app(); + top_app( const app_reward_object& rro ); + + app_tag app; + asset total_payout; +}; + class affiliate_stats_api { public: affiliate_stats_api(graphene::app::application& app); + std::vector list_historic_referral_rewards( account_id_type affiliate )const; + // get_pending_referral_reward() - not implemented because we have continuous payouts + // get_previous_referral_reward() - not implemented because we have continuous payouts + std::vector list_top_referred_accounts( asset_id_type asset, uint16_t limit = 100 )const; + std::vector list_top_rewards_per_app( asset_id_type asset, uint16_t limit = 100 )const; + std::shared_ptr my; }; } } // graphene::affiliate_stats -/* -FC_REFLECT(graphene::bookie::order_bin, (amount_to_bet)(backer_multiplier)) -FC_REFLECT(graphene::bookie::binned_order_book, (aggregated_back_bets)(aggregated_lay_bets)) -FC_REFLECT(graphene::bookie::matched_bet_object, (id)(bettor_id)(betting_market_id)(amount_to_bet)(backer_multiplier)(back_or_lay)(end_of_delay)(amount_matched)(associated_operations)) -*/ + +FC_REFLECT(graphene::affiliate_stats::referral_payment, ) +FC_REFLECT(graphene::affiliate_stats::top_referred_account, (referral)(total_payout) ) +FC_REFLECT(graphene::affiliate_stats::top_app, (app)(total_payout) ) + FC_API(graphene::affiliate_stats::affiliate_stats_api, + (list_historic_referral_rewards) + (list_top_referred_accounts) + (list_top_rewards_per_app) ) diff --git a/libraries/plugins/affiliate_stats/include/graphene/affiliate_stats/affiliate_stats_objects.hpp b/libraries/plugins/affiliate_stats/include/graphene/affiliate_stats/affiliate_stats_objects.hpp new file mode 100644 index 00000000..1dc70276 --- /dev/null +++ b/libraries/plugins/affiliate_stats/include/graphene/affiliate_stats/affiliate_stats_objects.hpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2018 Peerplays Blockchain Standards Association, and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once +#include +#include + +namespace graphene { namespace affiliate_stats { +using namespace chain; + +enum stats_object_type +{ + app_reward_object_type, + referral_reward_object_type, + STATS_OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types +}; + +class app_reward_object : public graphene::db::abstract_object +{ +public: + static const uint8_t space_id = AFFILIATE_STATS_SPACE_ID; + static const uint8_t type_id = app_reward_object_type; + + app_tag app; + asset total_payout; + + inline share_type get_amount()const { return total_payout.amount; } + inline asset_id_type get_asset_id()const { return total_payout.asset_id; } +}; + +typedef object_id app_reward_id_type; + +struct by_asset; +struct by_app_asset; +typedef multi_index_container< + app_reward_object, + indexed_by< + ordered_unique, member >, + ordered_non_unique, + composite_key< + app_reward_object, + const_mem_fun, + const_mem_fun >, + composite_key_compare< + std::less, + std::greater > + >, + ordered_unique, + composite_key< + app_reward_object, + member, + const_mem_fun > + > > > app_reward_multi_index_type; +typedef generic_index app_reward_index; + +class referral_reward_object : public graphene::db::abstract_object +{ +public: + static const uint8_t space_id = AFFILIATE_STATS_SPACE_ID; + static const uint8_t type_id = referral_reward_object_type; + + account_id_type referral; + asset total_payout; + + inline share_type get_amount()const { return total_payout.amount; } + inline asset_id_type get_asset_id()const { return total_payout.asset_id; } +}; + +typedef object_id referral_reward_id_type; + +struct by_referral_asset; +typedef multi_index_container< + referral_reward_object, + indexed_by< + ordered_unique, member >, + ordered_non_unique, + composite_key< + referral_reward_object, + const_mem_fun, + const_mem_fun >, + composite_key_compare< + std::less, + std::greater > + >, + ordered_unique, + composite_key< + referral_reward_object, + member, + const_mem_fun > + > > > referral_reward_multi_index_type; +typedef generic_index referral_reward_index; + +} } //graphene::affiliate_stats + +FC_REFLECT_DERIVED( graphene::affiliate_stats::app_reward_object, (graphene::db::object), (app)(total_payout) ) +FC_REFLECT_DERIVED( graphene::affiliate_stats::referral_reward_object, (graphene::db::object), (referral)(total_payout) ) +