同步代码

This commit is contained in:
TsMask
2023-08-21 11:00:22 +08:00
parent 2735cc3009
commit 788f01674a
37 changed files with 2211 additions and 1 deletions

44
.gitignore vendored Normal file
View File

@@ -0,0 +1,44 @@
# ---> VisualStudioCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Run temp file and dir
crontask/log/
crontask/ftp/
crontask/database/
crontask/export/
crontask/temp
crontask/crontask
restagent/backup/
restagent/log/
restagent/upload/
restagent/software/
restagent/database/
restagent/restagent
sshsvc/sshsvc
sshsvc/mmllog/
sshsvc/mmlhome/
sshsvc/log/
tools/loadmconf/loadmconf
vendor
# Built Visual Studio Code Extensions
*.vsix
*.log
*.log-*
*.bak
.idea
omc_log
data

15
api/close.go Normal file
View File

@@ -0,0 +1,15 @@
package api
import (
"github.com/aceld/zinx/ziface"
"github.com/aceld/zinx/znet"
)
// CloseApi 关闭连接API
type CloseApi struct {
znet.BaseRouter
}
func (*CloseApi) Handle(request ziface.IRequest) {
request.GetConnection().Stop()
}

44
api/heart_beat.go Normal file
View File

@@ -0,0 +1,44 @@
package api
import (
"omc/omc"
"github.com/aceld/zinx/ziface"
"github.com/aceld/zinx/zlog"
"github.com/aceld/zinx/znet"
)
// HeartBeatApi 心跳请求
type HeartBeatApi struct {
znet.BaseRouter
}
func (*HeartBeatApi) Handle(request ziface.IRequest) {
// 解包
msgBody := omc.MsgBody{
RawData: request.GetData(),
Msg: make(map[string]string, 0),
}
if err := msgBody.Decode(); err != nil {
zlog.Ins().ErrorF("inlaid message body %s", err.Error())
request.GetConnection().SendMsg(omc.AckHeartBeat, omc.ErrorMsg("ackHeartBeat", "", "inlaid message body"))
return
}
reqId, ok := msgBody.Msg["reqId"]
if !ok {
zlog.Ins().ErrorF("missing parameter of message body")
request.GetConnection().SendMsg(omc.AckHeartBeat, omc.ErrorMsg("ackHeartBeat", "", "missing parameter of message body"))
return
}
//ack
ackBody := omc.MsgBody{
MsgName: "ackHeartBeat",
Msg: make(map[string]string, 0),
}
ackBody.Msg["reqId"] = reqId
ackBody.Keys = append(ackBody.Keys, "reqId")
ackBody.Pack()
request.GetConnection().SendMsg(omc.AckHeartBeat, ackBody.RawData)
}

161
api/login.go Normal file
View File

@@ -0,0 +1,161 @@
package api
import (
"encoding/hex"
"github.com/aceld/zinx/ziface"
"github.com/aceld/zinx/zlog"
"github.com/aceld/zinx/znet"
"github.com/google/uuid"
"omc/core"
"omc/omc"
"omc/service"
"strings"
)
// LoginApi 登录API
type LoginApi struct {
znet.BaseRouter
}
// Handle Login reqLoginAlarm;user=yiy;key=qw#$@;type=msg
func (*LoginApi) Handle(request ziface.IRequest) {
// 登录消息处理
msgBody := omc.MsgBody{
RawData: request.GetData(),
Msg: make(map[string]string, 0),
}
if err := msgBody.Decode(); err != nil {
zlog.Ins().ErrorF("inlaid message body %s", err.Error())
request.GetConnection().SendMsg(omc.AckLoginAlarm, omc.ErrorMsg("ackLoginAlarm", "", "inlaid message body"))
return
}
user, userOK := msgBody.Msg["user"]
pw, pwOK := msgBody.Msg["key"]
tp, tpOK := msgBody.Msg["type"]
if !userOK || !pwOK || !tpOK {
zlog.Ins().ErrorF("missing parameter of message body")
request.GetConnection().SendMsg(omc.AckLoginAlarm, omc.ErrorMsg("ackLoginAlarm", "", "missing parameter of message body"))
return
}
m := core.GetManager(request.GetConnection().GetName())
if m == nil {
zlog.Ins().ErrorF("server internal error")
request.GetConnection().SendMsg(omc.AckLoginAlarm, omc.ErrorMsg("ackLoginAlarm", "", "server internal error"))
return
}
uID, err := request.GetConnection().GetProperty("UID")
if err != nil {
zlog.Ins().ErrorF("GetProperty UID error %s", err)
request.GetConnection().Stop()
return
}
//登录信息check
if err := service.UserLogin(user, pw); err != nil {
zlog.Ins().ErrorF("LoginFail %s", err)
request.GetConnection().SendMsg(omc.AckLoginAlarm, omc.ErrorMsg("ackLoginAlarm", "", "Incorrect username and password"))
isClose, _ := m.LoginFail(uID.(string)) //登录错误超过3次,断开连接
if isClose {
request.GetConnection().Stop()
return
}
return
}
//manager 更新
if err := m.LoginSuccess(uID.(string), user, tp); err != nil {
zlog.Ins().ErrorF("manager:%s", err)
request.GetConnection().SendMsg(omc.AckLoginAlarm, omc.ErrorMsg("ackLoginAlarm", "", err.Error()))
return
}
zlog.Ins().InfoF("user login loginSuccess,username:%s, type:%s, channel:%s", user, tp, request.GetConnection().GetName())
request.GetConnection().SendMsg(omc.AckLoginAlarm, omc.SuccessMsg("ackLoginAlarm", "", ""))
}
// CMCALoginSeq 登录API
type CMCALoginSeq struct {
znet.BaseRouter
}
//reqCMCALoginSeq
func (*CMCALoginSeq) Handle(request ziface.IRequest) {
uid := uuid.New()
seqNo := hex.EncodeToString(uid[0:])
seqNo = strings.ToUpper(seqNo)
//发送文件同步信息
ackBody := omc.MsgBody{
MsgName: "ackCMCALoginSeq",
Msg: make(map[string]string, 0),
}
ackBody.Msg["seqNo"] = seqNo
ackBody.Pack()
request.GetConnection().SendMsg(omc.AckCMCALoginSeq, ackBody.RawData)
}
//
type CMCALoginAlarm struct {
znet.BaseRouter
}
//reqCMCALoginSeq
//reqCMCALoginAlarm;user=yiy;key=12313121213123;cert=AAAAAAAAAA;type=msg
func (*CMCALoginAlarm) Handle(request ziface.IRequest) {
// 登录消息处理
msgBody := omc.MsgBody{
RawData: request.GetData(),
Msg: make(map[string]string, 0),
}
if err := msgBody.Decode(); err != nil {
zlog.Ins().ErrorF("inlaid message body %s", err.Error())
request.GetConnection().SendMsg(omc.AckLoginAlarm, omc.ErrorMsg("ackLoginAlarm", "", "inlaid message body"))
return
}
user, userOK := msgBody.Msg["user"]
pw, pwOK := msgBody.Msg["key"]
tp, tpOK := msgBody.Msg["type"]
if !userOK || !pwOK || !tpOK {
zlog.Ins().ErrorF("missing parameter of message body")
request.GetConnection().SendMsg(omc.AckLoginAlarm, omc.ErrorMsg("ackLoginAlarm", "", "missing parameter of message body"))
return
}
m := core.GetManager(request.GetConnection().GetName())
if m == nil {
zlog.Ins().ErrorF("server internal error")
request.GetConnection().SendMsg(omc.AckLoginAlarm, omc.ErrorMsg("ackLoginAlarm", "", "server internal error"))
return
}
uID, err := request.GetConnection().GetProperty("UID")
if err != nil {
zlog.Ins().ErrorF("GetProperty UID error %s", err)
request.GetConnection().Stop()
return
}
//登录信息check
if err := service.UserLogin(user, pw); err != nil {
zlog.Ins().ErrorF("LoginFail %s", err)
request.GetConnection().SendMsg(omc.AckLoginAlarm, omc.ErrorMsg("ackLoginAlarm", "", "Incorrect username and password"))
isClose, _ := m.LoginFail(uID.(string)) //登录错误超过3次,断开连接
if isClose {
request.GetConnection().Stop()
return
}
return
}
//manager 更新
if err := m.LoginSuccess(uID.(string), user, tp); err != nil {
zlog.Ins().ErrorF("manager:%s", err)
request.GetConnection().SendMsg(omc.AckLoginAlarm, omc.ErrorMsg("ackLoginAlarm", "", err.Error()))
return
}
zlog.Ins().InfoF("user login loginSuccess,username:%s, type:%s, channel:%s", user, tp, request.GetConnection().GetName())
request.GetConnection().SendMsg(omc.AckLoginAlarm, omc.SuccessMsg("ackLoginAlarm", "", ""))
}

