Abstracted CLI command handling interface, streamlined more logging

This commit is contained in:
Akkadius 2019-08-04 02:58:26 -05:00
parent 581cbccad5
commit 4498819fad
15 changed files with 1004 additions and 139 deletions

View File

@ -3,6 +3,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
SET(common_sources
base_packet.cpp
classes.cpp
cli/eqemu_command_handler.cpp
compression.cpp
condition.cpp
crash.cpp
@ -108,8 +109,7 @@ SET(common_sources
tinyxml/tinyxmlerror.cpp
tinyxml/tinyxmlparser.cpp
util/directory.cpp
util/uuid.cpp
)
util/uuid.cpp)
SET(common_headers
any.h
@ -123,6 +123,8 @@ SET(common_headers
crc16.h
crc32.h
cli/argh.h
cli/eqemu_command_handler.h
cli/terminal_color.hpp
data_verification.h
database.h
dbcore.h
@ -270,8 +272,7 @@ SET(common_headers
tinyxml/tinyxml.h
util/memory_stream.h
util/directory.h
util/uuid.h
)
util/uuid.h)
SOURCE_GROUP(Event FILES
event/event_loop.h

View File

@ -0,0 +1,192 @@
/**
* 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 <fmt/format.h>
#include "eqemu_command_handler.h"
#include "../platform.h"
namespace EQEmuCommand {
std::map<std::string, void (*)(
int argc,
char **argv,
argh::parser &cmd,
std::string &description
)> function_map;
/**
* @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 &param : cmd.params())
std::cout << '\t' << param.first << " : " << param.second << std::endl;
}
}
/**
* @param arguments
* @param options
* @param cmd
* @param argc
* @param argv
*/
void ValidateCmdInput(
std::vector<std::string> &arguments,
std::vector<std::string> &options,
argh::parser &cmd,
int argc,
char **argv
)
{
bool arguments_filled = true;
for (auto &arg : arguments) {
if (cmd(arg).str().empty()) {
arguments_filled = false;
}
}
if (!arguments_filled || argc == 2) {
std::string arguments_string;
for (auto &arg : arguments) {
arguments_string += " " + arg + "=*\n";
}
std::string options_string;
for (auto &opt : options) {
options_string += " " + opt + "\n";
}
std::cout << fmt::format(
"Command\n\n{0} \n\nArgs\n{1}\nOptions\n{2}",
argv[1],
arguments_string,
options_string
) << std::endl;
exit(1);
}
}
/**
* @param in_function_map
* @param cmd
* @param argc
* @param argv
*/
void HandleMenu(
std::map<std::string, void (*)(
int argc,
char **argv,
argh::parser &cmd,
std::string &description
)> &in_function_map,
argh::parser &cmd,
int argc,
char **argv
)
{
std::string description;
bool ran_command = false;
for (auto &it: in_function_map) {
if (it.first == argv[1]) {
std::cout << std::endl;
std::cout << "> " << termcolor::cyan << "Executing CLI Command" << termcolor::reset << std::endl;
std::cout << std::endl;
(it.second)(argc, argv, cmd, description);
ran_command = true;
}
}
if (cmd[{"-h", "--help"}]) {
std::cout << std::endl;
std::cout <<
"> " <<
termcolor::yellow <<
"EQEmulator [" + GetPlatformName() + "] CLI Menu" <<
termcolor::reset
<< std::endl
<< std::endl;
/**
* Get max command length for padding length
*/
int max_command_length = 0;
for (auto &it: in_function_map) {
if (it.first.length() > max_command_length) {
std::stringstream command;
command << termcolor::colorize << termcolor::yellow << it.first << termcolor::reset;
max_command_length = command.str().length() + 5;
}
}
/**
* Display command menu
*/
std::string command_section;
for (auto &it: in_function_map) {
description = "";
(it.second)(argc, argv, cmd, description);
/**
* Print section header
*/
std::string command_prefix = it.first.substr(0, it.first.find(":"));
if (command_section != command_prefix) {
command_section = command_prefix;
std::cout << termcolor::reset << command_prefix << std::endl;
}
/**
* Print commands
*/
std::stringstream command;
command << termcolor::colorize << termcolor::yellow << it.first << termcolor::reset;
printf(" %-*s %s\n", max_command_length, command.str().c_str(), description.c_str());
}
std::cout << std::endl;
}
else if (!ran_command) {
std::cerr << "Unknown command [" << argv[1] << "] ! Try --help" << std::endl;
}
exit(1);
}
}

View File

@ -0,0 +1,76 @@
/**
* 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_EQEMU_COMMAND_HANDLER_H
#define EQEMU_EQEMU_COMMAND_HANDLER_H
#include "argh.h"
#include "terminal_color.hpp"
namespace EQEmuCommand {
extern std::map<std::string, void (*)(
int argc,
char **argv,
argh::parser &cmd,
std::string &description
)> function_map;
/**
* @param arguments
* @param options
* @param cmd
* @param argc
* @param argv
*/
void ValidateCmdInput(
std::vector<std::string> &arguments,
std::vector<std::string> &options,
argh::parser &cmd,
int argc,
char **argv
);
/**
* @param cmd
*/
void DisplayDebug(argh::parser &cmd);
/**
* @param in_function_map
* @param cmd
* @param argc
* @param argv
*/
void HandleMenu(
std::map<std::string, void (*)(
int argc,
char **argv,
argh::parser &cmd,
std::string &description
)> &in_function_map,
argh::parser &cmd,
int argc,
char **argv
);
};
#endif //EQEMU_EQEMU_COMMAND_HANDLER_H

