feat: support tencent custom alarm now (close #87)

This commit is contained in:
JustSong
2023-05-15 22:57:12 +08:00
parent 0f73bf4185
commit 8ead1f76cd
6 changed files with 167 additions and 14 deletions
+17 -14
View File
@@ -58,6 +58,7 @@ _✨ 搭建专属于你的消息推送服务,支持多种消息推送方式,
+ WebSocket 客户端([官方客户端](https://github.com/songquanpeng/personal-assistant)[接入文档](./docs/API.md#websocket-客户端)),
+ Telegram 机器人,
+ Discord 群机器人,
+ 腾讯云自定义告警:免费的短信提醒,
+ 群组消息:可以将多个推送通道组合成一个群组,然后向群组发送消息,可以实现一次性推送到多个渠道的功能,
+ 自定义消息,可以自定义消息请求 URL 和请求体格式,实现与其他服务的对接,支持[众多第三方服务](https://iamazing.cn/page/message-pusher-common-custom-templates)。
2. 支持**自定义 Webhook,反向适配各种调用平台**,你可以接入各种已有的系统,而无需修改其代码。
@@ -211,7 +212,8 @@ proxy_send_timeout 300s;
12. `one_api`:通过 OneAPI 协议推送消息到 QQ。
13. `group`:通过预先配置的消息推送通道群组进行推送。
14. `custom`:通过预先配置好的自定义推送通道进行推送。
15. `none`:仅保存到数据库,不做推送
15. `tencent_alarm`:通过腾讯云监控告警进行推送,仅支持 `description` 字段
16. `none`:仅保存到数据库,不做推送。
5. `token`:如果你在后台设置了推送 token,则此项必填。另外可以通过设置 HTTP `Authorization` 头部设置此项。
6. `url`:选填,如果不填则系统自动为消息生成 URL,其内容为消息详情。
7. `to`:选填,推送给指定用户,如果不填则默认推送给自己,受限于具体的消息推送方式,有些推送方式不支持此项。
@@ -224,19 +226,20 @@ proxy_send_timeout 300s;
**各种通道的支持程度:**
| 通道类型 | `title` | `description` | `content` | `url` | `to` | Markdown 支持 |
|:----------:|:-------:|:-------------:|:---------:|:-----:|:----:|:-----------:|
| `email` | ✅ | ✅ | ✅ | ❌ | ✅️ | ✅️ |
| `test` | ✅ | ✅ | ✅ | ✅️ | ✅️ | ✅ |
| `corp_app` | ✅ | ✅ | ✅ | ✅️ | ✅ | ✅ |
| `corp` | ❌ | ✅ | ✅ | ✅️ | ✅️ | ✅ |
| `lark` | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ |
| `lark_app` | ❌ | ✅ | ✅ | ❌️ | ✅ | ✅ |
| `ding` | ✅ | ✅ | ✅ | ✅️ | ✅ | ✅ |
| `bark` | ✅ | ✅ | ✅ | ✅️ | ❌ | ✅ |
| `client` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| `telegram` | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ |
| `discord` | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ |
| 通道类型 | `title` | `description` | `content` | `url` | `to` | Markdown 支持 |
|:---------------:|:-------:|:-------------:|:---------:|:-----:|:----:|:-----------:|
| `email` | ✅ | ✅ | ✅ | ❌ | ✅️ | ✅️ |
| `test` | ✅ | ✅ | ✅ | ✅️ | ✅️ | ✅ |
| `corp_app` | ✅ | ✅ | ✅ | ✅️ | ✅ | ✅ |
| `corp` | ❌ | ✅ | ✅ | ✅️ | ✅️ | ✅ |
| `lark` | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ |
| `lark_app` | ❌ | ✅ | ✅ | ❌️ | ✅ | ✅ |
| `ding` | ✅ | ✅ | ✅ | ✅️ | ✅ | ✅ |
| `bark` | ✅ | ✅ | ✅ | ✅️ | ❌ | ✅ |
| `client` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| `telegram` | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ |
| `discord` | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ |
| `tencent_alarm` | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
注意:
1. 对于大部分通道,`description` 字段和 `content` 是不能同时存在的,如果你只需要文字消息,请使用 `description` 字段,如果你需要发送 Markdown 消息,请使用 `content` 字段。
+2
View File
@@ -37,6 +37,8 @@ func SendMessage(message *model.Message, user *model.User, channel_ *model.Chann
return SendLarkAppMessage(message, user, channel_)
case model.TypeCustom:
return SendCustomMessage(message, user, channel_)
case model.TypeTencentAlarm:
return SendTencentAlarmMessage(message, user, channel_)
default:
return errors.New("不支持的消息通道:" + channel_.Type)
}
+89
View File
@@ -0,0 +1,89 @@
package channel
import (
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"encoding/json"
"errors"
"math/rand"
"message-pusher/model"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
"time"
)
type TencentAlarmResponse struct {
Code int `json:"code"`
Message string `json:"message"`
CodeDesc string `json:"codeDesc"`
}
func SendTencentAlarmMessage(message *model.Message, user *model.User, channel_ *model.Channel) error {
secretId := channel_.AppId
secretKey := channel_.Secret
policyId := channel_.AccountId
region := channel_.Other
if message.Description == "" {
message.Description = message.Content
}
params := map[string]string{
"Action": "SendCustomAlarmMsg",
"Region": region,
"Timestamp": strconv.FormatInt(time.Now().Unix(), 10),
"Nonce": strconv.Itoa(rand.Intn(65535)),
"SecretId": secretId,
"policyId": policyId,
"msg": message.Description,
}
keys := make([]string, 0, len(params))
for key := range params {
keys = append(keys, key)
}
sort.Strings(keys)
srcStr := "GETmonitor.api.qcloud.com/v2/index.php?"
for _, key := range keys {
srcStr += key + "=" + params[key] + "&"
}
srcStr = srcStr[:len(srcStr)-1]
h := hmac.New(sha1.New, []byte(secretKey))
h.Write([]byte(srcStr))
signature := base64.StdEncoding.EncodeToString(h.Sum(nil))
params["Signature"] = signature
urlStr := "https://monitor.api.qcloud.com/v2/index.php?" + urlEncode(params)
client := &http.Client{}
req, err := http.NewRequest("GET", urlStr, nil)
if err != nil {
return err
}
resp, err := client.Do(req)
if err != nil {
return err
}
var response TencentAlarmResponse
err = json.NewDecoder(resp.Body).Decode(&response)
if err != nil {
return err
}
if response.Code != 0 {
return errors.New(response.Message)
}
return nil
}
func urlEncode(params map[string]string) string {
var encodedParams []string
for key, value := range params {
encodedParams = append(encodedParams, url.QueryEscape(key)+"="+url.QueryEscape(value))
}
return strings.Join(encodedParams, "&")
}
+1
View File
@@ -21,6 +21,7 @@ const (
TypeGroup = "group"
TypeLarkApp = "lark_app"
TypeCustom = "custom"
TypeTencentAlarm = "tencent_alarm"
)
type Channel struct {
+6
View File
@@ -53,6 +53,12 @@ export const CHANNEL_OPTIONS = [
value: 'group',
color: '#FF9800',
},
{
key: 'tencent_alarm',
text: '腾讯云消息告警',
value: 'tencent_alarm',
color: '#00a4ff',
},
{
key: 'none',
text: '不推送',
+52
View File
@@ -209,6 +209,58 @@ const EditChannel = () => {
</Form.Group>
</>
);
case 'tencent_alarm':
return (
<>
<Message>
通过腾讯云自定义消息告警进行推送
<a
target='_blank'
href='https://github.com/songquanpeng/message-pusher/issues/87#issuecomment-1547971847'
>
配置教程
</a>
</Message>
<Form.Group widths={3}>
<Form.Input
label='SecretId'
name='app_id'
onChange={handleInputChange}
autoComplete='new-password'
value={inputs.app_id}
placeholder='子账号的 SecretId'
/>
<Form.Input
label='SecretKey'
name='secret'
type='password'
onChange={handleInputChange}
autoComplete='new-password'
value={inputs.secret}
placeholder='子账号的 SecretKey'
/>
<Form.Input
label='消息策略 ID'
name='account_id'
onChange={handleInputChange}
autoComplete='new-password'
value={inputs.account_id}
placeholder='例如:cm-6gl3pq19'
/>
</Form.Group>
<Form.Group widths={3}>
<Form.Input
label='区域'
name='other'
onChange={handleInputChange}
autoComplete='new-password'
value={inputs.other}
placeholder='例如:ap-shanghai'
/>
</Form.Group>
</>
);
case 'corp_app':
return (
<>