61
api/req_sync_alarm.go Normal file
View File

@@ -0,0 +1,61 @@
package api
import (
"github.com/aceld/zinx/ziface"
"github.com/aceld/zinx/zlog"
"github.com/aceld/zinx/znet"
"omc/core"
"omc/omc"
"omc/service"
"strconv"
)
// SyncAlarmApi 消息方式同步告警请求
type SyncAlarmApi struct {
znet.BaseRouter
}
func (*SyncAlarmApi) Handle(request ziface.IRequest) {
// 消息处理
checker := []string{"reqId", "alarmSeq"}
msg, err := core.APIDecode(request, checker)
if err != nil {
zlog.Ins().ErrorF("inlaid message body %s", err.Error())
request.GetConnection().SendMsg(omc.AckSyncAlarmMsg, omc.ErrorMsg("ackSyncAlarmMsg", "", err.Error()))
return
}
//管理模块
m := core.GetManager(request.GetConnection().GetName())
if m == nil {
zlog.Ins().ErrorF("server internal error")
request.GetConnection().SendMsg(omc.AckSyncAlarmFile, omc.ErrorMsg("ackSyncAlarmFile", msg.Msg["reqId"], "server internal error"))
return
}
// 检查用户是否登录
u := m.GetUserByPID(msg.UID)
if !u.LoginState || u.AlarmType != omc.MSG {
zlog.Ins().ErrorF("no permissions ")
request.GetConnection().SendMsg(omc.AckSyncAlarmMsg, omc.ErrorMsg("ackSyncAlarmMsg", msg.Msg["reqId"], "no permissions"))
return
}
alarmSeq, err := strconv.Atoi(msg.Msg["alarmSeq"])
if err != nil || alarmSeq < 1 {
zlog.Ins().ErrorF("invalid parameter of message body")
request.GetConnection().SendMsg(omc.AckSyncAlarmMsg, omc.ErrorMsg("ackSyncAlarmMsg", msg.Msg["reqId"], "invalid parameter of message body"))
return
}
//check alarmSeq 是否存在
neBind, _ := core.ConvertBindFlag(m.BindFlag)
alarms, _ := service.GetRealTimeAlarm(neBind.NeType, neBind.NeId, int32(alarmSeq))
if len(alarms) == 0 {
request.GetConnection().SendMsg(omc.AckSyncAlarmMsg, omc.ErrorMsg("ackSyncAlarmMsg", msg.Msg["reqId"], "alarm seq does not exist"))
return
}
//更新实时上报的alarm seq
m.UpdateAlarmSeq(int32(alarmSeq))
request.GetConnection().SendMsg(omc.AckSyncAlarmMsg, omc.SuccessMsg("ackSyncAlarmMsg", msg.Msg["reqId"], ""))
}

View File

@@ -0,0 +1,91 @@
package api
import (
"fmt"
"github.com/aceld/zinx/ziface"
"github.com/aceld/zinx/zlog"
"github.com/aceld/zinx/znet"
"omc/conf"
"omc/core"
"omc/lib"
"omc/omc"
"omc/service"
"strconv"
"time"
)
// SyncAlarmFileApi 文件方式同步告警请求
type SyncAlarmFileApi struct {
znet.BaseRouter
}
// Handle
//reqSyncAlarmFile;reqId=33;startTime=2014-11-27 10:00:00;endTime=2014-11-27 10:30:00; syncSource =0
func (*SyncAlarmFileApi) Handle(request ziface.IRequest) {
// 消息处理
checker := []string{"reqId", "syncSource"}
msg, err := core.APIDecode(request, checker)
if err != nil {
zlog.Ins().ErrorF("inlaid message body %s", err.Error())
request.GetConnection().SendMsg(omc.AckSyncAlarmFile, omc.ErrorMsg("ackSyncAlarmFile", "", err.Error()))
return
}
//管理模块
m := core.GetManager(request.GetConnection().GetName())
if m == nil {
zlog.Ins().ErrorF("server internal error")
request.GetConnection().SendMsg(omc.AckSyncAlarmFile, omc.ErrorMsg("ackSyncAlarmFile", msg.Msg["reqId"], "server internal error"))
return
}
// 检查用户是否登录
u := m.GetUserByPID(msg.UID)
if !u.LoginState || u.AlarmType != omc.FILE {
zlog.Ins().ErrorF("no permissions ")
request.GetConnection().SendMsg(omc.AckSyncAlarmFile, omc.ErrorMsg("ackSyncAlarmFile", msg.Msg["reqId"], "no permissions"))
return
}
//查询需要上报的告警信息
start := ""
end := ""
syncSource := ""
alarmSeq := 0
fmt.Println("msg.Msg:", msg.Msg)
//map[alarmSeq:1 reqId:35 syncSource:1]
// map[endTime:2023-07-15 23:59:59 reqId:34 startTime:2023-01-08 16:07:00 syncSource:0]
if v, ok := msg.Msg["startTime"]; ok {
start = v
}
if v, ok := msg.Msg["endTime"]; ok {
end = v
}
if v, ok := msg.Msg["syncSource"]; ok {
syncSource = v
}
if v, ok := msg.Msg["alarmSeq"]; ok {
if seq, err := strconv.Atoi(v); err == nil {
alarmSeq = seq
}
}
neBind, _ := core.ConvertBindFlag(m.BindFlag)
alarms, err := service.GetAlarm(neBind.NeType, neBind.NeId, start, end, syncSource, alarmSeq)
if err != nil || len(alarms) == 0 {
request.GetConnection().SendMsg(omc.AckSyncAlarmFile, omc.ErrorMsg("ackSyncAlarmFile", msg.Msg["reqId"], "not find record"))
return
}
//ack
request.GetConnection().SendMsg(omc.AckSyncAlarmFile, omc.SuccessMsg("ackSyncAlarmFile", msg.Msg["reqId"], ""))
//打包结果文件
//打包生成文件
var meta lib.FileMeta
meta.DirRoot = conf.OmcConf.FTPRoot
meta.Province = m.Province
meta.DeviceCode = m.DeviceCode
meta.Index = "001"
meta.Time = time.Now().Format("20060102150405")
meta.Compress = false
go service.GenFile(request, &meta, alarms)
}

1
asdf
View File

@@ -1 +0,0 @@
vasd

219
client_robot.go Normal file
View File