View File

@ -0,0 +1,557 @@
//!
//! termcolor
//! ~~~~~~~~~
//!
//! termcolor is a header-only c++ library for printing colored messages
//! to the terminal. Written just for fun with a help of the Force.
//!
//! :copyright: (c) 2013 by Ihor Kalnytskyi
//! :license: BSD, see LICENSE for details
//!
#ifndef TERMCOLOR_HPP_
#define TERMCOLOR_HPP_
// the following snippet of code detects the current OS and
// defines the appropriate macro that is used to wrap some
// platform specific things
#if defined(_WIN32) || defined(_WIN64)
# define TERMCOLOR_OS_WINDOWS
#elif defined(__APPLE__)
# define TERMCOLOR_OS_MACOS
#elif defined(__unix__) || defined(__unix)
# define TERMCOLOR_OS_LINUX
#else
# error unsupported platform
#endif
// This headers provides the `isatty()`/`fileno()` functions,
// which are used for testing whether a standart stream refers
// to the terminal. As for Windows, we also need WinApi funcs
// for changing colors attributes of the terminal.
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
# include <unistd.h>
#elif defined(TERMCOLOR_OS_WINDOWS)
# include <io.h>
# include <windows.h>
#endif
#include <iostream>
#include <cstdio>
namespace termcolor
{
// Forward declaration of the `_internal` namespace.
// All comments are below.
namespace _internal
{
// An index to be used to access a private storage of I/O streams. See
// colorize / nocolorize I/O manipulators for details.
static int colorize_index = std::ios_base::xalloc();
inline FILE* get_standard_stream(const std::ostream& stream);
inline bool is_colorized(std::ostream& stream);
inline bool is_atty(const std::ostream& stream);
#if defined(TERMCOLOR_OS_WINDOWS)
inline void win_change_attributes(std::ostream& stream, int foreground, int background=-1);
#endif
}
inline
std::ostream& colorize(std::ostream& stream)
{
stream.iword(_internal::colorize_index) = 1L;
return stream;
}
inline
std::ostream& nocolorize(std::ostream& stream)
{
stream.iword(_internal::colorize_index) = 0L;
return stream;
}
inline
std::ostream& reset(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;00m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream, -1, -1);
#endif
}
return stream;
}
inline
std::ostream& bold(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;1m";
#elif defined(TERMCOLOR_OS_WINDOWS)
#endif
}
return stream;
}
inline
std::ostream& dark(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;2m";
#elif defined(TERMCOLOR_OS_WINDOWS)
#endif
}
return stream;
}
inline
std::ostream& underline(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;4m";
#elif defined(TERMCOLOR_OS_WINDOWS)
#endif
}
return stream;
}
inline
std::ostream& blink(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;5m";
#elif defined(TERMCOLOR_OS_WINDOWS)
#endif
}
return stream;
}
inline
std::ostream& reverse(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;7m";
#elif defined(TERMCOLOR_OS_WINDOWS)
#endif
}
return stream;
}
inline
std::ostream& concealed(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;8m";
#elif defined(TERMCOLOR_OS_WINDOWS)
#endif
}
return stream;
}
inline
std::ostream& grey(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;30m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream,
0 // grey (black)
);
#endif
}
return stream;
}
inline
std::ostream& red(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;31m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream,
FOREGROUND_RED
);
#endif
}
return stream;
}
inline
std::ostream& green(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;32m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream,
FOREGROUND_GREEN
);
#endif
}
return stream;
}
inline
std::ostream& yellow(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;33m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream,
FOREGROUND_GREEN | FOREGROUND_RED
);
#endif
}
return stream;
}
inline
std::ostream& blue(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;34m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream,
FOREGROUND_BLUE
);
#endif
}
return stream;
}
inline
std::ostream& magenta(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;35m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream,
FOREGROUND_BLUE | FOREGROUND_RED
);
#endif
}
return stream;
}
inline
std::ostream& cyan(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;36m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream,
FOREGROUND_BLUE | FOREGROUND_GREEN
);
#endif
}
return stream;
}
inline
std::ostream& white(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;37m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream,
FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
);
#endif
}
return stream;
}
inline
std::ostream& on_grey(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;40m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream, -1,
0 // grey (black)
);
#endif
}
return stream;
}
inline
std::ostream& on_red(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;41m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream, -1,
BACKGROUND_RED
);
#endif
}
return stream;
}
inline
std::ostream& on_green(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;42m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream, -1,
BACKGROUND_GREEN
);
#endif
}
return stream;
}
inline
std::ostream& on_yellow(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;43m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream, -1,
BACKGROUND_GREEN | BACKGROUND_RED
);
#endif
}
return stream;
}
inline
std::ostream& on_blue(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;44m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream, -1,
BACKGROUND_BLUE
);
#endif
}
return stream;
}
inline
std::ostream& on_magenta(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;45m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream, -1,
BACKGROUND_BLUE | BACKGROUND_RED
);
#endif
}
return stream;
}
inline
std::ostream& on_cyan(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;46m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream, -1,
BACKGROUND_GREEN | BACKGROUND_BLUE
);
#endif
}
return stream;
}
inline
std::ostream& on_white(std::ostream& stream)
{
if (_internal::is_colorized(stream))
{
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
stream << "\e[1;47m";
#elif defined(TERMCOLOR_OS_WINDOWS)
_internal::win_change_attributes(stream, -1,
BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED
);
#endif
}
return stream;
}
//! Since C++ hasn't a way to hide something in the header from
//! the outer access, I have to introduce this namespace which
//! is used for internal purpose and should't be access from
//! the user code.
namespace _internal
{
//! Since C++ hasn't a true way to extract stream handler
//! from the a given `std::ostream` object, I have to write
//! this kind of hack.
inline
FILE* get_standard_stream(const std::ostream& stream)
{
if (&stream == &std::cout)
return stdout;
else if ((&stream == &std::cerr) || (&stream == &std::clog))
return stderr;
return 0;
}
// Say whether a given stream should be colorized or not. It's always
// true for ATTY streams and may be true for streams marked with
// colorize flag.
inline
bool is_colorized(std::ostream& stream)
{
return is_atty(stream) || static_cast<bool>(stream.iword(colorize_index));
}
//! Test whether a given `std::ostream` object refers to
//! a terminal.
inline
bool is_atty(const std::ostream& stream)
{
FILE* std_stream = get_standard_stream(stream);
// Unfortunately, fileno() ends with segmentation fault
// if invalid file descriptor is passed. So we need to
// handle this case gracefully and assume it's not a tty
// if standard stream is not detected, and 0 is returned.
if (!std_stream)
return false;
#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX)
return ::isatty(fileno(std_stream));
#elif defined(TERMCOLOR_OS_WINDOWS)
return ::_isatty(_fileno(std_stream));
#endif
}
#if defined(TERMCOLOR_OS_WINDOWS)
//! Change Windows Terminal colors attribute. If some
//! parameter is `-1` then attribute won't changed.
inline void win_change_attributes(std::ostream& stream, int foreground, int background)
{
// yeah, i know.. it's ugly, it's windows.
static WORD defaultAttributes = 0;
// Windows doesn't have ANSI escape sequences and so we use special
// API to change Terminal output color. That means we can't
// manipulate colors by means of "std::stringstream" and hence
// should do nothing in this case.
if (!_internal::is_atty(stream))
return;
// get terminal handle
HANDLE hTerminal = INVALID_HANDLE_VALUE;
if (&stream == &std::cout)
hTerminal = GetStdHandle(STD_OUTPUT_HANDLE);
else if (&stream == &std::cerr)
hTerminal = GetStdHandle(STD_ERROR_HANDLE);
// save default terminal attributes if it unsaved
if (!defaultAttributes)
{
CONSOLE_SCREEN_BUFFER_INFO info;
if (!GetConsoleScreenBufferInfo(hTerminal, &info))
return;
defaultAttributes = info.wAttributes;
}
// restore all default settings
if (foreground == -1 && background == -1)
{
SetConsoleTextAttribute(hTerminal, defaultAttributes);
return;
}
// get current settings
CONSOLE_SCREEN_BUFFER_INFO info;
if (!GetConsoleScreenBufferInfo(hTerminal, &info))
return;
if (foreground != -1)
{
info.wAttributes &= ~(info.wAttributes & 0x0F);
info.wAttributes |= static_cast<WORD>(foreground);
}
if (background != -1)
{
info.wAttributes &= ~(info.wAttributes & 0xF0);
info.wAttributes |= static_cast<WORD>(background);
}
SetConsoleTextAttribute(hTerminal, info.wAttributes);
}
#endif // TERMCOLOR_OS_WINDOWS
} // namespace _internal
} // namespace termcolor
#undef TERMCOLOR_OS_WINDOWS
#undef TERMCOLOR_OS_MACOS
#undef TERMCOLOR_OS_LINUX
#endif // TERMCOLOR_HPP_

