feat: 新增通知模块,暂时只有邮件和smsc发送
This commit is contained in:
11
src/modules/notification/notification.go
Normal file
11
src/modules/notification/notification.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package notification
|
||||||
|
|
||||||
|
import (
|
||||||
|
"be.ems/src/framework/logger"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 模块路由注册
|
||||||
|
func Setup(router *gin.Engine) {
|
||||||
|
logger.Infof("开始加载 ====> notification 模块路由")
|
||||||
|
}
|
||||||
126
src/modules/notification/service/email.go
Normal file
126
src/modules/notification/service/email.go
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
ht "html/template"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/wneessen/go-mail"
|
||||||
|
|
||||||
|
"be.ems/src/framework/config"
|
||||||
|
"be.ems/src/framework/logger"
|
||||||
|
"be.ems/src/framework/utils/date"
|
||||||
|
"be.ems/src/framework/utils/parse"
|
||||||
|
neDataModel "be.ems/src/modules/network_data/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EmailAlarm 发告警邮件
|
||||||
|
func EmailAlarm(a neDataModel.Alarm, neIP string) error {
|
||||||
|
emailList := fmt.Sprint(config.Get("notification.email.list"))
|
||||||
|
if len(emailList) == 0 {
|
||||||
|
return fmt.Errorf("email list is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模板
|
||||||
|
htmlBodyTemplate := `
|
||||||
|
<strong>Alarm information</strong>
|
||||||
|
<p style="text-indent: 2.5em;">Sequence: {{.AlarmSeq}}</p>
|
||||||
|
<p style="text-indent: 2.5em;">NE Name: {{.NeName}}</p>
|
||||||
|
<p style="text-indent: 4.5em;">NE IP: {{.NeIp}}</p>
|
||||||
|
<p style="text-indent: 5em;">Title: {{.AlarmTitle}}</p>
|
||||||
|
<p style="text-indent: 3.5em;">Severity: {{.OrigSeverity}}</p>
|
||||||
|
<p style="text-indent: 2.5em;">Event Time: {{.AlarmTime}}</p>
|
||||||
|
<p style="text-indent: 2em;">Alarm Status: {{.AlarmStatus}}</p>
|
||||||
|
<i>Automatic sent by OMC, please do not reply!</i>
|
||||||
|
`
|
||||||
|
htmlTpl, err := ht.New("htmltpl").Parse(htmlBodyTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("EmailAlarm Parse alarmId:%s fail %s", a.AlarmId, err.Error())
|
||||||
|
}
|
||||||
|
// 参数值
|
||||||
|
data := map[string]any{
|
||||||
|
"AlarmSeq": a.AlarmSeq,
|
||||||
|
"NeName": a.NeName,
|
||||||
|
"NeIp": neIP,
|
||||||
|
"AlarmTitle": a.AlarmTitle,
|
||||||
|
"OrigSeverity": a.OrigSeverity,
|
||||||
|
"AlarmTime": date.ParseDateToStr(a.EventTime, time.RFC3339),
|
||||||
|
"AlarmStatus": a.AlarmStatus,
|
||||||
|
}
|
||||||
|
buffer := bytes.NewBuffer(nil)
|
||||||
|
if err := htmlTpl.Execute(buffer, data); err != nil {
|
||||||
|
return fmt.Errorf("EmailAlarm Execute alarmId:%s fail %s", a.AlarmId, err.Error())
|
||||||
|
}
|
||||||
|
htmlStr := buffer.String()
|
||||||
|
|
||||||
|
// 发送邮件
|
||||||
|
err = EmailSendHTML(htmlStr, strings.Split(emailList, ","))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("EmailAlarm alarmId:%s fail %s", a.AlarmId, err.Error())
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmailSendHTML 发送HTML邮件
|
||||||
|
func EmailSendHTML(htmlStr string, toEmailArr []string) error {
|
||||||
|
// QQ 邮箱:
|
||||||
|
// SMTP 服务器地址:smtp.qq.com(SSL协议端口:465/994 | 非SSL协议端口:25)
|
||||||
|
// 163 邮箱:
|
||||||
|
// SMTP 服务器地址:smtp.163.com(端口:25)
|
||||||
|
// host := "mail.agrandtech.com"
|
||||||
|
// port := 25
|
||||||
|
// userName := "smtpext@agrandtech.com"
|
||||||
|
// password := "1000smtp@omc!"
|
||||||
|
|
||||||
|
emailConf := config.Get("notification.email").(map[string]any)
|
||||||
|
enable := parse.Boolean(emailConf["enable"])
|
||||||
|
if !enable {
|
||||||
|
return fmt.Errorf("email notification not enable")
|
||||||
|
}
|
||||||
|
title := fmt.Sprint(emailConf["title"])
|
||||||
|
smtp := fmt.Sprint(emailConf["smtp"])
|
||||||
|
port := parse.Number(emailConf["port"])
|
||||||
|
user := fmt.Sprint(emailConf["user"])
|
||||||
|
password := fmt.Sprint(emailConf["password"])
|
||||||
|
|
||||||
|
message := mail.NewMsg()
|
||||||
|
// 发件人
|
||||||
|
if err := message.From(user); err != nil {
|
||||||
|
return fmt.Errorf("failed to set From address: %s", err)
|
||||||
|
}
|
||||||
|
// 收件人
|
||||||
|
hasTo := false
|
||||||
|
for _, v := range toEmailArr {
|
||||||
|
if err := message.AddTo(v); err != nil {
|
||||||
|
logger.Errorf("failed to set To address: %v %s", v, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
hasTo = true
|
||||||
|
}
|
||||||
|
if !hasTo {
|
||||||
|
return fmt.Errorf("failed to set To address not has")
|
||||||
|
}
|
||||||
|
// 邮件主题
|
||||||
|
message.Subject(title)
|
||||||
|
// 邮件HTML内容
|
||||||
|
message.SetBodyString(mail.TypeTextHTML, htmlStr)
|
||||||
|
// 连接到邮件SMTP服务器
|
||||||
|
client, err := mail.NewClient(smtp,
|
||||||
|
mail.WithSMTPAuth(mail.SMTPAuthAutoDiscover),
|
||||||
|
mail.WithUsername(user),
|
||||||
|
mail.WithPort(int(port)),
|
||||||
|
mail.WithPassword(password),
|
||||||
|
mail.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create mail client: %s", err)
|
||||||
|
}
|
||||||
|
// 发送
|
||||||
|
if err := client.DialAndSend(message); err != nil {
|
||||||
|
return fmt.Errorf("failed to send mail: %s", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
164
src/modules/notification/service/smsc.go
Normal file
164
src/modules/notification/service/smsc.go
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
tt "text/template"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/linxGnu/gosmpp"
|
||||||
|
"github.com/linxGnu/gosmpp/data"
|
||||||
|
"github.com/linxGnu/gosmpp/pdu"
|
||||||
|
|
||||||
|
"be.ems/src/framework/config"
|
||||||
|
"be.ems/src/framework/logger"
|
||||||
|
"be.ems/src/framework/utils/date"
|
||||||
|
"be.ems/src/framework/utils/parse"
|
||||||
|
neDataModel "be.ems/src/modules/network_data/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
var smscSession *gosmpp.Session
|
||||||
|
|
||||||
|
// connSM 连接smsc
|
||||||
|
func connSM() *gosmpp.Session {
|
||||||
|
if smscSession != nil {
|
||||||
|
return smscSession
|
||||||
|
}
|
||||||
|
smscAddr := fmt.Sprint(config.Get("notification.smsc.addr"))
|
||||||
|
systemType := fmt.Sprint(config.Get("notification.smsc.systemtype"))
|
||||||
|
systemID := fmt.Sprint(config.Get("notification.smsc.systemid"))
|
||||||
|
password := fmt.Sprint(config.Get("notification.smsc.password"))
|
||||||
|
// 建立连接
|
||||||
|
session, err := gosmpp.NewSession(
|
||||||
|
gosmpp.TXConnector(gosmpp.NonTLSDialer, gosmpp.Auth{
|
||||||
|
SMSC: smscAddr,
|
||||||
|
SystemID: systemID,
|
||||||
|
Password: password,
|
||||||
|
SystemType: systemType,
|
||||||
|
}),
|
||||||
|
gosmpp.Settings{
|
||||||
|
ReadTimeout: 2 * time.Second,
|
||||||
|
OnSubmitError: func(_ pdu.PDU, err error) {
|
||||||
|
logger.Errorf("failed to smpp submit error: %s", err.Error())
|
||||||
|
},
|
||||||
|
OnRebindingError: func(err error) {
|
||||||
|
logger.Errorf("failed to smpp rebinding error: %s", err.Error())
|
||||||
|
},
|
||||||
|
}, -1)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("failed to create smpp new session error: %s", err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// defer session.Close()
|
||||||
|
smscSession = session
|
||||||
|
return smscSession
|
||||||
|
}
|
||||||
|
|
||||||
|
// newSubmitSM 构建短信提交
|
||||||
|
func newSubmitSM(destSM string, message string) (*pdu.SubmitSM, error) {
|
||||||
|
dataCoding := parse.Number(config.Get("notification.smsc.coding"))
|
||||||
|
enc := data.FromDataCoding(byte(dataCoding))
|
||||||
|
srcSM := fmt.Sprint(config.Get("notification.smsc.servicenumber"))
|
||||||
|
// 源地址
|
||||||
|
srcAddr := pdu.NewAddress()
|
||||||
|
srcAddr.SetTon(5)
|
||||||
|
srcAddr.SetNpi(0)
|
||||||
|
err := srcAddr.SetAddress(srcSM)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
destAddr := pdu.NewAddress()
|
||||||
|
destAddr.SetTon(1)
|
||||||
|
destAddr.SetNpi(1)
|
||||||
|
err = destAddr.SetAddress(destSM)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// build up submitSM
|
||||||
|
submitSM := pdu.NewSubmitSM().(*pdu.SubmitSM)
|
||||||
|
submitSM.SourceAddr = srcAddr
|
||||||
|
submitSM.DestAddr = destAddr
|
||||||
|
if err = submitSM.Message.SetMessageWithEncoding(message, enc); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
submitSM.ProtocolID = 0
|
||||||
|
submitSM.RegisteredDelivery = 1
|
||||||
|
submitSM.ReplaceIfPresentFlag = 0
|
||||||
|
submitSM.EsmClass = 0
|
||||||
|
return submitSM, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SMSCAlarm 发告警短信
|
||||||
|
func SMSCAlarm(a neDataModel.Alarm, neIP string) error {
|
||||||
|
mobileList := fmt.Sprint(config.Get("notification.smsc.list"))
|
||||||
|
if len(mobileList) == 0 {
|
||||||
|
return fmt.Errorf("smsc list is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模板
|
||||||
|
textBodyTemplate := `Alarm Notification
|
||||||
|
Sequence: {{.AlarmSeq}},
|
||||||
|
NE Name: {{.NeName}}
|
||||||
|
NE IP: {{.NeIp}}
|
||||||
|
Title: {{.AlarmTitle}}
|
||||||
|
Severity: {{.OrigSeverity}}
|
||||||
|
Event Time: {{.AlarmTime}}
|
||||||
|
Alarm Status: {{.AlarmStatus}}
|
||||||
|
Automatic sent by OMC, please do not reply!`
|
||||||
|
textTpl, err := tt.New("texttpl").Parse(textBodyTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("SMSCAlarm alarmId:%s fail %s", a.AlarmId, err.Error())
|
||||||
|
}
|
||||||
|
// 参数值
|
||||||
|
data := map[string]any{
|
||||||
|
"AlarmSeq": a.AlarmSeq,
|
||||||
|
"NeName": a.NeName,
|
||||||
|
"NeIp": neIP,
|
||||||
|
"AlarmTitle": a.AlarmTitle,
|
||||||
|
"OrigSeverity": a.OrigSeverity,
|
||||||
|
"AlarmTime": date.ParseDateToStr(a.EventTime, time.RFC3339),
|
||||||
|
"AlarmStatus": a.AlarmStatus,
|
||||||
|
}
|
||||||
|
buffer := bytes.NewBuffer(nil)
|
||||||
|
if err := textTpl.Execute(buffer, data); err != nil {
|
||||||
|
return fmt.Errorf("EmailAlarm Execute alarmId:%s fail %s", a.AlarmId, err.Error())
|
||||||
|
}
|
||||||
|
textStr := buffer.String()
|
||||||
|
|
||||||
|
// 发送短信
|
||||||
|
err = SMSCSendText(textStr, strings.Split(mobileList, ","))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("EmailAlarm alarmId:%s fail %s", a.AlarmId, err.Error())
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SMSCSendText 发送文本短信
|
||||||
|
func SMSCSendText(textStr string, toMobileArr []string) error {
|
||||||
|
enable := parse.Boolean(config.Get("notification.smsc.enable"))
|
||||||
|
if !enable {
|
||||||
|
return fmt.Errorf("smsc notification not enable")
|
||||||
|
}
|
||||||
|
sm := connSM()
|
||||||
|
if sm == nil {
|
||||||
|
return fmt.Errorf("smpp new session create failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
errArr := []string{}
|
||||||
|
for _, v := range toMobileArr {
|
||||||
|
submitSM, err := newSubmitSM(v, textStr)
|
||||||
|
if err != nil {
|
||||||
|
errArr = append(errArr, err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err = sm.Transceiver().Submit(submitSM); err != nil {
|
||||||
|
errArr = append(errArr, err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(errArr) > 0 {
|
||||||
|
return fmt.Errorf("%s", strings.Join(errArr, ","))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user