@@ -0,0 +1,219 @@
package main
import (
"bytes"
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"github.com/aceld/zinx/zconf"
"github.com/aceld/zinx/zlog"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"io"
"net"
"omc/model"
"omc/omc"
"time"
)
type Message struct {
StartSign uint16
MsgType uint8
TimeStamp uint32
LenOfBody uint16
Value []byte
}
type TcpClient struct {
conn net.Conn
PID int32
isOnline chan bool
}
func (this *TcpClient) Unpack(headdata []byte) (head *Message, err error) {
fmt.Println("unpack:", hex.EncodeToString(headdata))
headBuf := bytes.NewReader(headdata)
head = &Message{}
// Read the startSign
if err := binary.Read(headBuf, binary.BigEndian, &head.StartSign); err != nil {
return nil, err
}
// Read the msgID
if err := binary.Read(headBuf, binary.BigEndian, &head.MsgType); err != nil {
return nil, err
}
// read timeStamp
if err := binary.Read(headBuf, binary.BigEndian, &head.TimeStamp); err != nil {
return nil, err
}
// Read the data length
if err := binary.Read(headBuf, binary.BigEndian, &head.LenOfBody); err != nil {
return nil, err
}
// Check whether the data length exceeds the maximum allowed packet size
// (判断dataLen的长度是否超出我们允许的最大包长度)
if zconf.GlobalObject.MaxPacketSize > 0 && uint32(head.LenOfBody) > zconf.GlobalObject.MaxPacketSize {
return nil, errors.New("too large msg data received")
}
return head, nil
}
func (this *TcpClient) Pack(msgID uint32, dataBytes []byte) (out []byte, err error) {
outbuff := bytes.NewBuffer([]byte{})
// Write the oxffff
if err := binary.Write(outbuff, binary.BigEndian, uint16(0xffff)); err != nil {
return nil, err
}
//Write the type
if err := binary.Write(outbuff, binary.BigEndian, uint8(msgID)); err != nil {
return nil, err
}
//Write the timestamp
if err := binary.Write(outbuff, binary.BigEndian, uint32(0x999999)); err != nil {
return nil, err
}
//Write the length
if err := binary.Write(outbuff, binary.BigEndian, uint16(len(dataBytes))); err != nil {
return nil, err
}
// Write the data
if err := binary.Write(outbuff, binary.BigEndian, dataBytes); err != nil {
return nil, err
}
out = outbuff.Bytes()
return
}
func (this *TcpClient) SendMsg(msgID uint32, data []byte) {
sendData, err := this.Pack(msgID, data)
if err == nil {
_, err := this.conn.Write(sendData)
fmt.Println("send msg:", hex.EncodeToString(sendData), " err:", err)
} else {
fmt.Println(err)
}
return
}
func (this *TcpClient) Receive() {
for {
//读取服务端发来的数据 ==》 SyncPID
//1.读取8字节
////第一次读取,读取数据头
headData := make([]byte, 9)
if _, err := io.ReadFull(this.conn, headData); err != nil {
fmt.Println(err)
return
}
pkgHead, err := this.Unpack(headData)
if err != nil {
fmt.Println("Unpack", err)
return
}
//data
if pkgHead.LenOfBody > 0 {
pkgHead.Value = make([]byte, pkgHead.LenOfBody)
if _, err := io.ReadFull(this.conn, pkgHead.Value); err != nil {
return
}
}
//处理服务器回执业务
fmt.Println("=================================")
fmt.Println("StartSign:", pkgHead.StartSign)
fmt.Println("MsgType:", pkgHead.MsgType)
fmt.Println("TimeStamp:", pkgHead.TimeStamp)
fmt.Println("LenOfBody:", pkgHead.LenOfBody)
fmt.Println("Value:", string(pkgHead.Value))
fmt.Println("=================================")
time.Sleep(10 * time.Microsecond)
}
}
func (this *TcpClient) Start() {
//登录
data := "reqLoginAlarm;user=omc;key=omc@password;type=ftp"
this.SendMsg(0x01, []byte(data))
//发送同步告警信息
//data = "reqSyncAlarmMsg;reqId=33;alarmSeq=1"
//this.SendMsg(omc.ReqSyncAlarmMsg, []byte(data))
//发送文件同步告警
//data = "reqSyncAlarmFile;reqId=35;alarmSeq=2000;syncSource=1"
//data = "reqSyncAlarmFile;reqId=33;startTime=2023-01-08 00:00:00;syncSource=0"
data = "reqSyncAlarmFile;reqId=34;startTime=2023-01-08 16:07:00;endTime=2023-07-19 23:59:59;syncSource=1"
this.SendMsg(omc.ReqSyncAlarmFile, []byte(data))
go this.Receive()
}
func DataMock() {
conf := "root:1000omc@kp!@tcp(192.168.0.229:33066)/omc_db?charset=utf8mb4&parseTime=True&loc=Local"
d, err := gorm.Open(mysql.Open(conf), &gorm.Config{})
if err != nil {
zlog.Ins().ErrorF("open mysql %s error, ", conf, err)
panic(err)
}
var alarms []model.Alarm
if err := d.Model(&model.Alarm{}).Where("ne_type = ? and ne_id = ? and alarm_seq >= ?", "SMF", "SZ_01", 0).Order("alarm_seq asc").Limit(5).Find(&alarms).Error; err != nil {
zlog.Ins().ErrorF("open mysql %s error, ", conf, err)
return
}
var alarm model.Alarm
if err := d.Model(&model.Alarm{}).Where("ne_type = ? and ne_id = ?", "SMF", "SZ_01").Order("alarm_seq desc").First(&alarm).Error; err != nil {
zlog.Ins().ErrorF("db error %s", err)
return
}
index := alarm.AlarmSeq + 1
for {
for _, v := range alarms {
v.AlarmSeq = index
v.Id = 0
d.Create(&v)
index++
}
time.Sleep(10 * time.Microsecond)
}
}
func NewTcpClient(ip string, port int) *TcpClient {
addrStr := fmt.Sprintf("%s:%d", ip, port)
conn, err := net.Dial("tcp", addrStr)
if err != nil {
fmt.Println("net.Dial err: ", err)
panic(err)
}
client := &TcpClient{
conn: conn,
PID: 0,
isOnline: make(chan bool),
}
fmt.Println(fmt.Sprintf("conn: %+v. Connected to server...", conn))
return client
}
func main() {
client := NewTcpClient("127.0.0.1", 31232)
client.Start()
//DataMock()
select {}
}

75
conf/global.go Normal file
View File

@@ -0,0 +1,75 @@
package conf
import (
"encoding/json"
"errors"
"fmt"
"github.com/aceld/zinx/zconf"
"github.com/aceld/zinx/zlog"
"io/ioutil"
"os"
)
type Config struct {
/*
Server
*/
Mysql string `json:"mysql"`
FTPRoot string `json:"ftp_root"`
Channel []struct {
TCPPort int `json:"tcp_port"` //当前通道的TCP监听端口
BindFlag string `json:"bind_flag"` //当前通道bind 的网元信息
Province string `json:"province"` //网元所在省份
DeviceCode string `json:"device_code"` //主机编码 四位每1位可用0-9、A-Z编码
} `json:"channel"`
//以下是zinx 的配置
Name string `json:"name"`
MaxConn int `json:"max_conn"`
WorkerPoolSize int `json:"worker_pool_size"`
HeartbeatMax int `json:"heartbeat_max"`
LogDir string `json:"log_dir"`
LogFile string `json:"log_file"`
}
var OmcConf Config
const ConfPath = "/conf/nbi_alarm_agent.json"
func Reload(path string) error {
if confFileExists, _ := zconf.PathExists(path); confFileExists != true {
zlog.Ins().ErrorF("Config File %s is not exist!!", path)
return errors.New("config file is not exist")
}
data, err := ioutil.ReadFile(path)
if err != nil {
return err
}
err = json.Unmarshal(data, &OmcConf)
if err != nil {
return err
}
return nil
}
func Init(path string) {
fmt.Println("filePath:", path)
if path == "" {
pwd, err := os.Getwd()
if err != nil {
pwd = "."
}
path = pwd + ConfPath
fmt.Println("path", path)
}
if err := Reload(path); err != nil {
zlog.Ins().ErrorF("Config File %s error, ", err)
panic(err)
}
}
//"mysql": "root:1000omc@kp!@tcp(192.168.2.119:33066)/omc_db?charset=utf8mb4&parseTime=True&loc=Local",

22
conf/nbi_alarm_agent.json Normal file
View File

@@ -0,0 +1,22 @@
{
"channel": [
{
"tcp_port": 31232,
"bind_flag": "SMF#SZ_01",
"province": "BJ",
"device_code": "0001"
},
{
"tcp_port": 31233,
"bind_flag": "UDM#SZ_03",
"province": "BJ",
"device_code": "0002"
}
],
"mysql": "root:1000omc@kp!@tcp(192.168.0.229:33066)/omc_db?charset=utf8mb4&parseTime=True&loc=Local",
"ftp_root": "data/ftp",
"mame":"nbi north alarm agent",
"heartbeat_max": 180,
"log_dir": "./nbi_alarm",
"log_file":"nbi_alarm.log"
}

23
core/heart_beat.go Normal file
View File

@@ -0,0 +1,23 @@
package core
import (
"github.com/aceld/zinx/ziface"
"github.com/aceld/zinx/zlog"
)
// MyHeartBeatMsg 用户自定义的心跳检测消息处理方法
func MyHeartBeatMsg(conn ziface.IConnection) []byte {
return []byte("heartbeat, I am server, I am alive")
}
// MyHeartBeat 用户自定义心跳发送函数
func MyHeartBeat(conn ziface.IConnection) error {
return nil
}
// MyOnRemoteNotAlive 用户自定义的远程连接不存活时的处理方法
func MyOnRemoteNotAlive(conn ziface.IConnection) {
zlog.Ins().ErrorF("myOnRemoteNotAlive is Called, connID=%v", conn.GetConnID(), "remoteAddr =%v ", conn.RemoteAddr())
//关闭链接
conn.Stop()
}

50
core/user.go Normal file
View File

@@ -0,0 +1,50 @@
package core
import (
"fmt"
"github.com/aceld/zinx/ziface"
"github.com/google/uuid"
)
// User User 对象
type User struct {
UID string //ID
Conn ziface.IConnection //当前User的连接
LoginState bool
LoginCount int
AlarmType string
UserName string
SeqNo string // 登录随机码
RemoteIp string
}
// NewUser 创建一个user对象
func NewUser(conn ziface.IConnection, addr string) *User {
p := &User{
UID: uuid.NewString(),
Conn: conn,
RemoteIp: addr,
}
return p
}
// LostConnection User下线
func (p *User) LostConnection(m *ChannelManager) {
m.RemoveUserByPID(p.UID)
}
// SendMsg /*
func (p *User) SendMsg(msgID uint32, msg []byte) {
if p.Conn == nil {
fmt.Println("connection in player is nil")
return
}
//调用SendMsg发包
if err := p.Conn.SendMsg(msgID, msg); err != nil {
fmt.Println("Player SendMsg error !")
return
}
return
}

