GB28181学习笔记5 给前面应用添加restful接口

一、说明

为了让之前的应用功能更完善 , 这里添加一个restful接口。

项目结构:
在这里插入图片描述

二、项目依赖:

  "dependencies": {
    "express": "^4.17.1",
    "fast-xml-parser": "^3.17.2",
    "log4js": "^6.3.0",
    "log4js-extend": "^0.2.1",
    "sip": "0.0.6",
    "xml2js": "^0.4.23"
  }

三、实现

1. http接口代码:

sip_app.js

const express     = require('express');
const app         = express();
const config      = require('./sip_config');
const sip_server  = require('./sip_server');
const log4js= require('./sip_log');
const logger = log4js.getLogger('request');

// 设置express日志
log4js.useLogger(app,logger)

/**
 * 获取设备列表的接口
 */
app.get('/api/v1/device/list', function (req, res) {
   res.send(config.registry);
});
/**
 * TODO:请求视频
 */
app.get('/api/v1/device/invite', function (req, res) {

});

/**
 * 启动http服务
 */ 
var server = app.listen(config.http.port, function () {
  var host = server.address().address
  var port = server.address().port
  logger.info("启动GB28181_Node_Http服务: http://%s:%s", host, port)
});
/**
 * 启动gb28181服务
 */
sip_server.start();

这里使用express实现http功能。

2. sip_config.js配置文件

/**
 * 配置文件
 */
var config={
    // 设备信息
    registry : {
        '34020000001110000001'  : { password : '12345678', online:false}
    },
    device:{
        // 设备登陆密码
        password:'tang3shan'
    },
    http:{
        port:8777
    },
    sip:{
       server:{
           port : 5060,
           realm: '3402000000'
       } 
    },
    logger:{
        path:'./sip.log'
    }
};

module.exports=config;

3. log4js 设置

为了方便记录日志,将log4js进行单独配置:

const log4js = require('log4js')

/**
 * log4js配置
 */
log4js.configure({
    replaceConsole: true,
    appenders: {
        // 控制台输出
        stdout: {
            type: 'stdout'
        },
        // express请求日志
        request: {
            type    : 'dateFile',
            filename: 'logs/request/',
            pattern : 'request-yyyy-MM-dd.log',
            alwaysIncludePattern: true
        },
        // 错误日志
        error: {
            type    : 'dateFile',
            filename: 'logs/error/',
            pattern : 'error-yyyy-MM-dd.log',
            alwaysIncludePattern: true
        },
        // 普通日志
        info: {
            type    : 'dateFile',
            filename: 'logs/info/',
            pattern : 'info-yyyy-MM-dd.log',
            alwaysIncludePattern: true
        }
    },
    categories: {
        // appenders:取appenders项, level:设置级别
        default:    { appenders: ['stdout', 'request','info']   , level: 'debug' },
        error:        { appenders: ['stdout', 'error']              , level: 'error' },
        info:       { appenders: ['stdout', 'info']             , level: 'info' },
        request:    { appenders: ['stdout', 'request']          , level: 'debug'}
    }
})
 
/**
 * name 取值categories里的某一键值
 */
exports.getLogger = function (name) {   
    return log4js.getLogger(name || 'default')
}
 
/**
 * 用来与express结合,记录请求日志
 */
exports.useLogger = function (app, logger) {
    app.use(log4js.connectLogger(logger || log4js.getLogger('default'), {
        // 自定义输出格式
        format: '[:remote-addr :method :url :status :response-timems][:referrer HTTP/:http-version :user-agent]'
    }))
}

4. sip_server功能调整

/**
 * GB28181服务程序
 */
const parseString   = require('xml2js').parseString;
const xml2js        = require('xml2js');
const sip           = require('sip');
const digest        = require('sip/digest');
const config        = require('./sip_config');
const log4js        = require('./sip_log');
const logger        = log4js.getLogger('info');
const SipUsLayer    = require('./SipUsLayer.class');

var realm =config.sip.server.realm; 
var sipUsLayer = new SipUsLayer();

// 设备信息
var registry = config.registry;

/**
 * SIP服务端
 */
