Rework the API calls for tournaments, add an index for getting tournaments

registered by a given account
This commit is contained in:
Eric Frias 2016-10-21 12:14:37 -04:00
parent 72d48cf3d2
commit 30874697cc
8 changed files with 137 additions and 65 deletions

View file

@ -139,8 +139,8 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
vector<blinded_balance_object> get_blinded_balances( const flat_set<commitment_type>& commitments )const;
// Tournaments
vector<tournament_object> get_upcoming_tournaments(fc::optional<account_id_type> account_filter, uint32_t limit)const;
vector<tournament_object> get_active_tournaments(fc::optional<account_id_type> account_filter, uint32_t limit)const;
vector<tournament_object> get_tournaments_in_state(tournament_state state, uint32_t limit) const;
vector<tournament_id_type> get_registered_tournaments(account_id_type account_filter, uint32_t limit) const;
//private:
@ -1769,26 +1769,20 @@ vector<blinded_balance_object> database_api_impl::get_blinded_balances( const fl
// Tournament methods //
// //
//////////////////////////////////////////////////////////////////////
vector<tournament_object> database_api::get_upcoming_tournaments(fc::optional<account_id_type> account_filter, uint32_t limit)const
vector<tournament_object> database_api::get_tournaments_in_state(tournament_state state, uint32_t limit) const
{
return my->get_upcoming_tournaments(account_filter, limit);
return my->get_tournaments_in_state(state, limit);
}
vector<tournament_object> database_api_impl::get_upcoming_tournaments(fc::optional<account_id_type> account_filter, uint32_t limit)const
vector<tournament_object> database_api_impl::get_tournaments_in_state(tournament_state state, uint32_t limit) const
{
vector<tournament_object> result;
const auto& registration_deadline_index = _db.get_index_type<tournament_index>().indices().get<by_registration_deadline>();
const auto range = registration_deadline_index.equal_range(boost::make_tuple(tournament_state::accepting_registrations));
const auto range = registration_deadline_index.equal_range(boost::make_tuple(state));
for (const tournament_object& tournament_obj : boost::make_iterator_range(range.first, range.second))
{
if (tournament_obj.options.whitelist.empty() ||
!account_filter ||
tournament_obj.options.whitelist.find(*account_filter) != tournament_obj.options.whitelist.end())
{
result.emplace_back(tournament_obj);
subscribe_to_item( tournament_obj.id );
}
result.emplace_back(tournament_obj);
subscribe_to_item( tournament_obj.id );
if (result.size() >= limit)
break;
@ -1796,39 +1790,21 @@ vector<tournament_object> database_api_impl::get_upcoming_tournaments(fc::option
return result;
}
vector<tournament_object> database_api::get_active_tournaments(fc::optional<account_id_type> account_filter, uint32_t limit)const
vector<tournament_id_type> database_api::get_registered_tournaments(account_id_type account_filter, uint32_t limit) const
{
return my->get_active_tournaments(account_filter, limit);
return my->get_registered_tournaments(account_filter, limit);
}
vector<tournament_object> database_api_impl::get_active_tournaments(fc::optional<account_id_type> account_filter, uint32_t limit)const
vector<tournament_id_type> database_api_impl::get_registered_tournaments(account_id_type account_filter, uint32_t limit) const
{
vector<tournament_object> result;
const auto& start_time_index = _db.get_index_type<tournament_index>().indices().get<by_start_time>();
const auto& tournament_details_idx = _db.get_index_type<tournament_details_index>();
const auto& tournament_details_primary_idx = dynamic_cast<const primary_index<tournament_details_index>&>(tournament_details_idx);
const auto& players_idx = tournament_details_primary_idx.get_secondary_index<graphene::chain::tournament_players_index>();
const auto begin = start_time_index.lower_bound(boost::make_tuple(tournament_state::awaiting_start));
const auto end = start_time_index.upper_bound(boost::make_tuple(tournament_state::in_progress));
for (const tournament_object& tournament_obj : boost::make_iterator_range(begin, end))
{
if (account_filter)
{
const tournament_details_object& tournament_details_obj = tournament_obj.tournament_details_id(_db);
if (tournament_details_obj.registered_players.find(*account_filter) != tournament_details_obj.registered_players.end())
{
result.emplace_back(tournament_obj);
subscribe_to_item( tournament_obj.id );
}
}
else
{
result.emplace_back(tournament_obj);
subscribe_to_item( tournament_obj.id );
}
if (result.size() >= limit)
break;
}
return result;
vector<tournament_id_type> tournament_ids = players_idx.get_registered_tournaments_for_account(account_filter);
if (tournament_ids.size() >= limit)
tournament_ids.resize(limit);
return tournament_ids;
}
//////////////////////////////////////////////////////////////////////

View file

@ -553,17 +553,14 @@ class database_api
// Tournaments //
/////////////////
/**
* @param account_filter if provided, this will only return tournaments the given account is
* allowed to join (public tournaments or tournaments the account is whitelisted for)
* @return the list of tournaments that are still accepting new registrations
* @return the list of tournaments in the given state
*/
vector<tournament_object> get_upcoming_tournaments(fc::optional<account_id_type> account_filter, uint32_t limit)const;
vector<tournament_object> get_tournaments_in_state(tournament_state state, uint32_t limit) const;
/**
* @return the list of tournaments that are either in-progress or fully-registered and just waiting on their start
* time to arrive
* @return the list of tournaments that a given account is registered to play in
*/
vector<tournament_object> get_active_tournaments(fc::optional<account_id_type> account_filter, uint32_t limit)const;
vector<tournament_id_type> get_registered_tournaments(account_id_type account_filter, uint32_t limit) const;
private:
std::shared_ptr< database_api_impl > my;
@ -667,6 +664,6 @@ FC_API(graphene::app::database_api,
(get_blinded_balances)
// Tournaments
(get_upcoming_tournaments)
(get_active_tournaments)
(get_tournaments_in_state)
(get_registered_tournaments)
)

View file

@ -208,7 +208,8 @@ void database::initialize_indexes()
add_index< primary_index<blinded_balance_index> >();
add_index< primary_index<tournament_index> >();
add_index< primary_index<tournament_details_index> >();
auto tournament_details_idx = add_index< primary_index<tournament_details_index> >();
tournament_details_idx->add_secondary_index<tournament_players_index>();
add_index< primary_index<match_index> >();
add_index< primary_index<game_index> >();

View file

@ -29,6 +29,9 @@ namespace graphene { namespace chain {
static const uint8_t space_id = protocol_ids;
static const uint8_t type_id = tournament_details_object_type;
/// the tournament object for which this is the details
tournament_id_type tournament_id;
/// List of players registered for this tournament
flat_set<account_id_type> registered_players;
@ -197,9 +200,35 @@ namespace graphene { namespace chain {
return s;
}
/**
* @brief This secondary index will allow a reverse lookup of all tournaments
* a particular account has registered for. This will be attached
* to the tournament details index because the registrations are contained
* in the tournament details object, but it will index the tournament ids
* since that is most useful to the GUI.
*/
class tournament_players_index : public secondary_index
{
public:
virtual void object_inserted( const object& obj ) override;
virtual void object_removed( const object& obj ) override;
virtual void about_to_modify( const object& before ) override;
virtual void object_modified( const object& after ) override;
/** given an account, map it to the set of tournaments in which that account is registered as a player */
map< account_id_type, flat_set<tournament_id_type> > account_to_joined_tournaments;
vector<tournament_id_type> get_registered_tournaments_for_account( const account_id_type& a )const;
protected:
flat_set<account_id_type> before_account_ids;
};
} }
FC_REFLECT_DERIVED(graphene::chain::tournament_details_object, (graphene::db::object),
(tournament_id)
(registered_players)
(payers)
(matches))

View file

@ -84,6 +84,12 @@ namespace graphene { namespace chain {
t.tournament_details_id = tournament_details.id;
});
// TODO: look up how to do this in the initial create
db().modify(tournament_details, [&]( tournament_details_object& a ) {
a.tournament_id = new_tournament.id;
});
fc_ilog(fc::logger::get("tournament"),
"Created tournament ${id} with details id ${details_id}",
("id", new_tournament.id)("details_id", tournament_details.id));
@ -107,7 +113,7 @@ namespace graphene { namespace chain {
"Registration deadline has already passed");
FC_ASSERT(_tournament_obj->options.whitelist.empty() ||
_tournament_obj->options.whitelist.find(op.player_account_id) == _tournament_obj->options.whitelist.end(),
_tournament_obj->options.whitelist.find(op.player_account_id) != _tournament_obj->options.whitelist.end(),
"Player is not on the whitelist for this tournament");
FC_ASSERT(_tournament_details_obj->registered_players.find(op.player_account_id) == _tournament_details_obj->registered_players.end(),

View file

@ -479,6 +479,73 @@ namespace graphene { namespace chain {
return fc::sha256::hash(full_throw_packed.data(), full_throw_packed.size());
}
vector<tournament_id_type> tournament_players_index::get_registered_tournaments_for_account( const account_id_type& a )const
{
auto iter = account_to_joined_tournaments.find(a);
if (iter != account_to_joined_tournaments.end())
return vector<tournament_id_type>(iter->second.begin(), iter->second.end());
return vector<tournament_id_type>();
}
void tournament_players_index::object_inserted(const object& obj)
{
assert( dynamic_cast<const tournament_details_object*>(&obj) ); // for debug only
const tournament_details_object& details = static_cast<const tournament_details_object&>(obj);
for (const account_id_type& account_id : details.registered_players)
account_to_joined_tournaments[account_id].insert(details.tournament_id);
}
void tournament_players_index::object_removed(const object& obj)
{
assert( dynamic_cast<const tournament_details_object*>(&obj) ); // for debug only
const tournament_details_object& details = static_cast<const tournament_details_object&>(obj);
for (const account_id_type& account_id : details.registered_players)
{
auto iter = account_to_joined_tournaments.find(account_id);
if (iter != account_to_joined_tournaments.end())
iter->second.erase(details.tournament_id);
}
}
void tournament_players_index::about_to_modify(const object& before)
{
assert( dynamic_cast<const tournament_details_object*>(&before) ); // for debug only
const tournament_details_object& details = static_cast<const tournament_details_object&>(before);
before_account_ids = details.registered_players;
}
void tournament_players_index::object_modified(const object& after)
{
assert( dynamic_cast<const tournament_details_object*>(&after) ); // for debug only
const tournament_details_object& details = static_cast<const tournament_details_object&>(after);
{
vector<account_id_type> newly_registered_players(details.registered_players.size());
auto end_iter = std::set_difference(details.registered_players.begin(), details.registered_players.end(),
before_account_ids.begin(), before_account_ids.end(),
newly_registered_players.begin());
newly_registered_players.resize(end_iter - newly_registered_players.begin());
for (const account_id_type& account_id : newly_registered_players)
account_to_joined_tournaments[account_id].insert(details.tournament_id);
}
{
vector<account_id_type> newly_unregistered_players(before_account_ids.size());
auto end_iter = std::set_difference(before_account_ids.begin(), before_account_ids.end(),
details.registered_players.begin(), details.registered_players.end(),
newly_unregistered_players.begin());
newly_unregistered_players.resize(end_iter - newly_unregistered_players.begin());
for (const account_id_type& account_id : newly_unregistered_players)
{
auto iter = account_to_joined_tournaments.find(account_id);
if (iter != account_to_joined_tournaments.end())
iter->second.erase(details.tournament_id);
}
}
}
} } // graphene::chain
namespace fc {

View file

@ -1422,10 +1422,9 @@ class wallet_api
signed_transaction tournament_join( string payer_account, string player_account, tournament_id_type tournament_id, string buy_in_amount, string buy_in_asset_symbol, bool broadcast = false );
/** Get a list of upcoming tournaments
* @param player_accounts if non-empty, only return tournaments for which at least one of the named players is eligible. If empty, return all tournaments
* @param limit the number of tournaments to return
*/
vector<tournament_object> get_upcoming_tournaments(optional<string> player_accounts, uint32_t limit);
vector<tournament_object> get_upcoming_tournaments(uint32_t limit);
/** Get specific information about a tournament
* @param tournament_id the ID of the tournament

View file

@ -951,12 +951,12 @@ public:
game_cache.clear();
for (const account_object& my_account : _wallet.my_accounts)
{
std::vector<tournament_object> tournaments = _remote_db->get_active_tournaments(my_account.id, 100);
std::vector<tournament_id_type> tournament_ids;
for (const tournament_object& tournament : tournaments)
std::vector<tournament_id_type> tournament_ids = _remote_db->get_registered_tournaments(my_account.id, 100);
for (const tournament_id_type& tournament_id : tournament_ids)
{
try
{
tournament_object tournament = get_object<tournament_object>(tournament_id);
auto insert_result = tournament_cache.insert(tournament);
if (insert_result.second)
{
@ -967,10 +967,10 @@ public:
}
catch (const fc::exception& e)
{
edump((e)(tournament));
edump((e)(tournament_id));
}
}
if (!tournaments.empty())
if (!tournament_ids.empty())
ilog("Account ${my_account} is registered for tournaments: ${tournaments}", ("my_account", my_account.name)("tournaments", tournament_ids));
else
ilog("Account ${my_account} is not registered for any tournaments", ("my_account", my_account.name));
@ -4552,12 +4552,9 @@ signed_transaction wallet_api::tournament_join( string payer_account,
return my->sign_transaction( tx, broadcast );
}
vector<tournament_object> wallet_api::get_upcoming_tournaments(fc::optional<string> player_account, uint32_t limit)
vector<tournament_object> wallet_api::get_upcoming_tournaments(uint32_t limit)
{
fc::optional<account_id_type> player_account_id;
if (player_account)
player_account_id = get_account(*player_account).id;
return my->_remote_db->get_upcoming_tournaments(player_account_id, limit);
return my->_remote_db->get_tournaments_in_state(tournament_state::accepting_registrations, limit);
}
tournament_object wallet_api::get_tournament(tournament_id_type id)