232
core/user_manager.go Normal file
View File

@@ -0,0 +1,232 @@
package core
import (
"errors"
"github.com/aceld/zinx/zlog"
"omc/db"
"omc/model"
"omc/omc"
"omc/service"
"strings"
"sync"
"time"
)
/*
ChannelManager 通道管理管理模块
*/
type ChannelManager struct {
Name string
User map[string]*User //当前在线的User集合
BindFlag string //bind 的网元标识ne_type#ne_id 格式
Province string //网元所在省份
DeviceCode string //主机编码 四位每1位可用0-9、A-Z编码
AlarmSeq int32 //当前告警的序列号
pLock sync.RWMutex //保护User的互斥读写机制
}
// MgrObj 多个通道管理模块集合
var MgrObj []*ChannelManager
// NewManager New 提供ChannelManager 初始化 方法
func NewManager(name, bind, province, deviceCode string) *ChannelManager {
newManager := ChannelManager{
Name: name,
BindFlag: bind,
Province: province,
DeviceCode: deviceCode,
User: make(map[string]*User),
}
MgrObj = append(MgrObj, &newManager)
return &newManager
}
func GetManager(name string) *ChannelManager {
for i := range MgrObj {
if MgrObj[i].Name == name {
return MgrObj[i]
}
}
return nil
}
// AddUser 提供添加一个user的功能
func (wm *ChannelManager) AddUser(User *User) {
//将User添加到 世界管理器中
wm.pLock.Lock()
wm.User[User.UID] = User
wm.pLock.Unlock()
}
// Talk User广播消息
func (wm *ChannelManager) Talk(msgID uint32, msg []byte) {
//2. 得到所有的在线user
users := wm.GetAllUser()
//3. 向所有的user发送消息
for _, user := range users {
if user.LoginState && user.AlarmType == omc.MSG {
user.SendMsg(msgID, msg)
}
}
}
// LoginSuccess 登录成功管理
func (wm *ChannelManager) LoginSuccess(UID, name, tp string) error {
wm.pLock.Lock()
defer wm.pLock.Unlock()
//判断是否重复登录
for _, v := range wm.User {
if v.UserName == name && v.AlarmType == tp && v.LoginState == true {
return errors.New("repeat login for the same account")
}
}
user, ok := wm.User[UID]
if !ok {
return errors.New("server internal error")
}
user.UserName = name
user.AlarmType = tp
user.LoginState = true
wm.User[UID] = user
return nil
}
// SetSeqNo 设置登录随机码
func (wm *ChannelManager) SetSeqNo(UID, seqNo string) error {
wm.pLock.Lock()
defer wm.pLock.Unlock()
//判断是否重复登录
user, ok := wm.User[UID]
if !ok {
return errors.New("server internal error")
}
user.SeqNo = seqNo
return nil
}
// LoginFail 登录失败管理
func (wm *ChannelManager) LoginFail(UID string) (bool, error) {
wm.pLock.Lock()
defer wm.pLock.Unlock()
//判断是否重复登录
user, ok := wm.User[UID]
if !ok {
return true, errors.New("server internal error")
}
user.LoginCount++
wm.User[UID] = user
if user.LoginCount >= 3 {
return true, errors.New("too many attempts, close connect")
}
return false, nil
}
// RemoveUserByPID 从信息表中移除一个user
func (wm *ChannelManager) RemoveUserByPID(uid string) {
wm.pLock.Lock()
delete(wm.User, uid)
wm.pLock.Unlock()
}
// GetUserByPID 通过user ID 获取对应user信息
func (wm *ChannelManager) GetUserByPID(uID string) *User {
wm.pLock.RLock()
defer wm.pLock.RUnlock()
return wm.User[uID]
}
// GetAllUser 获取所有user的信息
func (wm *ChannelManager) GetAllUser() []*User {
wm.pLock.RLock()
defer wm.pLock.RUnlock()
//创建返回的User集合切片
User := make([]*User, 0)
//添加切片
for _, v := range wm.User {
if v.LoginState && v.AlarmType == omc.MSG {
User = append(User, v)
}
}
//返回
return User
}
func (wm *ChannelManager) RealTimeAlarm() {
for {
wm.pLock.RLock()
//查询
var newAlarmSeq = wm.AlarmSeq
var alarms []service.OmcAlarm
neBind, _ := ConvertBindFlag(wm.BindFlag)
if wm.AlarmSeq == 0 {
newAlarmSeq = service.GetLastAlarmSeq(neBind.NeType, neBind.NeId)
} else {
ams, err := service.GetRealTimeAlarm(neBind.NeType, neBind.NeId, wm.AlarmSeq)
if err != nil {
zlog.Ins().ErrorF("db error %s", err)
}
alarms = ams
}
//上报实时告警信息
if len(alarms) > 0 {
go wm.SendAlarm(alarms)
newAlarmSeq = service.MaxAlarm(newAlarmSeq, alarms) + 1
}
var users []string
for _, user := range wm.User {
if user.LoginState && user.AlarmType == omc.MSG {
userInfo := strings.Join([]string{user.UserName, user.RemoteIp}, ";")
users = append(users, userInfo)
}
}
//更新AlarmSeq
wm.AlarmSeq = newAlarmSeq
wm.pLock.RUnlock()
//记录日志到alarm 日志表
for _, v := range alarms {
for _, u := range users {
var alarmLog model.NbiAlarmLog
ui := strings.Split(u, ";")
if len(ui) == 2 {
alarmLog.OpUser = ui[0]
alarmLog.SrcIp = ui[1]
}
alarmLog.NeType = v.NeType
alarmLog.NeId = v.NeUID
alarmLog.AlarmSeq = int64(v.AlarmSeq)
alarmLog.AlarmId = v.AlarmId
et, _ := time.Parse("2006-01-02 15:04:05", v.EventTime)
alarmLog.EventTime = et
alarmLog.LogTime = time.Now()
alarmLog.AId = v.AId
db.Client.Create(&alarmLog)
}
}
time.Sleep(3 * time.Second)
}
}
func (wm *ChannelManager) SendAlarm(alarms []service.OmcAlarm) error {
for _, v := range alarms {
//生产告警内容
data := service.GenAlarm(v)
//发送告警内容
wm.Talk(omc.RealTimeAlarm, data)
}
return nil
}
func (wm *ChannelManager) UpdateAlarmSeq(newSeq int32) {
wm.pLock.Lock()
wm.AlarmSeq = newSeq
wm.pLock.Unlock()
}

48
core/utils.go Normal file
View File

@@ -0,0 +1,48 @@
package core
import (
"errors"
"github.com/aceld/zinx/ziface"
"omc/omc"
"strings"
)
type NeBind struct {
NeType string
NeId string
}
func ConvertBindFlag(bindFlag string) (NeBind, error) {
var neBind NeBind
nb := strings.Split(bindFlag, "#")
if len(nb) != 2 {
return neBind, errors.New("ne bind flag invalid")
}
neBind.NeType = nb[0]
neBind.NeId = nb[1]
return neBind, nil
}
// APIDecode 消息解析
func APIDecode(request ziface.IRequest, checker []string) (*omc.MsgBody, error) {
// 消息处理
msgBody := omc.MsgBody{
RawData: request.GetData(),
Msg: make(map[string]string, 0),
}
if err := msgBody.Decode(); err != nil {
return nil, errors.New("inlaid message body")
}
for _, v := range checker {
if _, ok := msgBody.Msg[v]; !ok {
return nil, errors.New("missing parameter of message body")
}
}
uID, err := request.GetConnection().GetProperty("UID")
if err != nil {
request.GetConnection().Stop()
return nil, errors.New("server internal error")
}
msgBody.UID = uID.(string)
return &msgBody, nil
}

24
db/mysql.go Normal file
View File

@@ -0,0 +1,24 @@
package db
import (
"github.com/aceld/zinx/zlog"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"omc/conf"
)
var Client *gorm.DB
func Init() error {
d, err := gorm.Open(mysql.Open(conf.OmcConf.Mysql), &gorm.Config{})
if err != nil {
zlog.Ins().ErrorF("open mysql %s error, ", conf.OmcConf.Mysql, err)
panic(err)
}
sqlDB, _ := d.DB()
sqlDB.SetMaxOpenConns(20)
sqlDB.SetMaxIdleConns(10)
Client = d
return nil
}

88
decoder/decode_omc.go Normal file
View File

