diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d87b1d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/* diff --git a/cli.js b/cli.js new file mode 100644 index 0000000..41a8491 --- /dev/null +++ b/cli.js @@ -0,0 +1,14 @@ +const _ = require('lodash'); +const optimist = require('optimist'); +const options = require('./options'); +const argv = _.reduce(cliOptions, (optimist, option, name) => { + return optimist.options(name, option); +}, optimist); + +if (argv.help) { + optimist.showHelp(); + return; +} + +module.exports = require('smpp').spawnServer(argv); + diff --git a/index.js b/index.js new file mode 100644 index 0000000..1ba8b0a --- /dev/null +++ b/index.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = require('./smpp'); \ No newline at end of file diff --git a/logger.js b/logger.js new file mode 100644 index 0000000..4c92ab9 --- /dev/null +++ b/logger.js @@ -0,0 +1,13 @@ +'use strict'; + +const winston = require('winston'); +const logger = new (winston.Logger)({ + transports: [ + new (winston.transports.Console)({ + json: false, + timestamp: true + }) + ] + }); + +module.exports = logger; diff --git a/options.js b/options.js new file mode 100644 index 0000000..a68dcaf --- /dev/null +++ b/options.js @@ -0,0 +1,29 @@ +module.exports = Object.freeze({ + port: { + default: 2775, + alias: 'p', + describe: 'Port which server listen to.' + }, + ddmin: { + default: 0, + describe: 'Minimum delay after submit_sm requested and deliver_sm request to ESME.' + }, + ddmax: { + default: 0, + describe: 'Maximum delay after submit_sm requested and deliver_sm request to ESME.' + }, + statuses: { + alias: 's', + default: 'delivered', + describe: "Comma separated list of statuses, server send in deliver_sm request to ESME." + }, + auth: { + default: 'user:pass', + describe: 'Comma separated auth credentials in format [system_id]:[password]' + }, + help: { + default: false, + alias: 'h', + describe: 'Current help.' + } +}); \ No newline at end of file diff --git a/package.json b/package.json index f4649b4..84dc4b1 100644 --- a/package.json +++ b/package.json @@ -15,5 +15,11 @@ "bugs": { "url": "https://github.com/lab-coop/fakesmpp/issues" }, - "homepage": "https://github.com/lab-coop/fakesmpp#readme" + "homepage": "https://github.com/lab-coop/fakesmpp#readme", + "dependencies": { + "optimist": "^0.6.1", + "smpp": "^0.2.0", + "strftime": "^0.9.2", + "winston": "^2.2.0" + } } diff --git a/smpp.js b/smpp.js index 56ddfbc..dadb681 100644 --- a/smpp.js +++ b/smpp.js @@ -1,120 +1,105 @@ /** * Fake SMPP. */ -var smpp = require('smpp'); -var winston = require('winston'); -var strftime = require('strftime'); -var optimist = require('optimist'); -var argv = optimist - .options('port', {alias: 'p', default: 2775, describe: 'Port which server listen to.'}) - .options('ddmin', {default: 0, describe: 'Minimum delay after submit_sm requested and deliver_sm request to ESME.'}) // delivery min delay - .options('ddmax', {default: 0, describe: 'Maximum delay after submit_sm requested and deliver_sm request to ESME.'}) // delivery max delay - .options('statuses', {alias: 's', default: 'delivered', describe: "Comma separated list of statuses, server send in deliver_sm request to ESME."}) - .options('auth', {default: 'user:pass', describe: 'Comma separated auth credentials in format [system_id]:[password]'}) - .options('help', {default: false, alias: 'h', describe: 'Current help.'}) - .argv; +const _ = require('lodash'); +const smpp = require('smpp'); +const strftime = require('strftime'); +const optionsDefaults = _.mapValues(require('./options'), 'default'); -if (argv.help) { - optimist.showHelp(); - return; -} +const logger = require('./logger'); +const Statuses = require('./statuses').Statuses; -var Statuses = require('./statuses').Statuses; -// Read auth data -var auth_data = function(str) { - var auth = {}; - str.split(",").map(function(str) { - var l = str.split(":"); - if (l.length > 0 && l[0] != '') { - var val = ""; - var key = l[0]; - if (l.length > 1) { - val = l[1]; - } - auth[key] = val; - } - }); +module.exports = Object.freeze({ + spawnServer +}); + +function spawnServer(argv) { + // You may now use it as a package.json dependency + argv = _.defaults(argv, optionsDefaults); + + // Read auth data + const auth_data = (argv.auth || '').split(',').reduce((auth, str) => { + const pair = str.split(':'); + if (pair.length && pair[0].length) { + auth[pair[0]] = pair[1] || ''; + } return auth; -}(argv.auth); -// Init logger -var logger = new (winston.Logger)({ - transports: [ - new (winston.transports.Console)({ json: false, timestamp: true }) - ]}); + }); -// List of statuses which we iterate in response. -var statuses = new Statuses(argv.statuses.split(','));//.map(function (val) {return val.toUpperCase()})); + // List of statuses which we iterate in response. + var statuses = new Statuses(argv.statuses.split(','));//.map(function (val) {return val.toUpperCase()})); -// Validate options -if (argv.ddmax < argv.ddmin) { - logger.error("ddmin(%d) > ddmax(%d)", argv.ddmin, arg.ddmax); -} + // Validate options + if (argv.ddmax < argv.ddmin) { + logger.error("ddmin(%d) > ddmax(%d)", argv.ddmin, arg.ddmax); + } + const server = smpp.createServer(function(session) { + session.on('bind_transceiver', function(pdu) { + logger.info("bind_transceiver requested.", {system_id: pdu.system_id}); + session.on('submit_sm', function(pdu) { + var msg_received_on = new Date(); + var r = Math.floor(Math.random() * (99 - 10) + 10); + var msg_id = ""+msg_received_on.getTime() + "." + r; + var delivery_delay = getDeliveryDelay(argv.ddmin, argv.ddmax); + logger.info("Msg was received, id=%s assigned.", msg_id, {From: pdu.source_addr, To: pdu.destination_addr, ShortMsg: pdu.short_message.message.toString(), MsgPayload: pdu.message_payload.message.toString(), ScheduleDeliveryTime: pdu.schedule_delivery_time}); + + logger.info("Send submit_sm_resp for id=%s.", msg_id); + session.send(pdu.response({ + message_id: msg_id, + })); -var server = smpp.createServer(function(session) { - session.on('bind_transceiver', function(pdu) { - logger.info("bind_transceiver requested.", {system_id: pdu.system_id}); - session.on('submit_sm', function(pdu) { - var msg_received_on = new Date(); - var r = Math.floor(Math.random() * (99 - 10) + 10); - var msg_id = ""+msg_received_on.getTime() + "." + r; - var delivery_delay = getDeliveryDelay(argv.ddmin, argv.ddmax); - logger.info("Msg was received, id=%s assigned.", msg_id, {From: pdu.source_addr, To: pdu.destination_addr, ShortMsg: pdu.short_message.message.toString(), MsgPayload: pdu.message_payload.message.toString(), ScheduleDeliveryTime: pdu.schedule_delivery_time}); - - logger.info("Send submit_sm_resp for id=%s.", msg_id); - session.send(pdu.response({ - message_id: msg_id, - })); - - // Send request to ESME to confirm delivery - setTimeout(function() { - var status = statuses.next(); - var dr = getDeliveryReceipt(msg_id, status, msg_received_on, new Date(), pdu.short_message.message.toString()); - logger.info("delivery_sm.short_message=%s", dr); - logger.info("Send deliver_sm for id=%d with status.stat=%s, status.err=%s.", msg_id, status.stat, status.err); - session.deliver_sm({ - source_addr: pdu.source_addr, - source_addr_ton: pdu.source_addr_ton, - source_addr_npi: pdu.source_addr_npi, - dest_addr_ton: pdu.dest_addr_ton, - dest_addr_npi: pdu.dest_addr_npi, - destination_addr: pdu.destination_addr, - short_message: dr, - esm_class: smpp.ESM_CLASS.MC_DELIVERY_RECEIPT, - sequence_number: pdu.sequence_number, - }, function(pdu) { - logger.info("deliver_sm_resp received."); - }); - }, delivery_delay); - }); + // Send request to ESME to confirm delivery + setTimeout(function() { + var status = statuses.next(); + var dr = getDeliveryReceipt(msg_id, status, msg_received_on, new Date(), pdu.short_message.message.toString()); + logger.info("delivery_sm.short_message=%s", dr); + logger.info("Send deliver_sm for id=%d with status.stat=%s, status.err=%s.", msg_id, status.stat, status.err); + session.deliver_sm({ + source_addr: pdu.source_addr, + source_addr_ton: pdu.source_addr_ton, + source_addr_npi: pdu.source_addr_npi, + dest_addr_ton: pdu.dest_addr_ton, + dest_addr_npi: pdu.dest_addr_npi, + destination_addr: pdu.destination_addr, + short_message: dr, + esm_class: smpp.ESM_CLASS.MC_DELIVERY_RECEIPT, + sequence_number: pdu.sequence_number, + }, function(pdu) { + logger.info("deliver_sm_resp received."); + }); + }, delivery_delay); + }); - // Availability check - session.on('enquire_link', function(pdu) { - session.send(pdu.response()); - }); - session.on('unbind', function(pdu) { - session.send(pdu.response()); - session.close(); - }); - // we pause the session to prevent further incoming pdu events, - // untill we authorize the session with some async operation. - session.pause(); - checkAsyncUserPass(pdu.system_id, pdu.password, function(err) { - if (err) { - logger.error("bind_transceiver failed. Incorrert credentials."); - session.send(pdu.response({ - command_status: smpp.ESME_RBINDFAIL - })); - session.close(); - return; - } - session.send(pdu.response()); - logger.info("bind_transceiver completed successfully.", {system_id: pdu.system_id}); - session.resume(); - }); + // Availability check + session.on('enquire_link', function(pdu) { + session.send(pdu.response()); + }); + session.on('unbind', function(pdu) { + session.send(pdu.response()); + session.close(); }); -}); -server.listen(argv.port); -logger.info("Server listen port #%d", argv.port); + // we pause the session to prevent further incoming pdu events, + // untill we authorize the session with some async operation. + session.pause(); + checkAsyncUserPass(pdu.system_id, pdu.password, function(err) { + if (err) { + logger.error("bind_transceiver failed. Incorrert credentials."); + session.send(pdu.response({ + command_status: smpp.ESME_RBINDFAIL + })); + session.close(); + return; + } + session.send(pdu.response()); + logger.info("bind_transceiver completed successfully.", {system_id: pdu.system_id}); + session.resume(); + }); + }); + }); + server.listen(argv.port); + logger.info("Server listen port #%d", argv.port); + return server; +} // // Check if system_id with password has access to send messages.