View File

@ -213,7 +213,7 @@ void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
}
}
else {
LogF(Logs::General, Logs::Error, "Could not process hello, size != {0}", 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
LogError("Could not process hello, size != {0}", 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
}
}
else {
@ -225,7 +225,7 @@ void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
}
}
catch (std::exception &ex) {
LogF(Logs::General, Logs::Error, "Error parsing hello from server: {0}", ex.what());
LogError("Error parsing hello from server: {0}", ex.what());
m_connection->Disconnect();
if (m_on_connect_cb) {
@ -252,7 +252,7 @@ void EQ::Net::ServertalkClient::ProcessHello(EQ::Net::Packet &p)
}
}
catch (std::exception &ex) {
LogF(Logs::General, Logs::Error, "Error parsing hello from server: {0}", ex.what());
LogError("Error parsing hello from server: {0}", ex.what());
m_connection->Disconnect();
if (m_on_connect_cb) {
@ -275,7 +275,7 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
std::unique_ptr<unsigned char[]> decrypted_text(new unsigned char[message_len]);
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)&data[0], length, m_nonce_theirs, m_shared_key))
{
LogF(Logs::General, Logs::Error, "Error decrypting message from server");
LogError("Error decrypting message from server");
(*(uint64_t*)&m_nonce_theirs[0])++;
return;
}
@ -323,7 +323,7 @@ void EQ::Net::ServertalkClient::ProcessMessage(EQ::Net::Packet &p)
}
}
catch (std::exception &ex) {
LogF(Logs::General, Logs::Error, "Error parsing message from server: {0}", ex.what());
LogError("Error parsing message from server: {0}", ex.what());
}
}

