enhanced the sample app code
This commit is contained in:
		| @ -1,60 +1,63 @@ | ||||
| #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); | ||||
|  | ||||
| 	Proto (MainApp* app, QSE::Socket* sck): QSE::Sttp(), app(app), sck(sck) | ||||
| 	{ | ||||
| 		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); | ||||
| 	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); | ||||
| } | ||||
|  | ||||
| 	int sendCmd (const qse_mchar_t* cmd, qse_size_t nargs, ...) | ||||
| int TcpGateProto::sendCmd (const qse_mchar_t* cmd, qse_size_t nargs, ...) | ||||
| { | ||||
| 	int x; | ||||
| 	va_list ap; | ||||
| @ -137,7 +140,7 @@ public: | ||||
| 	return x; | ||||
| } | ||||
|  | ||||
| 	int sendCmd (const qse_wchar_t* cmd, qse_size_t nargs, ...) | ||||
| int TcpGateProto::sendCmd (const qse_wchar_t* cmd, qse_size_t nargs, ...) | ||||
| { | ||||
| 	int x; | ||||
| 	va_list ap; | ||||
| @ -221,67 +224,76 @@ public: | ||||
| 	return x; | ||||
| } | ||||
|  | ||||
| 	int sendErrCmd (ErrorNumber err, const qse_mchar_t* msg) | ||||
| 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, (msg? msg: x(err))); | ||||
| 	return this->sendCmd(CMD_ERR_, 2, buf, 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) | ||||
| 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_WARN, 2, buf, (msg? msg: x(err))); | ||||
| 	return this->sendCmd(CMD_ERR_, 2, buf, (msg? msg: x(err))); | ||||
| } | ||||
|  | ||||
| 	int sendWarnCmd (ErrorNumber err, const qse_wchar_t* msg) | ||||
| 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_WARN), 2, buf, (msg? msg: x(err))); | ||||
| 	return this->sendCmd(QSE_WT(CMD_ERR_), 2, buf, (msg? msg: x(err))); | ||||
| } | ||||
|  | ||||
| 	int sendOkCmd () | ||||
| int TcpGateProto::sendWarnCmd (ErrorNumber err) | ||||
| { | ||||
| 		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); | ||||
| 	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)); | ||||
| } | ||||
|  | ||||
| protected: | ||||
| 	MainApp* app; | ||||
| 	QSE::Socket* sck; | ||||
| 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))); | ||||
| } | ||||
|  | ||||
| 	typedef QSE::HashTable<QSE::String, CmdProc> CmdDict; | ||||
| 	CmdDict cmd_dict; | ||||
| 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 handle_command (const QSE::SttpCmd& cmd) | ||||
| 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)) | ||||
| 	{ | ||||
| @ -330,19 +342,19 @@ protected: | ||||
| 	} | ||||
|  | ||||
| 	CmdDict::Pair* pair = this->cmd_dict.search(cmd.name); | ||||
| 		if (!pair) return this->sendErrCmd(E_ENOENT, "unknown command"); | ||||
| 	if (!pair) return this->sendErrCmd(E_ENOENT, MSG_UNKNOWN_COMMAND_); | ||||
|  | ||||
| 	return (this->*(pair->value))(cmd); | ||||
| } | ||||
|  | ||||
| 	int write_bytes (const qse_uint8_t* data, qse_size_t len) | ||||
| 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 proc_discon (const QSE::SttpCmd& cmd) | ||||
| int TcpGateProto::proc_discon (const QSE::SttpCmd& cmd) | ||||
| { | ||||
| 	PROC_CHECK_ARG_COUNT (cmd, 0); | ||||
|  | ||||
| @ -351,7 +363,7 @@ protected: | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| 	int proc_shtdwn (const QSE::SttpCmd& cmd) | ||||
| int TcpGateProto::proc_shtdwn (const QSE::SttpCmd& cmd) | ||||
| { | ||||
| 	PROC_CHECK_ARG_COUNT_RANGE(cmd, 0, 1); | ||||
| 	int ret = 0; | ||||
| @ -363,7 +375,7 @@ protected: | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| 	int proc_envlst (const QSE::SttpCmd& cmd) | ||||
| int TcpGateProto::proc_envlst (const QSE::SttpCmd& cmd) | ||||
| { | ||||
| 	PROC_CHECK_ARG_COUNT (cmd, 0); | ||||
|  | ||||
| @ -375,14 +387,14 @@ protected: | ||||
| 			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; | ||||
| 			if (this->sendCmd(QSE_T(CMD_ENVITM_), 2, item.name, val) <= -1) return -1; | ||||
| 		 } | ||||
| 	} | ||||
|  | ||||
| 	return this->sendOkCmd(); | ||||
| } | ||||
|  | ||||
| 	int proc_envget (const QSE::SttpCmd& cmd) | ||||
| int TcpGateProto::proc_envget (const QSE::SttpCmd& cmd) | ||||
| { | ||||
| 	PROC_CHECK_ARG_COUNT (cmd, 1); | ||||
|  | ||||
| @ -394,10 +406,10 @@ protected: | ||||
| 	} | ||||
|  | ||||
| noent: | ||||
| 		return this->sendErrCmd(E_ENOENT, (const qse_mchar_t*)QSE_NULL); | ||||
| 	return this->sendErrCmd(E_ENOENT); | ||||
| } | ||||
|  | ||||
| 	int proc_envset (const QSE::SttpCmd& cmd) | ||||
| int TcpGateProto::proc_envset (const QSE::SttpCmd& cmd) | ||||
| { | ||||
| 	PROC_CHECK_ARG_COUNT (cmd, 2); | ||||
|  | ||||
| @ -412,22 +424,72 @@ protected: | ||||
| 	QSE::ScopedMutexLocker sml (this->app->getEnvMutex()); | ||||
| 	if (this->app->getEnv().setValue(name, val) <= -1) | ||||
| 	{ | ||||
| 			return this->sendErrCmd(E_EOTHER, "unable to set value"); | ||||
| 		return this->sendErrCmd(E_EOTHER, MSG_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->opt_autosave && env.store(this->app->getConfFile().getData()) <= -1) // TODO: full path | ||||
| 	{ | ||||
| 			if (this->sendWarnCmd(E_EOTHER, "unable to store") <= -1) return -1; | ||||
| 		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()) | ||||
| 	{ | ||||
|  | ||||
| @ -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: | ||||
|  | ||||
		Reference in New Issue
	
	Block a user