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