@@ -0,0 +1,88 @@
package decoder
import (
"bytes"
"encoding/binary"
"encoding/hex"
"github.com/aceld/zinx/ziface"
"github.com/aceld/zinx/zlog"
"math"
)
//ffff 01 00999999 000a 68656c6c6f2074657374
// +---------------+---------------+--------------------+----------------+-------------------
// | 开始标志 | type | 秒时间戳 | 长度 | 消息体
// | 0xffff(2byte) | uint8(1byte) | uint32(4byte) | uint16(2byte) | bytes(N byte)
// +---------------+---------------+--------------------+----------------+-------------------
const OmcMsgHeaderSize = 9 //表示OMC空包长度
type OmcDecoder struct {
StartSign uint16
MsgType uint8
TimeStamp uint32
LenOfBody uint16
Value []byte
}
func NewOmcDecoder() ziface.IDecoder {
return &OmcDecoder{}
}
func (omc *OmcDecoder) GetLengthField() *ziface.LengthField {
return &ziface.LengthField{
MaxFrameLength: math.MaxUint16 + 9,
LengthFieldOffset: 7,
LengthFieldLength: 2,
LengthAdjustment: 0,
InitialBytesToStrip: 0,
//注意现在默认是大端,使用小端需要指定编码方式
Order: binary.BigEndian,
}
}
func (omc *OmcDecoder) decode(data []byte) *OmcDecoder {
ltvData := OmcDecoder{}
ltvData.StartSign = binary.BigEndian.Uint16(data[0:2])
ltvData.MsgType = data[2]
ltvData.TimeStamp = binary.BigEndian.Uint32(data[3:7])
ltvData.LenOfBody = binary.BigEndian.Uint16(data[7:9])
//Determine the length of V. (确定V的长度)
ltvData.Value = make([]byte, ltvData.LenOfBody)
//5. Get V
binary.Read(bytes.NewBuffer(data[OmcMsgHeaderSize:OmcMsgHeaderSize+ltvData.LenOfBody]), binary.BigEndian, ltvData.Value)
return &ltvData
}
func (omc *OmcDecoder) Intercept(chain ziface.IChain) ziface.IcResp {
//1. Get the IMessage of zinx
iMessage := chain.GetIMessage()
if iMessage == nil {
// Go to the next layer in the chain of responsibility
return chain.ProceedWithIMessage(iMessage, nil)
}
//2. Get Data
data := iMessage.GetData()
zlog.Ins().DebugF("omc-RawData size:%d data:%s\n", len(data), hex.EncodeToString(data))
// (读取的数据不超过包头,直接进入下一层)
if len(data) < OmcMsgHeaderSize {
return chain.ProceedWithIMessage(iMessage, nil)
}
//4. Decode
ltvData := omc.decode(data)
zlog.Ins().DebugF("omc-decode %v", ltvData)
// (将解码后的数据重新设置到IMessage中, Zinx的Router需要MsgID来寻址)
iMessage.SetDataLen(uint32(ltvData.LenOfBody))
iMessage.SetMsgID(uint32(ltvData.MsgType))
iMessage.SetData(ltvData.Value)
//6. Pass the decoded data to the next layer.
// (将解码后的数据进入下一层)
return chain.ProceedWithIMessage(iMessage, *ltvData)
}

117
dpack/datapack_omc.go Normal file
View File

@@ -0,0 +1,117 @@
package dpack
import (
"bytes"
"encoding/binary"
"errors"
"github.com/aceld/zinx/zlog"
"github.com/aceld/zinx/zpack"
"time"
"github.com/aceld/zinx/zconf"
"github.com/aceld/zinx/ziface"
)
// +---------------+---------------+--------------------+----------------+-------------------
// | 开始标志 | type | 秒时间戳 | 长度 | 消息体
// | 0xffff(2byte) | uint8(1byte) | uint32(4byte) | uint16(2byte) | bytes(N byte)
// +---------------+---------------+--------------------+----------------+-------------------
var defaultHeaderLen uint32 = 9
type DataPack struct{}
// NewDataPack initializes a packing and unpacking instance
// (封包拆包实例初始化方法)
func NewDataPack() ziface.IDataPack {
return &DataPack{}
}
// GetHeadLen returns the length of the message header
// (获取包头长度方法)
func (dp *DataPack) GetHeadLen() uint32 {
//ID uint32(4 bytes) + DataLen uint32(4 bytes)
return defaultHeaderLen
}
// Pack packs the message (compresses the data)
// (封包方法,压缩数据)
func (dp *DataPack) Pack(msg ziface.IMessage) ([]byte, error) {
zlog.Ins().InfoF("my pack: %v", msg)
// Create a buffer to store the bytes
// (创建一个存放bytes字节的缓冲)
dataBuff := bytes.NewBuffer([]byte{})
// Write the oxffff
if err := binary.Write(dataBuff, binary.BigEndian, uint16(0xffff)); err != nil {
return nil, err
}
//Write the type
if err := binary.Write(dataBuff, binary.BigEndian, uint8(msg.GetMsgID())); err != nil {
return nil, err
}
//Write the timestamp
if err := binary.Write(dataBuff, binary.BigEndian, uint32(time.Now().Unix())); err != nil {
return nil, err
}
//Write the length
if err := binary.Write(dataBuff, binary.BigEndian, uint16(msg.GetDataLen())); err != nil {
return nil, err
}
// Write the data
if err := binary.Write(dataBuff, binary.BigEndian, msg.GetData()); err != nil {
return nil, err
}
return dataBuff.Bytes(), nil
}
// Unpack unpacks the message (decompresses the data)
// (拆包方法,解压数据)
func (dp *DataPack) Unpack(binaryData []byte) (ziface.IMessage, error) {
// Create an ioReader for the input binary data
dataBuff := bytes.NewReader(binaryData)
// Only unpack the header information to obtain the data length and message ID
// (只解压head的信息得到dataLen和msgID)
msg := &zpack.Message{}
// Read the startSign
var startSign uint16
if err := binary.Read(dataBuff, binary.BigEndian, &startSign); err != nil {
return nil, err
}
// Read the msgID
var msgType uint
if err := binary.Read(dataBuff, binary.BigEndian, &msgType); err != nil {
return nil, err
}
msg.ID = uint32(msgType)
// read timeStamp
var timeStamp uint32
if err := binary.Read(dataBuff, binary.BigEndian, &timeStamp); err != nil {
return nil, err
}
// Read the data length
var length uint16
if err := binary.Read(dataBuff, binary.BigEndian, &length); err != nil {
return nil, err
}
msg.DataLen = uint32(length)
// Check whether the data length exceeds the maximum allowed packet size
// (判断dataLen的长度是否超出我们允许的最大包长度)
if zconf.GlobalObject.MaxPacketSize > 0 && msg.GetDataLen() > zconf.GlobalObject.MaxPacketSize {
return nil, errors.New("too large msg data received")
}
// Only the header data needs to be unpacked, and then another data read is performed from the connection based on the header length
// (这里只需要把head的数据拆包出来就可以了然后再通过head的长度再从conn读取一次数据)
return msg, nil
}

18
go.mod Normal file
View File

@@ -0,0 +1,18 @@
module omc
go 1.18
require (
github.com/aceld/zinx v1.1.21
github.com/google/uuid v1.3.0
golang.org/x/crypto v0.11.0
gorm.io/driver/mysql v1.5.1
gorm.io/gorm v1.25.1
)
require (
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
)

40
go.sum Normal file
View File

@@ -0,0 +1,40 @@
github.com/aceld/zinx v1.1.21 h1:8zoZ+hcEAd7gDsl8xOKPaWPEs9vZDRQOvhjG3vuvAnQ=
github.com/aceld/zinx v1.1.21/go.mod h1:nITkdASGtkLSwNKZ5yj88IpcCHTCFCP6cL12JWms1Fo=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw=
gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o=
gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64=
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=

View File

@@ -0,0 +1 @@
this a test file

View File

@@ -0,0 +1 @@
this a test file

81
lib/file.go Normal file
View File