View File

@ -220,7 +220,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)p.Data() + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, cipher_len, m_nonce_theirs, m_shared_key))
{
LogF(Logs::General, Logs::Error, "Error decrypting handshake from client, dropping connection.");
LogError("Error decrypting handshake from client, dropping connection.");
m_connection->Disconnect();
return;
}
@ -229,7 +229,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
std::string credentials = (const char*)&decrypted_text[0] + (m_identifier.length() + 1);
if (!m_parent->CheckCredentials(credentials)) {
LogF(Logs::General, Logs::Error, "Got incoming connection with invalid credentials during handshake, dropping connection.");
LogError("Got incoming connection with invalid credentials during handshake, dropping connection.");
m_connection->Disconnect();
return;
}
@ -239,7 +239,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
}
}
catch (std::exception &ex) {
LogF(Logs::General, Logs::Error, "Error parsing handshake from client: {0}", ex.what());
LogError("Error parsing handshake from client: {0}", ex.what());
m_connection->Disconnect();
}
}
@ -249,7 +249,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
auto credentials = p.GetCString(m_identifier.length() + 1);
if (!m_parent->CheckCredentials(credentials)) {
LogF(Logs::General, Logs::Error, "Got incoming connection with invalid credentials during handshake, dropping connection.");
LogError("Got incoming connection with invalid credentials during handshake, dropping connection.");
m_connection->Disconnect();
return;
}
@ -257,7 +257,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
m_parent->ConnectionIdentified(this);
}
catch (std::exception &ex) {
LogF(Logs::General, Logs::Error, "Error parsing handshake from client: {0}", ex.what());
LogError("Error parsing handshake from client: {0}", ex.what());
m_connection->Disconnect();
}
}
@ -267,7 +267,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
auto credentials = p.GetCString(m_identifier.length() + 1);
if (!m_parent->CheckCredentials(credentials)) {
LogF(Logs::General, Logs::Error, "Got incoming connection with invalid credentials during handshake, dropping connection.");
LogError("Got incoming connection with invalid credentials during handshake, dropping connection.");
m_connection->Disconnect();
return;
}
@ -275,7 +275,7 @@ void EQ::Net::ServertalkServerConnection::ProcessHandshake(EQ::Net::Packet &p, b
m_parent->ConnectionIdentified(this);
}
catch (std::exception &ex) {
LogF(Logs::General, Logs::Error, "Error parsing handshake from client: {0}", ex.what());
LogError("Error parsing handshake from client: {0}", ex.what());
m_connection->Disconnect();
}
#endif
@ -295,7 +295,7 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
if (crypto_box_open_easy_afternm(&decrypted_text[0], (unsigned char*)&data[0], length, m_nonce_theirs, m_shared_key))
{
LogF(Logs::General, Logs::Error, "Error decrypting message from client");
LogError("Error decrypting message from client");
(*(uint64_t*)&m_nonce_theirs[0])++;
return;
}
@ -343,6 +343,6 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p)
}
}
catch (std::exception &ex) {
LogF(Logs::General, Logs::Error, "Error parsing message from client: {0}", ex.what());
LogError("Error parsing message from client: {0}", ex.what());
}
}

