Adding terminal pipes
This commit is contained in:
parent
7aa37e40b9
commit
8284748381
@ -1 +1 @@
|
|||||||
Subproject commit ef2d6842d547b8f84ebbe4fe9fa6f132bcd84d35
|
Subproject commit bc242db0517250877805f09700637973ad6c1c2a
|
@ -155,6 +155,8 @@ set(SERVER_SOURCE_FILES
|
|||||||
src/client/voice/PingHandler.cpp
|
src/client/voice/PingHandler.cpp
|
||||||
src/client/voice/CryptSetupHandler.cpp
|
src/client/voice/CryptSetupHandler.cpp
|
||||||
|
|
||||||
|
src/terminal/PipedTerminal.cpp
|
||||||
|
|
||||||
)
|
)
|
||||||
if (COMPILE_WEB_CLIENT)
|
if (COMPILE_WEB_CLIENT)
|
||||||
add_definitions(-DCOMPILE_WEB_CLIENT)
|
add_definitions(-DCOMPILE_WEB_CLIENT)
|
||||||
|
@ -45,6 +45,7 @@ extern void testTomMath();
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
|
#include <src/terminal/PipedTerminal.h>
|
||||||
#include "src/client/music/internal_provider/channel_replay/ChannelProvider.h"
|
#include "src/client/music/internal_provider/channel_replay/ChannelProvider.h"
|
||||||
|
|
||||||
class CLIParser {
|
class CLIParser {
|
||||||
@ -126,7 +127,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
if(!arguments.cmdOptionExists("--no-terminal")) {
|
if(!arguments.cmdOptionExists("--no-terminal")) {
|
||||||
terminal::install();
|
terminal::install();
|
||||||
if(!terminal::active()){ cerr << "could not setup terminal!" << endl; return -1; }
|
if(!terminal::active()) { cerr << "could not setup terminal!" << endl; return -1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
if(arguments.cmdOptionExists("--help") || arguments.cmdOptionExists("-h")) {
|
if(arguments.cmdOptionExists("--help") || arguments.cmdOptionExists("-h")) {
|
||||||
@ -405,6 +406,7 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
terminal::initialize_pipe(arguments.get_option("--pipe-path"));
|
||||||
if(terminal::instance()) terminal::instance()->setPrompt("§7> §f");
|
if(terminal::instance()) terminal::instance()->setPrompt("§7> §f");
|
||||||
while(mainThreadActive) {
|
while(mainThreadActive) {
|
||||||
usleep(5 * 1000);
|
usleep(5 * 1000);
|
||||||
@ -412,11 +414,23 @@ int main(int argc, char** argv) {
|
|||||||
if(terminal::instance()) {
|
if(terminal::instance()) {
|
||||||
if(terminal::instance()->linesAvailable() > 0){
|
if(terminal::instance()->linesAvailable() > 0){
|
||||||
while(!(line = terminal::instance()->readLine("§7> §f")).empty())
|
while(!(line = terminal::instance()->readLine("§7> §f")).empty())
|
||||||
threads::Thread(THREAD_DETACHED, [line](){ terminal::chandler::handleCommand(line); });
|
threads::Thread(THREAD_DETACHED, [line]{
|
||||||
|
terminal::chandler::CommandHandle handle{};
|
||||||
|
handle.command = line;
|
||||||
|
|
||||||
|
if(!terminal::chandler::handleCommand(handle)) {
|
||||||
|
for(const auto& response : handle.response)
|
||||||
|
logErrorFmt(true, LOG_GENERAL, "{}", response);
|
||||||
|
} else {
|
||||||
|
for(const auto& response : handle.response)
|
||||||
|
logMessageFmt(true, LOG_GENERAL, "{}", response);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
terminal::finalize_pipe();
|
||||||
|
|
||||||
stopApp:
|
stopApp:
|
||||||
logMessageFmt(true, LOG_GENERAL, "Stopping application");
|
logMessageFmt(true, LOG_GENERAL, "Stopping application");
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <log/LogUtils.h>
|
#include <log/LogUtils.h>
|
||||||
#include <StringVariable.h>
|
#include <StringVariable.h>
|
||||||
#include <ThreadPool/ThreadHelper.h>
|
#include <ThreadPool/ThreadHelper.h>
|
||||||
|
#include <src/terminal/PipedTerminal.h>
|
||||||
#include "ShutdownHelper.h"
|
#include "ShutdownHelper.h"
|
||||||
#include "InstanceHandler.h"
|
#include "InstanceHandler.h"
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ void ts::server::shutdownInstance(const std::string& message) {
|
|||||||
logCriticalFmt(true, 0, "Could not shutdown server within 30 seconds! (Hangup!)");
|
logCriticalFmt(true, 0, "Could not shutdown server within 30 seconds! (Hangup!)");
|
||||||
logCriticalFmt(true, 0, "Killing server!");
|
logCriticalFmt(true, 0, "Killing server!");
|
||||||
|
|
||||||
|
terminal::finalize_pipe();
|
||||||
auto force_kill = std::thread([]{
|
auto force_kill = std::thread([]{
|
||||||
threads::self::sleep_for(chrono::seconds(5));
|
threads::self::sleep_for(chrono::seconds(5));
|
||||||
logCriticalFmt(true, 0, "Failed to exit normally!");
|
logCriticalFmt(true, 0, "Failed to exit normally!");
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <log/LogUtils.h>
|
#include <log/LogUtils.h>
|
||||||
#include <experimental/filesystem>
|
#include <experimental/filesystem>
|
||||||
|
#include <src/terminal/PipedTerminal.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
namespace fs = std::experimental::filesystem;
|
namespace fs = std::experimental::filesystem;
|
||||||
@ -44,6 +45,8 @@ static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
|
|||||||
logCritical(LOG_GENERAL, "Official issue and bug tracker url: https://github.com/TeaSpeak/TeaSpeak/issues");
|
logCritical(LOG_GENERAL, "Official issue and bug tracker url: https://github.com/TeaSpeak/TeaSpeak/issues");
|
||||||
logCritical(LOG_GENERAL, "Any reports of crashes are useless if you not provide the above generated crashlog!");
|
logCritical(LOG_GENERAL, "Any reports of crashes are useless if you not provide the above generated crashlog!");
|
||||||
logCritical(LOG_GENERAL, "Stopping server");
|
logCritical(LOG_GENERAL, "Stopping server");
|
||||||
|
|
||||||
|
terminal::finalize_pipe();
|
||||||
ts::server::shutdownInstance(ts::config::messages::applicationCrashed);
|
ts::server::shutdownInstance(ts::config::messages::applicationCrashed);
|
||||||
while(!mainThreadDone) threads::self::sleep_for(chrono::seconds(1));
|
while(!mainThreadDone) threads::self::sleep_for(chrono::seconds(1));
|
||||||
return succeeded;
|
return succeeded;
|
||||||
|
@ -21,7 +21,7 @@ void PingHandler::received_pong(uint16_t ping_id) {
|
|||||||
if(this->last_ping_id != ping_id) return;
|
if(this->last_ping_id != ping_id) return;
|
||||||
|
|
||||||
auto now = std::chrono::system_clock::now();
|
auto now = std::chrono::system_clock::now();
|
||||||
this->current_ping_ = std::chrono::floor<std::chrono::milliseconds>(this->last_request_ - now);
|
this->current_ping_ = std::chrono::floor<std::chrono::milliseconds>(now - this->last_request_);
|
||||||
|
|
||||||
this->last_response_ = now;
|
this->last_response_ = now;
|
||||||
this->last_command_acknowledge_ = now; /* That's here for purpose!*/
|
this->last_command_acknowledge_ = now; /* That's here for purpose!*/
|
||||||
|
@ -32,15 +32,14 @@ extern ts::server::InstanceHandler* serverInstance;
|
|||||||
#define _STRINGIFY(x) #x
|
#define _STRINGIFY(x) #x
|
||||||
#define STRINGIFY(x) _STRINGIFY(x)
|
#define STRINGIFY(x) _STRINGIFY(x)
|
||||||
|
|
||||||
namespace terminal {
|
namespace terminal::chandler {
|
||||||
namespace chandler {
|
bool handleCommand(CommandHandle& command){
|
||||||
void handleCommand(std::string str){
|
|
||||||
TerminalCommand cmd{};
|
TerminalCommand cmd{};
|
||||||
|
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
do {
|
do {
|
||||||
size_t next = str.find(' ', index);
|
size_t next = command.command.find(' ', index);
|
||||||
auto elm = str.substr(index, next - index);
|
auto elm = command.command.substr(index, next - index);
|
||||||
|
|
||||||
if(index == 0){
|
if(index == 0){
|
||||||
cmd.command = elm;
|
cmd.command = elm;
|
||||||
@ -53,37 +52,42 @@ namespace terminal {
|
|||||||
}
|
}
|
||||||
index = next + 1; //if no next than next = ~0 and if we add 1 then next is 0
|
index = next + 1; //if no next than next = ~0 and if we add 1 then next is 0
|
||||||
} while(index != 0);
|
} while(index != 0);
|
||||||
|
cmd.line = command.command;
|
||||||
|
|
||||||
if(cmd.lcommand == "help")
|
if(cmd.lcommand == "help")
|
||||||
handleCommandHelp(cmd);
|
return handleCommandHelp(command, cmd);
|
||||||
else if(cmd.lcommand == "end" || cmd.lcommand == "shutdown")
|
else if(cmd.lcommand == "end" || cmd.lcommand == "shutdown")
|
||||||
handleCommandEnd(cmd);
|
return handleCommandEnd(command, cmd);
|
||||||
else if(cmd.lcommand == "info")
|
else if(cmd.lcommand == "info")
|
||||||
handleCommandInfo(cmd);
|
return handleCommandInfo(command, cmd);
|
||||||
else if(cmd.lcommand == "chat")
|
else if(cmd.lcommand == "chat")
|
||||||
handleCommandChat(cmd);
|
return handleCommandChat(command, cmd);
|
||||||
else if(cmd.lcommand == "permgrant")
|
else if(cmd.lcommand == "permgrant")
|
||||||
handleCommandPermGrant(cmd);
|
return handleCommandPermGrant(command, cmd);
|
||||||
else if(cmd.lcommand == "dummycrash" || cmd.lcommand == "dummy_crash")
|
else if(cmd.lcommand == "dummycrash" || cmd.lcommand == "dummy_crash")
|
||||||
handleCommandDummyCrash(cmd);
|
return handleCommandDummyCrash(command, cmd);
|
||||||
else if(cmd.lcommand == "dummyfdflood" || cmd.lcommand == "dummy_fdflood")
|
else if(cmd.lcommand == "dummyfdflood" || cmd.lcommand == "dummy_fdflood")
|
||||||
handleCommandDummyFdFlood(cmd);
|
return handleCommandDummyFdFlood(command, cmd);
|
||||||
else if(cmd.lcommand == "meminfo")
|
else if(cmd.lcommand == "meminfo")
|
||||||
handleCommandMemInfo(cmd);
|
return handleCommandMemInfo(command, cmd);
|
||||||
else if(cmd.lcommand == "spoken")
|
else if(cmd.lcommand == "spoken")
|
||||||
handleCommandSpoken(cmd);
|
return handleCommandSpoken(command, cmd);
|
||||||
else if(cmd.lcommand == "passwd")
|
else if(cmd.lcommand == "passwd")
|
||||||
handleCommandPasswd(cmd);
|
return handleCommandPasswd(command, cmd);
|
||||||
else if(cmd.lcommand == "memflush")
|
else if(cmd.lcommand == "memflush")
|
||||||
handleCommandMemFlush(cmd);
|
return handleCommandMemFlush(command, cmd);
|
||||||
else if(cmd.lcommand == "statsreset")
|
else if(cmd.lcommand == "statsreset")
|
||||||
handleCommandStatsReset(cmd);
|
return handleCommandStatsReset(command, cmd);
|
||||||
else if(cmd.lcommand == "reload")
|
else if(cmd.lcommand == "reload")
|
||||||
handleCommandReload(cmd);
|
return handleCommandReload(command, cmd);
|
||||||
else logError("Missing command " + cmd.command + "/" + cmd.line);
|
else {
|
||||||
|
logWarning(LOG_INSTANCE, "Missing terminal command {} ({})", cmd.command, cmd.line);
|
||||||
|
command.response.emplace_back("unknown command");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handleCommandDummyCrash(TerminalCommand& arguments) {
|
bool handleCommandDummyCrash(CommandHandle& /* handle */, TerminalCommand& arguments) {
|
||||||
if(!arguments.arguments.empty()) {
|
if(!arguments.arguments.empty()) {
|
||||||
if(arguments.larguments[0] == "raise") {
|
if(arguments.larguments[0] == "raise") {
|
||||||
raise(SIGABRT);
|
raise(SIGABRT);
|
||||||
@ -95,33 +99,34 @@ namespace terminal {
|
|||||||
throw std::bad_exception();
|
throw std::bad_exception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*(int*)(nullptr) = 0;
|
*(int*)(nullptr) = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handleCommandHelp(TerminalCommand& args){
|
bool handleCommandHelp(CommandHandle& handle, TerminalCommand& args) {
|
||||||
logMessage("§aAvariable commands:");
|
handle.response.emplace_back("Available commands:");
|
||||||
logMessage(" §7- §eend §7| §eshutdown");
|
handle.response.emplace_back(" - end | shutdown");
|
||||||
logMessage(" §7- §ereload config");
|
handle.response.emplace_back(" - reload config");
|
||||||
logMessage(" §7- §echat");
|
handle.response.emplace_back(" - chat");
|
||||||
logMessage(" §7- §einfo");
|
handle.response.emplace_back(" - info");
|
||||||
logMessage(" §7- §epermgrant");
|
handle.response.emplace_back(" - permgrant");
|
||||||
logMessage(" §7- §epasswd");
|
handle.response.emplace_back(" - passwd");
|
||||||
logMessage(" §7- §4dummy_crash");
|
handle.response.emplace_back(" - dummy_crash");
|
||||||
logMessage(" §7- §4memflush");
|
handle.response.emplace_back(" - memflush");
|
||||||
logMessage(" §7- §4meminfo");
|
handle.response.emplace_back(" - meminfo");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handleCommandEnd(TerminalCommand& arguments){
|
bool handleCommandEnd(CommandHandle& handle, TerminalCommand& arguments){
|
||||||
if(arguments.arguments.size() < 1) {
|
if(arguments.arguments.empty()) {
|
||||||
logMessage("Invalid argument count!");
|
handle.response.emplace_back("Invalid argument count!");
|
||||||
logMessage("Usage: shutdown <now|<number>[h|m|s]:...> <reason>");
|
handle.response.emplace_back("Usage: shutdown <now|<number>[h|m|s]:...> <reason>");
|
||||||
logMessage("Example: shutdown info | Displays info about the current scheduled shutdown");
|
handle.response.emplace_back("Example: shutdown info | Displays info about the current scheduled shutdown");
|
||||||
logMessage("Example: shutdown cancel | Cancels the currently scheduled shutdown");
|
handle.response.emplace_back("Example: shutdown cancel | Cancels the currently scheduled shutdown");
|
||||||
logMessage("Example: shutdown now Server shutdown | The server instance will shutdown instantly");
|
handle.response.emplace_back("Example: shutdown now Server shutdown | The server instance will shutdown instantly");
|
||||||
logMessage("Example: shutdown 1h:30m Server shutdown | The server instance will shutdown in 1h and 30 min");
|
handle.response.emplace_back("Example: shutdown 1h:30m Server shutdown | The server instance will shutdown in 1h and 30 min");
|
||||||
logMessage("Example: shutdown 1h:1m:1s Server shutdown | The server instance will shutdown in 1h and 1 min and 1 second");
|
handle.response.emplace_back("Example: shutdown 1h:1m:1s Server shutdown | The server instance will shutdown in 1h and 1 min and 1 second");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,26 +134,26 @@ namespace terminal {
|
|||||||
if(arguments.larguments[0] == "info") {
|
if(arguments.larguments[0] == "info") {
|
||||||
auto task = ts::server::scheduledShutdown();
|
auto task = ts::server::scheduledShutdown();
|
||||||
if(!task) {
|
if(!task) {
|
||||||
logMessage("It isn't a shutdown scheduled!");
|
handle.response.emplace_back("It isn't a shutdown scheduled!");
|
||||||
} else {
|
} else {
|
||||||
auto time = system_clock::to_time_t(task->time_point);
|
auto time = system_clock::to_time_t(task->time_point);
|
||||||
logMessage("You scheduled a shutdown task at " + string(ctime(&time)));
|
handle.response.emplace_back("You scheduled a shutdown task at " + string(ctime(&time)));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if(arguments.larguments[0] == "cancel") {
|
} else if(arguments.larguments[0] == "cancel") {
|
||||||
auto task = ts::server::scheduledShutdown();
|
auto task = ts::server::scheduledShutdown();
|
||||||
if(!task) {
|
if(!task) {
|
||||||
logMessage("The isnt a shutdown scheduled!");
|
handle.response.emplace_back("The isn't a shutdown scheduled!");
|
||||||
} else {
|
} else {
|
||||||
ts::server::cancelShutdown(true);
|
ts::server::cancelShutdown(true);
|
||||||
logMessage("Shutdown task canceled!");
|
handle.response.emplace_back("Shutdown task canceled!");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if(arguments.larguments[0] != "now") {
|
} else if(arguments.larguments[0] != "now") {
|
||||||
string error;
|
string error;
|
||||||
period = period::parse(arguments.larguments[0], error);
|
period = period::parse(arguments.larguments[0], error);
|
||||||
if(!error.empty()) {
|
if(!error.empty()) {
|
||||||
logError("Invalid period: " + error);
|
handle.response.emplace_back("Invalid period: " + error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -161,37 +166,37 @@ namespace terminal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(period.count() == 0) {
|
if(period.count() == 0) {
|
||||||
logMessage("Stopping instance");
|
handle.response.emplace_back("Stopping instance");
|
||||||
ts::server::shutdownInstance(reason);
|
ts::server::shutdownInstance(reason);
|
||||||
} else {
|
} else {
|
||||||
auto time = system_clock::to_time_t(system_clock::now() + period);
|
auto time = system_clock::to_time_t(system_clock::now() + period);
|
||||||
logMessage("Scheduled shutdown at " + string(ctime(&time)) + "");
|
handle.response.emplace_back("Scheduled shutdown at " + string(ctime(&time)) + "");
|
||||||
ts::server::scheduleShutdown(system_clock::now() + period, reason);
|
ts::server::scheduleShutdown(system_clock::now() + period, reason);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handleCommandInfo(TerminalCommand& cmd){
|
bool handleCommandInfo(CommandHandle& /* handle */, TerminalCommand& cmd){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handleCommandChat(TerminalCommand& cmd){
|
bool handleCommandChat(CommandHandle& handle, TerminalCommand& cmd){
|
||||||
if(cmd.arguments.size() < 3){
|
if(cmd.arguments.size() < 3){
|
||||||
logError("Invalid usage!");
|
handle.response.emplace_back("Invalid usage!");
|
||||||
logMessage("§e/chat <serverId> <mode{server=3|channel=2|manager=1}> <targetId> <message...>");
|
handle.response.emplace_back("§e/chat <serverId> <mode{server=3|channel=2|manager=1}> <targetId> <message...>");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerId sid = cmd.arguments[0];
|
ServerId sid = cmd.arguments[0];
|
||||||
auto server = sid == 0 ? nullptr : serverInstance->getVoiceServerManager()->findServerById(sid);
|
auto server = sid == 0 ? nullptr : serverInstance->getVoiceServerManager()->findServerById(sid);
|
||||||
if(sid != 0 && !server) {
|
if(sid != 0 && !server) {
|
||||||
logError("Could not resolve target server.");
|
handle.response.emplace_back("Could not resolve target server.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ts::ChatMessageMode mode = cmd.arguments[1];
|
ts::ChatMessageMode mode = cmd.arguments[1];
|
||||||
if(sid == 0 && mode != ChatMessageMode::TEXTMODE_SERVER){
|
if(sid == 0 && mode != ChatMessageMode::TEXTMODE_SERVER){
|
||||||
logError("Invalid mode/serverId");
|
handle.response.emplace_back("Invalid mode/serverId");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
debugMessage(LOG_GENERAL,"Chat message mode " + to_string(mode));
|
debugMessage(LOG_GENERAL,"Chat message mode " + to_string(mode));
|
||||||
@ -203,7 +208,7 @@ namespace terminal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(message.empty()){
|
if(message.empty()){
|
||||||
logError("Invalid message!");
|
handle.response.emplace_back("Invalid message!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
message = message.substr(1);
|
message = message.substr(1);
|
||||||
@ -222,7 +227,7 @@ namespace terminal {
|
|||||||
{
|
{
|
||||||
auto channel = server->getChannelTree()->findChannel(cmd.arguments[2].as<ChannelId>());
|
auto channel = server->getChannelTree()->findChannel(cmd.arguments[2].as<ChannelId>());
|
||||||
if(!channel){
|
if(!channel){
|
||||||
logError("Could not resole target channel!");
|
handle.response.emplace_back("Could not resole target channel!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for(const auto &cl : server->getClientsByChannel(channel))
|
for(const auto &cl : server->getClientsByChannel(channel))
|
||||||
@ -233,7 +238,7 @@ namespace terminal {
|
|||||||
{
|
{
|
||||||
ConnectedLockedClient<ConnectedClient> client{server->find_client_by_id(cmd.arguments[2].as<ClientId>())};
|
ConnectedLockedClient<ConnectedClient> client{server->find_client_by_id(cmd.arguments[2].as<ClientId>())};
|
||||||
if(!client){
|
if(!client){
|
||||||
logError("Cloud not find manager from clid");
|
handle.response.emplace_back("Cloud not find manager from clid");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,31 +246,31 @@ namespace terminal {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logError("Invalid chat message mode!");
|
handle.response.emplace_back("Invalid chat message mode!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
logMessage("Chat message successfully send!");
|
handle.response.emplace_back("Chat message successfully send!");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handleCommandPermGrant(TerminalCommand& cmd) {
|
bool handleCommandPermGrant(CommandHandle& handle, TerminalCommand& cmd) {
|
||||||
if(cmd.arguments.size() != 4) {
|
if(cmd.arguments.size() != 4) {
|
||||||
logError("Invalid arguments!");
|
handle.response.emplace_back("Invalid arguments!");
|
||||||
logMessage("Arguments: <ServerId> <GroupId> <Permission Name> <Grant>");
|
handle.response.emplace_back("Arguments: <ServerId> <GroupId> <Permission Name> <Grant>");
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cmd.larguments[0].find_first_not_of("0123456789") != std::string::npos) {
|
if(cmd.larguments[0].find_first_not_of("0123456789") != std::string::npos) {
|
||||||
logError("Invalid server id! (Given number isn't numeric!)");
|
handle.response.emplace_back("Invalid server id! (Given number isn't numeric!)");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(cmd.larguments[1].find_first_not_of("0123456789") != std::string::npos) {
|
if(cmd.larguments[1].find_first_not_of("0123456789") != std::string::npos) {
|
||||||
logError("Invalid group id! (Given number isn't numeric!)");
|
handle.response.emplace_back("Invalid group id! (Given number isn't numeric!)");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(cmd.larguments[3].find_first_not_of("-0123456789") != std::string::npos) {
|
if(cmd.larguments[3].find_first_not_of("-0123456789") != std::string::npos) {
|
||||||
logError("Invalid grant number! (Given number isn't numeric!)");
|
handle.response.emplace_back("Invalid grant number! (Given number isn't numeric!)");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,40 +283,40 @@ namespace terminal {
|
|||||||
groupId = cmd.arguments[1];
|
groupId = cmd.arguments[1];
|
||||||
grant = cmd.arguments[3];
|
grant = cmd.arguments[3];
|
||||||
} catch(const std::exception& ex){
|
} catch(const std::exception& ex){
|
||||||
logError("Could not parse given numbers");
|
handle.response.emplace_back("Could not parse given numbers");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto server = serverInstance->getVoiceServerManager()->findServerById(serverId);
|
auto server = serverInstance->getVoiceServerManager()->findServerById(serverId);
|
||||||
if(!server) {
|
if(!server) {
|
||||||
logError("Could not resolve server!");
|
handle.response.emplace_back("Could not resolve server!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto group = server->getGroupManager()->findGroup(groupId);
|
auto group = server->getGroupManager()->findGroup(groupId);
|
||||||
if(!group) {
|
if(!group) {
|
||||||
logError("Could not resolve server group!");
|
handle.response.emplace_back("Could not resolve server group!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto perm = permission::resolvePermissionData(cmd.larguments[2]);
|
auto perm = permission::resolvePermissionData(cmd.larguments[2]);
|
||||||
if(perm->type == permission::unknown) {
|
if(perm->type == permission::unknown) {
|
||||||
logError("Could not resolve permission!");
|
handle.response.emplace_back("Could not resolve permission!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
group->permissions()->set_permission(perm->type, {0, grant}, permission::v2::do_nothing, permission::v2::set_value);
|
group->permissions()->set_permission(perm->type, {0, grant}, permission::v2::do_nothing, permission::v2::set_value);
|
||||||
logMessage("§aSuccessfully updated grant permissions.");
|
handle.response.emplace_back("§aSuccessfully updated grant permissions.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//meminfo basic
|
//meminfo basic
|
||||||
//memflush buffer
|
//memflush buffer
|
||||||
//memflush alloc
|
//memflush alloc
|
||||||
bool handleCommandMemFlush(TerminalCommand& cmd) {
|
bool handleCommandMemFlush(CommandHandle& handle, TerminalCommand& cmd) {
|
||||||
if(cmd.arguments.size() > 0) {
|
if(cmd.arguments.size() > 0) {
|
||||||
if(cmd.larguments[0] == "db") {
|
if(cmd.larguments[0] == "db") {
|
||||||
if(serverInstance->getSql()->getType() != sql::TYPE_SQLITE) {
|
if(serverInstance->getSql()->getType() != sql::TYPE_SQLITE) {
|
||||||
logMessage("This command just works when you use sqlite!");
|
handle.response.emplace_back("This command just works when you use sqlite!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
logMessage("Memory used by SQLite:");
|
logMessage("Memory used by SQLite:");
|
||||||
@ -384,7 +389,7 @@ namespace terminal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//meminfo track
|
//meminfo track
|
||||||
bool handleCommandMemInfo(TerminalCommand& cmd){
|
bool handleCommandMemInfo(CommandHandle& /* handle */, TerminalCommand& cmd){
|
||||||
bool flag_base = false, flag_malloc = false, flag_track = false, flag_buffer = false;
|
bool flag_base = false, flag_malloc = false, flag_track = false, flag_buffer = false;
|
||||||
|
|
||||||
if(cmd.arguments.size() > 0) {
|
if(cmd.arguments.size() > 0) {
|
||||||
@ -429,18 +434,18 @@ namespace terminal {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handleCommandSpoken(TerminalCommand& cmd) {
|
bool handleCommandSpoken(CommandHandle& /* handle */, TerminalCommand& cmd) {
|
||||||
//TODO print spoken statistics
|
//TODO print spoken statistics
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handleCommandPasswd(TerminalCommand& cmd) {
|
bool handleCommandPasswd(CommandHandle& handle, TerminalCommand& cmd) {
|
||||||
if(cmd.arguments.size() != 2) {
|
if(cmd.arguments.size() != 2) {
|
||||||
logError("Invalid usage: passwd <new_password> <repeated>");
|
handle.response.emplace_back("Invalid usage: passwd <new_password> <repeated>");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(cmd.arguments[0].string() != cmd.arguments[1].string()) {
|
if(cmd.arguments[0].string() != cmd.arguments[1].string()) {
|
||||||
logError("Passwords does not match!");
|
handle.response.emplace_back("Passwords does not match!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,25 +454,25 @@ namespace terminal {
|
|||||||
auto password = "";
|
auto password = "";
|
||||||
logErrorFmt(true, 0, "Creating a new serveradmin query login!");
|
logErrorFmt(true, 0, "Creating a new serveradmin query login!");
|
||||||
if(!(serveradmin = serverInstance->getQueryServer()->create_query_account("serveradmin", 0, "serveradmin", password))) {
|
if(!(serveradmin = serverInstance->getQueryServer()->create_query_account("serveradmin", 0, "serveradmin", password))) {
|
||||||
logError("Could not create serveradmin account!");
|
handle.response.emplace_back("Could not create serveradmin account!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serverInstance->getQueryServer()->change_query_password(serveradmin, cmd.arguments[0]);
|
serverInstance->getQueryServer()->change_query_password(serveradmin, cmd.arguments[0]);
|
||||||
logMessage("Server admin successfully changed!");
|
handle.response.emplace_back("Server admin successfully changed!");
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern bool handleCommandStatsReset(TerminalCommand& cmd) {
|
extern bool handleCommandStatsReset(CommandHandle& handle, TerminalCommand& cmd) {
|
||||||
serverInstance->properties()[property::SERVERINSTANCE_MONTHLY_TIMESTAMP] = 0;
|
serverInstance->properties()[property::SERVERINSTANCE_MONTHLY_TIMESTAMP] = 0;
|
||||||
logMessage("Monthly statistics will be reset");
|
handle.response.emplace_back("Monthly statistics will be reset");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
deque<int> fd_leaks;
|
deque<int> fd_leaks;
|
||||||
bool handleCommandDummyFdFlood(TerminalCommand& cmd) {
|
bool handleCommandDummyFdFlood(CommandHandle& /* handle */, TerminalCommand& cmd) {
|
||||||
size_t value;
|
size_t value;
|
||||||
if(cmd.arguments.size() < 1) {
|
if(cmd.arguments.size() < 1) {
|
||||||
value = 1024;
|
value = 1024;
|
||||||
@ -502,26 +507,26 @@ namespace terminal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool handleCommandReload(TerminalCommand& cmd) {
|
bool handleCommandReload(CommandHandle& handle, TerminalCommand& cmd) {
|
||||||
if(cmd.larguments.size() < 1 || cmd.larguments[0] != "config") {
|
if(cmd.larguments.empty() || cmd.larguments[0] != "config") {
|
||||||
logMessage("Invalid target. Available: config");
|
handle.response.emplace_back("Invalid target. Available:");
|
||||||
return true;
|
handle.response.emplace_back(" - config");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<string> error;
|
vector<string> error;
|
||||||
if(!serverInstance->reloadConfig(error, true)) {
|
if(!serverInstance->reloadConfig(error, true)) {
|
||||||
logError("Failed to reload instance ({}):", error.size());
|
handle.response.emplace_back("Failed to reload instance ({}):", error.size());
|
||||||
for(auto& msg : error)
|
for(auto& msg : error)
|
||||||
logError(" - {}", msg);
|
handle.response.emplace_back(" - " + msg);
|
||||||
} else if(!error.empty()) {
|
} else if(!error.empty()) {
|
||||||
logMessage("Reloaded successfully. Messages:");
|
handle.response.emplace_back("Reloaded successfully. Messages:");
|
||||||
for(auto& msg : error)
|
for(auto& msg : error)
|
||||||
logMessage(" - {}", msg);
|
handle.response.emplace_back(" - " + msg);
|
||||||
} else {
|
} else {
|
||||||
logMessage("Reloaded successfully.");
|
handle.response.emplace_back("Reloaded successfully.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@ -3,8 +3,7 @@
|
|||||||
#include <query/Command.h>
|
#include <query/Command.h>
|
||||||
#include <Error.h>
|
#include <Error.h>
|
||||||
|
|
||||||
namespace terminal {
|
namespace terminal::chandler {
|
||||||
namespace chandler {
|
|
||||||
struct TerminalCommand {
|
struct TerminalCommand {
|
||||||
std::string line;
|
std::string line;
|
||||||
|
|
||||||
@ -15,26 +14,30 @@ namespace terminal {
|
|||||||
std::vector<std::string> larguments;
|
std::vector<std::string> larguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void handleCommand(std::string);
|
struct CommandHandle {
|
||||||
|
std::string command{};
|
||||||
|
std::deque<std::string> response{};
|
||||||
|
};
|
||||||
|
|
||||||
extern bool handleCommandDummyCrash(TerminalCommand&);
|
extern bool handleCommand(CommandHandle& /* command */);
|
||||||
extern bool handleCommandDummyFdFlood(TerminalCommand&);
|
|
||||||
|
|
||||||
extern bool handleCommandHelp(TerminalCommand&);
|
extern bool handleCommandDummyCrash(CommandHandle& /* handle */, TerminalCommand&);
|
||||||
extern bool handleCommandEnd(TerminalCommand&);
|
extern bool handleCommandDummyFdFlood(CommandHandle& /* handle */, TerminalCommand&);
|
||||||
extern bool handleCommandInfo(TerminalCommand&);
|
|
||||||
extern bool handleCommandChat(TerminalCommand&);
|
|
||||||
|
|
||||||
extern bool handleCommandPermGrant(TerminalCommand&);
|
extern bool handleCommandHelp(CommandHandle& /* handle */, TerminalCommand&);
|
||||||
|
extern bool handleCommandEnd(CommandHandle& /* handle */, TerminalCommand&);
|
||||||
|
extern bool handleCommandInfo(CommandHandle& /* handle */, TerminalCommand&);
|
||||||
|
extern bool handleCommandChat(CommandHandle& /* handle */, TerminalCommand&);
|
||||||
|
|
||||||
extern bool handleCommandMemFlush(TerminalCommand&);
|
extern bool handleCommandPermGrant(CommandHandle& /* handle */, TerminalCommand&);
|
||||||
extern bool handleCommandMemInfo(TerminalCommand&);
|
|
||||||
extern bool handleCommandSpoken(TerminalCommand&);
|
|
||||||
|
|
||||||
extern bool handleCommandPasswd(TerminalCommand&);
|
extern bool handleCommandMemFlush(CommandHandle& /* handle */, TerminalCommand&);
|
||||||
|
extern bool handleCommandMemInfo(CommandHandle& /* handle */, TerminalCommand&);
|
||||||
|
extern bool handleCommandSpoken(CommandHandle& /* handle */, TerminalCommand&);
|
||||||
|
|
||||||
extern bool handleCommandStatsReset(TerminalCommand&);
|
extern bool handleCommandPasswd(CommandHandle& /* handle */, TerminalCommand&);
|
||||||
|
|
||||||
extern bool handleCommandReload(TerminalCommand&);
|
extern bool handleCommandStatsReset(CommandHandle& /* handle */, TerminalCommand&);
|
||||||
}
|
|
||||||
|
extern bool handleCommandReload(CommandHandle& /* handle */, TerminalCommand&);
|
||||||
}
|
}
|
243
server/src/terminal/PipedTerminal.cpp
Normal file
243
server/src/terminal/PipedTerminal.cpp
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
//
|
||||||
|
// Created by WolverinDEV on 31/07/2020.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "PipedTerminal.h"
|
||||||
|
#include "CommandHandler.h"
|
||||||
|
|
||||||
|
#include <event.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <log/LogUtils.h>
|
||||||
|
#include <StringVariable.h>
|
||||||
|
|
||||||
|
std::string pipe_path_in{}, pipe_path_out{};
|
||||||
|
|
||||||
|
int file_descriptor_in{0}, file_descriptor_out{0};
|
||||||
|
std::thread event_loop_dispatcher{};
|
||||||
|
::event_base* event_base{nullptr};
|
||||||
|
|
||||||
|
event* event_read{nullptr};
|
||||||
|
event* event_write{nullptr};
|
||||||
|
|
||||||
|
void event_loop_executor(void*);
|
||||||
|
void event_read_callback(int, short, void*);
|
||||||
|
void event_write_callback(int, short, void*);
|
||||||
|
|
||||||
|
void terminal::initialize_pipe(const std::string& pipe_path) {
|
||||||
|
{
|
||||||
|
std::string path;
|
||||||
|
if(pipe_path.empty()) {
|
||||||
|
path = "/tmp/teaspeak_${pid}_${direction}.term";
|
||||||
|
} else {
|
||||||
|
path = pipe_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
pipe_path_in = strvar::transform(path, strvar::StringValue{"pid", std::to_string(getpid())}, strvar::StringValue{"direction", "in"});
|
||||||
|
pipe_path_out = strvar::transform(path, strvar::StringValue{"pid", std::to_string(getpid())}, strvar::StringValue{"direction", "out"});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = mkfifo(pipe_path_in.c_str(), 0666);
|
||||||
|
if(result != 0){
|
||||||
|
logWarning(LOG_INSTANCE, "Failed to create incoming terminal pipe ({}/{})", errno, strerror(errno));
|
||||||
|
finalize_pipe();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_descriptor_in = open(pipe_path_in.c_str(), (unsigned) O_NONBLOCK | (unsigned) O_RDONLY);
|
||||||
|
if(file_descriptor_in <= 0) {
|
||||||
|
logWarning(LOG_INSTANCE, "Failed to open incoming terminal pipe ({}/{})", errno, strerror(errno));
|
||||||
|
finalize_pipe();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = mkfifo(pipe_path_out.c_str(), 0666);
|
||||||
|
if(result != 0){
|
||||||
|
logWarning(LOG_INSTANCE, "Failed to create outgoing terminal pipe ({}/{})", errno, strerror(errno));
|
||||||
|
finalize_pipe();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we can't do a write only open, else along with the O_NONBLOCK we'll get No such device or address */
|
||||||
|
file_descriptor_out = open(pipe_path_out.c_str(), (unsigned) O_NONBLOCK | (unsigned) O_RDWR);
|
||||||
|
if(file_descriptor_out <= 0) {
|
||||||
|
logWarning(LOG_INSTANCE, "Failed to open outgoing terminal pipe ({}/{})", errno, strerror(errno));
|
||||||
|
finalize_pipe();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event_base = event_base_new();
|
||||||
|
if(!event_base) {
|
||||||
|
logWarning(LOG_INSTANCE, "Failed to open terminal pipe ({}/{})", errno, strerror(errno));
|
||||||
|
finalize_pipe();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event_loop_dispatcher = std::thread{event_loop_executor, event_base};
|
||||||
|
event_read = event_new(event_base, file_descriptor_in, (unsigned) EV_READ | (unsigned) EV_PERSIST, event_read_callback, nullptr);
|
||||||
|
event_write = event_new(event_base, file_descriptor_out, EV_WRITE, event_write_callback, nullptr);
|
||||||
|
event_add(event_read, nullptr);
|
||||||
|
|
||||||
|
logMessage(LOG_INSTANCE, "Terminal pipe started (Incoming: {}, Outgoing: {}).", pipe_path_in, pipe_path_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void terminal::finalize_pipe() {
|
||||||
|
if(event_base) {
|
||||||
|
event_base_loopexit(event_base, nullptr);
|
||||||
|
if(event_loop_dispatcher.joinable() && std::this_thread::get_id() != event_loop_dispatcher.get_id())
|
||||||
|
event_loop_dispatcher.join();
|
||||||
|
|
||||||
|
/* events get deleted when the base gets freed */
|
||||||
|
event_read = nullptr;
|
||||||
|
event_write = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(file_descriptor_in > 0) {
|
||||||
|
close(file_descriptor_in);
|
||||||
|
file_descriptor_in = 0;
|
||||||
|
|
||||||
|
remove(pipe_path_in.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(file_descriptor_out > 0) {
|
||||||
|
close(file_descriptor_out);
|
||||||
|
file_descriptor_out = 0;
|
||||||
|
|
||||||
|
remove(pipe_path_out.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void event_loop_executor(void* ptr_event_base) {
|
||||||
|
auto base = (struct event_base*) ptr_event_base;
|
||||||
|
|
||||||
|
while(!event_base_got_exit(base))
|
||||||
|
event_base_loop(base, EVLOOP_NO_EXIT_ON_EMPTY);
|
||||||
|
|
||||||
|
event_base_free(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no buffer lock needed since we're only accessing them via one thread */
|
||||||
|
constexpr static auto kReadBufferSize{8 * 1024};
|
||||||
|
char read_buffer[kReadBufferSize];
|
||||||
|
size_t read_buffer_index{0};
|
||||||
|
|
||||||
|
constexpr static auto kWriteBufferSize{64 * 1024};
|
||||||
|
char write_buffer[kWriteBufferSize];
|
||||||
|
size_t write_buffer_index{0};
|
||||||
|
|
||||||
|
void append_write_buffer(std::string_view message) {
|
||||||
|
if(message.length() > kWriteBufferSize) {
|
||||||
|
logWarning(LOG_INSTANCE, "Trying to write a too long message to the terminal pipe. Truncating {} bytes from the beginning.", message.length() - kWriteBufferSize);
|
||||||
|
message = message.substr(message.length() - kWriteBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(write_buffer_index + message.length() > kWriteBufferSize) {
|
||||||
|
logWarning(LOG_INSTANCE, "Encountering a write buffer overflow. Truncating bytes form the beginning.");
|
||||||
|
|
||||||
|
auto offset = message.length() + write_buffer_index - kWriteBufferSize;
|
||||||
|
if(write_buffer_index > offset) {
|
||||||
|
memcpy(write_buffer, write_buffer + offset, write_buffer_index - offset);
|
||||||
|
write_buffer_index = write_buffer_index - offset;
|
||||||
|
} else {
|
||||||
|
write_buffer_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(write_buffer + write_buffer_index, message.data(), message.length());
|
||||||
|
write_buffer_index += message.length();
|
||||||
|
|
||||||
|
event_add(event_write, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool process_next_command() {
|
||||||
|
auto new_line_index = (char*) memchr(read_buffer, '\n', read_buffer_index);
|
||||||
|
if(!new_line_index) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string command{read_buffer, (size_t) (new_line_index - read_buffer)};
|
||||||
|
if(new_line_index == read_buffer + read_buffer_index) {
|
||||||
|
read_buffer_index = 0;
|
||||||
|
} else {
|
||||||
|
auto length_left = read_buffer_index - (new_line_index - read_buffer + 1);
|
||||||
|
memcpy(read_buffer, new_line_index + 1, length_left);
|
||||||
|
read_buffer_index = length_left;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(command.find_first_not_of(' ') == std::string::npos) {
|
||||||
|
process_next_command();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
logMessage(LOG_INSTANCE, "Dispatching command received via pipe \"{}\".", command);
|
||||||
|
|
||||||
|
terminal::chandler::CommandHandle handle{};
|
||||||
|
handle.command = command;
|
||||||
|
if(!terminal::chandler::handleCommand(handle)) {
|
||||||
|
append_write_buffer("error\n");
|
||||||
|
} else {
|
||||||
|
append_write_buffer("ok\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const auto& line : handle.response)
|
||||||
|
append_write_buffer(line + "\n");
|
||||||
|
|
||||||
|
append_write_buffer("\r\n");
|
||||||
|
append_write_buffer("\r\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void event_read_callback(int fd, short events, void*) {
|
||||||
|
if((unsigned) events & (unsigned) EV_READ) {
|
||||||
|
while(true) {
|
||||||
|
if(kReadBufferSize == read_buffer_index) {
|
||||||
|
logWarning(LOG_INSTANCE, "Terminal pipe line buffer overflow. Flushing buffer.");
|
||||||
|
read_buffer_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto read = ::read(fd, read_buffer + read_buffer_index, kReadBufferSize - read_buffer_index);
|
||||||
|
if(read < 0) {
|
||||||
|
if(errno == EAGAIN) {
|
||||||
|
event_add(event_read, nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logError(LOG_INSTANCE, "Terminal pipe encountered a read error: {}/{}. Closing terminal.", errno, strerror(errno));
|
||||||
|
terminal::finalize_pipe();
|
||||||
|
return;
|
||||||
|
} else if(read == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_buffer_index += read;
|
||||||
|
if(process_next_command())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void event_write_callback(int fd, short events, void*) {
|
||||||
|
if((unsigned) events & (unsigned) EV_WRITE) {
|
||||||
|
while(true) {
|
||||||
|
auto written = ::write(fd, write_buffer, write_buffer_index);
|
||||||
|
if(written < 0) {
|
||||||
|
if(errno == EAGAIN) {
|
||||||
|
event_add(event_write, nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logError(LOG_INSTANCE, "Terminal pipe encountered a write error: {}/{}. Closing terminal.", errno, strerror(errno));
|
||||||
|
terminal::finalize_pipe();
|
||||||
|
return;
|
||||||
|
} else if(written == 0) {
|
||||||
|
return;
|
||||||
|
} else if(written == write_buffer_index) {
|
||||||
|
write_buffer_index = 0;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
memcpy(write_buffer, write_buffer + written, write_buffer_index - written);
|
||||||
|
write_buffer_index -= written;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
server/src/terminal/PipedTerminal.h
Normal file
8
server/src/terminal/PipedTerminal.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace terminal {
|
||||||
|
extern void initialize_pipe(const std::string& /* path */);
|
||||||
|
extern void finalize_pipe();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user