@@ -0,0 +1,81 @@
package lib
import (
"archive/zip"
"os"
"strings"
)
//BJ/HX/RJ/OMC/FM/告警文件生成时间
///FTP根目录/省份简称/专业简称/厂家编码/OMC名称/数据类别/日期或时间/
//<省份简称>-<数据类别>-<网元类型>[-网元子类]-<主机编号>-<数据版本>-<数据时间>[-登录用户名][-同步请求标识][-Ri][-统计周期] [-序列号].<后缀>
//BJ-FM-OMC-主机编码-v0-告警文件生成时间-001.txt
type FileMeta struct {
DirRoot string `json:"dir_root"`
Province string `json:"province"` //网元所在省份
DeviceCode string `json:"device_code"` //主机编码 四位每1位可用0-9、A-Z编码
Time string `json:"time"` //文件生成时间
Index string `json:"index"` //文件标识
Compress bool `json:"compress"` //文件是否压缩
ReqId string `json:"req_id"`
}
// HasDir 判断文件夹是否存在
func HasDir(path string) (bool, error) {
_, _err := os.Stat(path)
if _err == nil {
return true, nil
}
if os.IsNotExist(_err) {
return false, nil
}
return false, _err
}
func CreateDir(meta *FileMeta) (string, error) {
dir := strings.Join([]string{meta.DirRoot, meta.Province, "HX", "RJ", "OMC", "FM", meta.Time}, "/")
exist, err := HasDir(dir)
if err != nil {
return "", err
}
if !exist {
err := os.MkdirAll(dir, os.ModePerm)
if err != nil {
return "", err
}
}
return dir, err
}
func GetName(meta *FileMeta) string {
fileName := strings.Join([]string{meta.Province, "FM", "OMC", meta.DeviceCode, "v0", meta.Time, meta.Index}, "-")
return strings.ToUpper(fileName)
}
func GenFile(meta *FileMeta, content []byte) (string, error) {
// 创建文件夹
dir, err := CreateDir(meta)
if err != nil {
return "", err
}
//创建文件
fileName := dir + "/" + GetName(meta) + ".txt"
err = os.WriteFile(fileName, content, 0666)
if err != nil {
return "", err
}
// 创建一个新的ZIP文件
fileName = fileName + ".zip"
zipFile, err := os.Create(fileName)
if err != nil {
return "", err
}
defer zipFile.Close()
// 创建一个ZIP写入器
zipWriter := zip.NewWriter(zipFile)
defer zipWriter.Close()
return fileName, nil
}

20
lib/file_test.go Normal file
View File

@@ -0,0 +1,20 @@
package lib
import (
"fmt"
"testing"
"time"
)
func TestFile(t *testing.T) {
var meta FileMeta
meta.DirRoot = "FTP"
meta.Province = "BJ"
meta.DeviceCode = "0001"
meta.Index = "001"
meta.Time = time.Now().Format("20060102150405")
meta.Compress = false
content := "this a test file"
f, err := GenFile(&meta, []byte(content))
fmt.Println(f, err)
}

14
lib/password.go Normal file
View File

@@ -0,0 +1,14 @@
package lib
import "golang.org/x/crypto/bcrypt"
// Encrypt 加密明文密码
func Encrypt(password string) (string, error) {
hashedBytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
return string(hashedBytes), err
}
// Compare 密文校验
func Compare(hashedPassword, password string) error {
return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
}

51
model/alarm.go Normal file
View File

@@ -0,0 +1,51 @@
package model
import "time"
type Alarm struct {
Id int
AlarmSeq int
AlarmId string
NeId string
AlarmCode int
AlarmTitle string
EventTime time.Time
AlarmType string
OrigSeverity string
PVFlag string
NeName string
NeType string
ObjectName string
ObjectUID string
ObjectType string
LocationInfo string
Province string
AlarmStatus int
SpecificProblem string
SpecificProblemID string
AddInfo string
ClearType int
ClearTime time.Time
}
func (Alarm) TableName() string {
return "alarm"
}
type NbiAlarmLog struct {
ID int64
AId int64
OpUser string
SrcIp string
NeType string
NeId string
AlarmSeq int64
AlarmId string
AlarmCode int
EventTime time.Time
LogTime time.Time
}
func (NbiAlarmLog) TableName() string {
return "nbi_alarm_log"
}

38
model/user.go Normal file
View File

@@ -0,0 +1,38 @@
package model
import "time"
type User struct {
Id int `json:"id"`
AccountId string `json:"account_id"`
Name string `json:"name"`
RealName string `json:"real_name"`
Sn string `json:"sn"`
Gender string `json:"gender"`
Email string `json:"email"`
IdCardNumber string `json:"id_card_number"`
Description string `json:"description"`
TelephoneNumber string `json:"telephone_number"`
Phone string `json:"phone"`
Mobile string `json:"mobile"`
EmployeeNumber string `json:"employee_number"`
EmployeeType string `json:"employee_type"`
Organize string `json:"organize"`
SupporterCorpName string `json:"supporter_corp_name"`
StartTime time.Time `json:"start_time"`
EndTime time.Time `json:"end_time"`
Password string `json:"password"`
PasswordSha512 string `json:"password_sha512"`
ChangePasswordFlag int `json:"change_password_flag"`
PasswordExpiration string `json:"password_expiration"`
Status string `json:"status"`
UserExpiration string `json:"user_expiration"`
GroupName string `json:"group_name"`
Profile string `json:"profile"`
CreateTime time.Time `json:"create_time"`
UpdateTime time.Time `json:"update_time"`
}
func (User) TableName() string {
return "user"
}

BIN
mysql_robot.exe Normal file

Binary file not shown.

BIN
nbi_alarm Normal file

Binary file not shown.

BIN
nbi_alarm_agent Normal file

Binary file not shown.

134
nbi_alarm_agent.go Normal file
View File

@@ -0,0 +1,134 @@
package main
import (
"fmt"
"github.com/aceld/zinx/zutils/commandline/args"
"omc/conf"
api2 "omc/api"
"omc/core"
"omc/db"
"omc/decoder"
"omc/dpack"
"omc/omc"
"os"
"os/signal"
"time"
"github.com/aceld/zinx/zconf"
"github.com/aceld/zinx/ziface"
"github.com/aceld/zinx/zlog"
"github.com/aceld/zinx/znet"
)
// OnConnectionAdd 当客户端建立连接的时候的hook函数
func OnConnectionAdd(conn ziface.IConnection) {
//创建一个user
user := core.NewUser(conn, conn.RemoteAddrString())
//将当前新上线玩家添加到ChannelManager中
m := core.GetManager(conn.GetName())
if m == nil {
zlog.Ins().ErrorF("server internal error in GetManager")
conn.Stop()
return
}
m.AddUser(user)
//将该连接绑定属性PID
conn.SetProperty("UID", user.UID)
zlog.Ins().InfoF("====> User uID = %s", user.UID, " arrived ====", "")
}
// OnConnectionLost 当客户端断开连接的时候的hook函数
func OnConnectionLost(conn ziface.IConnection) {
//获取当前连接的PID属性
uID, _ := conn.GetProperty("UID")
var userID string
if uID != nil {
userID = uID.(string)
}
//根据pID获取对应usr
m := core.GetManager(conn.GetName())
if m == nil {
zlog.Ins().ErrorF("server internal error in GetManager")
return
}
user := m.GetUserByPID(userID)
//触发玩家下线业务
if user != nil {
user.LostConnection(m)
}
zlog.Ins().InfoF("====> User %s-%s", user.UID, user.UserName, " left =====")
}
func main() {
//配置初始化
conf.Init(args.Args.ConfigFile)
db.Init()
//创建服务器句柄
for _, cg := range conf.OmcConf.Channel {
serverName := fmt.Sprintf("omc-tcp-Server-port:%d", cg.TCPPort)
//注册用户管理模块
m := core.NewManager(serverName, cg.BindFlag, cg.Province, cg.DeviceCode)
//new 一个TCP服务
s := znet.NewUserConfServer(&zconf.Config{
TCPPort: cg.TCPPort,
Name: serverName,
Host: "0.0.0.0",
MaxConn: 3000,
WorkerPoolSize: 10,
HeartbeatMax: conf.OmcConf.HeartbeatMax,
LogDir: conf.OmcConf.LogDir,
LogFile: conf.OmcConf.LogFile,
})
//注册客户端连接建立和丢失函数
s.SetOnConnStart(OnConnectionAdd)
s.SetOnConnStop(OnConnectionLost)
//注册路由
s.AddRouter(omc.ReqLoginAlarm, &api2.LoginApi{})
s.AddRouter(omc.ReqHeartBeat, &api2.HeartBeatApi{})
s.AddRouter(omc.CloseConnAlarm, &api2.CloseApi{})
s.AddRouter(omc.ReqSyncAlarmMsg, &api2.SyncAlarmApi{})
s.AddRouter(omc.ReqSyncAlarmFile, &api2.SyncAlarmFileApi{})
s.AddRouter(omc.ReqCMCALoginSeq, &api2.SyncAlarmFileApi{})
s.AddRouter(omc.ReqCMCALoginAlarm, &api2.SyncAlarmFileApi{})
//添加LTV数据格式Decoder
s.SetDecoder(decoder.NewOmcDecoder())
//添加LTV数据格式的Pack封包Encoder
s.SetPacket(dpack.NewDataPack())
// (启动心跳检测)
s.StartHeartBeatWithOption(60*time.Second, &ziface.HeartBeatOption{
MakeMsg: core.MyHeartBeatMsg,
OnRemoteNotAlive: core.MyOnRemoteNotAlive,
Router: &api2.HeartBeatApi{},
HeadBeatMsgID: uint32(0xFF),
})
// 设置默认的心跳发送函数
heart := s.GetHeartBeat()
heart.SetHeartbeatFunc(core.MyHeartBeat)
//启动服务
go s.Serve()
//启动实时告警
go m.RealTimeAlarm()
}
// close
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill)
sig := <-c
zlog.Ins().InfoF("===exit=== %s", sig)
}