View File

@ -26,11 +26,13 @@ extern LoginServer server;
/**
* @param username
* @param password
* @param email
* @return
*/
bool AccountManagement::CreateLocalLoginServerAccount(
uint32 AccountManagement::CreateLocalLoginServerAccount(
std::string username,
std::string password
std::string password,
std::string email
)
{
auto mode = server.options.GetEncryptionMode();
@ -46,29 +48,32 @@ bool AccountManagement::CreateLocalLoginServerAccount(
unsigned int db_id = 0;
std::string db_loginserver = server.options.GetDefaultLoginServerName();
if (server.db->DoesLoginServerAccountExist(username, hash, db_loginserver, 1)) {
LogInfo(
LogWarning(
"Attempting to create local login account for user [{0}] login [{1}] db_id [{2}] but already exists!",
username,
db_loginserver,
db_id
);
return false;
return 0;
}
if (server.db->CreateLoginData(username, hash, db_loginserver, db_id)) {
uint32 created_account_id = server.db->CreateLoginAccount(username, hash, db_loginserver, email);
if (created_account_id > 0) {
LogInfo(
"Account creation success for user [{0}] encryption algorithm [{1}] ({2})",
"Account creation success for user [{0}] encryption algorithm [{1}] ({2}) id: [{3}]",
username,
GetEncryptionByModeId(mode),
mode
mode,
created_account_id
);
return true;
return created_account_id;
}
LogError("Failed to create local login account for user [{0}]!", username);
return false;
return 0;
}
/**
@ -97,7 +102,7 @@ bool AccountManagement::CreateLoginserverWorldAdminAccount(
);
if (server.db->DoesLoginserverWorldAdminAccountExist(username)) {
LogInfo(
LogWarning(
"Attempting to create world admin account for user [{0}] but already exists!",
username
);

View File

@ -21,6 +21,7 @@
#define EQEMU_ACCOUNT_MANAGEMENT_H
#include "iostream"
#include "../common/types.h"
class AccountManagement {
public:
@ -28,9 +29,10 @@ public:
/**
* @param username
* @param password
* @param email
* @return
*/
static bool CreateLocalLoginServerAccount(std::string username, std::string password);
static uint32 CreateLocalLoginServerAccount(std::string username, std::string password, std::string email = "");
/**
* @param username

View File

@ -226,6 +226,41 @@ bool Database::CreateLoginData(
return CreateLoginDataWithID(name, password, loginserver, free_id);
}
/**
* @param name
* @param password
* @param loginserver
* @param email
* @return
*/
uint32 Database::CreateLoginAccount(
const std::string &name,
const std::string &password,
const std::string &loginserver,
const std::string &email
)
{
uint32 free_id = GetFreeID(loginserver);
if (free_id <= 0) {
return 0;
}
auto query = fmt::format(
"INSERT INTO login_accounts (id, source_loginserver, account_name, account_password, account_email, last_login_date, last_ip_address, created_at) "
"VALUES ({0}, '{1}', '{2}', '{3}', '{4}', NOW(), '127.0.0.1', NOW())",
free_id,
EscapeString(loginserver),
EscapeString(name),
EscapeString(password),
EscapeString(email)
);
auto results = QueryDatabase(query);
return (results.Success() ? free_id : 0);
}
/**
* @param in_account_name
* @param in_account_password

View File

@ -248,6 +248,20 @@ public:
Database::DbLoginServerAdmin GetLoginServerAdmin(const std::string &account_name);
/**
* @param name
* @param password
* @param loginserver
* @param email
* @return
*/
uint32 CreateLoginAccount(
const std::string &name,
const std::string &password,
const std::string &loginserver = "local",
const std::string &email = "local_creation"
);
protected:
std::string user, pass, host, port, name;
MYSQL *database{};

View File

@ -30,30 +30,6 @@ 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 &param : cmd.params())
std::cout << '\t' << param.first << " : " << param.second << std::endl;
}
}
/**
* @param argc
* @param argv
@ -64,74 +40,46 @@ namespace LoginserverCommandHandler {
argh::parser cmd;
cmd.parse(argc, argv, argh::parser::PREFER_PARAM_FOR_UNREG_OPTION);
LoginserverCommandHandler::DisplayDebug(cmd);
EQEmuCommand::DisplayDebug(cmd);
/**
* Declare command mapping
*/
std::map<std::string, void (*)(int argc, char **argv, argh::parser &cmd)> function_map;
auto function_map = EQEmuCommand::function_map;
function_map["create-loginserver-account"] = &LoginserverCommandHandler::CreateLocalLoginserverAccount;
function_map["create-loginserver-api-token"] = &LoginserverCommandHandler::CreateLoginserverApiToken;
function_map["create-loginserver-world-admin-account"] = &LoginserverCommandHandler::CreateLoginserverWorldAdminAccount;
function_map["list-loginserver-api-tokens"] = &LoginserverCommandHandler::ListLoginserverApiTokens;
/**
* Register commands
*/
function_map["login-user:create"] = &LoginserverCommandHandler::CreateLocalLoginserverAccount;
function_map["web-api-token:create"] = &LoginserverCommandHandler::CreateLoginserverApiToken;
function_map["web-api-token:list"] = &LoginserverCommandHandler::ListLoginserverApiTokens;
function_map["world-admin:create"] = &LoginserverCommandHandler::CreateLoginserverWorldAdminAccount;
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]) {
std::cout << std::endl;
std::cout << "###########################################################" << std::endl;
std::cout << "# Executing CLI Command" << std::endl;
std::cout << "###########################################################" << std::endl;
std::cout << std::endl;
(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 << "# API" << 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 << "# User Accounts" << std::endl;
std::cout << "> create-loginserver-account --username=* --password=*" << std::endl;
std::cout << std::endl;
std::cout << "# World Accounts" << std::endl;
std::cout << "> create-loginserver-world-admin-account --username=* --password=* --email=*" << std::endl;
std::cout << std::endl;
std::cout << std::endl;
}
exit(1);
EQEmuCommand::HandleMenu(function_map, cmd, argc, argv);
}
/**
* @param argc
* @param argv
* @param cmd
* @param description
*/
void CreateLoginserverApiToken(int argc, char **argv, argh::parser &cmd)
void CreateLoginserverApiToken(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Creates Loginserver API Token";
if (cmd[{"-h", "--help"}]) {
return;
}
std::vector<std::string> arguments = {};
std::vector<std::string> options = {
"--read",
"--write"
};
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
bool can_read = cmd[{"-r", "--read"}];
bool can_write = cmd[{"-w", "--write"}];
@ -150,9 +98,16 @@ namespace LoginserverCommandHandler {
* @param argc
* @param argv
* @param cmd
* @param description
*/
void ListLoginserverApiTokens(int argc, char **argv, argh::parser &cmd)
void ListLoginserverApiTokens(int argc, char **argv, argh::parser &cmd, std::string &description)
{
description = "Lists Loginserver API Tokens";
if (cmd[{"-h", "--help"}]) {
return;
}
for (auto &it : server.token_manager->loaded_api_tokens) {
LogInfo(
"token [{0}] can_write [{1}] can_read [{2}]",
@ -167,17 +122,30 @@ namespace LoginserverCommandHandler {
* @param argc
* @param argv
* @param cmd
* @param description
*/
void CreateLocalLoginserverAccount(int argc, char **argv, argh::parser &cmd)
void CreateLocalLoginserverAccount(int argc, char **argv, argh::parser &cmd, std::string &description)
{
if (cmd("--username").str().empty() || cmd("--password").str().empty()) {
LogInfo("Command Example: create-loginserver-account --username=user --password=password");
exit(1);
description = "Creates Local Loginserver Account";
std::vector<std::string> arguments = {
"--username",
"--password"
};
std::vector<std::string> options = {
"--email=*"
};
if (cmd[{"-h", "--help"}]) {
return;
}
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
AccountManagement::CreateLocalLoginServerAccount(
cmd("--username").str(),
cmd("--password").str()
cmd("--password").str(),
cmd("--email").str()
);
}
@ -185,18 +153,25 @@ namespace LoginserverCommandHandler {
* @param argc
* @param argv
* @param cmd
* @param description
*/
void CreateLoginserverWorldAdminAccount(int argc, char **argv, argh::parser &cmd)
void CreateLoginserverWorldAdminAccount(int argc, char **argv, argh::parser &cmd, std::string &description)
{
if (
cmd("--username").str().empty() ||
cmd("--password").str().empty() ||
cmd("--email").str().empty()) {
description = "Creates Loginserver World Administrator Account";
LogInfo("Command Example: create-loginserver-world-admin-account --username=* --password=* --email=*");
exit(1);
std::vector<std::string> arguments = {
"--username",
"--password"
"--email"
};
std::vector<std::string> options = {};
if (cmd[{"-h", "--help"}]) {
return;
}
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
AccountManagement::CreateLoginserverWorldAdminAccount(
cmd("--username").str(),
cmd("--password").str(),

View File

@ -19,17 +19,17 @@
*/
#include "iostream"
#include "../common/cli/argh.h"
#include "../common/cli/eqemu_command_handler.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);
void CreateLocalLoginserverAccount(int argc, char **argv, argh::parser &cmd);
void CreateLoginserverWorldAdminAccount(int argc, char **argv, argh::parser &cmd);
void CreateLoginserverApiToken(int argc, char **argv, argh::parser &cmd, std::string &description);
void ListLoginserverApiTokens(int argc, char **argv, argh::parser &cmd, std::string &description);
void CreateLocalLoginserverAccount(int argc, char **argv, argh::parser &cmd, std::string &description);
void CreateLoginserverWorldAdminAccount(int argc, char **argv, argh::parser &cmd, std::string &description);
};

View File

@ -67,6 +67,7 @@ namespace LoginserverWebserver {
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
std::string username = request_body.get("username", "").asString();
std::string password = request_body.get("password", "").asString();
std::string email = request_body.get("email", "").asString();
Json::Value response;
if (username.empty() || password.empty()) {

View File

@ -48,10 +48,12 @@ int main(int argc, char** argv)
RegisterExecutablePlatform(ExePlatformLogin);
set_exception_handler();
LogSys.LoadLogSettingsDefaults();
LogInfo("Logging System Init");
if (argc == 1) {
LogSys.LoadLogSettingsDefaults();
}
server.config = EQ::JsonConfigFile::Load("login.json");
LogInfo("Config System Init");
@ -123,7 +125,9 @@ int main(int argc, char** argv)
server.config.GetVariableString("database", "db", "peq")
);
server.db->LoadLogSettings(LogSys.log_settings);
if (argc == 1) {
server.db->LoadLogSettings(LogSys.log_settings);
}
/**
* make sure our database got created okay, otherwise cleanup and exit
@ -186,7 +190,10 @@ int main(int argc, char** argv)
LoginserverWebserver::RegisterRoutes(api);
}
LoginserverCommandHandler::CommandHandler(argc, argv);
if (argc > 1) {
LogSys.LoadLogSettingsDefaults();
LoginserverCommandHandler::CommandHandler(argc, argv);
}
LogInfo("[Config] [Logging] IsTraceOn [{0}]", server.options.IsTraceOn());
LogInfo("[Config] [Logging] IsWorldTraceOn [{0}]", server.options.IsWorldTraceOn());

View File

@ -427,7 +427,7 @@ int main(int argc, char** argv) {
Log(Logs::General, Logs::World_Server, "Server (TCP) listener started.");
server_connection->OnConnectionIdentified("Zone", [&console](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
LogF(Logs::General, Logs::World_Server, "New Zone Server connection from {2} at {0}:{1}",
LogInfo("New Zone Server connection from {2} at {0}:{1}",
connection->Handle()->RemoteIP(), connection->Handle()->RemotePort(), connection->GetUUID());
numzones++;
@ -435,7 +435,7 @@ int main(int argc, char** argv) {
});
server_connection->OnConnectionRemoved("Zone", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
LogF(Logs::General, Logs::World_Server, "Removed Zone Server connection from {0}",
LogInfo("Removed Zone Server connection from {0}",
connection->GetUUID());
numzones--;
@ -443,35 +443,35 @@ int main(int argc, char** argv) {
});
server_connection->OnConnectionIdentified("Launcher", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
LogF(Logs::General, Logs::World_Server, "New Launcher connection from {2} at {0}:{1}",
LogInfo("New Launcher connection from {2} at {0}:{1}",
connection->Handle()->RemoteIP(), connection->Handle()->RemotePort(), connection->GetUUID());
launcher_list.Add(connection);
});
server_connection->OnConnectionRemoved("Launcher", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
LogF(Logs::General, Logs::World_Server, "Removed Launcher connection from {0}",
LogInfo("Removed Launcher connection from {0}",
connection->GetUUID());
launcher_list.Remove(connection);
});
server_connection->OnConnectionIdentified("QueryServ", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
LogF(Logs::General, Logs::World_Server, "New Query Server connection from {2} at {0}:{1}",
LogInfo("New Query Server connection from {2} at {0}:{1}",
connection->Handle()->RemoteIP(), connection->Handle()->RemotePort(), connection->GetUUID());
QSLink.AddConnection(connection);
});
server_connection->OnConnectionRemoved("QueryServ", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
LogF(Logs::General, Logs::World_Server, "Removed Query Server connection from {0}",
LogInfo("Removed Query Server connection from {0}",
connection->GetUUID());
QSLink.RemoveConnection(connection);
});
server_connection->OnConnectionIdentified("UCS", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
LogF(Logs::General, Logs::World_Server, "New UCS Server connection from {2} at {0}:{1}",
LogInfo("New UCS Server connection from {2} at {0}:{1}",
connection->Handle()->RemoteIP(), connection->Handle()->RemotePort(), connection->GetUUID());
UCSLink.SetConnection(connection);
@ -480,7 +480,7 @@ int main(int argc, char** argv) {
});
server_connection->OnConnectionRemoved("UCS", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
LogF(Logs::General, Logs::World_Server, "Removed Query Server connection from {0}",
LogInfo("Removed Query Server connection from {0}",
connection->GetUUID());
UCSLink.SetConnection(nullptr);
@ -489,14 +489,14 @@ int main(int argc, char** argv) {
});
server_connection->OnConnectionIdentified("WebInterface", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
LogF(Logs::General, Logs::World_Server, "New WebInterface Server connection from {2} at {0}:{1}",
LogInfo("New WebInterface Server connection from {2} at {0}:{1}",
connection->Handle()->RemoteIP(), connection->Handle()->RemotePort(), connection->GetUUID());
web_interface.AddConnection(connection);
});
server_connection->OnConnectionRemoved("WebInterface", [](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
LogF(Logs::General, Logs::World_Server, "Removed WebInterface Server connection from {0}",
LogInfo("Removed WebInterface Server connection from {0}",
connection->GetUUID());
web_interface.RemoveConnection(connection);