|
Home Resources Products
Developers |
Main • Messages
Messages are the main piece of Yate. We use them between modules insted of using functions. We do this mainly because if one module is changing we don't have to change all the other modules that are dependent, and also because we can debug what's happening in the engine much easier since we know which module passes which data to another module. A message is a holder for several components:
All the messages are binary inside of yate. However you can use rmanager to get them out in a human readable form. The messages are passed using memory sharing. In this way we have a pretty optimized system. Other options like pipes or sockets have been considered, but failed to give us the flexibility and speed needed. When passed to external modules the messages are converted to an escaped string encoding that allows handling any special characters that may be present in the message's components. Please see the documentation on external module for details. Messages are processed by message handlers. These receive messages whose names match the handler's name. They can freely modify the message's components (parameters, returned value, even the name) and finally they can stop processing the message or let it slip to the next handler. The order in which handlers are called to attempt to process a message is established when the handlers are inserted in the dispatcher. The ordering of handlers is by their priority, a handler with a lower numerical priority is inserted earlier in list and receives the message before a handler with a higher numerical priority. There is NO GUARANTEE about the order between handlers of equal priority although currently the following rules apply:
A very good example about how the message system works is the "call.route" message: Message *m = new Message("call.route");
m->addParam("driver","iax");
if (e->ies.calling_name)
m->addParam("callername",e->ies.calling_name);
else
m->addParam("callername",e->session->callerid);
if (e->ies.called_number)
m->addParam("called",e->ies.called_number);
else
m->addParam("called",e->session->dnid);
Then we send the message to the Engine and we find out if some module did actually accept to handle it. We must also destruct the message.
if (Engine::dispatch(m))
Output("Routing returned: %s",m->retValue().c_str());
else
Output("Nobody routed the call!");
m->destruct();
The Engine is getting the above message and is sending it to all the modules that have registered a "route" handler. It is also possible to fire-and-forget messages. They are stored in a queue in the engine and dispatched later in threads that belong to the engine. Once such a message is dispatched it is destroyed by the engine.
Message *m = new Message("alert");
m->addParam("reason","Hardware malfunction");
Engine::enqueue(m);
To handle a route request (probably in another module) we first have to declare a class RouteHandler derived from MessageHandler.
class RouteHandler : public MessageHandler
{
public:
RouteHandler(int prio)
: MessageHandler("call.route",prio) { }
virtual bool received(Message &msg);
};
Then, because the received method is a pure virtual in the MessageHandler class, we must override it.
bool RouteHandler::received(Message &msg)
{
const char *driver = msg.getValue("driver")
Debug(DebugInfo,"Route for driver %s",driver);
// don't actually route anything, let message continue
return false;
}
And finally, in the plugin initialized method we can install the handler. m_route = new RouteHandler(priority); Engine::install(m_route); To get more references about messages read the Message class documentation at API::Message |
3 May 2010: 8 March 2010: 6-7 February 2010: 2 Nov 2009: 6 Aug 2008: 4 Aug 2008: 10 Jul 2008: Feb 2008: 21 Jan 2008: 3 September: 14 August: 16 April: 25 September: 25 September: 11 July 2006: 10 July 2006: June 1st 2006: |