369 lines
15 KiB
C++
369 lines
15 KiB
C++
#include "AdminServiceServer.h"
|
|
|
|
#include "lib/persistence/SqliteStore.h"
|
|
#include "lib/logging/logging.h"
|
|
#include "lib/utils/bts_assert.h"
|
|
#include "lib/utils/PBUtils.h"
|
|
#include "lib/api/service_helpers/AdminServiceUtils.h"
|
|
#include "lib/orderman/orderman_utils/orderman_utils.h"
|
|
#include "lib/utils/TimeStamp.h"
|
|
#include "lib/utils/AuthToken.h"
|
|
|
|
#include <boost/container/flat_map.hpp>
|
|
#include <boost/tokenizer.hpp>
|
|
#include <fmt/format.h>
|
|
#include <map>
|
|
#include <set>
|
|
#include <utility>
|
|
|
|
namespace bts {
|
|
namespace admin{
|
|
|
|
AdminServiceServer::AdminServiceServer(bts::api::ServiceContext& context)
|
|
:
|
|
bts::api::admin::AuthenticatedAdminServiceBase (context),
|
|
_db_name("admin"),
|
|
_table_name("admin_data"),
|
|
_unique_key("0"),
|
|
_state(),
|
|
_store(new bts::persistence::SqliteStore(_db_name)),
|
|
_publisher(make_admin_data_stateful_publisher()),
|
|
_md_entit_publisher(make_md_entitlement_data_stateful_publisher()),
|
|
_md_perm_publisher(make_md_permissions_data_stateful_publisher()),
|
|
_order_service(context.locate<bts::api::orderman::OrderService>()),
|
|
_order_map()
|
|
{
|
|
LOG(Gen, Info, "AdminServiceServer: service started");
|
|
map<string,map<string,string>> all_data = _store->retrieve_all();
|
|
auto table = all_data.find(_table_name);
|
|
bool data_found = false;
|
|
if (table != all_data.end())
|
|
{
|
|
auto row = table->second.find(_unique_key);
|
|
if (row != table->second.end())
|
|
{
|
|
std::string& ser_data = row->second;
|
|
if (_state.ParseFromString(ser_data))
|
|
{
|
|
data_found = true;
|
|
_check_data_on_start();
|
|
_update_and_publish(false);
|
|
}
|
|
}
|
|
}
|
|
if (!data_found)
|
|
{
|
|
LOG(Gen, Info, "AdminServiceServer: data created for the first time");
|
|
AdminServiceUtils::fill_connections_from_config(_state);
|
|
AdminServiceUtils::bootstrap_data(_state);
|
|
_update_and_publish(true);
|
|
}
|
|
_order_service.subscribe_orders() |
|
|
rxcpp::operators::subscribe<api::orderman::OrdersUpdate>(
|
|
[this](auto const& update) {
|
|
for (const auto& o : update.removed()){
|
|
const auto& it = _order_map.find(o->key());
|
|
if(it != _order_map.end())
|
|
_order_map.erase(it);
|
|
}
|
|
for (const auto& ch : update.changed()) {
|
|
const auto& o = ch.current();
|
|
_order_map[o->key()] = o;
|
|
}
|
|
for (const auto& o : update.added()){
|
|
_order_map[o->key()]=o;
|
|
}
|
|
});
|
|
}
|
|
AdminServiceServer::~AdminServiceServer() {}
|
|
void AdminServiceServer::create_account(
|
|
const api::AuthToken&,
|
|
const AccountCreateAPIArgument& request,
|
|
const api::Response<AdminServiceCreateAccountResult>& reply){
|
|
bts::api::admin::AdminServiceCreateAccountResult result;
|
|
AdminServiceUtils::create_account(_state,
|
|
request.parent_account_id(),
|
|
request.account_name(),
|
|
request.description(),
|
|
false,
|
|
result);
|
|
if(request.creator_user() != "" && result.new_id() != 0)
|
|
{
|
|
const bts::api::admin::BTSUser* user = AdminServiceUtils::find_user(_state, request.creator_user(), false);
|
|
if(user)
|
|
{
|
|
BTSUser update(*user);
|
|
UserAccountPermissionUnit unit(UserAccountPermissionUnit::default_instance());
|
|
unit.mutable_admin_permission()->set_has_permissions(true);
|
|
unit.mutable_admin_permission()->set_has_md_permissions(true);
|
|
|
|
google::protobuf::MapPair<uint32_t,UserAccountPermissionUnit> v(result.new_id(), unit);
|
|
update.mutable_user_data()->mutable_account_permissions()->mutable_account_permissions()->insert(v);
|
|
AdminServiceOperationResult res;
|
|
AdminServiceUtils::update_user(_state, update, res);
|
|
}
|
|
}
|
|
_update_and_publish(false);
|
|
reply(result);
|
|
}
|
|
void AdminServiceServer::update_account(
|
|
const api::AuthToken&,
|
|
const AccountUpdateAPIArgument& request,
|
|
const api::Response<AdminServiceOperationResult>& reply){
|
|
bts::api::admin::AdminServiceOperationResult result;
|
|
AdminServiceUtils::update_account(_state, request.complete_data(), result);
|
|
_update_and_publish(false);
|
|
reply(result);
|
|
}
|
|
void AdminServiceServer::create_user(
|
|
const api::AuthToken&,
|
|
const UserCreateAPIArgument& request,
|
|
const api::Response<AdminServiceCreateEntityResult>& reply){
|
|
AdminServiceCreateEntityResult result;
|
|
AdminServiceUtils::create_user(_state,
|
|
request.parent_group_id(),
|
|
request.name(),
|
|
request.password(),
|
|
request.full_name(),
|
|
request.company(),
|
|
false,
|
|
request.license_data(),
|
|
request.license_entitlements(),
|
|
result);
|
|
_update_and_publish(false);
|
|
reply(result);
|
|
}
|
|
void AdminServiceServer::update_user(
|
|
const api::AuthToken&,
|
|
const UserUpdateAPIArgument& request,
|
|
const api::Response<AdminServiceOperationResult>& reply){
|
|
AdminServiceOperationResult result;
|
|
AdminServiceUtils::update_user(_state, request.complete_data(), result);
|
|
_update_and_publish(false);
|
|
reply(result);
|
|
}
|
|
void AdminServiceServer::get_admin_data(
|
|
const api::AuthToken&,
|
|
const bts::api::VoidMessage&,
|
|
const api::Response<AdminData>& reply){
|
|
reply(_state);
|
|
}
|
|
|
|
void AdminServiceServer::get_filtered_admin_data(
|
|
const api::AuthToken& token,
|
|
const bts::api::admin::FilteredAdminDataRequest&,
|
|
const api::Response<AdminData>& reply)
|
|
{
|
|
bts::api::user::TokenPayload toke;
|
|
bts::api::auth::decode_token(token, &toke);
|
|
{
|
|
if(toke.wheel())
|
|
reply(_state);
|
|
else
|
|
{
|
|
const BTSUser* admin_user = AdminServiceUtils::find_user(_state, toke.id());
|
|
AdminData filtered(_state);
|
|
boost::container::flat_map<std::string, int> added_accounts, added_users;
|
|
filtered.clear_users();
|
|
filtered.clear_accounts();
|
|
if(admin_user && admin_user->has_user_data())
|
|
{
|
|
const auto& permis = admin_user->user_data().account_permissions();
|
|
for(const auto& map_entry : permis.account_permissions())
|
|
{
|
|
auto acct_id = map_entry.first;
|
|
const bts::api::admin::UserAccountPermissionUnit& unit = map_entry.second;
|
|
const bts::api::admin::BTSAccount* acct = AdminServiceUtils::find_account(_state, acct_id, false);
|
|
if(!acct)
|
|
continue;
|
|
|
|
std::vector<const api::admin::BTSUser*> users_for_account;
|
|
admin::AdminServiceUtils::find_users_for_trading_account(_state, acct_id, users_for_account);
|
|
if(unit.admin_permission().has_permissions())
|
|
{
|
|
if(added_accounts.find(acct->name()) == added_accounts.end())
|
|
{
|
|
added_accounts[acct->name()] = 0;
|
|
filtered.add_accounts()->CopyFrom(*acct);
|
|
for(const auto& acctuser : users_for_account)
|
|
{
|
|
if(added_users.find(acctuser->name()) == added_users.end())
|
|
{
|
|
added_users[acctuser->name()] = 0;
|
|
const auto newuser = filtered.add_users();
|
|
newuser->CopyFrom(*acctuser);
|
|
if(!unit.admin_permission().has_md_permissions())
|
|
newuser->mutable_user_data()->mutable_exchange_user_data()->
|
|
mutable_cme_data()->set_admin_display_flag(bts::api::admin::CMEUserData_AdminDisplay::CMEUserData_AdminDisplay_Routing);
|
|
else
|
|
newuser->mutable_user_data()->mutable_exchange_user_data()->
|
|
mutable_cme_data()->set_admin_display_flag(bts::api::admin::CMEUserData_AdminDisplay::CMEUserData_AdminDisplay_All);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(unit.admin_permission().has_md_permissions())
|
|
{
|
|
for(const auto& acctuser : users_for_account)
|
|
{
|
|
if(added_users.find(acctuser->name()) == added_users.end())
|
|
{
|
|
added_users[acctuser->name()] = 0;
|
|
const auto newuser = filtered.add_users();
|
|
newuser->CopyFrom(*acctuser);
|
|
newuser->mutable_user_data()->mutable_exchange_user_data()->
|
|
mutable_cme_data()->set_admin_display_flag(bts::api::admin::CMEUserData_AdminDisplay::CMEUserData_AdminDisplay_MD);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
reply(filtered);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void AdminServiceServer::delete_user(
|
|
const api::AuthToken&,
|
|
const IDAPIArgument& id,
|
|
const api::Response<AdminServiceOperationResult>& reply){
|
|
AdminServiceOperationResult result; result.set_is_success(true);
|
|
AdminServiceUtils::delete_user(_state, id, result);
|
|
_update_and_publish(false);
|
|
reply(result);
|
|
}
|
|
void AdminServiceServer::delete_account(
|
|
const api::AuthToken&,
|
|
const IDAPIArgument& id,
|
|
const api::Response<AdminServiceOperationResult>& reply){
|
|
AdminServiceOperationResult result; result.set_is_success(true);
|
|
bts::admin::AdminServiceUtils::delete_account(_state, id, result);
|
|
_update_and_publish(false);
|
|
reply(result);
|
|
}
|
|
void AdminServiceServer::_update_and_publish(bool is_insert){
|
|
std::string ser_state;
|
|
auto start = utils::TimeStamp::now();
|
|
if (_state.SerializeToString(&ser_state))
|
|
{
|
|
LOG(Gen, Info, "Saving admin data");
|
|
if(is_insert)
|
|
_store->insert(_table_name, _unique_key, ser_state);
|
|
else
|
|
_store->update(_table_name, _unique_key, ser_state);
|
|
_publisher.add_or_update(_state);
|
|
_publisher.flush();
|
|
_publish_md_entitlements();
|
|
// _publish_md_permissions();
|
|
auto elapsed = (utils::TimeStamp::now() - start).milliseconds();
|
|
LOG(Gen, Info, "Saved admin data ({}ms)", elapsed);
|
|
}
|
|
else
|
|
LOG(Gen, Error, "Could not serialize admin data, saving failed");
|
|
|
|
}
|
|
void AdminServiceServer::get_order_summary(
|
|
const api::AuthToken&,
|
|
const bts::api::VoidMessage&,
|
|
const api::Response<OrdersSummary>& reply){
|
|
std::map<std::string,std::map<std::string,OrdersSummaryUnit>> agg;
|
|
for(auto it=_order_map.begin();it!=_order_map.end();it++){
|
|
const OrderRecord& ord=*(it->second);
|
|
if(bts::orderman::order_in_working_state(ord.state().status()) &&
|
|
bts::orderman::is_parent_order(ord))
|
|
_add_live_order(agg,ord);
|
|
}
|
|
OrdersSummary rv;
|
|
for (auto acct_it=agg.begin();acct_it!=agg.end();acct_it++){
|
|
const std::map<std::string,OrdersSummaryUnit>& user_map=acct_it->second;
|
|
for(auto user_it=user_map.begin();user_it!=user_map.end();user_it++){
|
|
const OrdersSummaryUnit& u=user_it->second;
|
|
OrdersSummaryUnit* nv=rv.add_units();
|
|
nv->CopyFrom(u);
|
|
}
|
|
}
|
|
reply(rv);
|
|
}
|
|
void AdminServiceServer::cancel_orders(
|
|
const api::AuthToken&,
|
|
const OrderCancelRequest& req,
|
|
const api::Response<bts::api::VoidMessage>&){
|
|
vector<string> accts, users;
|
|
for(auto it=req.accounts().begin();it!=req.accounts().end();it++)
|
|
accts.push_back(*it);
|
|
for(auto it=req.users().begin();it!=req.users().end();it++)
|
|
users.push_back(*it);
|
|
_cancel_orders(accts,users);
|
|
}
|
|
|
|
void AdminServiceServer::_add_live_order(
|
|
map<string,map<string,OrdersSummaryUnit>>& agg,
|
|
const OrderRecord& ord){
|
|
const std::string& acct=ord.def().account();
|
|
const std::string& user=ord.def().user();
|
|
auto acct_it=agg.find(acct);
|
|
if(acct_it==agg.end())
|
|
agg[acct]=std::map<std::string,OrdersSummaryUnit>();
|
|
acct_it=agg.find(acct);
|
|
bts_assert(acct_it!=agg.end());
|
|
std::map<std::string,OrdersSummaryUnit>& user_map=acct_it->second;
|
|
auto user_it=user_map.find(user);
|
|
if(user_it==user_map.end()){
|
|
OrdersSummaryUnit nu;
|
|
nu.set_account(acct);
|
|
nu.set_user(user);
|
|
user_map[user]=nu;
|
|
}
|
|
user_it=user_map.find(user);
|
|
bts_assert(user_it!=user_map.end());
|
|
OrdersSummaryUnit& u=user_it->second;
|
|
u.set_total_orders(u.total_orders()+1);
|
|
u.set_total_contracts(u.total_contracts()+ord.state().quantity());
|
|
}
|
|
void AdminServiceServer::_cancel_orders(const vector<string>& accounts,
|
|
const vector<string>& users){
|
|
map<string, bool> acct_map, user_map;
|
|
vector<uint32_t> keys;
|
|
for(const std::string& a : accounts)
|
|
acct_map[a]=true;
|
|
for(const std::string& u : users)
|
|
user_map[u]=true;
|
|
for(auto it=_order_map.begin();it!=_order_map.end();it++){
|
|
const OrderRecord& ord=*(it->second);
|
|
if(bts::orderman::order_in_working_state(ord.state().status()) &&
|
|
bts::orderman::is_parent_order(ord) &&
|
|
acct_map.find(ord.def().account()) != acct_map.end() &&
|
|
user_map.find(ord.def().user()) != user_map.end())
|
|
keys.push_back(ord.key());
|
|
}
|
|
for(uint32_t k : keys){
|
|
Cancel c;
|
|
c.set_order_key(k);
|
|
_order_service.cancel_order(c, [](const auto&){});
|
|
}
|
|
}
|
|
void AdminServiceServer::_publish_md_entitlements(){
|
|
// TODO, need to delete all state
|
|
std::vector<MDEntitlementReportUnit> entitlements;
|
|
AdminServiceUtils::get_md_entitlement_report(_state,entitlements);
|
|
for (const auto& e : entitlements)
|
|
_md_entit_publisher.add_or_update(e);
|
|
_md_entit_publisher.flush();
|
|
}
|
|
// void AdminServiceServer::_publish_md_permissions(){
|
|
// std::vector<UserSymbolMDPermissionUnit> perms;
|
|
// for (const BTSUser* user : AdminServiceUtils::users(_state,false))
|
|
// AdminServiceUtils::get_user_symbol_permissions(_state,*user,perms);
|
|
// for (const auto& p : perms)
|
|
// _md_perm_publisher.add_or_update(p);
|
|
// _md_perm_publisher.flush();
|
|
// }
|
|
void AdminServiceServer::_check_data_on_start (){
|
|
AdminServiceUtils::fill_connections_from_config(_state);
|
|
for(int i=0; i<_state.accounts().size(); i++)
|
|
if(!_state.mutable_accounts(i)->has_risk_limit_enforcement())
|
|
_state.mutable_accounts(i)->mutable_risk_limit_enforcement()->set_product_limit_in_net_terms(true);
|
|
}
|
|
}}
|