feat: support tencent custom alarm now (close #87)
This commit is contained in:
@@ -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` 字段。
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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, "&")
|
||||
}
|
||||
@@ -21,6 +21,7 @@ const (
|
||||
TypeGroup = "group"
|
||||
TypeLarkApp = "lark_app"
|
||||
TypeCustom = "custom"
|
||||
TypeTencentAlarm = "tencent_alarm"
|
||||
)
|
||||
|
||||
type Channel struct {
|
||||
|
||||
@@ -53,6 +53,12 @@ export const CHANNEL_OPTIONS = [
|
||||
value: 'group',
|
||||
color: '#FF9800',
|
||||
},
|
||||
{
|
||||
key: 'tencent_alarm',
|
||||
text: '腾讯云消息告警',
|
||||
value: 'tencent_alarm',
|
||||
color: '#00a4ff',
|
||||
},
|
||||
{
|
||||
key: 'none',
|
||||
text: '不推送',
|
||||
|
||||
@@ -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 (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user