add /y/shell-exec in HTTP server
This commit is contained in:
+20
-16
@@ -291,8 +291,8 @@ phosg::JSON Account::json() const {
|
||||
});
|
||||
}
|
||||
|
||||
void Account::print(FILE* stream) const {
|
||||
fprintf(stream, "Account: %010" PRIu32 "/%08" PRIX32 "\n", this->account_id, this->account_id);
|
||||
string Account::str() const {
|
||||
std::string ret = phosg::string_printf("Account: %010" PRIu32 "/%08" PRIX32 "\n", this->account_id, this->account_id);
|
||||
|
||||
if (this->flags) {
|
||||
string flags_str = "";
|
||||
@@ -339,7 +339,7 @@ void Account::print(FILE* stream) const {
|
||||
} else if (phosg::ends_with(flags_str, ",")) {
|
||||
flags_str.pop_back();
|
||||
}
|
||||
fprintf(stream, " Flags: %08" PRIX32 " (%s)\n", this->flags, flags_str.c_str());
|
||||
ret += phosg::string_printf(" Flags: %08" PRIX32 " (%s)\n", this->flags, flags_str.c_str());
|
||||
}
|
||||
|
||||
if (this->user_flags) {
|
||||
@@ -352,53 +352,57 @@ void Account::print(FILE* stream) const {
|
||||
} else if (phosg::ends_with(user_flags_str, ",")) {
|
||||
user_flags_str.pop_back();
|
||||
}
|
||||
fprintf(stream, " User flags: %08" PRIX32 " (%s)\n", this->user_flags, user_flags_str.c_str());
|
||||
ret += phosg::string_printf(" User flags: %08" PRIX32 " (%s)\n", this->user_flags, user_flags_str.c_str());
|
||||
}
|
||||
|
||||
if (this->ban_end_time) {
|
||||
string time_str = phosg::format_time(this->ban_end_time);
|
||||
fprintf(stream, " Banned until: %" PRIu64 " (%s)\n", this->ban_end_time, time_str.c_str());
|
||||
ret += phosg::string_printf(" Banned until: %" PRIu64 " (%s)\n", this->ban_end_time, time_str.c_str());
|
||||
}
|
||||
if (this->ep3_current_meseta || this->ep3_total_meseta_earned) {
|
||||
fprintf(stream, " Episode 3 meseta: %" PRIu32 " (total earned: %" PRIu32 ")\n", this->ep3_current_meseta, this->ep3_total_meseta_earned);
|
||||
ret += phosg::string_printf(" Episode 3 meseta: %" PRIu32 " (total earned: %" PRIu32 ")\n",
|
||||
this->ep3_current_meseta, this->ep3_total_meseta_earned);
|
||||
}
|
||||
if (!this->last_player_name.empty()) {
|
||||
fprintf(stream, " Last player name: \"%s\"\n", this->last_player_name.c_str());
|
||||
ret += phosg::string_printf(" Last player name: \"%s\"\n", this->last_player_name.c_str());
|
||||
}
|
||||
if (!this->auto_reply_message.empty()) {
|
||||
fprintf(stream, " Auto reply message: \"%s\"\n", this->auto_reply_message.c_str());
|
||||
ret += phosg::string_printf(" Auto reply message: \"%s\"\n", this->auto_reply_message.c_str());
|
||||
}
|
||||
if (this->bb_team_id) {
|
||||
fprintf(stream, " BB team ID: %08" PRIX32 "\n", this->bb_team_id);
|
||||
ret += phosg::string_printf(" BB team ID: %08" PRIX32 "\n", this->bb_team_id);
|
||||
}
|
||||
if (this->is_temporary) {
|
||||
fprintf(stream, " Is temporary license: true\n");
|
||||
ret += phosg::string_printf(" Is temporary license: true\n");
|
||||
}
|
||||
|
||||
for (const auto& it : this->dc_nte_licenses) {
|
||||
fprintf(stream, " DC NTE license: serial_number=%s access_key=%s\n",
|
||||
ret += phosg::string_printf(" DC NTE license: serial_number=%s access_key=%s\n",
|
||||
it.second->serial_number.c_str(), it.second->access_key.c_str());
|
||||
}
|
||||
for (const auto& it : this->dc_licenses) {
|
||||
fprintf(stream, " DC license: serial_number=%" PRIX32 " access_key=%s\n",
|
||||
ret += phosg::string_printf(" DC license: serial_number=%" PRIX32 " access_key=%s\n",
|
||||
it.second->serial_number, it.second->access_key.c_str());
|
||||
}
|
||||
for (const auto& it : this->pc_licenses) {
|
||||
fprintf(stream, " PC license: serial_number=%" PRIX32 " access_key=%s\n",
|
||||
ret += phosg::string_printf(" PC license: serial_number=%" PRIX32 " access_key=%s\n",
|
||||
it.second->serial_number, it.second->access_key.c_str());
|
||||
}
|
||||
for (const auto& it : this->gc_licenses) {
|
||||
fprintf(stream, " GC license: serial_number=%010" PRIu32 " access_key=%s password=%s\n",
|
||||
ret += phosg::string_printf(" GC license: serial_number=%010" PRIu32 " access_key=%s password=%s\n",
|
||||
it.second->serial_number, it.second->access_key.c_str(), it.second->password.c_str());
|
||||
}
|
||||
for (const auto& it : this->xb_licenses) {
|
||||
fprintf(stream, " XB license: gamertag=%s user_id=%016" PRIX64 " account_id=%016" PRIX64 "\n",
|
||||
ret += phosg::string_printf(" XB license: gamertag=%s user_id=%016" PRIX64 " account_id=%016" PRIX64 "\n",
|
||||
it.second->gamertag.c_str(), it.second->user_id, it.second->account_id);
|
||||
}
|
||||
for (const auto& it : this->bb_licenses) {
|
||||
fprintf(stream, " BB license: username=%s password=%s\n",
|
||||
ret += phosg::string_printf(" BB license: username=%s password=%s\n",
|
||||
it.second->username.c_str(), it.second->password.c_str());
|
||||
}
|
||||
|
||||
phosg::strip_trailing_whitespace(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Account::save() const {
|
||||
|
||||
+1
-1
@@ -162,7 +162,7 @@ struct Account {
|
||||
this->user_flags ^= static_cast<uint32_t>(flag);
|
||||
}
|
||||
|
||||
void print(FILE* stream) const;
|
||||
std::string str() const;
|
||||
};
|
||||
|
||||
struct Login {
|
||||
|
||||
+32
-27
@@ -717,66 +717,71 @@ void Tournament::send_all_state_updates_on_deletion() const {
|
||||
}
|
||||
}
|
||||
|
||||
void Tournament::print_bracket(FILE* stream) const {
|
||||
function<void(shared_ptr<Match>, size_t)> print_match = [&](shared_ptr<Match> m, size_t indent_level) -> void {
|
||||
for (size_t z = 0; z < indent_level; z++) {
|
||||
fputc(' ', stream);
|
||||
fputc(' ', stream);
|
||||
string Tournament::bracket_str() const {
|
||||
string ret = phosg::string_printf("Tournament \"%s\"\n", this->name.c_str());
|
||||
|
||||
function<void(shared_ptr<Match>, size_t)> add_match = [&](shared_ptr<Match> m, size_t indent_level) -> void {
|
||||
ret.append(2 * indent_level, ' ');
|
||||
ret += m->str();
|
||||
if (this->pending_matches.count(m)) {
|
||||
ret += " (PENDING)";
|
||||
}
|
||||
string match_str = m->str();
|
||||
fprintf(stream, "%s%s\n", match_str.c_str(), this->pending_matches.count(m) ? " (PENDING)" : "");
|
||||
ret.push_back('\n');
|
||||
if (m->preceding_a) {
|
||||
print_match(m->preceding_a, indent_level + 1);
|
||||
add_match(m->preceding_a, indent_level + 1);
|
||||
}
|
||||
if (m->preceding_b) {
|
||||
print_match(m->preceding_b, indent_level + 1);
|
||||
add_match(m->preceding_b, indent_level + 1);
|
||||
}
|
||||
};
|
||||
fprintf(stream, "Tournament \"%s\"\n", this->name.c_str());
|
||||
|
||||
auto en_vm = this->map->version(1);
|
||||
if (en_vm) {
|
||||
string map_name = en_vm->map->name.decode(en_vm->language);
|
||||
fprintf(stream, " Map: %08" PRIX32 " (%s)\n", this->map->map_number, map_name.c_str());
|
||||
ret += phosg::string_printf(" Map: %08" PRIX32 " (%s)\n", this->map->map_number, map_name.c_str());
|
||||
} else {
|
||||
fprintf(stream, " Map: %08" PRIX32 "\n", this->map->map_number);
|
||||
ret += phosg::string_printf(" Map: %08" PRIX32 "\n", this->map->map_number);
|
||||
}
|
||||
string rules_str = this->rules.str();
|
||||
fprintf(stream, " Rules: %s\n", rules_str.c_str());
|
||||
fprintf(stream, " Structure: %s, %zu entries\n", (this->flags & Flag::IS_2V2) ? "2v2" : "1v1", this->num_teams);
|
||||
fprintf(stream, " COM teams: %s\n", (this->flags & Flag::HAS_COM_TEAMS) ? "allowed" : "forbidden");
|
||||
fprintf(stream, " Shuffle entries: %s\n", (this->flags & Flag::SHUFFLE_ENTRIES) ? "yes" : "no");
|
||||
fprintf(stream, " Resize on start: %s\n", (this->flags & Flag::RESIZE_ON_START) ? "yes" : "no");
|
||||
ret += phosg::string_printf(" Rules: %s\n", rules_str.c_str());
|
||||
ret += phosg::string_printf(" Structure: %s, %zu entries\n", (this->flags & Flag::IS_2V2) ? "2v2" : "1v1", this->num_teams);
|
||||
ret += phosg::string_printf(" COM teams: %s\n", (this->flags & Flag::HAS_COM_TEAMS) ? "allowed" : "forbidden");
|
||||
ret += phosg::string_printf(" Shuffle entries: %s\n", (this->flags & Flag::SHUFFLE_ENTRIES) ? "yes" : "no");
|
||||
ret += phosg::string_printf(" Resize on start: %s\n", (this->flags & Flag::RESIZE_ON_START) ? "yes" : "no");
|
||||
switch (this->current_state) {
|
||||
case State::REGISTRATION:
|
||||
fprintf(stream, " State: REGISTRATION\n");
|
||||
ret += " State: REGISTRATION\n";
|
||||
break;
|
||||
case State::IN_PROGRESS:
|
||||
fprintf(stream, " State: IN_PROGRESS\n");
|
||||
ret += " State: IN_PROGRESS\n";
|
||||
break;
|
||||
case State::COMPLETE:
|
||||
fprintf(stream, " State: COMPLETE\n");
|
||||
ret += " State: COMPLETE\n";
|
||||
break;
|
||||
default:
|
||||
fprintf(stream, " State: UNKNOWN\n");
|
||||
ret += " State: UNKNOWN\n";
|
||||
break;
|
||||
}
|
||||
if (this->final_match) {
|
||||
fprintf(stream, " Standings:\n");
|
||||
print_match(this->final_match, 2);
|
||||
ret += " Standings:\n";
|
||||
add_match(this->final_match, 2);
|
||||
}
|
||||
if (this->current_state == State::REGISTRATION) {
|
||||
fprintf(stream, " Teams:\n");
|
||||
ret += " Teams:\n";
|
||||
for (const auto& team : this->teams) {
|
||||
string team_str = team->str();
|
||||
fprintf(stream, " %s\n", team_str.c_str());
|
||||
ret += phosg::string_printf(" %s\n", team_str.c_str());
|
||||
}
|
||||
} else {
|
||||
fprintf(stream, " Pending matches:\n");
|
||||
ret += " Pending matches:\n";
|
||||
for (const auto& match : this->pending_matches) {
|
||||
string match_str = match->str();
|
||||
fprintf(stream, " %s\n", match_str.c_str());
|
||||
ret += phosg::string_printf(" %s\n", match_str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
phosg::strip_trailing_whitespace(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
TournamentIndex::TournamentIndex(
|
||||
|
||||
@@ -160,7 +160,7 @@ public:
|
||||
void send_all_state_updates() const;
|
||||
void send_all_state_updates_on_deletion() const;
|
||||
|
||||
void print_bracket(FILE* stream) const;
|
||||
std::string bracket_str() const;
|
||||
|
||||
private:
|
||||
void create_bracket_matches();
|
||||
|
||||
+30
-11
@@ -1,5 +1,6 @@
|
||||
#include "EventUtils.hh"
|
||||
|
||||
#include <event2/buffer.h>
|
||||
#include <event2/event.h>
|
||||
|
||||
#include <deque>
|
||||
@@ -7,37 +8,55 @@
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static void dispatch_forward_to_event_thread(evutil_socket_t, short, void* ctx) {
|
||||
auto* fn = reinterpret_cast<std::function<void()>*>(ctx);
|
||||
auto* fn = reinterpret_cast<function<void()>*>(ctx);
|
||||
(*fn)();
|
||||
delete fn;
|
||||
}
|
||||
|
||||
void forward_to_event_thread(std::shared_ptr<struct event_base> base, std::function<void()>&& fn) {
|
||||
void forward_to_event_thread(shared_ptr<struct event_base> base, function<void()>&& fn) {
|
||||
struct timeval tv = {0, 0};
|
||||
std::function<void()>* new_fn = new std::function<void()>(std::move(fn));
|
||||
function<void()>* new_fn = new function<void()>(std::move(fn));
|
||||
event_base_once(base.get(), -1, EV_TIMEOUT, dispatch_forward_to_event_thread, new_fn, &tv);
|
||||
}
|
||||
|
||||
template <>
|
||||
void call_on_event_thread<void>(std::shared_ptr<struct event_base> base, std::function<void()>&& compute) {
|
||||
void call_on_event_thread<void>(shared_ptr<struct event_base> base, function<void()>&& compute) {
|
||||
bool succeeded = false;
|
||||
std::string exc_what;
|
||||
std::mutex ret_lock;
|
||||
std::condition_variable ret_cv;
|
||||
std::unique_lock<std::mutex> g(ret_lock);
|
||||
string exc_what;
|
||||
mutex ret_lock;
|
||||
condition_variable ret_cv;
|
||||
unique_lock<mutex> g(ret_lock);
|
||||
forward_to_event_thread(base, [&]() -> void {
|
||||
std::lock_guard<std::mutex> g(ret_lock);
|
||||
lock_guard<mutex> g(ret_lock);
|
||||
try {
|
||||
compute();
|
||||
succeeded = true;
|
||||
} catch (const std::exception& e) {
|
||||
} catch (const exception& e) {
|
||||
exc_what = e.what();
|
||||
}
|
||||
ret_cv.notify_one();
|
||||
});
|
||||
ret_cv.wait(g);
|
||||
if (!succeeded) {
|
||||
throw std::runtime_error(exc_what);
|
||||
throw runtime_error(exc_what);
|
||||
}
|
||||
}
|
||||
|
||||
string evbuffer_remove_str(struct evbuffer* buf, ssize_t size) {
|
||||
if (!buf) {
|
||||
return "";
|
||||
}
|
||||
if (size < 0) {
|
||||
size = static_cast<size_t>(evbuffer_get_length(buf));
|
||||
}
|
||||
string ret(size, '\0');
|
||||
ssize_t bytes_removed = evbuffer_remove(buf, ret.data(), ret.size());
|
||||
if (bytes_removed < 0) {
|
||||
throw std::runtime_error("can\'t remove data from buffer");
|
||||
}
|
||||
ret.resize(bytes_removed);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
// Calls a function on the given base's event thread. This function returns
|
||||
// when the call has been enqueued, not necessarily after it returns.
|
||||
@@ -40,3 +41,5 @@ T call_on_event_thread(std::shared_ptr<struct event_base> base, std::function<T(
|
||||
|
||||
template <>
|
||||
void call_on_event_thread<void>(std::shared_ptr<struct event_base> base, std::function<void()>&& compute);
|
||||
|
||||
std::string evbuffer_remove_str(struct evbuffer* buf, ssize_t size = -1);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "Loggers.hh"
|
||||
#include "ProxyServer.hh"
|
||||
#include "Server.hh"
|
||||
#include "ShellCommands.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -1154,6 +1155,25 @@ phosg::JSON HTTPServer::generate_rare_table_json(const std::string& table_name)
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPServer::require_GET(struct evhttp_request* req) {
|
||||
if (evhttp_request_get_command(req) != EVHTTP_REQ_GET) {
|
||||
throw HTTPServer::http_error(405, "GET method required for this endpoint");
|
||||
}
|
||||
}
|
||||
|
||||
phosg::JSON HTTPServer::require_POST(struct evhttp_request* req) {
|
||||
if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) {
|
||||
throw HTTPServer::http_error(405, "POST method required for this endpoint");
|
||||
}
|
||||
const evkeyvalq* headers = evhttp_request_get_input_headers(req);
|
||||
const char* content_type = evhttp_find_header(headers, "Content-Type");
|
||||
if (!content_type || strcmp(content_type, "application/json")) {
|
||||
throw HTTPServer::http_error(400, "POST requests must use the application/json content type");
|
||||
}
|
||||
struct evbuffer* in_buf = evhttp_request_get_input_buffer(req);
|
||||
return phosg::JSON::parse(evbuffer_remove_str(in_buf));
|
||||
}
|
||||
|
||||
void HTTPServer::handle_request(struct evhttp_request* req) {
|
||||
shared_ptr<const phosg::JSON> ret;
|
||||
uint32_t serialize_options = 0;
|
||||
@@ -1177,6 +1197,7 @@ void HTTPServer::handle_request(struct evhttp_request* req) {
|
||||
}
|
||||
|
||||
if (uri == "/") {
|
||||
this->require_GET(req);
|
||||
auto endpoints_json = phosg::JSON::list({
|
||||
"/y/data/ep3-cards",
|
||||
"/y/data/ep3-cards-trial",
|
||||
@@ -1191,10 +1212,22 @@ void HTTPServer::handle_request(struct evhttp_request* req) {
|
||||
"/y/rare-drops/stream",
|
||||
"/y/summary",
|
||||
"/y/all",
|
||||
"/y/shell-exec",
|
||||
});
|
||||
ret = make_shared<phosg::JSON>(phosg::JSON::dict({{"endpoints", std::move(endpoints_json)}}));
|
||||
|
||||
} else if (uri == "/y/shell-exec") {
|
||||
auto json = this->require_POST(req);
|
||||
auto command = json.get_string("command");
|
||||
try {
|
||||
ret = make_shared<phosg::JSON>(phosg::JSON::dict(
|
||||
{{"result", phosg::join(ShellCommand::dispatch_str(this->state, command), "\n")}}));
|
||||
} catch (const exception& e) {
|
||||
throw http_error(400, e.what());
|
||||
}
|
||||
|
||||
} else if (uri == "/y/rare-drops/stream") {
|
||||
this->require_GET(req);
|
||||
auto c = this->enable_websockets(req);
|
||||
if (!c) {
|
||||
throw http_error(400, "this path requires a websocket connection");
|
||||
@@ -1206,28 +1239,40 @@ void HTTPServer::handle_request(struct evhttp_request* req) {
|
||||
}
|
||||
|
||||
} else if (uri == "/y/data/ep3-cards") {
|
||||
this->require_GET(req);
|
||||
ret = make_shared<phosg::JSON>(this->generate_ep3_cards_json(false));
|
||||
} else if (uri == "/y/data/ep3-cards-trial") {
|
||||
this->require_GET(req);
|
||||
ret = make_shared<phosg::JSON>(this->generate_ep3_cards_json(true));
|
||||
} else if (uri == "/y/data/common-tables") {
|
||||
this->require_GET(req);
|
||||
ret = make_shared<phosg::JSON>(this->generate_common_tables_json());
|
||||
} else if (uri == "/y/data/rare-tables") {
|
||||
this->require_GET(req);
|
||||
ret = make_shared<phosg::JSON>(this->generate_rare_tables_json());
|
||||
} else if (!strncmp(uri.c_str(), "/y/data/rare-tables/", 20)) {
|
||||
this->require_GET(req);
|
||||
ret = make_shared<phosg::JSON>(this->generate_rare_table_json(uri.substr(20)));
|
||||
} else if (uri == "/y/data/config") {
|
||||
this->require_GET(req);
|
||||
ret = call_on_event_thread<shared_ptr<const phosg::JSON>>(this->state->base, [this]() { return this->state->config_json; });
|
||||
} else if (uri == "/y/clients") {
|
||||
this->require_GET(req);
|
||||
ret = make_shared<phosg::JSON>(this->generate_game_server_clients_json());
|
||||
} else if (uri == "/y/proxy-clients") {
|
||||
this->require_GET(req);
|
||||
ret = make_shared<phosg::JSON>(this->generate_proxy_server_clients_json());
|
||||
} else if (uri == "/y/lobbies") {
|
||||
this->require_GET(req);
|
||||
ret = make_shared<phosg::JSON>(this->generate_lobbies_json());
|
||||
} else if (uri == "/y/server") {
|
||||
this->require_GET(req);
|
||||
ret = make_shared<phosg::JSON>(this->generate_server_info_json());
|
||||
} else if (uri == "/y/summary") {
|
||||
this->require_GET(req);
|
||||
ret = make_shared<phosg::JSON>(this->generate_summary_json());
|
||||
} else if (uri == "/y/all") {
|
||||
this->require_GET(req);
|
||||
ret = make_shared<phosg::JSON>(this->generate_all_json());
|
||||
|
||||
} else {
|
||||
@@ -1248,6 +1293,10 @@ void HTTPServer::handle_request(struct evhttp_request* req) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
throw logic_error("ret was not set after HTTP handler completed");
|
||||
}
|
||||
|
||||
uint64_t handler_end = phosg::now();
|
||||
unique_ptr<struct evbuffer, void (*)(struct evbuffer*)> out_buffer(evbuffer_new(), evbuffer_free);
|
||||
string* serialized = new string(ret->serialize(phosg::JSON::SerializeOption::ESCAPE_CONTROLS_ONLY | serialize_options));
|
||||
|
||||
@@ -66,6 +66,9 @@ protected:
|
||||
|
||||
std::unordered_map<struct bufferevent*, std::shared_ptr<WebsocketClient>> bev_to_websocket_client;
|
||||
|
||||
static void require_GET(struct evhttp_request* req);
|
||||
static phosg::JSON require_POST(struct evhttp_request* req);
|
||||
|
||||
std::shared_ptr<WebsocketClient> enable_websockets(struct evhttp_request* req);
|
||||
|
||||
static void dispatch_on_websocket_read(struct bufferevent* bev, void* ctx);
|
||||
|
||||
@@ -1763,7 +1763,6 @@ static void on_CA_Ep3(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
}
|
||||
|
||||
auto tourn = l->tournament_match->tournament.lock();
|
||||
tourn->print_bracket(stderr);
|
||||
|
||||
shared_ptr<Episode3::Tournament::Team> winner_team;
|
||||
shared_ptr<Episode3::Tournament::Team> loser_team;
|
||||
@@ -1785,7 +1784,7 @@ static void on_CA_Ep3(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
meseta_reward = (l->tournament_match->round_num - 1 < round_rewards.size())
|
||||
? round_rewards[l->tournament_match->round_num - 1]
|
||||
: round_rewards.back();
|
||||
if (l->tournament_match == tourn->get_final_match()) {
|
||||
if (tourn && (l->tournament_match == tourn->get_final_match())) {
|
||||
meseta_reward += s->ep3_final_round_meseta_bonus;
|
||||
}
|
||||
for (const auto& player : winner_team->players) {
|
||||
@@ -1803,7 +1802,9 @@ static void on_CA_Ep3(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
}
|
||||
send_ep3_tournament_match_result(l, meseta_reward);
|
||||
|
||||
on_tournament_bracket_updated(s, tourn);
|
||||
if (tourn) {
|
||||
on_tournament_bracket_updated(s, tourn);
|
||||
}
|
||||
l->ep3_server->tournament_match_result_sent = true;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1168
File diff suppressed because it is too large
Load Diff
@@ -10,12 +10,6 @@
|
||||
|
||||
class ServerShell : public std::enable_shared_from_this<ServerShell> {
|
||||
public:
|
||||
class exit_shell : public std::runtime_error {
|
||||
public:
|
||||
exit_shell();
|
||||
~exit_shell() = default;
|
||||
};
|
||||
|
||||
explicit ServerShell(std::shared_ptr<ServerState> state);
|
||||
ServerShell(const ServerShell&) = delete;
|
||||
ServerShell(ServerShell&&) = delete;
|
||||
@@ -25,8 +19,6 @@ public:
|
||||
|
||||
std::shared_ptr<ProxyServer::LinkedSession> get_proxy_session(const std::string& name);
|
||||
|
||||
void execute_command(const std::string& command);
|
||||
|
||||
protected:
|
||||
std::shared_ptr<ServerState> state;
|
||||
std::thread th;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "ProxyServer.hh"
|
||||
#include "ServerState.hh"
|
||||
|
||||
class exit_shell : public std::runtime_error {
|
||||
public:
|
||||
exit_shell();
|
||||
~exit_shell() = default;
|
||||
};
|
||||
|
||||
struct ShellCommand {
|
||||
struct Args {
|
||||
std::shared_ptr<ServerState> s;
|
||||
std::string command;
|
||||
std::string args;
|
||||
std::string session_name;
|
||||
};
|
||||
|
||||
const char* name;
|
||||
const char* help_text;
|
||||
bool run_on_event_thread;
|
||||
std::deque<std::string> (*run)(Args&);
|
||||
|
||||
static std::vector<const ShellCommand*> commands_by_order;
|
||||
static std::unordered_map<std::string, const ShellCommand*> commands_by_name;
|
||||
|
||||
ShellCommand(const char* name, const char* help_text, bool run_on_event_thread, std::deque<std::string> (*run)(Args&));
|
||||
|
||||
static std::deque<std::string> dispatch_str(std::shared_ptr<ServerState> s, const std::string& command);
|
||||
static std::deque<std::string> dispatch(Args& args);
|
||||
};
|
||||
Reference in New Issue
Block a user