const sip_server={
    'start':function(){
        logger.info('启动sip服务端');
        sip.start({
            logger: { 
              send: function(message, address) { 
              logger.info("==send==:" , message,address); 
            },
              recv: function(message, address) {
                logger.info("==recv==:" , message,address); 
              }
            }
          },
          function(rq) {
            try {
              if(rq.method ==='REGISTER') {  
                var username = sip.parseUri(rq.headers.to.uri).user;
                var userinfo = registry[username];
          
                if(!userinfo) {
                  logger.error('没有登记的用户 禁止授权:' , username);
                  var session = {realm: realm};
                  sip.send(digest.challenge(session, sip.makeResponse(rq, 401, 'Unauthorized')));
                  return;
                }
                else {
                  userinfo.session = userinfo.session || {realm: realm};
                  if(!digest.authenticateRequest(userinfo.session, rq, {user: username, password: userinfo.password})) {
                    let ret0 = digest.challenge(userinfo.session, sip.makeResponse(rq, 401, 'Unauthorized'));
                    sip.send(ret0);
                  }
                  else {
                    // 完成授权
                    userinfo.contact = rq.headers.contact;
                    var rs = sip.makeResponse(rq, 200, 'Ok');
                    sip.send(rs);
                    logger.info('请求设备目录');
                    registry[username].online=true;
                    command.catalog(rq,username);
                  }
                }
              }
              else if(rq.method === 'INVITE') {
                
                var username = sip.parseUri(rq.uri).user;
                var userinfo = registry[username]
                
                if(userinfo && Array.isArray(userinfo.contact) && userinfo.contact.length > 0) {
                  var rs = sip.makeResponse(rq, 302, 'Moved');
                  rs.headers.contact = userinfo.contact;
                  sip.send(rs);
                }
                else {
                  logger.error(userinfo);
                  sip.send(sip.makeResponse(rq, 404, 'Not Found'));
                }
              }
              else if(rq.method==='MESSAGE'){
               
                parseString(rq.content,function(err,result){
                  if(result.Notify){
                    var CmdType = result.Notify.CmdType[0];
                    if(CmdType==='Keepalive'){
                      // 心跳
                      var rs = sip.makeResponse(rq,200,'OK');
                      sip.send(rs);
                    }else{
                      
                
                    }
                  }else if(result.Response){
                    var CmdType = result.Response.CmdType;
                    if(CmdType=='Catalog'){
                      // 获取到的设备列表
                      if(result.Response.DeviceList){
                      
                        for(var s in  result.Response.DeviceList[0].Item){
                          var temp = result.Response.DeviceList[0].Item[s];
                          var exists = devices.indexOf(temp)>-1;
                          if(!exists) {
                            devices.push(temp);
                          }
                        }
                        logger.info('----------devices---------',devices);
                        sip.send(sip.makeResponse(rq,200,'OK'));
                      }
                    }
                  }
                  
                });
                
              }
              else if(rq.method=='ACK'){
                logger.info(rq);
              }
              else if(rq.method=='BYTE'){
                logger.info(rq);
              }
              else {
                logger.debug(rq.method);
                sip.send(sip.makeResponse(rq, 405, 'Method Not Allowed'));
              }
            } catch(e) {
              logger.error(e);
              sip.send(sip.makeResponse(rq, 500, "Server Internal Error"));
            }
          });
    }
    
}
var command={
    // 请求目录 
    catalog: function(rs,deviceId){
      //TODO: 这个SN以后看怎么赋值才合理
      let SN=1;
      const json = {
        Query: {
              CmdType: 'Catalog',
              SN: SN,
              DeviceID: deviceId
          }
      };
      const builder = new xml2js.Builder();
      const content = builder.buildObject(json);
  
      const username = sip.parseUri(rs.headers.to.uri).user;
      // 从via解析摄像头的ip 端口
      const via = sip.parseUri(rs.headers.via)[0];
      var cseq = rs.headers.cseq;
      cseq.method = 'MESSAGE';
      var res = {
        method:'MESSAGE',
        uri: 'sip:' + username + '@' + via.host + ':' + via.port,
        version:rs.version,
        headers:{
          via        : rs.headers.via,
          from      : rs.headers.from, 
          to        : rs.headers.to, 
          'call-id' : rs.headers['call-id'],
          cseq:cseq,
          'Content-Type':'Application/MANSCDP+xml',
          'expires':'3600',
          'Max-Forwards':70
        },
        content:content
      };
  
      logger.info(res);
      sip.send(res);
  
    }
  };
module.exports = sip_server;

下一步再将一些功能提取到SipUsLayer类里。

请求示例:
http://你的ip:8777/api/v1/device/list
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/xundh/article/details/106467290