Browse Source
Merge pull request #645 from nightsimon/feat/notify-dingding
Merge pull request #645 from nightsimon/feat/notify-dingding
Feat/notify dingdingmain
奇淼(piexlmax
3 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 270 additions and 0 deletions
-
25server/initialize/router.go
-
38server/plugin/notify/README.MD
-
21server/plugin/notify/api/api.go
-
7server/plugin/notify/api/enter.go
-
7server/plugin/notify/config/dingding.go
-
9server/plugin/notify/global/global.go
-
24server/plugin/notify/main.go
-
7server/plugin/notify/router/enter.go
-
18server/plugin/notify/router/router.go
-
7server/plugin/notify/service/enter.go
-
106server/plugin/notify/service/notify.go
-
1server/plugin/notify/utils/utils.go
@ -0,0 +1,38 @@ |
|||
## GVA 钉钉群通知插件 |
|||
|
|||
本插件用于向钉钉群推送消息 |
|||
|
|||
### 1. 使用场景 |
|||
|
|||
- 当服务运行异常时,可以向钉钉推送异常信息,便于及时发现解决问题 |
|||
- 推送一些关键业务的运行日志等 |
|||
|
|||
### 2. 配置说明 |
|||
|
|||
钉钉 token 等相关信息的获取,请参考 [钉钉官网](https://developers.dingtalk.com/document/robots/custom-robot-access?spm=ding_open_doc.document.0.0.7f8710afbfzduV#topic-2026027) |
|||
|
|||
在`plugin/notify/global/global.go` 文件中配置钉钉通知的URL ,Token 等 |
|||
|
|||
```go |
|||
var GlobalConfig_ = &config.DingDing{ |
|||
Url: "https://oapi.dingtalk.com/robot/send", |
|||
Token: "xxx", |
|||
Secret: "xxx", |
|||
} |
|||
``` |
|||
### 3. 使用说明 |
|||
|
|||
在代码中调用 `SendTextMessage` 方法即可 |
|||
```go |
|||
func NotifyController(c *gin.Context) { |
|||
if err := service.ServiceGroupApp.SendTextMessage("test"); err != nil { |
|||
global.GVA_LOG.Error("发送失败!", zap.Any("err", err)) |
|||
response.FailWithMessage("发送失败", c) |
|||
} else { |
|||
response.OkWithData("发送成功", c) |
|||
} |
|||
} |
|||
|
|||
``` |
|||
### 方法API |
|||
|
@ -0,0 +1,21 @@ |
|||
package api |
|||
|
|||
import ( |
|||
"github.com/flipped-aurora/gin-vue-admin/server/global" |
|||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response" |
|||
"github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/service" |
|||
"github.com/gin-gonic/gin" |
|||
"go.uber.org/zap" |
|||
) |
|||
|
|||
type Api struct { |
|||
} |
|||
|
|||
func (s *Api) NotifyController(c *gin.Context) { |
|||
if err := service.ServiceGroupApp.SendTextMessage("test"); err != nil { |
|||
global.GVA_LOG.Error("发送失败!", zap.Any("err", err)) |
|||
response.FailWithMessage("发送失败", c) |
|||
} else { |
|||
response.OkWithData("发送成功", c) |
|||
} |
|||
} |
@ -0,0 +1,7 @@ |
|||
package api |
|||
|
|||
type ApiGroup struct { |
|||
Api |
|||
} |
|||
|
|||
var ApiGroupApp = new(ApiGroup) |
@ -0,0 +1,7 @@ |
|||
package config |
|||
|
|||
type DingDing struct { |
|||
Url string `mapstructure:"url" json:"url" yaml:"url"` // Url
|
|||
Token string `mapstructure:"token" json:"token" yaml:"token"` // Token
|
|||
Secret string `mapstructure:"secret" json:"secret" yaml:"secret"` // 密钥
|
|||
} |
@ -0,0 +1,9 @@ |
|||
package global |
|||
|
|||
import "github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/config" |
|||
|
|||
var GlobalConfig_ = &config.DingDing{ |
|||
Url: "https://oapi.dingtalk.com/robot/send", |
|||
Token: "77d18293e221b3b7bdae7330d19a213c3cbb20fa07de5f4c273c0363ae475c34", |
|||
Secret: "SEC38425b7bd57c6bca9ce20611c41b437994ed65e0ddbd42e840ffa7a8c7da2106", |
|||
} |
@ -0,0 +1,24 @@ |
|||
package notify |
|||
|
|||
import ( |
|||
"github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/router" |
|||
"github.com/gin-gonic/gin" |
|||
) |
|||
|
|||
type ddPlugin struct { |
|||
Secret string |
|||
Token string |
|||
Url string |
|||
} |
|||
|
|||
func CreateDDPlug() *ddPlugin { |
|||
return &ddPlugin{} |
|||
} |
|||
|
|||
func (*ddPlugin) Register(group *gin.RouterGroup) { |
|||
router.RouterGroupApp.InitRouter(group) |
|||
} |
|||
|
|||
func (*ddPlugin) RouterPath() string { |
|||
return "notify" |
|||
} |
@ -0,0 +1,7 @@ |
|||
package router |
|||
|
|||
type RouterGroup struct { |
|||
NotifyRouter |
|||
} |
|||
|
|||
var RouterGroupApp = new(RouterGroup) |
@ -0,0 +1,18 @@ |
|||
package router |
|||
|
|||
import ( |
|||
"github.com/flipped-aurora/gin-vue-admin/server/middleware" |
|||
"github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/api" |
|||
"github.com/gin-gonic/gin" |
|||
) |
|||
|
|||
type NotifyRouter struct { |
|||
} |
|||
|
|||
func (s *NotifyRouter) InitRouter(Router *gin.RouterGroup) { |
|||
router := Router.Use(middleware.OperationRecord()) |
|||
var Controller = api.ApiGroupApp.Api.NotifyController |
|||
{ |
|||
router.POST("dingding", Controller) |
|||
} |
|||
} |
@ -0,0 +1,7 @@ |
|||
package service |
|||
|
|||
type ServiceGroup struct { |
|||
NotifyService |
|||
} |
|||
|
|||
var ServiceGroupApp = new(ServiceGroup) |
@ -0,0 +1,106 @@ |
|||
package service |
|||
|
|||
import ( |
|||
"bytes" |
|||
"crypto/hmac" |
|||
"crypto/sha256" |
|||
"encoding/base64" |
|||
"encoding/json" |
|||
"fmt" |
|||
"github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/global" |
|||
"io/ioutil" |
|||
"net/http" |
|||
"net/url" |
|||
"time" |
|||
) |
|||
|
|||
type NotifyService struct { |
|||
} |
|||
|
|||
//@author: [Espoir](https://github.com/nightsimon)
|
|||
//@function: NotifyController
|
|||
//@description: 钉钉通知测试
|
|||
//@return: err error
|
|||
|
|||
func (e *NotifyService) SendTextMessage(content string) (err error) { |
|||
msg := map[string]interface{}{ |
|||
"msgtype": "text", |
|||
"text": map[string]string{ |
|||
"content": content, |
|||
}, |
|||
//"at": map[string]interface{}{
|
|||
// "atMobiles": atMobiles,
|
|||
// "isAtAll": isAtAll,
|
|||
//},
|
|||
} |
|||
return SendMessage(msg) |
|||
} |
|||
|
|||
func SendMessage(msg interface{}) error { |
|||
body := bytes.NewBuffer(nil) |
|||
err := json.NewEncoder(body).Encode(msg) |
|||
if err != nil { |
|||
return fmt.Errorf("msg json failed, msg: %v, err: %v", msg, err.Error()) |
|||
} |
|||
|
|||
value := url.Values{} |
|||
value.Set("access_token", global.GlobalConfig_.Token) |
|||
if global.GlobalConfig_.Secret != "" { |
|||
t := time.Now().UnixNano() / 1e6 |
|||
value.Set("timestamp", fmt.Sprintf("%d", t)) |
|||
value.Set("sign", sign(t, global.GlobalConfig_.Secret)) |
|||
} |
|||
|
|||
request, err := http.NewRequest(http.MethodPost, global.GlobalConfig_.Url, body) |
|||
if err != nil { |
|||
return fmt.Errorf("error request: %v", err.Error()) |
|||
} |
|||
request.URL.RawQuery = value.Encode() |
|||
request.Header.Add("Content-Type", "application/json") |
|||
res, err := (&http.Client{}).Do(request) |
|||
if err != nil { |
|||
return fmt.Errorf("send dingTalk message failed, error: %v", err.Error()) |
|||
} |
|||
defer func() { _ = res.Body.Close() }() |
|||
result, err := ioutil.ReadAll(res.Body) |
|||
|
|||
if res.StatusCode != 200 { |
|||
return fmt.Errorf("send dingTalk message failed, %s", httpError(request, res, result, "http code is not 200")) |
|||
} |
|||
if err != nil { |
|||
return fmt.Errorf("send dingTalk message failed, %s", httpError(request, res, result, err.Error())) |
|||
} |
|||
|
|||
type response struct { |
|||
ErrCode int `json:"errcode"` |
|||
} |
|||
var ret response |
|||
|
|||
if err := json.Unmarshal(result, &ret); err != nil { |
|||
return fmt.Errorf("send dingTalk message failed, %s", httpError(request, res, result, err.Error())) |
|||
} |
|||
|
|||
if ret.ErrCode != 0 { |
|||
return fmt.Errorf("send dingTalk message failed, %s", httpError(request, res, result, "errcode is not 0")) |
|||
} |
|||
|
|||
return nil |
|||
} |
|||
|
|||
func httpError(request *http.Request, response *http.Response, body []byte, error string) string { |
|||
return fmt.Sprintf( |
|||
"http request failure, error: %s, status code: %d, %s %s, body:\n%s", |
|||
error, |
|||
response.StatusCode, |
|||
request.Method, |
|||
request.URL.String(), |
|||
string(body), |
|||
) |
|||
} |
|||
func sign(t int64, secret string) string { |
|||
strToHash := fmt.Sprintf("%d\n%s", t, secret) |
|||
hmac256 := hmac.New(sha256.New, []byte(secret)) |
|||
hmac256.Write([]byte(strToHash)) |
|||
data := hmac256.Sum(nil) |
|||
return base64.StdEncoding.EncodeToString(data) |
|||
} |
@ -0,0 +1 @@ |
|||
package utils |
Write
Preview
Loading…
Cancel
Save
Reference in new issue