onem2m_client
Version:
Synctechno's Library for communicating with Mobius on KETI through oneM2M platform
257 lines (212 loc) • 6.93 kB
JavaScript
module.exports = function(CONFIG) {
var Mqtt, MqttClients, Uuid, _, util, debug, onem2mModel;
Mqtt = require('mqtt');
Uuid = require('uuid');
_ = require('lodash');
util = require('util');
debug = require('debug')('keti');
onem2mModel = require('./onem2m-model.js');
MqttClients = {};
var MqttClient = function(mqttServerAddress, from) {
var thisObj = this;
thisObj.mqttServerAddress = mqttServerAddress;
thisObj.from = from;
thisObj.eventHandlers = [];
thisObj.mqttClient = Mqtt.connect(mqttServerAddress);
thisObj.mqttClient.on('connect', function () {
mqttSubscribe(thisObj.mqttClient, from);
});
thisObj.mqttClient.on('message', mqttMessageHandler);
/**
*
* @param {*} mqttClient
* @param {String} origin
*/
function mqttSubscribe(mqttClient, origin) {
/*
SPEC: TS-0010-V2.4.1 MQTT Protocol Binding
6.4.2 Sending a Request
/oneM2M/req/<originator>/<receiver>/<type>
- <receiver> is the SP-relative-AE-ID or SP-relative-CSE-ID of the Receiver (AE, Transit CSE or Hosting
CSE) on this hop, omitting any leading
*/
var aeTopicName = origin;
// if SP-relative-AE-ID or SP-relative-CSE-ID
if( aeTopicName.startsWith("/") ) {
aeTopicName = aeTopicName.substring(1);
}
aeTopicName = aeTopicName.replace('/', ':');
// subscribe onem2m requet topic
var reqTopic = util.format('/oneM2M/req/+/%s/#', aeTopicName);
debug( 'SUBSCRIBE MQTT : ' + reqTopic );
mqttClient.subscribe(reqTopic);
}
function mqttMessageHandler(topic, message) {
debug(topic + " :: " + message );
var topicArray = topic.split('/');
var topicFrom = topicArray[3];
var topicTo = topicArray[4];
var topicParams = topicArray.splice(5);
// mqtt req primitive param changed on Mobius 2.0
var mesgObj = null;
try {
mesgObj = JSON.parse(message.toString());
}
catch(ex) {
debug(ex);
}
if(mesgObj == null)
return;
var primitiveParameters = null;
if( !mesgObj['m2m:rqp'] ) // message가 request primitive인 경우만 처리
primitiveParameters = mesgObj;
else
primitiveParameters = mesgObj['m2m:rqp'];
//var primitiveParameters = mesgObj['m2m:rqp'];
var operation = primitiveParameters['op'];
var to = primitiveParameters['to'];
var from = primitiveParameters['fr'];
var reqId = primitiveParameters['rqi'];
if( operation != '5' ) // notification operation만 처리
return;
var notiEventType = primitiveParameters['net'];
var primitiveContent = primitiveParameters['pc'];
if(typeof(notiEventType) == 'string'){
primitiveContent.notiEventType = parseInt(notiEventType);
}
var handler = thisObj.eventHandlers['notification'];
if( handler ) {
var handled = handler(thisObj.mqttServerAddress, topicTo, topicParams, notiEventType, primitiveContent);
// var handled = handler(thisObj.mqttServerAddress, primitiveContent);
if(handled) {
// publish response
var respObj = {
'm2m:rsp': {
'rsc': '2000',
'to': '',
'fr': thisObj.from,
'rqi': reqId,
'pc': ''
}
};
var respTopic = "/oneM2M/resp/" + topicFrom + "/" + topicTo + "/json";
thisObj.mqttClient.publish(respTopic, JSON.stringify(respObj));
}
}
}
};
/**
* @typedef {Object} mqttHandleData
* @property {String} representation
* - nev/rep
* @property {Number|String} notiEventType
* - 1 : resource's infomation was modified
* - 2 : resource was removed
* - 3 : resource's child was created
* - 4 : resource's cihld was removed
* @property {Number|String} resourceType
* @property {String} resourcePath
* @property {Number|String} resourceTypeCode
* - 1 AccessControlPolicy(ACP)
* - 2 AE
* - 3 Container(CNT)
* - 4 ContentInstance(CIN)
* - 5 CSEBase
* - 6 Delivery
* - 7 EventConfig
* - 8 ExecInstance
* - 9 FanOutPoint
* - 10 Group
* - 11 LocalPolicy
* - 12 M2mServiceSubscription
* - 13 MgmtCmd
* - 14 MgmtObj
* - 15 Node
* - 16 NodeInfo
* - 17 PollingChannel
* - 18 RemoteCSE
* - 19 Request
* - 20 Schedule
* - 21 StatsCollect
* - 22 StatsConfig
* - 23 Subscription
* @property {Object} resource
*/
/**
* This callback is displayed as a global member.
* @callback mqttCallback
* @param {String} mqttAddress
* @param {String} topicTo
* @param {String} topicParams
* @param {Number} notiEventType
* @param {mqttHandleData} primitiveContent
* */
/**
* @param {string} event EnventName
* @param {mqttCallback} mqttCallback
*/
MqttClient.prototype.on = function(event, mqttCallback) {
this.eventHandlers[event] = function(mqttServerAddress, topicTo, topicParams, notiEventType, primitiveContent){
try{
var sgn = primitiveContent['sgn'] || primitiveContent['m2m:sgn'];
if(sgn.vrq) {
return;
}
var data = {};
data.representation = sgn.nev.rep;
data.notiEventType = sgn.net||sgn.nev.net;
data.resourceType = _.keys(data.representation)[0];
data.resourcePath = sgn.sur;
data.resource = sgn.nev.rep[data.resourceType];
data.resourceTypeCode = onem2mModel.Resource.getTypeCode(data.resourceType);
return mqttCallback(mqttServerAddress, topicTo, topicParams, notiEventType, data);
}catch(err){
console.error(err);
}
};
}
MqttClient.prototype.off = function(event, handler) {
if(this.eventHandlers[event])
delete this.eventHandlers[event];
}
return {
getClient: getClient,
Disconnect: Disconnect,
Subscribe: Subscribe,
Unsubscribe: Unsubscribe
};
/**
*
* @param {string} to mqttAddress
* @param {string} from
* @returns {MqttClient}
*/
function getClient(to, from) {
if( !(from && to) )
return null;
var mqttServerAddress = '';
if( to.startsWith('mqtt://') )
mqttServerAddress = to;
else
mqttServerAddress = 'mqtt://' + to;
if( ! MqttClients[mqttServerAddress] ) {
MqttClients[mqttServerAddress] = new MqttClient(mqttServerAddress, from);
}
return MqttClients[mqttServerAddress];
}
/**
* @method Disconnect this feature isn't ready
* @param {string} from
*/
function Disconnect(from) {}
/**
* @method Subscribe this feature isn't ready
* @param {string} topic
*/
function Subscribe(topic) {}
/**
* @method Unsubscribe this feature isn't ready
* @param {string} topic
*/
function Unsubscribe(topic) {}
}