Add the initCall TCL function in a generic way

The EventHandler now have a function called addCommand that can be used
by a logic core to add TCL commands that are specific for that logic
core. That mean that the EventHandler does no longer have to be modified
to add custom TCL commands.
This commit is contained in:
Tobias Blomberg 2022-08-05 18:33:57 +02:00
parent a229559963
commit 1ec6dca463
4 changed files with 66 additions and 29 deletions

View File

@ -151,7 +151,6 @@ EventHandler::EventHandler(const string& event_script, const string& logic_name)
Tcl_CreateCommand(interp, "injectDtmf", injectDtmfHandler, this, NULL);
Tcl_CreateCommand(interp, "setConfigValue", setConfigValueHandler,
this, NULL);
Tcl_CreateCommand(interp, "initCall", initCallHandler, this, NULL);
setVariable("script_path", event_script);
@ -191,6 +190,16 @@ bool EventHandler::initialize(void)
} /* EventHandler::initialize */
void EventHandler::addCommand(const std::string& name, CommandHandler f)
{
Tcl_CreateCommand(interp, name.c_str(), genericCommandHandler,
new CommandHandler(f),
[](ClientData cdata) {
delete static_cast<CommandHandler*>(cdata);
});
} /* EventHandler::addCommand */
void EventHandler::setVariable(const string& name, const string& value)
{
if (interp == 0)
@ -465,24 +474,21 @@ int EventHandler::setConfigValueHandler(ClientData cdata, Tcl_Interp *irp,
} /* EventHandler::setConfigValueHandler */
int EventHandler::initCallHandler(ClientData cdata, Tcl_Interp *irp, int argc,
const char *argv[])
int EventHandler::genericCommandHandler(ClientData cdata, Tcl_Interp *irp,
int argc, const char *argv[])
{
if(argc != 2)
const auto& func = *static_cast<CommandHandler*>(cdata);
std::string msg = func(argc, argv);
if (!msg.empty())
{
static char msg[] = "Usage: initCall: <phone number>";
Tcl_SetResult(irp, msg, TCL_STATIC);
auto msg_alloc_len = msg.size()+1;
char* msg_copy = Tcl_Alloc(msg_alloc_len);
memcpy(msg_copy, msg.c_str(), msg_alloc_len);
Tcl_SetResult(irp, msg_copy, TCL_DYNAMIC);
return TCL_ERROR;
}
//cout << "EventHandler::playFile: " << argv[1] << endl;
EventHandler *self = static_cast<EventHandler *>(cdata);
string phonenumber(argv[1]);
self->initCall(phonenumber);
return TCL_OK;
}
} /* EventHandler::genericCommandHandler */
/*

View File

@ -113,6 +113,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
class EventHandler : public sigc::trackable
{
public:
using CommandHandler = std::function<std::string(int argc, const char *argv[])>;
/**
* @brief Constuctor
*/
@ -128,7 +130,34 @@ class EventHandler : public sigc::trackable
* @return Returns \em true on success or else \em false
*/
bool initialize(void);
/**
* @brief Add a custom command to the event handler
* @param name The name of the command
* @param f The handler function
* @return Return empty string on success or else an error string
*
* This is an example of how to add a TCL event handler command that take
* one argument. The example use a lambda function but other methods
* compatible with std::function may be used as well.
*
* event_handler->addCommand("demoCommand",
* [&](int argc, const char* argv[])
* {
* if (argc != 2)
* {
* return std::string("Usage: demoCommand: <arg1>");
* }
* std::cout << "### demoCommand(" << argv[1] << ")" << std::endl;
* return std::string();
* });
*
* It would be executed in TCL like this:
*
* demoCommand "hello"
*/
void addCommand(const std::string& name, CommandHandler f);
/**
* @brief Set a TCL variable
* @param name The name of the variable to set
@ -236,14 +265,6 @@ class EventHandler : public sigc::trackable
sigc::signal<void, const std::string&, const std::string&,
const std::string&> setConfigValue;
/**
* @brief A signal that is emitted when the TCL script want to call
* a sip user
* @param The phone number of the user
*/
sigc::signal<void, const std::string&> initCall;
protected:
private:
@ -269,7 +290,7 @@ class EventHandler : public sigc::trackable
int argc, const char *argv[]);
static int setConfigValueHandler(ClientData cdata, Tcl_Interp *irp,
int argc, const char *argv[]);
static int initCallHandler(ClientData cdata, Tcl_Interp *irp,
static int genericCommandHandler(ClientData cdata, Tcl_Interp *irp,
int argc, const char *argv[]);
}; /* class EventHandler */

View File

@ -749,7 +749,10 @@ bool SipLogic::initialize(void)
logic_event_handler->playSilence.connect(mem_fun(*this, &SipLogic::playLogicSilence));
logic_event_handler->playTone.connect(mem_fun(*this, &SipLogic::playLogicTone));
logic_event_handler->playDtmf.connect(mem_fun(*this, &SipLogic::playLogicDtmf));
logic_event_handler->initCall.connect(mem_fun(*this, &SipLogic::initCall));
using namespace std::placeholders;
logic_event_handler->addCommand("initCall",
std::bind(&SipLogic::initCallHandler, this, _1, _2));
logic_event_handler->processEvent("namespace eval " + name() + " {}");
if (!logic_event_handler->initialize())
@ -843,10 +846,17 @@ bool SipLogic::initialize(void)
*
****************************************************************************/
void SipLogic::initCall(const string& remote)
std::string SipLogic::initCallHandler(int argc, const char* argv[])
{
makeCall(acc, remote);
} /* SipLogic::initCall */
if (argc != 2)
{
return std::string("Usage: initCall: <phone number>");
}
std::string phonenumber(argv[1]);
//std::cout << "### initCall(" << phonenumber << ")" << std::endl;
makeCall(acc, phonenumber);
return std::string();
} /* SipLogic::initCallHandler */
void SipLogic::allMsgsWritten(void)

View File

@ -167,7 +167,7 @@ class SipLogic : public LogicBase
protected:
virtual void allMsgsWritten(void);
virtual void initCall(const std::string& remote);
std::string initCallHandler(int argc, const char* argv[]);
void checkIdle(void);
private: