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