mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
Add standalone web api server, cli handler, authorization, commands
This commit is contained in:
parent
7d71163fa0
commit
78d8b909be
@ -122,6 +122,7 @@ SET(common_headers
|
||||
crash.h
|
||||
crc16.h
|
||||
crc32.h
|
||||
cli/argh.h
|
||||
data_verification.h
|
||||
database.h
|
||||
dbcore.h
|
||||
@ -156,6 +157,7 @@ SET(common_headers
|
||||
global_define.h
|
||||
guild_base.h
|
||||
guilds.h
|
||||
http/httplib.h
|
||||
inventory_profile.h
|
||||
inventory_slot.h
|
||||
ipc_mutex.h
|
||||
|
||||
434
common/cli/argh.h
Normal file
434
common/cli/argh.h
Normal file
@ -0,0 +1,434 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
|
||||
namespace argh
|
||||
{
|
||||
// Terminology:
|
||||
// A command line is composed of 2 types of args:
|
||||
// 1. Positional args, i.e. free standing values
|
||||
// 2. Options: args beginning with '-'. We identify two kinds:
|
||||
// 2.1: Flags: boolean options => (exist ? true : false)
|
||||
// 2.2: Parameters: a name followed by a non-option value
|
||||
|
||||
#if !defined(__GNUC__) || (__GNUC__ >= 5)
|
||||
using string_stream = std::istringstream;
|
||||
#else
|
||||
// Until GCC 5, istringstream did not have a move constructor.
|
||||
// stringstream_proxy is used instead, as a workaround.
|
||||
class stringstream_proxy
|
||||
{
|
||||
public:
|
||||
stringstream_proxy() = default;
|
||||
|
||||
// Construct with a value.
|
||||
stringstream_proxy(std::string const& value) :
|
||||
stream_(value)
|
||||
{}
|
||||
|
||||
// Copy constructor.
|
||||
stringstream_proxy(const stringstream_proxy& other) :
|
||||
stream_(other.stream_.str())
|
||||
{
|
||||
stream_.setstate(other.stream_.rdstate());
|
||||
}
|
||||
|
||||
void setstate(std::ios_base::iostate state) { stream_.setstate(state); }
|
||||
|
||||
// Stream out the value of the parameter.
|
||||
// If the conversion was not possible, the stream will enter the fail state,
|
||||
// and operator bool will return false.
|
||||
template<typename T>
|
||||
stringstream_proxy& operator >> (T& thing)
|
||||
{
|
||||
stream_ >> thing;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Get the string value.
|
||||
std::string str() const { return stream_.str(); }
|
||||
|
||||
std::stringbuf* rdbuf() const { return stream_.rdbuf(); }
|
||||
|
||||
// Check the state of the stream.
|
||||
// False when the most recent stream operation failed
|
||||
operator bool() const { return !!stream_; }
|
||||
|
||||
~stringstream_proxy() = default;
|
||||
private:
|
||||
std::istringstream stream_;
|
||||
};
|
||||
using string_stream = stringstream_proxy;
|
||||
#endif
|
||||
|
||||
class parser
|
||||
{
|
||||
public:
|
||||
enum Mode { PREFER_FLAG_FOR_UNREG_OPTION = 1 << 0,
|
||||
PREFER_PARAM_FOR_UNREG_OPTION = 1 << 1,
|
||||
NO_SPLIT_ON_EQUALSIGN = 1 << 2,
|
||||
SINGLE_DASH_IS_MULTIFLAG = 1 << 3,
|
||||
};
|
||||
|
||||
parser() = default;
|
||||
|
||||
parser(std::initializer_list<char const* const> pre_reg_names)
|
||||
{ add_params(pre_reg_names); }
|
||||
|
||||
parser(const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION)
|
||||
{ parse(argv, mode); }
|
||||
|
||||
parser(int argc, const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION)
|
||||
{ parse(argc, argv, mode); }
|
||||
|
||||
void add_param(std::string const& name);
|
||||
void add_params(std::initializer_list<char const* const> init_list);
|
||||
|
||||
void parse(const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION);
|
||||
void parse(int argc, const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION);
|
||||
|
||||
std::multiset<std::string> const& flags() const { return flags_; }
|
||||
std::map<std::string, std::string> const& params() const { return params_; }
|
||||
std::vector<std::string> const& pos_args() const { return pos_args_; }
|
||||
|
||||
// begin() and end() for using range-for over positional args.
|
||||
std::vector<std::string>::const_iterator begin() const { return pos_args_.cbegin(); }
|
||||
std::vector<std::string>::const_iterator end() const { return pos_args_.cend(); }
|
||||
size_t size() const { return pos_args_.size(); }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Accessors
|
||||
|
||||
// flag (boolean) accessors: return true if the flag appeared, otherwise false.
|
||||
bool operator[](std::string const& name) const;
|
||||
|
||||
// multiple flag (boolean) accessors: return true if at least one of the flag appeared, otherwise false.
|
||||
bool operator[](std::initializer_list<char const* const> init_list) const;
|
||||
|
||||
// returns positional arg string by order. Like argv[] but without the options
|
||||
std::string const& operator[](size_t ind) const;
|
||||
|
||||
// returns a std::istream that can be used to convert a positional arg to a typed value.
|
||||
string_stream operator()(size_t ind) const;
|
||||
|
||||
// same as above, but with a default value in case the arg is missing (index out of range).
|
||||
template<typename T>
|
||||
string_stream operator()(size_t ind, T&& def_val) const;
|
||||
|
||||
// parameter accessors, give a name get an std::istream that can be used to convert to a typed value.
|
||||
// call .str() on result to get as string
|
||||
string_stream operator()(std::string const& name) const;
|
||||
|
||||
// accessor for a parameter with multiple names, give a list of names, get an std::istream that can be used to convert to a typed value.
|
||||
// call .str() on result to get as string
|
||||
// returns the first value in the list to be found.
|
||||
string_stream operator()(std::initializer_list<char const* const> init_list) const;
|
||||
|
||||
// same as above, but with a default value in case the param was missing.
|
||||
// Non-string def_val types must have an operator<<() (output stream operator)
|
||||
// If T only has an input stream operator, pass the string version of the type as in "3" instead of 3.
|
||||
template<typename T>
|
||||
string_stream operator()(std::string const& name, T&& def_val) const;
|
||||
|
||||
// same as above but for a list of names. returns the first value to be found.
|
||||
template<typename T>
|
||||
string_stream operator()(std::initializer_list<char const* const> init_list, T&& def_val) const;
|
||||
|
||||
private:
|
||||
string_stream bad_stream() const;
|
||||
std::string trim_leading_dashes(std::string const& name) const;
|
||||
bool is_number(std::string const& arg) const;
|
||||
bool is_option(std::string const& arg) const;
|
||||
bool got_flag(std::string const& name) const;
|
||||
bool is_param(std::string const& name) const;
|
||||
|
||||
private:
|
||||
std::vector<std::string> args_;
|
||||
std::map<std::string, std::string> params_;
|
||||
std::vector<std::string> pos_args_;
|
||||
std::multiset<std::string> flags_;
|
||||
std::set<std::string> registeredParams_;
|
||||
std::string empty_;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::parse(const char * const argv[], int mode)
|
||||
{
|
||||
int argc = 0;
|
||||
for (auto argvp = argv; *argvp; ++argc, ++argvp);
|
||||
parse(argc, argv, mode);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::parse(int argc, const char* const argv[], int mode /*= PREFER_FLAG_FOR_UNREG_OPTION*/)
|
||||
{
|
||||
// convert to strings
|
||||
args_.resize(argc);
|
||||
std::transform(argv, argv + argc, args_.begin(), [](const char* const arg) { return arg; });
|
||||
|
||||
// parse line
|
||||
for (auto i = 0u; i < args_.size(); ++i)
|
||||
{
|
||||
if (!is_option(args_[i]))
|
||||
{
|
||||
pos_args_.emplace_back(args_[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto name = trim_leading_dashes(args_[i]);
|
||||
|
||||
if (!(mode & NO_SPLIT_ON_EQUALSIGN))
|
||||
{
|
||||
auto equalPos = name.find('=');
|
||||
if (equalPos != std::string::npos)
|
||||
{
|
||||
params_.insert({ name.substr(0, equalPos), name.substr(equalPos + 1) });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// if the option is unregistered and should be a multi-flag
|
||||
if (1 == (args_[i].size() - name.size()) && // single dash
|
||||
argh::parser::SINGLE_DASH_IS_MULTIFLAG & mode && // multi-flag mode
|
||||
!is_param(name)) // unregistered
|
||||
{
|
||||
std::string keep_param;
|
||||
|
||||
if (!name.empty() && is_param(std::string(1ul, name.back()))) // last char is param
|
||||
{
|
||||
keep_param += name.back();
|
||||
name.resize(name.size() - 1);
|
||||
}
|
||||
|
||||
for (auto const& c : name)
|
||||
{
|
||||
flags_.emplace(std::string{ c });
|
||||
}
|
||||
|
||||
if (!keep_param.empty())
|
||||
{
|
||||
name = keep_param;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue; // do not consider other options for this arg
|
||||
}
|
||||
}
|
||||
|
||||
// any potential option will get as its value the next arg, unless that arg is an option too
|
||||
// in that case it will be determined a flag.
|
||||
if (i == args_.size() - 1 || is_option(args_[i + 1]))
|
||||
{
|
||||
flags_.emplace(name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// if 'name' is a pre-registered option, then the next arg cannot be a free parameter to it is skipped
|
||||
// otherwise we have 2 modes:
|
||||
// PREFER_FLAG_FOR_UNREG_OPTION: a non-registered 'name' is determined a flag.
|
||||
// The following value (the next arg) will be a free parameter.
|
||||
//
|
||||
// PREFER_PARAM_FOR_UNREG_OPTION: a non-registered 'name' is determined a parameter, the next arg
|
||||
// will be the value of that option.
|
||||
|
||||
assert(!(mode & argh::parser::PREFER_FLAG_FOR_UNREG_OPTION)
|
||||
|| !(mode & argh::parser::PREFER_PARAM_FOR_UNREG_OPTION));
|
||||
|
||||
bool preferParam = mode & argh::parser::PREFER_PARAM_FOR_UNREG_OPTION;
|
||||
|
||||
if (is_param(name) || preferParam)
|
||||
{
|
||||
params_.insert({ name, args_[i + 1] });
|
||||
++i; // skip next value, it is not a free parameter
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags_.emplace(name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline string_stream parser::bad_stream() const
|
||||
{
|
||||
string_stream bad;
|
||||
bad.setstate(std::ios_base::failbit);
|
||||
return bad;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool parser::is_number(std::string const& arg) const
|
||||
{
|
||||
// inefficient but simple way to determine if a string is a number (which can start with a '-')
|
||||
std::istringstream istr(arg);
|
||||
double number;
|
||||
istr >> number;
|
||||
return !(istr.fail() || istr.bad());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool parser::is_option(std::string const& arg) const
|
||||
{
|
||||
assert(0 != arg.size());
|
||||
if (is_number(arg))
|
||||
return false;
|
||||
return '-' == arg[0];
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline std::string parser::trim_leading_dashes(std::string const& name) const
|
||||
{
|
||||
auto pos = name.find_first_not_of('-');
|
||||
return std::string::npos != pos ? name.substr(pos) : name;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool argh::parser::got_flag(std::string const& name) const
|
||||
{
|
||||
return flags_.end() != flags_.find(trim_leading_dashes(name));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool argh::parser::is_param(std::string const& name) const
|
||||
{
|
||||
return registeredParams_.count(name);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool parser::operator[](std::string const& name) const
|
||||
{
|
||||
return got_flag(name);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool parser::operator[](std::initializer_list<char const* const> init_list) const
|
||||
{
|
||||
return std::any_of(init_list.begin(), init_list.end(), [&](char const* const name) { return got_flag(name); });
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline std::string const& parser::operator[](size_t ind) const
|
||||
{
|
||||
if (ind < pos_args_.size())
|
||||
return pos_args_[ind];
|
||||
return empty_;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline string_stream parser::operator()(std::string const& name) const
|
||||
{
|
||||
auto optIt = params_.find(trim_leading_dashes(name));
|
||||
if (params_.end() != optIt)
|
||||
return string_stream(optIt->second);
|
||||
return bad_stream();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline string_stream parser::operator()(std::initializer_list<char const* const> init_list) const
|
||||
{
|
||||
for (auto& name : init_list)
|
||||
{
|
||||
auto optIt = params_.find(trim_leading_dashes(name));
|
||||
if (params_.end() != optIt)
|
||||
return string_stream(optIt->second);
|
||||
}
|
||||
return bad_stream();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename T>
|
||||
string_stream parser::operator()(std::string const& name, T&& def_val) const
|
||||
{
|
||||
auto optIt = params_.find(trim_leading_dashes(name));
|
||||
if (params_.end() != optIt)
|
||||
return string_stream(optIt->second);
|
||||
|
||||
std::ostringstream ostr;
|
||||
ostr.precision(std::numeric_limits<long double>::max_digits10);
|
||||
ostr << def_val;
|
||||
return string_stream(ostr.str()); // use default
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// same as above but for a list of names. returns the first value to be found.
|
||||
template<typename T>
|
||||
string_stream parser::operator()(std::initializer_list<char const* const> init_list, T&& def_val) const
|
||||
{
|
||||
for (auto& name : init_list)
|
||||
{
|
||||
auto optIt = params_.find(trim_leading_dashes(name));
|
||||
if (params_.end() != optIt)
|
||||
return string_stream(optIt->second);
|
||||
}
|
||||
std::ostringstream ostr;
|
||||
ostr.precision(std::numeric_limits<long double>::max_digits10);
|
||||
ostr << def_val;
|
||||
return string_stream(ostr.str()); // use default
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline string_stream parser::operator()(size_t ind) const
|
||||
{
|
||||
if (pos_args_.size() <= ind)
|
||||
return bad_stream();
|
||||
|
||||
return string_stream(pos_args_[ind]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename T>
|
||||
string_stream parser::operator()(size_t ind, T&& def_val) const
|
||||
{
|
||||
if (pos_args_.size() <= ind)
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
ostr.precision(std::numeric_limits<long double>::max_digits10);
|
||||
ostr << def_val;
|
||||
return string_stream(ostr.str());
|
||||
}
|
||||
|
||||
return string_stream(pos_args_[ind]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::add_param(std::string const& name)
|
||||
{
|
||||
registeredParams_.insert(trim_leading_dashes(name));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::add_params(std::initializer_list<char const* const> init_list)
|
||||
{
|
||||
for (auto& name : init_list)
|
||||
registeredParams_.insert(trim_leading_dashes(name));
|
||||
}
|
||||
}
|
||||
@ -193,7 +193,6 @@ namespace Logs {
|
||||
OutF(LogSys, Logs::General, Logs::Error, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
|
||||
#define LogWarning(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::Warning].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::Warning, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
|
||||
2694
common/http/httplib.h
Normal file
2694
common/http/httplib.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -12,16 +12,18 @@ EQ::JsonConfigFile::JsonConfigFile(const Json::Value &value)
|
||||
EQ::JsonConfigFile::~JsonConfigFile() = default;
|
||||
|
||||
/**
|
||||
* @param filename
|
||||
* @param file_name
|
||||
* @return
|
||||
*/
|
||||
EQ::JsonConfigFile EQ::JsonConfigFile::Load(const std::string &filename)
|
||||
EQ::JsonConfigFile EQ::JsonConfigFile::Load(
|
||||
const std::string &file_name
|
||||
)
|
||||
{
|
||||
JsonConfigFile ret;
|
||||
ret.m_root = Json::Value();
|
||||
|
||||
std::ifstream ifs;
|
||||
ifs.open(filename, std::ifstream::in);
|
||||
ifs.open(file_name, std::ifstream::in);
|
||||
|
||||
if (!ifs.good()) {
|
||||
return ret;
|
||||
@ -37,6 +39,31 @@ EQ::JsonConfigFile EQ::JsonConfigFile::Load(const std::string &filename)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param file_name
|
||||
* @return
|
||||
*/
|
||||
void EQ::JsonConfigFile::Save(
|
||||
const std::string &file_name
|
||||
)
|
||||
{
|
||||
std::ofstream opened_config_file;
|
||||
opened_config_file.open(file_name);
|
||||
|
||||
/**
|
||||
* Grab and build config contents
|
||||
*/
|
||||
Json::StreamWriterBuilder write_builder;
|
||||
write_builder["indentation"] = " ";
|
||||
std::string document = Json::writeString(write_builder, m_root);
|
||||
|
||||
/**
|
||||
* Write current contents and close
|
||||
*/
|
||||
opened_config_file << document;
|
||||
opened_config_file.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param title
|
||||
* @param parameter
|
||||
|
||||
@ -11,7 +11,8 @@ namespace EQ
|
||||
JsonConfigFile(const Json::Value &value);
|
||||
~JsonConfigFile();
|
||||
|
||||
static JsonConfigFile Load(const std::string &filename);
|
||||
static JsonConfigFile Load(const std::string &file_name);
|
||||
void Save(const std::string &file_name);
|
||||
|
||||
std::string GetVariableString(const std::string &title, const std::string ¶meter, const std::string &default_value);
|
||||
int GetVariableInt(const std::string &title, const std::string ¶meter, const int default_value);
|
||||
|
||||
@ -5,6 +5,8 @@ SET(eqlogin_sources
|
||||
client_manager.cpp
|
||||
database.cpp
|
||||
encryption.cpp
|
||||
loginserver_command_handler.cpp
|
||||
loginserver_webserver.cpp
|
||||
main.cpp
|
||||
server_manager.cpp
|
||||
world_server.cpp
|
||||
@ -15,6 +17,8 @@ SET(eqlogin_headers
|
||||
client_manager.h
|
||||
database.h
|
||||
encryption.h
|
||||
loginserver_command_handler.h
|
||||
loginserver_webserver.h
|
||||
login_server.h
|
||||
login_structures.h
|
||||
options.h
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include "login_server.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/util/uuid.h"
|
||||
|
||||
extern LoginServer server;
|
||||
|
||||
@ -463,7 +464,11 @@ void Database::UpdateWorldRegistration(unsigned int id, std::string long_name, s
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
bool Database::CreateWorldRegistration(std::string long_name, std::string short_name, unsigned int &id)
|
||||
bool Database::CreateWorldRegistration(
|
||||
std::string long_name,
|
||||
std::string short_name,
|
||||
unsigned int &id
|
||||
)
|
||||
{
|
||||
auto query = fmt::format(
|
||||
"SELECT ifnull(max(ServerID),0) + 1 FROM {0}",
|
||||
@ -504,6 +509,44 @@ bool Database::CreateWorldRegistration(std::string long_name, std::string short_
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param long_name
|
||||
* @param short_name
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
std::string Database::CreateLoginserverApiToken(
|
||||
bool write_mode,
|
||||
bool read_mode
|
||||
)
|
||||
{
|
||||
std::string token = EQ::Util::UUID::Generate().ToString();
|
||||
auto query = fmt::format(
|
||||
"INSERT INTO loginserver_api_tokens (token, can_write, can_read, created_at) VALUES ('{0}', {1}, {2}, NOW())",
|
||||
token,
|
||||
(write_mode ? "1" : "0"),
|
||||
(read_mode ? "1" : "0")
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param long_name
|
||||
* @param short_name
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
MySQLRequestResult Database::GetLoginserverApiTokens()
|
||||
{
|
||||
return QueryDatabase("SELECT token, can_write, can_read FROM loginserver_api_tokens");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log_settings
|
||||
*/
|
||||
|
||||
@ -128,6 +128,15 @@ public:
|
||||
void UpdateWorldRegistration(unsigned int id, std::string long_name, std::string ip_address);
|
||||
bool CreateWorldRegistration(std::string long_name, std::string short_name, unsigned int &id);
|
||||
void LoadLogSettings(EQEmuLogSys::LogSettings *log_settings);
|
||||
|
||||
/**
|
||||
* @param write_mode
|
||||
* @param read_mode
|
||||
* @return
|
||||
*/
|
||||
std::string CreateLoginserverApiToken(bool write_mode, bool read_mode);
|
||||
MySQLRequestResult GetLoginserverApiTokens();
|
||||
|
||||
protected:
|
||||
std::string user, pass, host, port, name;
|
||||
MYSQL *database;
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
#include <utility>
|
||||
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
@ -28,6 +30,7 @@
|
||||
#include "options.h"
|
||||
#include "server_manager.h"
|
||||
#include "client_manager.h"
|
||||
#include "loginserver_webserver.h"
|
||||
|
||||
/**
|
||||
* Login server struct, contains every variable for the server that needs to exist outside the scope of main()
|
||||
@ -35,10 +38,13 @@
|
||||
struct LoginServer
|
||||
{
|
||||
public:
|
||||
LoginServer() : db(nullptr), server_manager(nullptr) { }
|
||||
LoginServer() : db(nullptr), server_manager(nullptr) {
|
||||
|
||||
}
|
||||
|
||||
EQ::JsonConfigFile config;
|
||||
Database *db;
|
||||
LoginserverWebserver::TokenManager *token_manager{};
|
||||
Options options;
|
||||
ServerManager *server_manager;
|
||||
ClientManager *client_manager{};
|
||||
|
||||
142
loginserver/loginserver_command_handler.cpp
Normal file
142
loginserver/loginserver_command_handler.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include "loginserver_command_handler.h"
|
||||
#include "../common/util/uuid.h"
|
||||
#include "login_server.h"
|
||||
#include "loginserver_webserver.h"
|
||||
|
||||
extern LoginServer server;
|
||||
|
||||
namespace LoginserverCommandHandler {
|
||||
|
||||
/**
|
||||
* @param cmd
|
||||
*/
|
||||
void DisplayDebug(argh::parser &cmd)
|
||||
{
|
||||
if (cmd[{"-d", "--debug"}]) {
|
||||
std::cout << "Positional args:\n";
|
||||
for (auto &pos_arg : cmd)
|
||||
std::cout << '\t' << pos_arg << std::endl;
|
||||
|
||||
std::cout << "Positional args:\n";
|
||||
for (auto &pos_arg : cmd.pos_args())
|
||||
std::cout << '\t' << pos_arg << std::endl;
|
||||
|
||||
std::cout << "\nFlags:\n";
|
||||
for (auto &flag : cmd.flags())
|
||||
std::cout << '\t' << flag << std::endl;
|
||||
|
||||
std::cout << "\nParameters:\n";
|
||||
for (auto ¶m : cmd.params())
|
||||
std::cout << '\t' << param.first << " : " << param.second << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
*/
|
||||
void CommandHandler(int argc, char **argv)
|
||||
{
|
||||
if (argc == 1) { return; }
|
||||
|
||||
argh::parser cmd;
|
||||
cmd.parse(argc, argv, argh::parser::PREFER_PARAM_FOR_UNREG_OPTION);
|
||||
|
||||
LoginserverCommandHandler::DisplayDebug(cmd);
|
||||
|
||||
/**
|
||||
* Declare command mapping
|
||||
*/
|
||||
std::map<std::string, void (*)(int argc, char **argv, argh::parser &cmd)> function_map;
|
||||
function_map["create-loginserver-api-token"] = &LoginserverCommandHandler::CreateLoginserverApiToken;
|
||||
function_map["list-loginserver-api-tokens"] = &LoginserverCommandHandler::ListLoginserverApiTokens;
|
||||
|
||||
std::map<std::string, void (*)(int argc, char **argv, argh::parser &cmd)>::const_iterator it = function_map.begin();
|
||||
std::map<std::string, void (*)(int argc, char **argv, argh::parser &cmd)>::const_iterator end = function_map.end();
|
||||
|
||||
bool ran_command = false;
|
||||
while (it != end) {
|
||||
if (it->first == argv[1]) {
|
||||
(it->second)(argc, argv, cmd);
|
||||
ran_command = true;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
if (cmd[{"-h", "--help"}] || !ran_command) {
|
||||
std::cout << std::endl;
|
||||
std::cout << "###########################################################" << std::endl;
|
||||
std::cout << "# Loginserver CLI Menu" << std::endl;
|
||||
std::cout << "###########################################################" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "> create-loginserver-api-token --write --read" << std::endl;
|
||||
std::cout << "> list-loginserver-api-tokens" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
*/
|
||||
void CreateLoginserverApiToken(int argc, char **argv, argh::parser &cmd)
|
||||
{
|
||||
bool can_read = cmd[{"-r", "--read"}];
|
||||
bool can_write = cmd[{"-w", "--write"}];
|
||||
|
||||
if (!can_read || !can_write) {
|
||||
LogInfo("[{0}] --read or --write must be set or both!", __func__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::string token = server.db->CreateLoginserverApiToken(can_write, can_read);
|
||||
if (!token.empty()) {
|
||||
LogInfo("[{0}] Created Loginserver API token [{1}]", __func__, token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @param cmd
|
||||
*/
|
||||
void ListLoginserverApiTokens(int argc, char **argv, argh::parser &cmd)
|
||||
{
|
||||
for (auto it = server.token_manager->loaded_api_tokens.begin();
|
||||
it != server.token_manager->loaded_api_tokens.end();
|
||||
++it) {
|
||||
LogInfo(
|
||||
"token [{0}] can_write [{1}] can_read [{2}]",
|
||||
it->second.token,
|
||||
it->second.can_write,
|
||||
it->second.can_read
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
34
loginserver/loginserver_command_handler.h
Normal file
34
loginserver/loginserver_command_handler.h
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "iostream"
|
||||
#include "../common/cli/argh.h"
|
||||
|
||||
#ifndef EQEMU_LOGINSERVER_COMMAND_HANDLER_H
|
||||
#define EQEMU_LOGINSERVER_COMMAND_HANDLER_H
|
||||
|
||||
namespace LoginserverCommandHandler {
|
||||
void CommandHandler(int argc, char **argv);
|
||||
void CreateLoginserverApiToken(int argc, char **argv, argh::parser &cmd);
|
||||
void ListLoginserverApiTokens(int argc, char **argv, argh::parser &cmd);
|
||||
};
|
||||
|
||||
|
||||
#endif //EQEMU_LOGINSERVER_COMMAND_HANDLER_H
|
||||
243
loginserver/loginserver_webserver.cpp
Normal file
243
loginserver/loginserver_webserver.cpp
Normal file
@ -0,0 +1,243 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "loginserver_webserver.h"
|
||||
#include "server_manager.h"
|
||||
#include "login_server.h"
|
||||
#include "../common/json/json.h"
|
||||
#include "../common/string_util.h"
|
||||
|
||||
extern LoginServer server;
|
||||
|
||||
namespace LoginserverWebserver {
|
||||
|
||||
/**
|
||||
* @param api
|
||||
*/
|
||||
void RegisterRoutes(httplib::Server &api)
|
||||
{
|
||||
server.token_manager = new LoginserverWebserver::TokenManager;
|
||||
server.token_manager->LoadApiTokens();
|
||||
|
||||
api.Get(
|
||||
"/servers/list", [](const httplib::Request &request, httplib::Response &res) {
|
||||
|
||||
LoginserverWebserver::TokenManager::AuthCanRead(request, res);
|
||||
|
||||
Json::Value response;
|
||||
auto iter = server.server_manager->getWorldServers().begin();
|
||||
while (iter != server.server_manager->getWorldServers().end()) {
|
||||
Json::Value row;
|
||||
row["server_long_name"] = (*iter)->GetLongName();
|
||||
row["server_short_name"] = (*iter)->GetLongName();
|
||||
row["server_list_id"] = (*iter)->GetServerListID();
|
||||
row["server_status"] = (*iter)->GetStatus();
|
||||
row["zones_booted"] = (*iter)->GetZonesBooted();
|
||||
row["local_ip"] = (*iter)->GetLocalIP();
|
||||
row["remote_ip"] = (*iter)->GetRemoteIP();
|
||||
row["players_online"] = (*iter)->GetPlayersOnline();
|
||||
response.append(row);
|
||||
++iter;
|
||||
}
|
||||
|
||||
LoginserverWebserver::SendResponse(response, res);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param payload
|
||||
* @param res
|
||||
*/
|
||||
void SendResponse(const Json::Value &payload, httplib::Response &res)
|
||||
{
|
||||
if (res.get_header_value("response_set") == "true") {
|
||||
res.set_header("response_set", "");
|
||||
return;
|
||||
}
|
||||
|
||||
std::stringstream response_payload;
|
||||
|
||||
if (payload.empty()) {
|
||||
Json::Value response;
|
||||
response["message"] = "There were no results found";
|
||||
response_payload << response;
|
||||
res.set_content(response_payload.str(), "application/json");
|
||||
return;
|
||||
}
|
||||
|
||||
response_payload << payload;
|
||||
res.set_content(response_payload.str(), "application/json");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param request
|
||||
* @param res
|
||||
*/
|
||||
void LoginserverWebserver::TokenManager::AuthCanRead(const httplib::Request &request, httplib::Response &res)
|
||||
{
|
||||
LoginserverWebserver::TokenManager::token_data
|
||||
user_token = LoginserverWebserver::TokenManager::CheckApiAuthorizationHeaders(request);
|
||||
|
||||
if (!user_token.can_read) {
|
||||
Json::Value response;
|
||||
std::stringstream response_payload;
|
||||
response["message"] = "Authorization token is either invalid or cannot read!";
|
||||
response_payload << response;
|
||||
res.set_content(response_payload.str(), "application/json");
|
||||
res.set_header("response_set", "true");
|
||||
|
||||
LogWarning(
|
||||
"AuthCanRead access failure | token [{0}] remote_address [{1}] user_agent [{2}]",
|
||||
user_token.token,
|
||||
user_token.remote_address,
|
||||
user_token.user_agent
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param request
|
||||
* @param res
|
||||
*/
|
||||
void LoginserverWebserver::TokenManager::AuthCanWrite(const httplib::Request &request, httplib::Response &res)
|
||||
{
|
||||
LoginserverWebserver::TokenManager::token_data
|
||||
user_token = LoginserverWebserver::TokenManager::CheckApiAuthorizationHeaders(request);
|
||||
|
||||
if (!user_token.can_write) {
|
||||
Json::Value response;
|
||||
std::stringstream response_payload;
|
||||
response["message"] = "Authorization token is either invalid or cannot write!";
|
||||
response_payload << response;
|
||||
res.set_content(response_payload.str(), "application/json");
|
||||
res.set_header("response_set", "true");
|
||||
|
||||
LogWarning(
|
||||
"AuthCanWrite access failure | token [{0}] remote_address [{1}] user_agent [{2}]",
|
||||
user_token.token,
|
||||
user_token.remote_address,
|
||||
user_token.user_agent
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
LoginserverWebserver::TokenManager::token_data
|
||||
LoginserverWebserver::TokenManager::CheckApiAuthorizationHeaders(
|
||||
const httplib::Request &request
|
||||
)
|
||||
{
|
||||
std::string authorization_key;
|
||||
|
||||
LoginserverWebserver::TokenManager::token_data user_token{};
|
||||
|
||||
for (const auto &header : request.headers) {
|
||||
auto header_key = header.first;
|
||||
auto header_value = header.second;
|
||||
if (header_key == "Authorization") {
|
||||
authorization_key = header.second;
|
||||
find_replace(authorization_key, "Bearer: ", "");
|
||||
if (LoginserverWebserver::TokenManager::TokenExists(authorization_key)) {
|
||||
user_token = server.token_manager->GetToken(authorization_key);
|
||||
}
|
||||
}
|
||||
|
||||
if (header_key == "REMOTE_ADDR") {
|
||||
user_token.remote_address = header.second;
|
||||
}
|
||||
|
||||
if (header_key == "User-Agent") {
|
||||
user_token.user_agent = header.second;
|
||||
}
|
||||
}
|
||||
|
||||
LogDebug(
|
||||
"Authentication Request | remote_address [{0}] user_agent [{1}] authorization_key [{2}]",
|
||||
user_token.remote_address,
|
||||
user_token.user_agent,
|
||||
authorization_key
|
||||
);
|
||||
|
||||
return user_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads API Tokens
|
||||
*/
|
||||
void TokenManager::LoadApiTokens()
|
||||
{
|
||||
auto results = server.db->GetLoginserverApiTokens();
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
LoginserverWebserver::TokenManager::token_data token_data;
|
||||
token_data.token = row[0];
|
||||
token_data.can_write = std::stoi(row[1]) > 0;
|
||||
token_data.can_read = std::stoi(row[2]) > 0;
|
||||
|
||||
LogDebug(
|
||||
"Inserting api token to internal list [{0}] write {1} read {2}",
|
||||
token_data.token,
|
||||
token_data.can_read,
|
||||
token_data.can_write
|
||||
);
|
||||
|
||||
server.token_manager->loaded_api_tokens.insert(
|
||||
std::make_pair(
|
||||
token_data.token,
|
||||
token_data
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
bool TokenManager::TokenExists(const std::string &token)
|
||||
{
|
||||
auto it = server.token_manager->loaded_api_tokens.find(token);
|
||||
|
||||
return !(it == server.token_manager->loaded_api_tokens.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
LoginserverWebserver::TokenManager::token_data TokenManager::GetToken(
|
||||
const std::string &token
|
||||
)
|
||||
{
|
||||
auto iter = server.token_manager->loaded_api_tokens.find(token);
|
||||
if (iter != server.token_manager->loaded_api_tokens.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
57
loginserver/loginserver_webserver.h
Normal file
57
loginserver/loginserver_webserver.h
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EQEMU_LOGINSERVER_WEBSERVER_H
|
||||
#define EQEMU_LOGINSERVER_WEBSERVER_H
|
||||
|
||||
#include "../common/http/httplib.h"
|
||||
#include "../common/json/json.h"
|
||||
#include "../common/types.h"
|
||||
|
||||
namespace LoginserverWebserver {
|
||||
|
||||
class TokenManager {
|
||||
|
||||
public:
|
||||
TokenManager() = default;
|
||||
|
||||
struct token_data {
|
||||
std::string token;
|
||||
bool can_read;
|
||||
bool can_write;
|
||||
std::string user_agent;
|
||||
std::string remote_address;
|
||||
};
|
||||
|
||||
std::map<std::string, token_data> loaded_api_tokens{};
|
||||
|
||||
void LoadApiTokens();
|
||||
static bool TokenExists(const std::string &token);
|
||||
token_data GetToken(const std::string &token);
|
||||
static token_data CheckApiAuthorizationHeaders(const httplib::Request &request);
|
||||
static void AuthCanRead(const httplib::Request &request, httplib::Response &res);
|
||||
static void AuthCanWrite(const httplib::Request &request, httplib::Response &res);
|
||||
};
|
||||
|
||||
void RegisterRoutes(httplib::Server &api);
|
||||
void SendResponse(const Json::Value &payload, httplib::Response &res);
|
||||
};
|
||||
|
||||
#endif //EQEMU_LOGINSERVER_WEBSERVER_H
|
||||
@ -26,7 +26,10 @@
|
||||
#include "../common/platform.h"
|
||||
#include "../common/crash.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/http/httplib.h"
|
||||
#include "login_server.h"
|
||||
#include "loginserver_webserver.h"
|
||||
#include "loginserver_command_handler.h"
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
@ -40,7 +43,7 @@ void CatchSignal(int sig_num)
|
||||
{
|
||||
}
|
||||
|
||||
int main()
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
RegisterExecutablePlatform(ExePlatformLogin);
|
||||
set_exception_handler();
|
||||
@ -176,25 +179,46 @@ int main()
|
||||
#endif
|
||||
|
||||
LogInfo("Server Started");
|
||||
|
||||
if (LogSys.log_settings[Logs::Login_Server].log_to_console == 1) {
|
||||
LogInfo("Loginserver logging set to level [1] for more debugging, enable detail [3]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Web API
|
||||
*/
|
||||
httplib::Server api;
|
||||
int web_api_port = server.config.GetVariableInt("web_api", "port", 6000);
|
||||
bool web_api_enabled = server.config.GetVariableBool("web_api", "enabled", true);
|
||||
if (web_api_enabled) {
|
||||
api.bind("0.0.0.0", web_api_port);
|
||||
LogInfo("Webserver API now listening on port [{0}]", web_api_port);
|
||||
LoginserverWebserver::RegisterRoutes(api);
|
||||
}
|
||||
|
||||
LoginserverCommandHandler::CommandHandler(argc, argv);
|
||||
|
||||
while (run_server) {
|
||||
Timer::SetCurrentTime();
|
||||
server.client_manager->Process();
|
||||
EQ::EventLoop::Get().Process();
|
||||
Sleep(50);
|
||||
|
||||
if (web_api_enabled) {
|
||||
api.poll();
|
||||
}
|
||||
|
||||
Sleep(5);
|
||||
}
|
||||
|
||||
LogInfo("Server Shutdown");
|
||||
|
||||
LogInfo("Client Manager Shutdown");
|
||||
delete server.client_manager;
|
||||
|
||||
LogInfo("Server Manager Shutdown");
|
||||
delete server.server_manager;
|
||||
|
||||
LogInfo("Database System Shutdown");
|
||||
delete server.db;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -37,7 +37,6 @@ public:
|
||||
dump_in_packets(false),
|
||||
dump_out_packets(false),
|
||||
encryption_mode(5),
|
||||
local_network("127.0.0.1"),
|
||||
reject_duplicate_servers(false),
|
||||
allow_password_login(true),
|
||||
allow_token_login(false),
|
||||
@ -187,7 +186,6 @@ private:
|
||||
bool auto_link_accounts;
|
||||
bool update_insecure_passwords;
|
||||
int encryption_mode;
|
||||
std::string local_network;
|
||||
std::string account_table;
|
||||
std::string world_registration_table;
|
||||
std::string world_admin_registration_table;
|
||||
|
||||
@ -332,3 +332,11 @@ void ServerManager::DestroyServerByName(
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
const std::list<std::unique_ptr<WorldServer>> &ServerManager::getWorldServers() const
|
||||
{
|
||||
return world_servers;
|
||||
}
|
||||
|
||||
@ -86,6 +86,11 @@ public:
|
||||
*/
|
||||
void DestroyServerByName(std::string server_long_name, std::string server_short_name, WorldServer *ignore = nullptr);
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
const std::list<std::unique_ptr<WorldServer>> &getWorldServers() const;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
@ -100,6 +105,7 @@ private:
|
||||
|
||||
std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
|
||||
std::list<std::unique_ptr<WorldServer>> world_servers;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user