For quite some time, EMG has supported customer specific functionality in plugins, written in C or Perl. They are very useful, but have some problems. When the plugin is written in C, performance is high, but the memory management can be tricky. With Perl, the code becomes simpler. However, if the implementation is modified, the EMG server must be restarted. Furthermore, both C and Perl are run within the emgd process, which is good for performance. In order to support any additional languages, a new interface would have to be added to EMG. This can be both complex and time consuming. Starting with EMG version 7.2.4, EMG is taking a small step towards microservices. In a PLUGIN section, there is therefore now support for a new option called “URL”. The value of this option is the base address to a server supporting one or more plugin calls.
Having the plugins running in a separate process brings several advantages.
- The plugin server can be written in any language, as long as it can provide an interface over HTTP.
- The plugin server can be restarted at any point, without disturbing EMG.
- As multiple plugins can be served from the same server, it is trivial to share code between them.
- It is easy to see whether a high CPU load is caused by EMG or a plugin.
- The plugin server can run a separate machine, further increasing the scalability.
- A long running plugin can not cause any issues for the main emgd process. Previously “emgd -reload” and “emgd -stop” were blocked until all plugins had completed.
The added network roundtrip obviously results in a slightly longer response times back to clients, but this can be mitigated to some degree by using multiple plugin instances. There is however no point in configuring more instances than what the plugin server can handle.
Request / response
For each plugin call, the plugin function name is appended to the base URL. The usual set of plugin hooks are supported:
- /before_receive
- /route
- /before_route (only for connector with PROTOCOL=ROUTE)
- /before_send
- /after_send
- /before_dlr
- /after_dlr
The data sent to the plugin is formatted in JSON, and sent in a POST request.
For a node.js application, the data will be available in the req.body object, in the following fields.
name | description |
---|---|
ccarg | from PLUGIN=pluginname:ccarg of the current connector |
qe | message or delivery report, with field names in uppercase |
result | for /after_send and /after_dlr |
dlrinfo | custom options for incoming delivery reports, only used for the /before_dlr hook |
route | as returned by the previously called plugin |
connector | information about the current connector instance |
connectors | the full list of defined connectors, optionally limited by the ones mentioned by the CONNECTORS plugin option |
groups | the full list of defined connector groups |
To return data from the plugin, it should be formatted as KEY=VALUE pairs, one per line.
name | description |
---|---|
result | for /before_receive, where non-zero means the message will be rejected |
route | the name of the outgoing connector or connector group, used for the /route endpoint |
qe.OPTION_NAME | new value for a message option called “OPTION_NAME” |
dlrinfo.OPTION_NAME | for /before_dlr, to return HLR lookup results: OPTION_NAME can be mnc, mcc, msc, and imsi |
EMG will try each plugin endpoint as needed. If the endpoint is not supported and HTTP status 404 is returned, it is blocked from further calls. This is reset when emgd is restarted, or when the EMG configuration is reloaded.
Example in node.js
As an example, there is a small implementation written in node.js. A node.js server is single threaded, so there are no issues with sharing data between parallel requests. It is also asynchronous, processing other requests when one is waiting for I/O. This makes it ideal for this type of work, where data often needs to be fetched from a database or some other HTTP based server.
To use it, the following steps are required.
- Install git and npm: yum install git npm
- Open a web browser at https://bitbucket.org/infoflexconnect/pluginservice.
- Download the Git repository, using the “clone” command on the BitBucket page.
- Change directory to the downloaded respository.
- Install the node modules: npm install
- If needed, update the port number in bin/www.
- Add a PLUGIN section in the server.cfg file, with URL pointing to the node server.
- Start the node server: npm run
The node module “nodemon” can be used to automatically restart the server when one of the files are modified. This can simplify the development process when implementing a new plugin.