38
omc/msg.go Normal file
View File

@@ -0,0 +1,38 @@
package omc
// ErrorMsg ackLoginAlarm;result=fail;resDesc=username-error
func ErrorMsg(msgType string, reqID string, desc string) []byte {
msgBody := MsgBody{
MsgName: msgType,
Msg: make(map[string]string, 0),
}
if reqID != "" {
msgBody.Msg["reqId"] = reqID
msgBody.Keys = append(msgBody.Keys, "reqId")
}
msgBody.Msg["result"] = "fail"
msgBody.Keys = append(msgBody.Keys, "result")
msgBody.Msg["resDesc"] = desc
msgBody.Keys = append(msgBody.Keys, "resDesc")
msgBody.Pack()
return msgBody.RawData
}
func SuccessMsg(msgType string, reqID string, desc string) []byte {
msgBody := MsgBody{
MsgName: msgType,
Msg: make(map[string]string, 0),
}
if reqID != "" {
msgBody.Msg["reqId"] = reqID
msgBody.Keys = append(msgBody.Keys, "reqId")
}
msgBody.Msg["result"] = "succ"
msgBody.Keys = append(msgBody.Keys, "result")
//msgBody.Msg["resDesc"] = desc
msgBody.Msg["resDesc"] = "succ"
msgBody.Keys = append(msgBody.Keys, "resDesc")
msgBody.Pack()
return msgBody.RawData
}

46
omc/omc_pack.go Normal file
View File

@@ -0,0 +1,46 @@
package omc
import (
"errors"
"fmt"
"strings"
)
type MsgBody struct {
UID string
RawData []byte
MsgName string
Msg map[string]string
Keys []string
}
// Decode
// reqLoginAlarm;user=yiy;key=qw#$@;type=msg
func (o *MsgBody) Decode() error {
multi := strings.Split(string(o.RawData), ";")
if len(multi) < 1 {
return errors.New("invalid msg body")
}
for i := 1; i < len(multi); i++ {
m := strings.Split(multi[i], "=")
if len(m) != 2 {
return errors.New("invalid msg body")
}
o.Msg[m[0]] = m[1]
}
return nil
}
// Pack
// reqLoginAlarm;user=yiy;key=qw#$@;type=msg
func (o *MsgBody) Pack() error {
var multi []string
multi = append(multi, o.MsgName)
for _, key := range o.Keys {
item := fmt.Sprintf("%s=%s", key, o.Msg[key])
multi = append(multi, item)
}
raw := strings.Join(multi, ";")
o.RawData = []byte(raw)
return nil
}

39
omc/omc_type.go Normal file
View File

@@ -0,0 +1,39 @@
package omc
const (
RealTimeAlarm = 0
ReqLoginAlarm = 1
AckLoginAlarm = 2
ReqSyncAlarmMsg = 3
AckSyncAlarmMsg = 4
ReqSyncAlarmFile = 5
AckSyncAlarmFile = 6
AckSyncAlarmFileResult = 7
ReqHeartBeat = 8
AckHeartBeat = 9
CloseConnAlarm = 10
ReqCMCALoginAlarm = 11
ReqCMCALoginSeq = 12
AckCMCALoginSeq = 13
)
//定义user type
const (
MSG = "msg"
FILE = "ftp"
)
func OrigSeverity(os string) int32 {
switch os {
case "Critical":
return 1
case "Major":
return 2
case "Minor":
return 3
case "Warning":
return 4
default:
return 0
}
}

43
readme.txt Normal file
View File

@@ -0,0 +1,43 @@
项目交付文件:
fpt://192.168.0.229/home/guodeng/bin
服务启动:
./nb_alarm_agent -c /home/guodeng/omc/conf/nb_alarm_agent.json
配置文件详情:
{
/* 通道配置项*/
"channel": [
{
"tcp_port": 31232, //通道TCP监听端口
"bind_flag": "SMF#SZ_01", //通道Bind网元格式为 ne_type#ne_id
"province": "BJ", //网元所在省份
"device_code": "0001" //网元主机编码
},
{
"tcp_port": 31233, //通道TCP监听端口
"bind_flag": "UDM#SZ_03", //通道Bind网元格式为 ne_type#ne_id
"province": "BJ", //网元所在省份
"device_code": "0002" //网元主机编码
}
],
// 数据库配置
"mysql": "root:1000omc@kp!@tcp(192.168.0.229:33066)/omc_db?charset=utf8mb4&parseTime=True&loc=Local",
// FTP服务器根目录
"ftp_root": "ftp:192.168.0.229/data/ftp",
//服务名称
"mame":"north agent",
// 心跳保活时间, 如果服务器检查client 在超过心跳时间没有数据(心跳数据或者业务数据)发送,则断开连接
"heartbeat_max": 180,
// 日志存放目录
"log_dir": "./omc_log",
// 日志文件名称
"log_file":"omc.log"
}

23
service/login.go Normal file
View File

@@ -0,0 +1,23 @@
package service
import (
"errors"
"github.com/aceld/zinx/zlog"
"omc/db"
"omc/lib"
"omc/model"
)
func UserLogin(name, pw string) error {
// 用户名密码校验
var user model.User
if err := db.Client.Model(&model.User{}).Where("account_id=?", name).First(&user).Error; err != nil {
return err
}
if err := lib.Compare(user.Password, pw); err != nil {
zlog.Ins().ErrorF("Password Login[%s]:%s", name, err)
return errors.New("incorrect username and password")
}
return nil
}

View File

@@ -0,0 +1,91 @@
package service
import (
"encoding/json"
"github.com/aceld/zinx/zlog"
"omc/db"
"omc/model"
"omc/omc"
)
type OmcAlarm struct {
AId int64 `json:"-"`
AlarmSeq int32 `json:"alarmSeq"` //告警序列号
AlarmTitle string `json:"alarmTitle"` //告警事件标题
AlarmStatus int32 `json:"alarmStatus"` //告警状态
AlarmType string `json:"alarmType"` //告警类型
OrigSeverity int32 `json:"origSeverity"` //原始级别
EventTime string `json:"eventTime"` //事件发生时间
AlarmId string `json:"alarmId"` //告警事件唯一标识
SpecificProblemID string `json:"specificProblemID"` //告警问题原因ID
SpecificProblem string `json:"specificProblem"` //告警问题原因
NeUID string `json:"neUID"` //告警网元UID
NeName string `json:"neName"` //告警网元名称
NeType string `json:"neType"` //告警网元设备类型
ObjectUID string `json:"objectUID"` //告警定位对象UID
ObjectName string `json:"objectName"` //告警定位对象名称
ObjectType string `json:"objectType"` //告警定位对象资源类型
LocationInfo string `json:"locationInfo"` //告警定位信息
AddInfo string `json:"addInfo"` //告警辅助信息[条件必选]
PVFlag string `json:"PVFlag"` //网元虚实性[条件必选]
Province string `json:"province"` //网元服务省份
}
// GetRealTimeAlarm 获取最新的告警信息
func GetRealTimeAlarm(neType, neId string, alarmSeq int32) ([]OmcAlarm, error) {
var alarms []model.Alarm
var result []OmcAlarm
if err := db.Client.Model(&model.Alarm{}).Where("ne_type = ? and ne_id = ? and alarm_seq >= ?", neType, neId, alarmSeq).Order("alarm_seq asc").Find(&alarms).Error; err != nil {
return nil, err
}
for _, v := range alarms {
var item OmcAlarm
item.AlarmSeq = int32(v.AlarmSeq)
item.AlarmTitle = v.AlarmTitle
item.AlarmStatus = int32(v.AlarmStatus)
item.AlarmType = v.AlarmType
item.OrigSeverity = omc.OrigSeverity(v.OrigSeverity)
item.EventTime = v.EventTime.Format("2006-01-02 15:04:05")
item.AlarmId = v.AlarmId
item.SpecificProblemID = v.SpecificProblemID
item.SpecificProblem = v.SpecificProblem
item.NeUID = v.NeId
item.NeName = v.NeName
item.NeType = v.NeType
item.ObjectUID = v.ObjectUID
item.ObjectName = v.NeName
item.ObjectType = v.ObjectType
item.LocationInfo = v.LocationInfo
item.AddInfo = v.AddInfo
item.PVFlag = v.PVFlag
item.Province = v.Province
item.AId = int64(v.Id)
result = append(result, item)
}
return result, nil
}
// GetLastAlarmSeq 获取最新的alarm seq
func GetLastAlarmSeq(neType, neId string) int32 {
var alarm model.Alarm
if err := db.Client.Model(&model.Alarm{}).Where("ne_type = ? and ne_id = ?", neType, neId).Order("alarm_seq desc").First(&alarm).Error; err != nil {
zlog.Ins().ErrorF("db error %s", err)
return 0
}
return int32(alarm.AlarmSeq) + 1
}
func GenAlarm(alarm OmcAlarm) []byte {
data, _ := json.Marshal(&alarm)
return data
}
func MaxAlarm(current int32, alarms []OmcAlarm) int32 {
var req = current
for _, v := range alarms {
if v.AlarmSeq > req {
req = v.AlarmSeq
}
}
return req
}

