enhanced the sample app code

This commit is contained in:
hyung-hwan 2020-09-15 10:48:14 +00:00
parent d97cb915c5
commit 4d409839e0
2 changed files with 466 additions and 359 deletions

View File

@ -1,433 +1,495 @@
#include "TcpGate.hpp"
#include "MainApp.hpp"
#include <qse/sttp/Sttp.hpp>
#include <qse/cmn/HashTable.hpp>
#include <qse/cmn/ErrorGrab.hpp>
#include <qse/cmn/fmt.h>
// --------------------------------------------------------------------------
#define CMD_OK "OK"
#define CMD_ERR "ERR"
#define CMD_WARN "WARN"
#define CMD_OK_ "OK"
#define CMD_ERR_ "ERR"
#define CMD_WARN_ "WARN"
#define CMD_DISCON "DISCON"
#define CMD_SHTDWN "SHTDWN"
#define CMD_ENVGET "ENVGET"
#define CMD_ENVSET "ENVSET"
#define CMD_ENVLST "ENVLST"
#define CMD_ENVITM "ENVITM"
#define CMD_DISCON_ "DISCON"
#define CMD_SHTDWN_ "SHTDWN"
#define CMD_ENVGET_ "ENVGET"
#define CMD_ENVSET_ "ENVSET"
#define CMD_ENVSAV_ "ENVSAV"
#define CMD_ENVLST_ "ENVLST"
#define CMD_ENVITM_ "ENVITM"
#define CMD_OPTGET_ "OPTGET"
#define CMD_OPTSET_ "OPTSET"
#define MSG_UNABLE_TO_STORE_ "unable to store"
#define MSG_UNABLE_TO_SET_VALUE_ "unable to set value"
#define MSG_UNKNOWN_COMMAND_ "unknown command"
#define PROC_CHECK_ARG_COUNT(cmd,n) do { \
if (cmd.getArgCount() != (n)) { \
this->sendErrCmd (E_ENARGS, (const qse_mchar_t*)QSE_NULL); \
this->sendErrCmd (E_ENARGS); \
return 0; \
} \
} while(0)
#define PROC_CHECK_ARG_COUNT2(cmd,n1,n2) do { \
if (cmd.getArgCount() != (n1) && cmd.getArgCount() != (n2)) { \
this->sendErrCmd (E_ENARGS, (const qse_mchar_t*)QSE_NULL); \
this->sendErrCmd (E_ENARGS); \
return 0; \
} \
} while(0)
#define PROC_CHECK_ARG_COUNT_RANGE(cmd,n1,n2) do { \
if (cmd.getArgCount() < (n1) || cmd.getArgCount() > (n2)) { \
this->sendErrCmd (E_ENARGS, (const qse_mchar_t*)QSE_NULL); \
this->sendErrCmd (E_ENARGS); \
return 0; \
} \
} while(0)
class Proto: public QSE::Sttp
TcpGateProto::TcpGateProto (MainApp* app, QSE::Socket* sck): QSE::Sttp(), app(app), sck(sck), opt_autosave(1)
{
public:
typedef int (Proto::*CmdProc) (const QSE::SttpCmd& cmd);
this->cmd_dict.insert (QSE_T(CMD_DISCON_), &TcpGateProto::proc_discon);
this->cmd_dict.insert (QSE_T(CMD_SHTDWN_), &TcpGateProto::proc_shtdwn);
this->cmd_dict.insert (QSE_T(CMD_ENVLST_), &TcpGateProto::proc_envlst);
this->cmd_dict.insert (QSE_T(CMD_ENVGET_), &TcpGateProto::proc_envget);
this->cmd_dict.insert (QSE_T(CMD_ENVSET_), &TcpGateProto::proc_envset);
this->cmd_dict.insert (QSE_T(CMD_ENVSAV_), &TcpGateProto::proc_envsav);
this->cmd_dict.insert (QSE_T(CMD_OPTGET_), &TcpGateProto::proc_optget);
this->cmd_dict.insert (QSE_T(CMD_OPTSET_), &TcpGateProto::proc_optset);
}
Proto (MainApp* app, QSE::Socket* sck): QSE::Sttp(), app(app), sck(sck)
int TcpGateProto::sendCmd (const qse_mchar_t* cmd, qse_size_t nargs, ...)
{
int x;
va_list ap;
va_start (ap, nargs);
if (QSE_APP_LOG_ENABLED(this->app, QSE_LOG_INFO))
{
this->cmd_dict.insert (QSE_T(CMD_DISCON), &Proto::proc_discon);
this->cmd_dict.insert (QSE_T(CMD_SHTDWN), &Proto::proc_shtdwn);
this->cmd_dict.insert (QSE_T(CMD_ENVLST), &Proto::proc_envlst);
this->cmd_dict.insert (QSE_T(CMD_ENVGET), &Proto::proc_envget);
this->cmd_dict.insert (QSE_T(CMD_ENVSET), &Proto::proc_envset);
}
va_list xap;
int h = (int)this->sck->getHandle();
int sendCmd (const qse_mchar_t* cmd, qse_size_t nargs, ...)
{
int x;
va_list ap;
va_copy (xap, ap);
va_start (ap, nargs);
if (QSE_APP_LOG_ENABLED(this->app, QSE_LOG_INFO))
// ugly - any better way to call QSE_APP_LOGX in a single call? better to store arguments to a buffer first and call QSE_APP_LOGX with it?
switch (nargs)
{
va_list xap;
int h = (int)this->sck->getHandle();
case 0:
QSE_APP_LOG2 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs\n"), h, cmd);
break;
va_copy (xap, ap);
case 1:
QSE_APP_LOG3 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs\n"), h, cmd, va_arg(xap, qse_mchar_t*));
break;
// ugly - any better way to call QSE_APP_LOGX in a single call? better to store arguments to a buffer first and call QSE_APP_LOGX with it?
switch (nargs)
case 2:
{
case 0:
QSE_APP_LOG2 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs\n"), h, cmd);
break;
case 1:
QSE_APP_LOG3 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs\n"), h, cmd, va_arg(xap, qse_mchar_t*));
break;
case 2:
{
qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) };
QSE_APP_LOG4 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs\n"), h, cmd, x[0], x[1]);
break;
}
case 3:
{
qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) };
QSE_APP_LOG5 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2]);
break;
}
case 4:
{
qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) };
QSE_APP_LOG6 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2], x[3]);
break;
}
case 5:
{
qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) };
QSE_APP_LOG7 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2], x[3], x[4]);
break;
}
case 6:
{
qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) };
QSE_APP_LOG8 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5]);
break;
}
case 7:
{
qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) };
QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5], x[6]);
break;
}
default:
{
qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) };
QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs %hs %hs %hs %hs ...\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5], x[6]);
break;
}
qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) };
QSE_APP_LOG4 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs\n"), h, cmd, x[0], x[1]);
break;
}
va_end (xap);
}
x = QSE::Sttp::sendCmdV(cmd, nargs, ap);
va_end (ap);
return x;
}
int sendCmd (const qse_wchar_t* cmd, qse_size_t nargs, ...)
{
int x;
va_list ap;
va_start (ap, nargs);
if (QSE_APP_LOG_ENABLED(this->app, QSE_LOG_INFO))
{
va_list xap;
int h = (int)this->sck->getHandle();
va_copy (xap, ap);
// ugly - any better way to call QSE_APP_LOGX in a single call? better to store arguments to a buffer first and call QSE_APP_LOGX with it?
switch (nargs)
case 3:
{
case 0:
QSE_APP_LOG2 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls\n"), h, cmd);
break;
case 1:
QSE_APP_LOG3 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls\n"), h, cmd, va_arg(xap, qse_wchar_t*));
break;
case 2:
{
qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) };
QSE_APP_LOG4 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls\n"), h, cmd, x[0], x[1]);
break;
}
case 3:
{
qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) };
QSE_APP_LOG5 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2]);
break;
}
case 4:
{
qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) };
QSE_APP_LOG6 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2], x[3]);
break;
}
case 5:
{
qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) };
QSE_APP_LOG7 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2], x[3], x[4]);
break;
}
case 6:
{
qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) };
QSE_APP_LOG8 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5]);
break;
}
case 7:
{
qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) };
QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5], x[6]);
break;
}
default:
{
qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) };
QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls %ls %ls %ls %ls ...\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5], x[6]);
break;
}
qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) };
QSE_APP_LOG5 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2]);
break;
}
va_end (xap);
}
x = QSE::Sttp::sendCmdV(cmd, nargs, ap);
va_end (ap);
return x;
}
int sendErrCmd (ErrorNumber err, const qse_mchar_t* msg)
{
qse_mchar_t buf[32];
qse_fmtintmaxtombs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL);
QSE::TypesErrorNumberToMbstr x;
return this->sendCmd(CMD_ERR, 2, buf, (msg? msg: x(err)));
}
int sendErrCmd (ErrorNumber err, const qse_wchar_t* msg)
{
qse_wchar_t buf[32];
qse_fmtintmaxtowcs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL);
QSE::TypesErrorNumberToWcstr x;
return this->sendCmd(QSE_WT(CMD_ERR), 2, buf, (msg? msg: x(err)));
}
int sendWarnCmd (ErrorNumber err, const qse_mchar_t* msg)
{
qse_mchar_t buf[32];
qse_fmtintmaxtombs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL);
QSE::TypesErrorNumberToMbstr x;
return this->sendCmd(CMD_WARN, 2, buf, (msg? msg: x(err)));
}
int sendWarnCmd (ErrorNumber err, const qse_wchar_t* msg)
{
qse_wchar_t buf[32];
qse_fmtintmaxtowcs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL);
QSE::TypesErrorNumberToWcstr x;
return this->sendCmd(QSE_WT(CMD_WARN), 2, buf, (msg? msg: x(err)));
}
int sendOkCmd ()
{
return this->sendCmd(CMD_OK, 0);
}
int sendOkCmd (const qse_mchar_t* msg1)
{
return this->sendCmd(CMD_OK, 1, msg1);
}
int sendOkCmd (const qse_mchar_t* msg1, const qse_mchar_t* msg2)
{
return this->sendCmd(CMD_OK, 2, msg1, msg2);
}
int sendOkCmd (const qse_wchar_t* msg1)
{
return this->sendCmd(QSE_WT(CMD_OK), 1, msg1);
}
int sendOkCmd (const qse_wchar_t* msg1, const qse_wchar_t* msg2)
{
return this->sendCmd(QSE_WT(CMD_OK), 2, msg1, msg2);
}
protected:
MainApp* app;
QSE::Socket* sck;
typedef QSE::HashTable<QSE::String, CmdProc> CmdDict;
CmdDict cmd_dict;
int handle_command (const QSE::SttpCmd& cmd)
{
if (QSE_APP_LOG_ENABLED(this->app, QSE_LOG_INFO))
{
int h = this->sck->getHandle();
const qse_char_t* name = cmd.name.getData();
// ugly - any better way to call QSE_APP_LOGX in a single call? better to store arguments to a buffer first and call QSE_APP_LOGX with it?
switch (cmd.getArgCount())
case 4:
{
case 0:
QSE_APP_LOG2 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js\n"), h, name);
break;
qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) };
QSE_APP_LOG6 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2], x[3]);
break;
}
case 1:
QSE_APP_LOG3 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js\n"), h, name, cmd.getArgAt(0));
break;
case 5:
{
qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) };
QSE_APP_LOG7 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2], x[3], x[4]);
break;
}
case 2:
QSE_APP_LOG4 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1));
break;
case 6:
{
qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) };
QSE_APP_LOG8 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5]);
break;
}
case 3:
QSE_APP_LOG5 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2));
break;
case 7:
{
qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) };
QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs %hs %hs %hs\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5], x[6]);
break;
}
case 4:
QSE_APP_LOG6 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3));
break;
case 5:
QSE_APP_LOG7 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3), cmd.getArgAt(4));
break;
case 6:
QSE_APP_LOG8 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3), cmd.getArgAt(4), cmd.getArgAt(5));
break;
case 7:
QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3), cmd.getArgAt(4), cmd.getArgAt(5), cmd.getArgAt(6));
break;
default:
QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js %js %js %js ...\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3), cmd.getArgAt(4), cmd.getArgAt(5), cmd.getArgAt(6));
break;
default:
{
qse_mchar_t* x[] = { va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*), va_arg(xap, qse_mchar_t*) };
QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %hs %hs %hs %hs %hs %hs %hs %hs %hs ...\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5], x[6]);
break;
}
}
CmdDict::Pair* pair = this->cmd_dict.search(cmd.name);
if (!pair) return this->sendErrCmd(E_ENOENT, "unknown command");
return (this->*(pair->value))(cmd);
va_end (xap);
}
int write_bytes (const qse_uint8_t* data, qse_size_t len)
x = QSE::Sttp::sendCmdV(cmd, nargs, ap);
va_end (ap);
return x;
}
int TcpGateProto::sendCmd (const qse_wchar_t* cmd, qse_size_t nargs, ...)
{
int x;
va_list ap;
va_start (ap, nargs);
if (QSE_APP_LOG_ENABLED(this->app, QSE_LOG_INFO))
{
int n = this->sck->sendx(data, len, QSE_NULL);
if (QSE_UNLIKELY(n <= -1)) this->setErrorFmt(E_ESYSERR, QSE_T("%js"), sck->getErrorMsg());
return n;
}
va_list xap;
int h = (int)this->sck->getHandle();
int proc_discon (const QSE::SttpCmd& cmd)
{
PROC_CHECK_ARG_COUNT (cmd, 0);
this->sendOkCmd (); // success and failure doesn't matter
sck->shutdown ();
return 0;
}
int proc_shtdwn (const QSE::SttpCmd& cmd)
{
PROC_CHECK_ARG_COUNT_RANGE(cmd, 0, 1);
int ret = 0;
if (cmd.getArgCount() >= 1) ret = qse_strtoi(cmd.getArgAt(0), 0, QSE_NULL);
this->sendOkCmd (); // success and failure doesn't matter
this->app->stop (ret);
return 0;
}
int proc_envlst (const QSE::SttpCmd& cmd)
{
PROC_CHECK_ARG_COUNT (cmd, 0);
va_copy (xap, ap);
// ugly - any better way to call QSE_APP_LOGX in a single call? better to store arguments to a buffer first and call QSE_APP_LOGX with it?
switch (nargs)
{
QSE::ScopedMutexLocker sml (this->app->getEnvMutex());
const MainApp::Env::ItemList& item_list = this->app->getEnv().getItemList();
for (const MainApp::Env::ItemList::Node* np = item_list.getHeadNode(); np; np = np->getNextNode())
case 0:
QSE_APP_LOG2 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls\n"), h, cmd);
break;
case 1:
QSE_APP_LOG3 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls\n"), h, cmd, va_arg(xap, qse_wchar_t*));
break;
case 2:
{
const MainApp::Env::Item& item = np->value;
const qse_char_t* val = this->app->getEnv().getValue(item.name);
QSE_ASSERT (val != QSE_NULL);
if (this->sendCmd(QSE_T(CMD_ENVITM), 2, item.name, val) <= -1) return -1;
}
qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) };
QSE_APP_LOG4 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls\n"), h, cmd, x[0], x[1]);
break;
}
case 3:
{
qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) };
QSE_APP_LOG5 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2]);
break;
}
case 4:
{
qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) };
QSE_APP_LOG6 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2], x[3]);
break;
}
case 5:
{
qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) };
QSE_APP_LOG7 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2], x[3], x[4]);
break;
}
case 6:
{
qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) };
QSE_APP_LOG8 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5]);
break;
}
case 7:
{
qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) };
QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls %ls %ls %ls\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5], x[6]);
break;
}
default:
{
qse_wchar_t* x[] = { va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*), va_arg(xap, qse_wchar_t*) };
QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,R] %ls %ls %ls %ls %ls %ls %ls %ls %ls ...\n"), h, cmd, x[0], x[1], x[2], x[3], x[4], x[5], x[6]);
break;
}
}
return this->sendOkCmd();
va_end (xap);
}
int proc_envget (const QSE::SttpCmd& cmd)
{
PROC_CHECK_ARG_COUNT (cmd, 1);
x = QSE::Sttp::sendCmdV(cmd, nargs, ap);
va_end (ap);
return x;
}
int TcpGateProto::sendErrCmd (ErrorNumber err)
{
qse_mchar_t buf[32];
qse_fmtintmaxtombs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL);
QSE::TypesErrorNumberToMbstr x;
return this->sendCmd(CMD_ERR_, 2, buf, x(err));
}
int TcpGateProto::sendErrCmd (ErrorNumber err, const qse_mchar_t* msg)
{
qse_mchar_t buf[32];
qse_fmtintmaxtombs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL);
QSE::TypesErrorNumberToMbstr x;
return this->sendCmd(CMD_ERR_, 2, buf, (msg? msg: x(err)));
}
int TcpGateProto::sendErrCmd (ErrorNumber err, const qse_wchar_t* msg)
{
qse_wchar_t buf[32];
qse_fmtintmaxtowcs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL);
QSE::TypesErrorNumberToWcstr x;
return this->sendCmd(QSE_WT(CMD_ERR_), 2, buf, (msg? msg: x(err)));
}
int TcpGateProto::sendWarnCmd (ErrorNumber err)
{
qse_mchar_t buf[32];
qse_fmtintmaxtombs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL);
QSE::TypesErrorNumberToMbstr x;
return this->sendCmd(CMD_WARN_, 2, buf, x(err));
}
int TcpGateProto::sendWarnCmd (ErrorNumber err, const qse_mchar_t* msg)
{
qse_mchar_t buf[32];
qse_fmtintmaxtombs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL);
QSE::TypesErrorNumberToMbstr x;
return this->sendCmd(CMD_WARN_, 2, buf, (msg? msg: x(err)));
}
int TcpGateProto::sendWarnCmd (ErrorNumber err, const qse_wchar_t* msg)
{
qse_wchar_t buf[32];
qse_fmtintmaxtowcs(buf, QSE_COUNTOF(buf), err, 10, -1, '\0', QSE_NULL);
QSE::TypesErrorNumberToWcstr x;
return this->sendCmd(QSE_WT(CMD_WARN_), 2, buf, (msg? msg: x(err)));
}
int TcpGateProto::sendOkCmd ()
{
return this->sendCmd(CMD_OK_, 0);
}
int TcpGateProto::sendOkCmd (const qse_mchar_t* msg1)
{
return this->sendCmd(CMD_OK_, 1, msg1);
}
int TcpGateProto::sendOkCmd (const qse_mchar_t* msg1, const qse_mchar_t* msg2)
{
return this->sendCmd(CMD_OK_, 2, msg1, msg2);
}
int TcpGateProto::sendOkCmd (const qse_wchar_t* msg1)
{
return this->sendCmd(QSE_WT(CMD_OK_), 1, msg1);
}
int TcpGateProto::sendOkCmd (const qse_wchar_t* msg1, const qse_wchar_t* msg2)
{
return this->sendCmd(QSE_WT(CMD_OK_), 2, msg1, msg2);
}
int TcpGateProto::handle_command (const QSE::SttpCmd& cmd)
{
if (QSE_APP_LOG_ENABLED(this->app, QSE_LOG_INFO))
{
int h = this->sck->getHandle();
const qse_char_t* name = cmd.name.getData();
// ugly - any better way to call QSE_APP_LOGX in a single call? better to store arguments to a buffer first and call QSE_APP_LOGX with it?
switch (cmd.getArgCount())
{
QSE::ScopedMutexLocker sml (this->app->getEnvMutex());
const qse_char_t* val = this->app->getEnv().getValue(cmd.getArgAt(0));
if (!val) goto noent;
return this->sendOkCmd(val);
}
case 0:
QSE_APP_LOG2 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js\n"), h, name);
break;
noent:
return this->sendErrCmd(E_ENOENT, (const qse_mchar_t*)QSE_NULL);
case 1:
QSE_APP_LOG3 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js\n"), h, name, cmd.getArgAt(0));
break;
case 2:
QSE_APP_LOG4 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1));
break;
case 3:
QSE_APP_LOG5 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2));
break;
case 4:
QSE_APP_LOG6 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3));
break;
case 5:
QSE_APP_LOG7 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3), cmd.getArgAt(4));
break;
case 6:
QSE_APP_LOG8 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3), cmd.getArgAt(4), cmd.getArgAt(5));
break;
case 7:
QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js %js %js %js\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3), cmd.getArgAt(4), cmd.getArgAt(5), cmd.getArgAt(6));
break;
default:
QSE_APP_LOG9 (this->app, QSE_LOG_INFO, QSE_T("[h=%d,Q] %js %js %js %js %js %js %js %js ...\n"), h, name, cmd.getArgAt(0), cmd.getArgAt(1), cmd.getArgAt(2), cmd.getArgAt(3), cmd.getArgAt(4), cmd.getArgAt(5), cmd.getArgAt(6));
break;
}
}
int proc_envset (const QSE::SttpCmd& cmd)
CmdDict::Pair* pair = this->cmd_dict.search(cmd.name);
if (!pair) return this->sendErrCmd(E_ENOENT, MSG_UNKNOWN_COMMAND_);
return (this->*(pair->value))(cmd);
}
int TcpGateProto::write_bytes (const qse_uint8_t* data, qse_size_t len)
{
int n = this->sck->sendx(data, len, QSE_NULL);
if (QSE_UNLIKELY(n <= -1)) this->setErrorFmt(E_ESYSERR, QSE_T("%js"), sck->getErrorMsg());
return n;
}
int TcpGateProto::proc_discon (const QSE::SttpCmd& cmd)
{
PROC_CHECK_ARG_COUNT (cmd, 0);
this->sendOkCmd (); // success and failure doesn't matter
sck->shutdown ();
return 0;
}
int TcpGateProto::proc_shtdwn (const QSE::SttpCmd& cmd)
{
PROC_CHECK_ARG_COUNT_RANGE(cmd, 0, 1);
int ret = 0;
if (cmd.getArgCount() >= 1) ret = qse_strtoi(cmd.getArgAt(0), 0, QSE_NULL);
this->sendOkCmd (); // success and failure doesn't matter
this->app->stop (ret);
return 0;
}
int TcpGateProto::proc_envlst (const QSE::SttpCmd& cmd)
{
PROC_CHECK_ARG_COUNT (cmd, 0);
{
PROC_CHECK_ARG_COUNT (cmd, 2);
const qse_char_t* name = cmd.getArgAt(0);
const qse_char_t* val = cmd.getArgAt(1);
// TODO: session acl?
//if (!this->_login.isRootUser()) return this->sendErrCmd (ERR_EPERM);
MainApp::Env& env = this->app->getEnv();
QSE::ScopedMutexLocker sml (this->app->getEnvMutex());
if (this->app->getEnv().setValue(name, val) <= -1)
const MainApp::Env::ItemList& item_list = this->app->getEnv().getItemList();
for (const MainApp::Env::ItemList::Node* np = item_list.getHeadNode(); np; np = np->getNextNode())
{
return this->sendErrCmd(E_EOTHER, "unable to set value");
}
const qse_char_t* v = env.getValue(name);
QSE_ASSERT (v != QSE_NULL);
if (env.store(this->app->getConfFile().getData()) <= -1) // TODO: full path
{
if (this->sendWarnCmd(E_EOTHER, "unable to store") <= -1) return -1;
}
return this->sendOkCmd(v);
const MainApp::Env::Item& item = np->value;
const qse_char_t* val = this->app->getEnv().getValue(item.name);
QSE_ASSERT (val != QSE_NULL);
if (this->sendCmd(QSE_T(CMD_ENVITM_), 2, item.name, val) <= -1) return -1;
}
}
};
return this->sendOkCmd();
}
int TcpGateProto::proc_envget (const QSE::SttpCmd& cmd)
{
PROC_CHECK_ARG_COUNT (cmd, 1);
{
QSE::ScopedMutexLocker sml (this->app->getEnvMutex());
const qse_char_t* val = this->app->getEnv().getValue(cmd.getArgAt(0));
if (!val) goto noent;
return this->sendOkCmd(val);
}
noent:
return this->sendErrCmd(E_ENOENT);
}
int TcpGateProto::proc_envset (const QSE::SttpCmd& cmd)
{
PROC_CHECK_ARG_COUNT (cmd, 2);
const qse_char_t* name = cmd.getArgAt(0);
const qse_char_t* val = cmd.getArgAt(1);
// TODO: session acl?
//if (!this->_login.isRootUser()) return this->sendErrCmd (ERR_EPERM);
MainApp::Env& env = this->app->getEnv();
QSE::ScopedMutexLocker sml (this->app->getEnvMutex());
if (this->app->getEnv().setValue(name, val) <= -1)
{
return this->sendErrCmd(E_EOTHER, MSG_UNABLE_TO_SET_VALUE_);
}
const qse_char_t* v = env.getValue(name);
QSE_ASSERT (v != QSE_NULL);
if (this->opt_autosave && env.store(this->app->getConfFile().getData()) <= -1) // TODO: full path
{
if (this->sendWarnCmd(E_EOTHER, MSG_UNABLE_TO_STORE_) <= -1) return -1;
}
return this->sendOkCmd(v);
}
int TcpGateProto::proc_envsav (const QSE::SttpCmd& cmd)
{
PROC_CHECK_ARG_COUNT (cmd, 0);
// TODO: session acl?
//if (!this->_login.isRootUser()) return this->sendErrCmd (ERR_EPERM);
MainApp::Env& env = this->app->getEnv();
QSE::ScopedMutexLocker sml (this->app->getEnvMutex());
if (env.store(this->app->getConfFile().getData()) <= -1)
{
return this->sendWarnCmd(E_EOTHER, MSG_UNABLE_TO_STORE_);
}
return this->sendOkCmd();
}
int TcpGateProto::proc_optget (const QSE::SttpCmd& cmd)
{
PROC_CHECK_ARG_COUNT (cmd, 1);
const qse_char_t* k = cmd.getArgAt(0);
if (qse_strcasecmp(k, QSE_T("AUTOSAVE")) == 0)
{
qse_mchar_t tmp[32];
qse_mbsxfmt(tmp, QSE_COUNTOF(tmp), "%d", this->opt_autosave);
return this->sendOkCmd(tmp);
}
return this->sendErrCmd(E_EINVAL);
}
int TcpGateProto::proc_optset (const QSE::SttpCmd& cmd)
{
PROC_CHECK_ARG_COUNT (cmd, 2);
const qse_char_t* k = cmd.getArgAt(0);
const qse_char_t* v = cmd.getArgAt(1);
if (qse_strcasecmp(k, QSE_T("AUTOSAVE")) == 0)
{
this->opt_autosave = qse_strtoi(v, 10, QSE_NULL);
}
else
{
return this->sendErrCmd(E_EINVAL);
}
return this->sendOkCmd();
}
// --------------------------------------------------------------------------
@ -451,7 +513,7 @@ int TcpGate::handle_connection (Connection* connection)
connection->address.toStrBuf(addrbuf, QSE_COUNTOF(addrbuf));
Proto proto (this->app, &connection->socket);
TcpGateProto proto(this->app, &connection->socket);
while (!this->isHaltRequested())
{

View File

@ -3,9 +3,54 @@
#include <qse/si/TcpServer.hpp>
#include <qse/cmn/String.hpp>
#include <qse/cmn/HashTable.hpp>
#include <qse/sttp/Sttp.hpp>
class MainApp;
class TcpGateProto: public QSE::Sttp
{
public:
typedef int (TcpGateProto::*CmdProc) (const QSE::SttpCmd& cmd);
TcpGateProto (MainApp* app, QSE::Socket* sck);
int sendCmd (const qse_mchar_t* cmd, qse_size_t nargs, ...);
int sendCmd (const qse_wchar_t* cmd, qse_size_t nargs, ...);
int sendErrCmd (ErrorNumber err);
int sendErrCmd (ErrorNumber err, const qse_mchar_t* msg);
int sendErrCmd (ErrorNumber err, const qse_wchar_t* msg);
int sendWarnCmd (ErrorNumber err);
int sendWarnCmd (ErrorNumber err, const qse_mchar_t* msg);
int sendWarnCmd (ErrorNumber err, const qse_wchar_t* msg);
int sendOkCmd ();
int sendOkCmd (const qse_mchar_t* msg1);
int sendOkCmd (const qse_mchar_t* msg1, const qse_mchar_t* msg2);
int sendOkCmd (const qse_wchar_t* msg1);
int sendOkCmd (const qse_wchar_t* msg1, const qse_wchar_t* msg2);
protected:
MainApp* app;
QSE::Socket* sck;
typedef QSE::HashTable<QSE::String, CmdProc> CmdDict;
CmdDict cmd_dict;
int opt_autosave;
int handle_command (const QSE::SttpCmd& cmd);
int write_bytes (const qse_uint8_t* data, qse_size_t len);
int proc_discon (const QSE::SttpCmd& cmd);
int proc_shtdwn (const QSE::SttpCmd& cmd);
int proc_envlst (const QSE::SttpCmd& cmd);
int proc_envget (const QSE::SttpCmd& cmd);
int proc_envset (const QSE::SttpCmd& cmd);
int proc_envsav (const QSE::SttpCmd& cmd);
int proc_optget (const QSE::SttpCmd& cmd);
int proc_optset (const QSE::SttpCmd& cmd);
};
class TcpGate: public QSE::TcpServer, public QSE::Thread
{
public: