Files
spark/src/server/sparkd/user/AdminServiceServer.cpp
T

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);
}
}}