219
service/sysn_alarm_file.go Normal file
View File

@@ -0,0 +1,219 @@
package service
import (
"bytes"
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"omc/db"
"omc/lib"
"omc/model"
"omc/omc"
"time"
"github.com/aceld/zinx/ziface"
)
func GenFile(request ziface.IRequest, meta *lib.FileMeta, data []OmcAlarm) {
//生成文件内容
dataBuff := bytes.NewBuffer([]byte{})
for _, v := range data {
b, _ := json.Marshal(v)
binary.Write(dataBuff, binary.BigEndian, b)
binary.Write(dataBuff, binary.BigEndian, '\r')
binary.Write(dataBuff, binary.BigEndian, '\n')
}
file, err := lib.GenFile(meta, dataBuff.Bytes())
if err != nil {
return
}
// add by simon at 2023/08/14
fmt.Println("meta:", meta)
if meta.ReqId == "" {
meta.ReqId = "2"
}
//发送文件同步信息
ackBody := omc.MsgBody{
MsgName: "ackSyncAlarmFileResult",
Msg: make(map[string]string, 0),
}
ackBody.Msg["reqId"] = meta.ReqId
ackBody.Keys = append(ackBody.Keys, "reqId")
ackBody.Msg["result"] = "succ"
ackBody.Keys = append(ackBody.Keys, "result")
ackBody.Msg["fileName"] = file
ackBody.Keys = append(ackBody.Keys, "fileName")
ackBody.Msg["resDesc"] = "succ"
ackBody.Keys = append(ackBody.Keys, "resDesc")
ackBody.Pack()
request.GetConnection().SendMsg(omc.AckSyncAlarmFileResult, ackBody.RawData)
}
// GetAlarmOfAlarmSeq 获取告警信息
func GetAlarmOfAlarmSeq(neType, neId string, alarmSeq int) ([]OmcAlarm, error) {
var alarms []model.Alarm
var result []OmcAlarm
query := db.Client.Model(&model.Alarm{}).Where("ne_type = ? and ne_id = ? and alarm_seq > ?", neType, neId, alarmSeq)
if err := query.Order("alarm_seq asc").Find(&alarms).Error; err != nil {
return nil, err
}
for _, v := range alarms {
var item OmcAlarm
item.AlarmSeq = int32(v.AlarmSeq)
item.AlarmTitle = v.AlarmTitle
item.AlarmStatus = int32(v.AlarmStatus)
item.AlarmType = v.AlarmType
item.OrigSeverity = omc.OrigSeverity(v.OrigSeverity)
item.EventTime = v.EventTime.Format("2006-01-02 15:04:05")
item.AlarmId = v.AlarmId
item.SpecificProblemID = v.SpecificProblemID
item.SpecificProblem = v.SpecificProblem
item.NeUID = v.NeId
item.NeName = v.NeName
item.NeType = v.NeType
item.ObjectUID = v.ObjectUID
item.ObjectName = v.NeName
item.ObjectType = v.ObjectType
item.LocationInfo = v.LocationInfo
item.AddInfo = v.AddInfo
item.PVFlag = v.PVFlag
item.Province = v.Province
result = append(result, item)
}
return result, nil
}
//GetAlarm
/*
1 如果syncSource=1 && alarmSeq 为空: 从北向告警上报日志中(nbi_alarm_log)取数据ID然后反查告警信息表(alarm)取出告警日志
2 其他情况: 从告警信息表中取数据, 数据来源为设备告警事件
*/
func GetAlarm(neType, neId, startTime, endTime, syncSource string, alarmSeq int) ([]OmcAlarm, error) {
if syncSource == "0" {
return GetAlarmOfEventTime(neType, neId, startTime, endTime)
} else {
if alarmSeq > 0 {
return GetAlarmOfAlarmSeq(neType, neId, alarmSeq)
} else {
return GetAlarmOfLog(neType, neId, startTime, endTime)
}
}
}
// GetAlarmOfEventTime 获取告警信息
func GetAlarmOfEventTime(neType, neId, startTime, endTime string) ([]OmcAlarm, error) {
var alarms []model.Alarm
var result []OmcAlarm
if startTime == "" && endTime == "" {
return result, nil
}
query := db.Client.Model(&model.Alarm{}).Where("ne_type = ? and ne_id = ?", neType, neId)
if startTime != "" {
t1, err := time.Parse("2006-01-02 15:04:05", startTime)
if err != nil {
return nil, errors.New("startTime invalid")
}
query = query.Where("event_time > ?", t1)
}
if endTime != "" {
t2, err := time.Parse("2006-01-02 15:04:05", endTime)
if err != nil {
return nil, errors.New("endTime invalid")
}
query = query.Where("event_time < ?", t2)
}
if err := query.Order("alarm_seq asc").Find(&alarms).Error; err != nil {
return nil, err
}
for _, v := range alarms {
var item OmcAlarm
item.AlarmSeq = int32(v.AlarmSeq)
item.AlarmTitle = v.AlarmTitle
item.AlarmStatus = int32(v.AlarmStatus)
item.AlarmType = v.AlarmType
item.OrigSeverity = omc.OrigSeverity(v.OrigSeverity)
item.EventTime = v.EventTime.Format("2006-01-02 15:04:05")
item.AlarmId = v.AlarmId
item.SpecificProblemID = v.SpecificProblemID
item.SpecificProblem = v.SpecificProblem
item.NeUID = v.NeId
item.NeName = v.NeName
item.NeType = v.NeType
item.ObjectUID = v.ObjectUID
item.ObjectName = v.NeName
item.ObjectType = v.ObjectType
item.LocationInfo = v.LocationInfo
item.AddInfo = v.AddInfo
item.PVFlag = v.PVFlag
item.Province = v.Province
result = append(result, item)
}
return result, nil
}
// GetAlarmOfLog 获取告警信息
func GetAlarmOfLog(neType, neId, startTime, endTime string) ([]OmcAlarm, error) {
var alarms []model.Alarm
var result []OmcAlarm
if startTime == "" && endTime == "" {
return result, nil
}
var aIDs []int64
query := db.Client.Model(&model.NbiAlarmLog{}).Select("distinct a_id").Where("ne_type = ? and ne_id = ?", neType, neId)
if startTime != "" {
t1, err := time.Parse("2006-01-02 15:04:05", startTime)
if err != nil {
return nil, errors.New("startTime invalid")
}
query = query.Where("log_time >= ?", t1)
}
if endTime != "" {
t2, err := time.Parse("2006-01-02 15:04:05", endTime)
if err != nil {
return nil, errors.New("endTime invalid")
}
query = query.Where("log_time <= ?", t2)
}
if err := query.Order("alarm_seq asc").Find(&aIDs).Error; err != nil {
return nil, err
}
if err := db.Client.Model(&model.Alarm{}).Where("id in (?)", aIDs).Find(&alarms).Error; err != nil {
return nil, err
}
for _, v := range alarms {
var item OmcAlarm
item.AlarmSeq = int32(v.AlarmSeq)
item.AlarmTitle = v.AlarmTitle
item.AlarmStatus = int32(v.AlarmStatus)
item.AlarmType = v.AlarmType
item.OrigSeverity = omc.OrigSeverity(v.OrigSeverity)
item.EventTime = v.EventTime.Format("2006-01-02 15:04:05")
item.AlarmId = v.AlarmId
item.SpecificProblemID = v.SpecificProblemID
item.SpecificProblem = v.SpecificProblem
item.NeUID = v.NeId
item.NeName = v.NeName
item.NeType = v.NeType
item.ObjectUID = v.ObjectUID
item.ObjectName = v.NeName
item.ObjectType = v.ObjectType
item.LocationInfo = v.LocationInfo
item.AddInfo = v.AddInfo
item.PVFlag = v.PVFlag
item.Province = v.Province
result = append(result, item)
}
return result, nil
}