版本更新
This commit is contained in:
parent
2176a9dd4b
commit
4d8c3dbfcf
11
README.md
11
README.md
@ -1,10 +1,3 @@
|
||||
生成一个方法
|
||||
## 方法名
|
||||
ToTmplStr
|
||||
|
||||
## 参数
|
||||
string
|
||||
|
||||
## 逻辑
|
||||
将字符串转换成一行的字符串格式,并再进行一次转义输出
|
||||
## 游戏服务更新
|
||||
<font sizeToken=common_footnote_text_style__font_size>此成果由<font colorTokenV2=common_blue1_color>@钉三多</font>确认完成</font>
|
||||
|
||||
|
||||
52
Type/t.go
52
Type/t.go
@ -17,19 +17,20 @@ type App struct {
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
Id int `json:"NodeId" db:"id"`
|
||||
Name string `json:"NodeName" db:"name"`
|
||||
Host string `json:"NodeIp" db:"host"`
|
||||
InternalHost string `json:"NodeInternalIp" db:"internalHost"`
|
||||
Hardware string `json:"NodeHardware" db:"hardware"`
|
||||
Area string `json:"NodeArea" db:"area"`
|
||||
Operator string `json:"NodeOperator" db:"operator"`
|
||||
Status int `json:"NodeStatus" db:"status"`
|
||||
CreateTime int64 `json:"createTime" db:"createTime"`
|
||||
UpdateTime int64 `json:"updateTime" db:"updateTime"`
|
||||
User string `json:"NodeUser" db:"user"`
|
||||
Password string `json:"NodePassword" db:"password"`
|
||||
Tz string `json:"NodeTz" db:"tz"`
|
||||
Id int `json:"NodeId" db:"id"`
|
||||
Name string `json:"NodeName" db:"name"`
|
||||
Host string `json:"NodeIp" db:"host"`
|
||||
InternalHost string `json:"NodeInternalIp" db:"internalHost"`
|
||||
Hardware string `json:"NodeHardware" db:"hardware"`
|
||||
Area string `json:"NodeArea" db:"area"`
|
||||
Operator string `json:"NodeOperator" db:"operator"`
|
||||
Status int `json:"NodeStatus" db:"status"`
|
||||
CreateTime int64 `json:"createTime" db:"createTime"`
|
||||
UpdateTime int64 `json:"updateTime" db:"updateTime"`
|
||||
User string `json:"NodeUser" db:"user"`
|
||||
Password string `json:"NodePassword" db:"password"`
|
||||
Tz string `json:"NodeTz" db:"tz"`
|
||||
PrivateKeyPath string
|
||||
}
|
||||
|
||||
type Mysql struct {
|
||||
@ -137,6 +138,16 @@ type NotifyData struct {
|
||||
NotifyMsg string `json:"notify_msg"`
|
||||
}
|
||||
|
||||
type NotifyRecoveryData struct {
|
||||
Host string `json:"host"`
|
||||
EventName string `json:"event_name"`
|
||||
Severity string `json:"severity"`
|
||||
AlarmTime string `json:"alarm_time"`
|
||||
Recovery string `json:"recovery"`
|
||||
Age string `json:"age"`
|
||||
NotifyMsg string `json:"notify_msg"`
|
||||
}
|
||||
|
||||
type NotifyClientData struct {
|
||||
Log string `json:"log"`
|
||||
StackTrace string `json:"stackTrace"`
|
||||
@ -158,3 +169,18 @@ type OrderData struct {
|
||||
EventRecovery string `db:"EventRecovery"`
|
||||
EventAge string `db:"EventAge"`
|
||||
}
|
||||
|
||||
type AlibabaUpdateCardParam struct {
|
||||
Server string
|
||||
UpdateTime string
|
||||
Duration string
|
||||
SrcGitLog string
|
||||
DocGitLog string
|
||||
}
|
||||
|
||||
type AlibabaNotifyData struct {
|
||||
Stack string `json:"stack"`
|
||||
FuncName string `json:"func_name"`
|
||||
AlarmTime string `json:"alarm_time"`
|
||||
NotifyMsg string `json:"notify_msg"`
|
||||
}
|
||||
|
||||
459
alibaba/card.go
Normal file
459
alibaba/card.go
Normal file
@ -0,0 +1,459 @@
|
||||
package alibaba
|
||||
|
||||
import (
|
||||
"backend/Type"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
clientv2 "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||
dingtalkcard_1_0 "github.com/alibabacloud-go/dingtalk/card_1_0"
|
||||
dingtalkim_1_0 "github.com/alibabacloud-go/dingtalk/im_1_0"
|
||||
util "github.com/alibabacloud-go/tea-utils/v2/service"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
)
|
||||
|
||||
var NOTIFY_TITLE_COLOR = map[string]string{
|
||||
"Not classified": "grey",
|
||||
"Information": "blue",
|
||||
"Warning": "yellow",
|
||||
"Average": "orange",
|
||||
"High": "pink",
|
||||
"Disaster": "red",
|
||||
}
|
||||
|
||||
// 由于接口要求卡片数据的键值对均为 string 类型,需要对卡片数据进行预处理
|
||||
func convertJSONValuesToString(obj map[string]any) map[string]*string {
|
||||
result := make(map[string]*string)
|
||||
for key, value := range obj {
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
result[key] = tea.String(v)
|
||||
default:
|
||||
bytes, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
result[key] = tea.String("")
|
||||
} else {
|
||||
result[key] = tea.String(string(bytes))
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Description:
|
||||
// 使用 Token 初始化账号Client
|
||||
// @return Client
|
||||
// @throws Exception
|
||||
func createCardClient() (_result *dingtalkcard_1_0.Client, _err error) {
|
||||
config := &openapi.Config{}
|
||||
config.Protocol = tea.String("https")
|
||||
config.RegionId = tea.String("central")
|
||||
_result = &dingtalkcard_1_0.Client{}
|
||||
_result, _err = dingtalkcard_1_0.NewClient(config)
|
||||
return _result, _err
|
||||
}
|
||||
|
||||
func SendCard() (_err error) {
|
||||
client, _err := createCardClient()
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
|
||||
accessToken, _ := GetToken()
|
||||
robotCode := "dingrmgtodzxaik76jpc"
|
||||
userId := ""
|
||||
openConversationId := "cidivmW+tO/JGyIFM/XHNeQcA=="
|
||||
templateId := "679d07b8-f649-4b5d-b223-d082db55b0d6.schema"
|
||||
lastMessage := "<用于消息列表展示、搜索结果展示的文案>"
|
||||
searchIcon := "<搜索结果展示的图标>"
|
||||
searchDesc := "<用于搜索的字段,最多 200 个字符>"
|
||||
|
||||
createAndDeliverHeaders := &dingtalkcard_1_0.CreateAndDeliverHeaders{}
|
||||
createAndDeliverHeaders.XAcsDingtalkAccessToken = tea.String(accessToken)
|
||||
|
||||
imGroupOpenDeliverModel := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
|
||||
RobotCode: tea.String(robotCode),
|
||||
// 卡片接收人
|
||||
Recipients: []*string{},
|
||||
}
|
||||
imGroupOpenSpaceModelLastMessageI18n := map[string]*string{
|
||||
"ZH_CN": tea.String(lastMessage),
|
||||
}
|
||||
imGroupOpenSpaceModelSearchSupport := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenSpaceModelSearchSupport{
|
||||
SearchIcon: tea.String(searchIcon),
|
||||
SearchDesc: tea.String(searchDesc),
|
||||
}
|
||||
imGroupOpenSpaceModel := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{
|
||||
SupportForward: tea.Bool(true),
|
||||
LastMessageI18n: imGroupOpenSpaceModelLastMessageI18n,
|
||||
SearchSupport: imGroupOpenSpaceModelSearchSupport,
|
||||
}
|
||||
|
||||
// 此处使用了 MockData 作为测试数据,请结合真实场景设置卡片公有数据
|
||||
cardDataJSONStr := `{
|
||||
"grid_object_list": [
|
||||
{
|
||||
"text": "Grid 11"
|
||||
},
|
||||
{
|
||||
"text": "Grid 12"
|
||||
},
|
||||
{
|
||||
"text": "Grid 13"
|
||||
},
|
||||
{
|
||||
"text": "Grid 21"
|
||||
},
|
||||
{
|
||||
"text": "Grid 22"
|
||||
},
|
||||
{
|
||||
"text": "Grid 23"
|
||||
}
|
||||
],
|
||||
"host": "测试主机"
|
||||
}`
|
||||
var cardDataCardParamMap map[string]any
|
||||
cardDataError := json.Unmarshal([]byte(cardDataJSONStr), &cardDataCardParamMap)
|
||||
if cardDataError != nil {
|
||||
panic(cardDataError)
|
||||
}
|
||||
cardData := &dingtalkcard_1_0.CreateAndDeliverRequestCardData{
|
||||
CardParamMap: convertJSONValuesToString(cardDataCardParamMap),
|
||||
}
|
||||
createAndDeliverRequest := &dingtalkcard_1_0.CreateAndDeliverRequest{
|
||||
UserId: tea.String(userId),
|
||||
CardTemplateId: tea.String(templateId),
|
||||
// 用于标识卡片的唯一 ID,业务需自行建立关联关系,用于后续的卡片更新
|
||||
OutTrackId: tea.String(fmt.Sprintf("test-out-track-id-%d", time.Now().Unix())),
|
||||
CallbackType: tea.String("STREAM"),
|
||||
CardData: cardData,
|
||||
ImGroupOpenSpaceModel: imGroupOpenSpaceModel,
|
||||
ImGroupOpenDeliverModel: imGroupOpenDeliverModel,
|
||||
OpenSpaceId: tea.String(fmt.Sprintf("dtv1.card//im_group.%s", openConversationId)),
|
||||
UserIdType: tea.Int32(1),
|
||||
}
|
||||
tryErr := func() (_e error) {
|
||||
defer func() {
|
||||
if r := tea.Recover(recover()); r != nil {
|
||||
_e = r
|
||||
}
|
||||
}()
|
||||
fmt.Println("createAndDeliverRequest", createAndDeliverRequest)
|
||||
_, _err = client.CreateAndDeliverWithOptions(createAndDeliverRequest, createAndDeliverHeaders, &util.RuntimeOptions{})
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
if tryErr != nil {
|
||||
var err = &tea.SDKError{}
|
||||
if _t, ok := tryErr.(*tea.SDKError); ok {
|
||||
err = _t
|
||||
} else {
|
||||
err.Message = tea.String(tryErr.Error())
|
||||
}
|
||||
if !tea.BoolValue(util.Empty(err.Code)) && !tea.BoolValue(util.Empty(err.Message)) {
|
||||
// err 中含有 code 和 message 属性,可帮助开发定位问题
|
||||
}
|
||||
}
|
||||
return _err
|
||||
}
|
||||
func CreateImClient() (_result *dingtalkim_1_0.Client, _err error) {
|
||||
config := &clientv2.Config{}
|
||||
config.Protocol = tea.String("https")
|
||||
config.RegionId = tea.String("central")
|
||||
_result = &dingtalkim_1_0.Client{}
|
||||
_result, _err = dingtalkim_1_0.NewClient(config)
|
||||
return _result, _err
|
||||
}
|
||||
|
||||
func SendZabbixMsg(data *Type.NotifyData) (_err error) {
|
||||
client, _err := createCardClient()
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
|
||||
accessToken, _ := GetToken()
|
||||
robotCode := "dingrmgtodzxaik76jpc"
|
||||
userId := ""
|
||||
openConversationId := "cidivmW+tO/JGyIFM/XHNeQcA=="
|
||||
templateId := "15624ae4-b499-40b4-bf04-af03c38ee8d7.schema"
|
||||
lastMessage := "Zabbix告警"
|
||||
searchIcon := ""
|
||||
searchDesc := ""
|
||||
|
||||
createAndDeliverHeaders := &dingtalkcard_1_0.CreateAndDeliverHeaders{}
|
||||
createAndDeliverHeaders.XAcsDingtalkAccessToken = tea.String(accessToken)
|
||||
imGroupOpenDeliverModel := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
|
||||
RobotCode: tea.String(robotCode),
|
||||
// 卡片接收人
|
||||
Recipients: []*string{},
|
||||
}
|
||||
if data.Severity == "Disaster" || data.Severity == "High" {
|
||||
imGroupOpenDeliverModel.Recipients = []*string{tea.String("035105216620273488")}
|
||||
imGroupOpenDeliverModel.AtUserIds = map[string]*string{
|
||||
"035105216620273488": tea.String("伍敏哲"),
|
||||
}
|
||||
}
|
||||
imGroupOpenSpaceModelLastMessageI18n := map[string]*string{
|
||||
"ZH_CN": tea.String(lastMessage),
|
||||
}
|
||||
imGroupOpenSpaceModelSearchSupport := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenSpaceModelSearchSupport{
|
||||
SearchIcon: tea.String(searchIcon),
|
||||
SearchDesc: tea.String(searchDesc),
|
||||
}
|
||||
imGroupOpenSpaceModel := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{
|
||||
SupportForward: tea.Bool(true),
|
||||
LastMessageI18n: imGroupOpenSpaceModelLastMessageI18n,
|
||||
SearchSupport: imGroupOpenSpaceModelSearchSupport,
|
||||
}
|
||||
|
||||
// 此处使用了 MockData 作为测试数据,请结合真实场景设置卡片公有数据
|
||||
cardDataJSONStr := `{
|
||||
"host": "` + data.Host + `",
|
||||
"notify_msg": "` + data.NotifyMsg + `",
|
||||
"event_name": "` + data.EventName + `",
|
||||
"severity": "` + data.Severity + `",
|
||||
"alarm_time": "` + data.AlarmTime + `",
|
||||
"title_color": "` + NOTIFY_TITLE_COLOR[data.Severity] + `"
|
||||
}`
|
||||
var cardDataCardParamMap map[string]any
|
||||
cardDataError := json.Unmarshal([]byte(cardDataJSONStr), &cardDataCardParamMap)
|
||||
if cardDataError != nil {
|
||||
panic(cardDataError)
|
||||
}
|
||||
cardData := &dingtalkcard_1_0.CreateAndDeliverRequestCardData{
|
||||
CardParamMap: convertJSONValuesToString(cardDataCardParamMap),
|
||||
}
|
||||
createAndDeliverRequest := &dingtalkcard_1_0.CreateAndDeliverRequest{
|
||||
UserId: tea.String(userId),
|
||||
CardTemplateId: tea.String(templateId),
|
||||
// 用于标识卡片的唯一 ID,业务需自行建立关联关系,用于后续的卡片更新
|
||||
OutTrackId: tea.String(fmt.Sprintf("test-out-track-id-%d", time.Now().Unix())),
|
||||
CallbackType: tea.String("STREAM"),
|
||||
CardData: cardData,
|
||||
ImGroupOpenSpaceModel: imGroupOpenSpaceModel,
|
||||
ImGroupOpenDeliverModel: imGroupOpenDeliverModel,
|
||||
OpenSpaceId: tea.String(fmt.Sprintf("dtv1.card//im_group.%s", openConversationId)),
|
||||
UserIdType: tea.Int32(1),
|
||||
}
|
||||
tryErr := func() (_e error) {
|
||||
defer func() {
|
||||
if r := tea.Recover(recover()); r != nil {
|
||||
_e = r
|
||||
}
|
||||
}()
|
||||
fmt.Println("createAndDeliverRequest", createAndDeliverRequest)
|
||||
_, _err = client.CreateAndDeliverWithOptions(createAndDeliverRequest, createAndDeliverHeaders, &util.RuntimeOptions{})
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
if tryErr != nil {
|
||||
var err = &tea.SDKError{}
|
||||
if _t, ok := tryErr.(*tea.SDKError); ok {
|
||||
err = _t
|
||||
} else {
|
||||
err.Message = tea.String(tryErr.Error())
|
||||
}
|
||||
if !tea.BoolValue(util.Empty(err.Code)) && !tea.BoolValue(util.Empty(err.Message)) {
|
||||
// err 中含有 code 和 message 属性,可帮助开发定位问题
|
||||
}
|
||||
}
|
||||
return _err
|
||||
}
|
||||
|
||||
func SendZabbixRecoveryMsg(data *Type.NotifyRecoveryData) (_err error) {
|
||||
client, _err := createCardClient()
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
|
||||
accessToken, _ := GetToken()
|
||||
robotCode := "dingrmgtodzxaik76jpc"
|
||||
userId := ""
|
||||
openConversationId := "cidivmW+tO/JGyIFM/XHNeQcA=="
|
||||
templateId := "9a6ae88a-ba93-419e-b640-2e5fcd2556cf.schema"
|
||||
lastMessage := "Zabbix告警"
|
||||
searchIcon := ""
|
||||
searchDesc := ""
|
||||
|
||||
createAndDeliverHeaders := &dingtalkcard_1_0.CreateAndDeliverHeaders{}
|
||||
createAndDeliverHeaders.XAcsDingtalkAccessToken = tea.String(accessToken)
|
||||
|
||||
imGroupOpenDeliverModel := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
|
||||
RobotCode: tea.String(robotCode),
|
||||
// 卡片接收人
|
||||
Recipients: []*string{},
|
||||
}
|
||||
imGroupOpenSpaceModelLastMessageI18n := map[string]*string{
|
||||
"ZH_CN": tea.String(lastMessage),
|
||||
}
|
||||
imGroupOpenSpaceModelSearchSupport := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenSpaceModelSearchSupport{
|
||||
SearchIcon: tea.String(searchIcon),
|
||||
SearchDesc: tea.String(searchDesc),
|
||||
}
|
||||
imGroupOpenSpaceModel := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{
|
||||
SupportForward: tea.Bool(true),
|
||||
LastMessageI18n: imGroupOpenSpaceModelLastMessageI18n,
|
||||
SearchSupport: imGroupOpenSpaceModelSearchSupport,
|
||||
}
|
||||
|
||||
// 此处使用了 MockData 作为测试数据,请结合真实场景设置卡片公有数据
|
||||
cardDataJSONStr := `{
|
||||
"host": "` + data.Host + `",
|
||||
"notify_msg": "` + data.NotifyMsg + `",
|
||||
"event_name": "` + data.EventName + `",
|
||||
"severity": "` + data.Severity + `",
|
||||
"alarm_time": "` + data.AlarmTime + `",
|
||||
"recovery": "` + data.Recovery + `",
|
||||
"age": "` + data.Age + `",
|
||||
"title_color": "` + NOTIFY_TITLE_COLOR[data.Severity] + `"
|
||||
}`
|
||||
var cardDataCardParamMap map[string]any
|
||||
cardDataError := json.Unmarshal([]byte(cardDataJSONStr), &cardDataCardParamMap)
|
||||
if cardDataError != nil {
|
||||
panic(cardDataError)
|
||||
}
|
||||
cardData := &dingtalkcard_1_0.CreateAndDeliverRequestCardData{
|
||||
CardParamMap: convertJSONValuesToString(cardDataCardParamMap),
|
||||
}
|
||||
createAndDeliverRequest := &dingtalkcard_1_0.CreateAndDeliverRequest{
|
||||
UserId: tea.String(userId),
|
||||
CardTemplateId: tea.String(templateId),
|
||||
// 用于标识卡片的唯一 ID,业务需自行建立关联关系,用于后续的卡片更新
|
||||
OutTrackId: tea.String(fmt.Sprintf("test-out-track-id-%d", time.Now().Unix())),
|
||||
CallbackType: tea.String("STREAM"),
|
||||
CardData: cardData,
|
||||
ImGroupOpenSpaceModel: imGroupOpenSpaceModel,
|
||||
ImGroupOpenDeliverModel: imGroupOpenDeliverModel,
|
||||
OpenSpaceId: tea.String(fmt.Sprintf("dtv1.card//im_group.%s", openConversationId)),
|
||||
UserIdType: tea.Int32(1),
|
||||
}
|
||||
tryErr := func() (_e error) {
|
||||
defer func() {
|
||||
if r := tea.Recover(recover()); r != nil {
|
||||
_e = r
|
||||
}
|
||||
}()
|
||||
fmt.Println("createAndDeliverRequest", createAndDeliverRequest)
|
||||
_, _err = client.CreateAndDeliverWithOptions(createAndDeliverRequest, createAndDeliverHeaders, &util.RuntimeOptions{})
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
if tryErr != nil {
|
||||
var err = &tea.SDKError{}
|
||||
if _t, ok := tryErr.(*tea.SDKError); ok {
|
||||
err = _t
|
||||
} else {
|
||||
err.Message = tea.String(tryErr.Error())
|
||||
}
|
||||
if !tea.BoolValue(util.Empty(err.Code)) && !tea.BoolValue(util.Empty(err.Message)) {
|
||||
// err 中含有 code 和 message 属性,可帮助开发定位问题
|
||||
}
|
||||
}
|
||||
return _err
|
||||
}
|
||||
|
||||
func SendStandardMsg(title, content, color string) (_err error) {
|
||||
client, _err := createCardClient()
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
|
||||
accessToken, _ := GetToken()
|
||||
robotCode := "dingrmgtodzxaik76jpc"
|
||||
userId := ""
|
||||
openConversationId := "cidSdyTEELI8btxKdGnSprffg=="
|
||||
templateId := "843a23ff-29d2-4efc-b7f4-2dea2766d7db.schema"
|
||||
lastMessage := title
|
||||
searchIcon := ""
|
||||
searchDesc := ""
|
||||
|
||||
createAndDeliverHeaders := &dingtalkcard_1_0.CreateAndDeliverHeaders{}
|
||||
createAndDeliverHeaders.XAcsDingtalkAccessToken = tea.String(accessToken)
|
||||
|
||||
imGroupOpenDeliverModel := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
|
||||
RobotCode: tea.String(robotCode),
|
||||
// 卡片接收人
|
||||
Recipients: []*string{},
|
||||
}
|
||||
imGroupOpenSpaceModelLastMessageI18n := map[string]*string{
|
||||
"ZH_CN": tea.String(lastMessage),
|
||||
}
|
||||
imGroupOpenSpaceModelSearchSupport := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenSpaceModelSearchSupport{
|
||||
SearchIcon: tea.String(searchIcon),
|
||||
SearchDesc: tea.String(searchDesc),
|
||||
}
|
||||
imGroupOpenSpaceModel := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{
|
||||
SupportForward: tea.Bool(true),
|
||||
LastMessageI18n: imGroupOpenSpaceModelLastMessageI18n,
|
||||
SearchSupport: imGroupOpenSpaceModelSearchSupport,
|
||||
}
|
||||
|
||||
// 此处使用了 MockData 作为测试数据,请结合真实场景设置卡片公有数据
|
||||
cardDataCardParamMap := map[string]any{
|
||||
"title": title,
|
||||
"markdown": content,
|
||||
"color": color,
|
||||
"config": map[string]any{
|
||||
"autoLayout": true,
|
||||
},
|
||||
}
|
||||
cardDataError := error(nil)
|
||||
_ = cardDataError
|
||||
cardData := &dingtalkcard_1_0.CreateAndDeliverRequestCardData{
|
||||
CardParamMap: convertJSONValuesToString(cardDataCardParamMap),
|
||||
}
|
||||
createAndDeliverRequest := &dingtalkcard_1_0.CreateAndDeliverRequest{
|
||||
UserId: tea.String(userId),
|
||||
CardTemplateId: tea.String(templateId),
|
||||
// 用于标识卡片的唯一 ID,业务需自行建立关联关系,用于后续的卡片更新
|
||||
OutTrackId: tea.String(fmt.Sprintf("standard-out-track-id-%d", time.Now().Unix())),
|
||||
CallbackType: tea.String("STREAM"),
|
||||
CardData: cardData,
|
||||
ImGroupOpenSpaceModel: imGroupOpenSpaceModel,
|
||||
ImGroupOpenDeliverModel: imGroupOpenDeliverModel,
|
||||
OpenSpaceId: tea.String(fmt.Sprintf("dtv1.card//im_group.%s", openConversationId)),
|
||||
UserIdType: tea.Int32(1),
|
||||
}
|
||||
tryErr := func() (_e error) {
|
||||
defer func() {
|
||||
if r := tea.Recover(recover()); r != nil {
|
||||
_e = r
|
||||
}
|
||||
}()
|
||||
fmt.Println("createAndDeliverRequest", createAndDeliverRequest)
|
||||
_, _err = client.CreateAndDeliverWithOptions(createAndDeliverRequest, createAndDeliverHeaders, &util.RuntimeOptions{})
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
if tryErr != nil {
|
||||
var err = &tea.SDKError{}
|
||||
if _t, ok := tryErr.(*tea.SDKError); ok {
|
||||
err = _t
|
||||
} else {
|
||||
err.Message = tea.String(tryErr.Error())
|
||||
}
|
||||
if !tea.BoolValue(util.Empty(err.Code)) && !tea.BoolValue(util.Empty(err.Message)) {
|
||||
// err 中含有 code 和 message 属性,可帮助开发定位问题
|
||||
}
|
||||
}
|
||||
return _err
|
||||
}
|
||||
291
alibaba/card_example.go
Normal file
291
alibaba/card_example.go
Normal file
@ -0,0 +1,291 @@
|
||||
package alibaba
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||
dingtalkcard_1_0 "github.com/alibabacloud-go/dingtalk/card_1_0"
|
||||
dingtalkim_1_0 "github.com/alibabacloud-go/dingtalk/im_1_0"
|
||||
dingtalkoauth2_1_0 "github.com/alibabacloud-go/dingtalk/oauth2_1_0"
|
||||
util "github.com/alibabacloud-go/tea-utils/v2/service"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
"github.com/google/uuid"
|
||||
"github.com/open-dingtalk/dingtalk-stream-sdk-go/card"
|
||||
"github.com/open-dingtalk/dingtalk-stream-sdk-go/chatbot"
|
||||
"github.com/open-dingtalk/dingtalk-stream-sdk-go/client"
|
||||
"github.com/open-dingtalk/dingtalk-stream-sdk-go/logger"
|
||||
)
|
||||
|
||||
type DingTalkClient struct {
|
||||
ClientID string
|
||||
clientSecret string
|
||||
imClient *dingtalkim_1_0.Client
|
||||
oauthClient *dingtalkoauth2_1_0.Client
|
||||
cardClient *dingtalkcard_1_0.Client
|
||||
}
|
||||
|
||||
var (
|
||||
dingtalkClient *DingTalkClient = nil
|
||||
)
|
||||
|
||||
func NewDingTalkClient(clientId, clientSecret string) *DingTalkClient {
|
||||
config := &openapi.Config{}
|
||||
config.Protocol = tea.String("https")
|
||||
config.RegionId = tea.String("central")
|
||||
oauthClient, _ := dingtalkoauth2_1_0.NewClient(config)
|
||||
imClient, _ := dingtalkim_1_0.NewClient(config)
|
||||
cardClient, _ := dingtalkcard_1_0.NewClient(config)
|
||||
return &DingTalkClient{
|
||||
ClientID: clientId,
|
||||
clientSecret: clientSecret,
|
||||
oauthClient: oauthClient,
|
||||
imClient: imClient,
|
||||
cardClient: cardClient,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *DingTalkClient) GetAccessToken() (string, error) {
|
||||
request := &dingtalkoauth2_1_0.GetAccessTokenRequest{
|
||||
AppKey: tea.String(c.ClientID),
|
||||
AppSecret: tea.String(c.clientSecret),
|
||||
}
|
||||
response, tryErr := func() (_resp *dingtalkoauth2_1_0.GetAccessTokenResponse, _e error) {
|
||||
defer func() {
|
||||
if r := tea.Recover(recover()); r != nil {
|
||||
_e = r
|
||||
}
|
||||
}()
|
||||
_resp, _err := c.oauthClient.GetAccessToken(request)
|
||||
if _err != nil {
|
||||
return nil, _err
|
||||
}
|
||||
|
||||
return _resp, nil
|
||||
}()
|
||||
if tryErr != nil {
|
||||
return "", tryErr
|
||||
}
|
||||
return *response.Body.AccessToken, nil
|
||||
}
|
||||
|
||||
func (c *DingTalkClient) SendCard(request *dingtalkcard_1_0.CreateAndDeliverRequest) (*dingtalkcard_1_0.CreateAndDeliverResponse, error) {
|
||||
accessToken, err := c.GetAccessToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
headers := &dingtalkcard_1_0.CreateAndDeliverHeaders{}
|
||||
headers.XAcsDingtalkAccessToken = tea.String(accessToken)
|
||||
|
||||
resp, tryErr := func() (resp *dingtalkcard_1_0.CreateAndDeliverResponse, _e error) {
|
||||
defer func() {
|
||||
if r := tea.Recover(recover()); r != nil {
|
||||
_e = r
|
||||
}
|
||||
}()
|
||||
result, _err := c.cardClient.CreateAndDeliverWithOptions(request, headers, &util.RuntimeOptions{})
|
||||
if _err != nil {
|
||||
return nil, _err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}()
|
||||
if tryErr != nil {
|
||||
var sdkError = &tea.SDKError{}
|
||||
if _t, ok := tryErr.(*tea.SDKError); ok {
|
||||
sdkError = _t
|
||||
} else {
|
||||
sdkError.Message = tea.String(tryErr.Error())
|
||||
}
|
||||
if !tea.BoolValue(util.Empty(sdkError.Code)) && !tea.BoolValue(util.Empty(sdkError.Message)) {
|
||||
logger.GetLogger().Errorf("CreateAndDeliverWithOptions failed, clientId=%s, err=%+v", c.ClientID, sdkError)
|
||||
}
|
||||
return nil, tryErr
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *DingTalkClient) UpdateCard(request *dingtalkcard_1_0.UpdateCardRequest) (*dingtalkcard_1_0.UpdateCardResponse, error) {
|
||||
accessToken, err := c.GetAccessToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
headers := &dingtalkcard_1_0.UpdateCardHeaders{}
|
||||
headers.XAcsDingtalkAccessToken = tea.String(accessToken)
|
||||
|
||||
resp, tryErr := func() (resp *dingtalkcard_1_0.UpdateCardResponse, _e error) {
|
||||
defer func() {
|
||||
if r := tea.Recover(recover()); r != nil {
|
||||
_e = r
|
||||
}
|
||||
}()
|
||||
result, _err := c.cardClient.UpdateCardWithOptions(request, headers, &util.RuntimeOptions{})
|
||||
if _err != nil {
|
||||
return nil, _err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}()
|
||||
if tryErr != nil {
|
||||
var sdkError = &tea.SDKError{}
|
||||
if _t, ok := tryErr.(*tea.SDKError); ok {
|
||||
sdkError = _t
|
||||
} else {
|
||||
sdkError.Message = tea.String(tryErr.Error())
|
||||
}
|
||||
if !tea.BoolValue(util.Empty(sdkError.Code)) && !tea.BoolValue(util.Empty(sdkError.Message)) {
|
||||
logger.GetLogger().Errorf("UpdateCardWithOptions failed, clientId=%s, err=%+v", c.ClientID, sdkError)
|
||||
}
|
||||
return nil, tryErr
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func OnChatBotMessageReceived(ctx context.Context, data *chatbot.BotCallbackDataModel) ([]byte, error) {
|
||||
content := strings.TrimSpace(data.Text.Content)
|
||||
logger.GetLogger().Infof("received message: %v", content)
|
||||
|
||||
// 卡片模板 ID
|
||||
CARD_TEMPLATE_ID := "2c278d79-fc0b-41b4-b14e-8b8089dc08e8.schema" // 该模板只用于测试使用,如需投入线上使用,请导入卡片模板 json 到自己的应用下
|
||||
// 卡片公有数据,非字符串类型的卡片数据参考文档:https://open.dingtalk.com/document/orgapp/instructions-for-filling-in-api-card-data
|
||||
cardData := &dingtalkcard_1_0.CreateAndDeliverRequestCardData{
|
||||
CardParamMap: make(map[string]*string),
|
||||
}
|
||||
cardData.CardParamMap["title"] = tea.String("钉钉互动卡片")
|
||||
cardData.CardParamMap["markdown"] = tea.String(content)
|
||||
cardData.CardParamMap["submitted"] = tea.String("false")
|
||||
cardData.CardParamMap["tag"] = tea.String("标签")
|
||||
imGroupOpenSpaceModel := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenSpaceModel{
|
||||
SupportForward: tea.Bool(true),
|
||||
}
|
||||
imGroupOpenDeliverModel := &dingtalkcard_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
|
||||
Extension: make(map[string]*string),
|
||||
RobotCode: tea.String(dingtalkClient.ClientID),
|
||||
}
|
||||
imRobotOpenSpaceModel := &dingtalkcard_1_0.CreateAndDeliverRequestImRobotOpenSpaceModel{
|
||||
SupportForward: tea.Bool(true),
|
||||
}
|
||||
imRobotOpenDeliverModel := &dingtalkcard_1_0.CreateAndDeliverRequestImRobotOpenDeliverModel{
|
||||
Extension: make(map[string]*string),
|
||||
RobotCode: tea.String(dingtalkClient.ClientID),
|
||||
SpaceType: tea.String("IM_ROBOT"),
|
||||
}
|
||||
u, _ := uuid.NewUUID()
|
||||
outTrackId := u.String()
|
||||
|
||||
sendCardRequest := &dingtalkcard_1_0.CreateAndDeliverRequest{
|
||||
UserIdType: tea.Int32(1), // 1(默认):userid模式;2:unionId模式;
|
||||
CardTemplateId: tea.String(CARD_TEMPLATE_ID),
|
||||
OutTrackId: tea.String(outTrackId),
|
||||
CallbackType: tea.String("STREAM"), // 采用 Stream 模式接收回调事件
|
||||
CardData: cardData,
|
||||
}
|
||||
if data.ConversationType == "2" {
|
||||
// 群聊
|
||||
sendCardRequest.OpenSpaceId = tea.String(fmt.Sprintf("dtv1.card//IM_GROUP.%s", data.ConversationId))
|
||||
sendCardRequest.ImGroupOpenSpaceModel = imGroupOpenSpaceModel
|
||||
sendCardRequest.ImGroupOpenDeliverModel = imGroupOpenDeliverModel
|
||||
} else {
|
||||
// 单聊
|
||||
sendCardRequest.OpenSpaceId = tea.String(fmt.Sprintf("dtv1.card//IM_ROBOT.%s", data.SenderStaffId))
|
||||
sendCardRequest.ImRobotOpenSpaceModel = imRobotOpenSpaceModel
|
||||
sendCardRequest.ImRobotOpenDeliverModel = imRobotOpenDeliverModel
|
||||
}
|
||||
|
||||
// 创建并投放卡片: https://open.dingtalk.com/document/isvapp/create-and-deliver-cards
|
||||
sendCardResponse, err := dingtalkClient.SendCard(sendCardRequest)
|
||||
if err != nil {
|
||||
logger.GetLogger().Errorf("reply card failed: %+v", sendCardResponse)
|
||||
return nil, err
|
||||
}
|
||||
logger.GetLogger().Infof("reply card: %v %+v", outTrackId, sendCardRequest.CardData)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
updateCardData := &dingtalkcard_1_0.UpdateCardRequestCardData{
|
||||
CardParamMap: make(map[string]*string),
|
||||
}
|
||||
updateCardData.CardParamMap["tag"] = tea.String("更新后的标签")
|
||||
updateOptions := &dingtalkcard_1_0.UpdateCardRequestCardUpdateOptions{
|
||||
UpdateCardDataByKey: tea.Bool(true),
|
||||
}
|
||||
updateCardRequest := &dingtalkcard_1_0.UpdateCardRequest{
|
||||
OutTrackId: tea.String(outTrackId),
|
||||
CardData: updateCardData,
|
||||
CardUpdateOptions: updateOptions,
|
||||
}
|
||||
// 更新卡片: https://open.dingtalk.com/document/orgapp/interactive-card-update-interface
|
||||
updateCardResponse, err := dingtalkClient.UpdateCard(updateCardRequest)
|
||||
if err != nil {
|
||||
logger.GetLogger().Errorf("update card failed: %+v", updateCardResponse)
|
||||
return nil, err
|
||||
}
|
||||
logger.GetLogger().Infof("update card: %v %+v", outTrackId, updateCardRequest.CardData)
|
||||
|
||||
return []byte(""), nil
|
||||
}
|
||||
|
||||
func onCardCallback(ctx context.Context, request *card.CardRequest) (*card.CardResponse, error) {
|
||||
/**
|
||||
* 卡片事件回调文档:https://open.dingtalk.com/document/orgapp/event-callback-card
|
||||
*/
|
||||
logger.GetLogger().Infof("card callback message: %v", request)
|
||||
|
||||
userPrivateData := make(map[string]string)
|
||||
|
||||
params := request.CardActionData.CardPrivateData.Params
|
||||
if localInput, ok := params["local_input"]; ok && localInput != nil {
|
||||
userPrivateData["priavte_input"] = localInput.(string)
|
||||
userPrivateData["submitted"] = "true"
|
||||
}
|
||||
|
||||
response := &card.CardResponse{
|
||||
CardUpdateOptions: &card.CardUpdateOptions{
|
||||
UpdateCardDataByKey: true,
|
||||
UpdatePrivateDataByKey: true,
|
||||
},
|
||||
UserPrivateData: &card.CardDataDto{
|
||||
CardParamMap: userPrivateData,
|
||||
},
|
||||
}
|
||||
|
||||
responseJSON, err := json.MarshalIndent(response, "", " ") // 使用 MarshalIndent 来美化输出
|
||||
if err == nil {
|
||||
logger.GetLogger().Infof("card callback response: \n%s", string(responseJSON))
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
var clientId, clientSecret string
|
||||
flag.StringVar(&clientId, "client_id", os.Getenv("DINGTALK_APP_CLIENT_ID"), "your-client-id")
|
||||
flag.StringVar(&clientSecret, "client_secret", os.Getenv("DINGTALK_APP_CLIENT_SECRET"), "your-client-secret")
|
||||
flag.Parse()
|
||||
if len(clientId) == 0 || len(clientSecret) == 0 {
|
||||
panic("command line options --client_id and --client_secret required")
|
||||
}
|
||||
|
||||
logger.SetLogger(logger.NewStdTestLogger())
|
||||
|
||||
dingtalkClient = NewDingTalkClient(clientId, clientSecret)
|
||||
|
||||
cli := client.NewStreamClient(client.WithAppCredential(client.NewAppCredentialConfig(clientId, clientSecret)))
|
||||
cli.RegisterChatBotCallbackRouter(OnChatBotMessageReceived)
|
||||
cli.RegisterCardCallbackRouter(onCardCallback)
|
||||
|
||||
err := cli.Start(context.Background())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer cli.Close()
|
||||
|
||||
select {}
|
||||
}
|
||||
65
alibaba/robot.go
Normal file
65
alibaba/robot.go
Normal file
@ -0,0 +1,65 @@
|
||||
// This file is auto-generated, don't edit it. Thanks.
|
||||
package alibaba
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||
dingtalkrobot_1_0 "github.com/alibabacloud-go/dingtalk/robot_1_0"
|
||||
util "github.com/alibabacloud-go/tea-utils/v2/service"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
)
|
||||
|
||||
const (
|
||||
AUTO_NOTIFY_CHAT_ID = "cidSdyTEELI8btxKdGnSprffg=="
|
||||
ROBOT_TOKEN = "dingrmgtodzxaik76jpc"
|
||||
)
|
||||
|
||||
/**
|
||||
* 使用 Token 初始化账号Client
|
||||
* @return Client
|
||||
* @throws Exception
|
||||
*/
|
||||
func CreateRobotClient() (_result *dingtalkrobot_1_0.Client, _err error) {
|
||||
config := &openapi.Config{}
|
||||
config.Protocol = tea.String("https")
|
||||
config.RegionId = tea.String("central")
|
||||
_result = &dingtalkrobot_1_0.Client{}
|
||||
_result, _err = dingtalkrobot_1_0.NewClient(config)
|
||||
return _result, _err
|
||||
}
|
||||
|
||||
func SendMessage() (_err error) {
|
||||
client, _err := CreateRobotClient()
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
token, err := GetToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
type msgP struct {
|
||||
Title string `json:"title"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
message := msgP{
|
||||
Title: "更新通知",
|
||||
Text: "```golang\n{\n\"message\": \"新版本 1.2.3 已发布,请及时更新!\"\n}\n```",
|
||||
}
|
||||
|
||||
msgStr, _ := json.Marshal(message)
|
||||
orgGroupSendHeaders := &dingtalkrobot_1_0.OrgGroupSendHeaders{}
|
||||
orgGroupSendHeaders.XAcsDingtalkAccessToken = tea.String(token)
|
||||
orgGroupSendRequest := &dingtalkrobot_1_0.OrgGroupSendRequest{
|
||||
MsgParam: tea.String(string(msgStr)),
|
||||
MsgKey: tea.String("sampleMarkdown"),
|
||||
OpenConversationId: tea.String("cidSdyTEELI8btxKdGnSprffg=="),
|
||||
RobotCode: tea.String(ROBOT_TOKEN),
|
||||
CoolAppCode: tea.String(""),
|
||||
}
|
||||
resp, _err := client.OrgGroupSendWithOptions(orgGroupSendRequest, orgGroupSendHeaders, &util.RuntimeOptions{})
|
||||
fmt.Println(resp)
|
||||
return _err
|
||||
}
|
||||
@ -9,11 +9,12 @@ import (
|
||||
)
|
||||
|
||||
type SshConfig struct {
|
||||
Name string `yaml:"name"`
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
Name string `yaml:"name"`
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
PrivateKeyPath string
|
||||
}
|
||||
|
||||
type MysqlConfig struct {
|
||||
|
||||
49
controller/alibaba.go
Normal file
49
controller/alibaba.go
Normal file
@ -0,0 +1,49 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"backend/Type"
|
||||
"backend/alibaba"
|
||||
"backend/util"
|
||||
"log"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func AlibabaNotify(c *gin.Context) {
|
||||
r := Type.NotifyData{}
|
||||
if err := c.ShouldBindJSON(&r); err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
err := alibaba.SendZabbixMsg(&r)
|
||||
if err != nil {
|
||||
log.Printf("failed to send notify message: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func AlibabaGameNotify(c *gin.Context) {
|
||||
r := Type.AlibabaNotifyData{}
|
||||
if err := c.ShouldBindJSON(&r); err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
content := util.ParseTmpl("./template/alibaba_notify.tmpl", r)
|
||||
err := alibaba.SendStandardMsg("游戏服务报警通知", content, "red")
|
||||
if err != nil {
|
||||
log.Printf("failed to send notify message: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func AlibabaRecovery(c *gin.Context) {
|
||||
r := Type.NotifyRecoveryData{}
|
||||
if err := c.ShouldBindJSON(&r); err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
err := alibaba.SendZabbixRecoveryMsg(&r)
|
||||
if err != nil {
|
||||
log.Printf("failed to send recovery message: %v", err)
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,10 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"backend/model"
|
||||
"backend/util"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@ -54,17 +56,18 @@ func CopyUserOperation(srcAppID, dstAppID, srcUid, dstUid int) error {
|
||||
defer DstDb.Close()
|
||||
// 复制 Mod 表
|
||||
srcData := DbData{}
|
||||
// _, err = model.UserGM(dstAppID, 1, dstUid, "logout")
|
||||
// time.Sleep(time.Second * 2)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
err = SrcDb.Get(&srcData, "SELECT dwUin, mData, updateTime FROM t_player_mod WHERE dwUin = ? LIMIT 1", srcUid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var auto_id int64
|
||||
_ = DstDb.Get(&auto_id, "SELECT auto_id FROM t_account WHERE user_name = ?", srcData.DwUin)
|
||||
_, err = model.UserGM(dstAppID, 1, dstUid, "logout")
|
||||
time.Sleep(time.Second * 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if auto_id == 0 {
|
||||
result, err := DstDb.Exec("INSERT INTO t_account (user_name, user_password) VALUES (?, ?) ON DUPLICATE KEY UPDATE user_password = VALUES(user_password)", srcData.DwUin, "123456")
|
||||
if err != nil {
|
||||
|
||||
@ -51,7 +51,11 @@ func AddNode(c *gin.Context) {
|
||||
|
||||
func ServerList(c *gin.Context) {
|
||||
Server := model.Server{}
|
||||
c.BindJSON(&Server)
|
||||
err := c.BindJSON(&Server)
|
||||
if err != nil {
|
||||
failed(c, "参数绑定失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
ServerList, err := Server.ServerList()
|
||||
if err != nil {
|
||||
failed(c, err.Error())
|
||||
@ -96,6 +100,18 @@ func UpdateApp(c *gin.Context) {
|
||||
success(c, map[string]string{"msg": msg})
|
||||
}
|
||||
|
||||
func UpdateAppReview(c *gin.Context) {
|
||||
Server := model.Server{}
|
||||
c.BindJSON(&Server)
|
||||
msg, err := Server.UpdateAppReview()
|
||||
if err != nil {
|
||||
failed(c, err.Error())
|
||||
return
|
||||
}
|
||||
util.AddAdminLog(c, "更新Review应用", Server)
|
||||
success(c, map[string]string{"msg": msg})
|
||||
}
|
||||
|
||||
func UpdateAppFeishu(c *gin.Context) {
|
||||
Server := model.Server{}
|
||||
c.BindJSON(&Server)
|
||||
|
||||
2
go.mod
2
go.mod
@ -33,6 +33,7 @@ require (
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
|
||||
github.com/alibabacloud-go/darabonba-openapi v0.2.1 // indirect
|
||||
github.com/alibabacloud-go/debug v1.0.1 // indirect
|
||||
github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect
|
||||
github.com/alibabacloud-go/gateway-dingtalk v1.0.2 // indirect
|
||||
@ -64,6 +65,7 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/open-dingtalk/dingtalk-stream-sdk-go v0.9.1 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.13.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
|
||||
6
go.sum
6
go.sum
@ -17,6 +17,8 @@ github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC
|
||||
github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8=
|
||||
github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc=
|
||||
github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc=
|
||||
github.com/alibabacloud-go/darabonba-openapi v0.2.1 h1:WyzxxKvhdVDlwpAMOHgAiCJ+NXa6g5ZWPFEzaK/ewwY=
|
||||
github.com/alibabacloud-go/darabonba-openapi v0.2.1/go.mod h1:zXOqLbpIqq543oioL9IuuZYOQgHQ5B8/n5OPrnko8aY=
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.0/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.11/go.mod h1:wHxkgZT1ClZdcwEVP/pDgYK/9HucsnCfMipmJgCz4xY=
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.12/go.mod h1:cgtLEj8i4ddXMcQgq4PnpVQvlzS+y5B+QtdSfmcLM3A=
|
||||
@ -24,6 +26,7 @@ github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.9 h1:7P0KWfed/YMtpeuW3E2iwo
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.9/go.mod h1:kgnXaV74AVjM3ZWJu1GhyXGuCtxljJ677oUfz6MyJOE=
|
||||
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
|
||||
github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
|
||||
github.com/alibabacloud-go/darabonba-string v1.0.0/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
|
||||
github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
|
||||
github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
|
||||
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
|
||||
@ -65,6 +68,7 @@ github.com/alibabacloud-go/tea-oss-sdk v1.1.5/go.mod h1:5fhlKMa/kWRJNgPYRt+5qSg3
|
||||
github.com/alibabacloud-go/tea-oss-utils v1.1.0 h1:y65crjjcZ2Pbb6UZtC2deuIZHDVTS3IaDWE7M9nVLRc=
|
||||
github.com/alibabacloud-go/tea-oss-utils v1.1.0/go.mod h1:PFCF12e9yEKyBUIn7X1IrF/pNjvxgkHy0CgxX4+xRuY=
|
||||
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
|
||||
github.com/alibabacloud-go/tea-utils v1.4.3/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=
|
||||
github.com/alibabacloud-go/tea-utils v1.4.5 h1:h0/6Xd2f3bPE4XHTvkpjwxowIwRCJAJOqY6Eq8f3zfA=
|
||||
github.com/alibabacloud-go/tea-utils v1.4.5/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.0/go.mod h1:U5MTY10WwlquGPS34DOeomUGBB0gXbLueiq5Trwu0C4=
|
||||
@ -188,6 +192,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/open-dingtalk/dingtalk-stream-sdk-go v0.9.1 h1:Lb/Uzkiw2Ugt2Xf03J5wmv81PdkYOiWbI8CNBi1boC8=
|
||||
github.com/open-dingtalk/dingtalk-stream-sdk-go v0.9.1/go.mod h1:ln3IqPYYocZbYvl9TAOrG/cxGR9xcn4pnZRLdCTEGEU=
|
||||
github.com/oschwald/geoip2-golang v1.13.0 h1:Q44/Ldc703pasJeP5V9+aFSZFmBN7DKHbNsSFzQATJI=
|
||||
github.com/oschwald/geoip2-golang v1.13.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo=
|
||||
github.com/oschwald/maxminddb-golang v1.13.0 h1:R8xBorY71s84yO06NgTmQvqvTvlS/bnYZrrWX1MElnU=
|
||||
|
||||
16
main.go
16
main.go
@ -97,6 +97,13 @@ func main() {
|
||||
feishuApi.POST("/notify/client", controller.FeishuNotifyClient) // 客户端报警
|
||||
feishuApi.POST("/notify/order", controller.FeishuNotifyOrder) // 订单通知
|
||||
}
|
||||
alibabaApi := r.Group("/api/alibaba")
|
||||
{
|
||||
// 阿里云
|
||||
alibabaApi.POST("/zabbix/notify", controller.AlibabaNotify) // 系统报警
|
||||
alibabaApi.POST("/zabbix/recovery", controller.AlibabaRecovery) // 系统报警
|
||||
alibabaApi.POST("/game/notify", controller.AlibabaGameNotify) // 游戏报警
|
||||
}
|
||||
api := r.Group("/api", middleware.ValidateToken())
|
||||
{
|
||||
// 账号管理
|
||||
@ -123,6 +130,7 @@ func main() {
|
||||
api.POST("/server/editServer", controller.EditServer)
|
||||
|
||||
api.POST("/server/updateApp", controller.UpdateApp)
|
||||
api.POST("/server/updateAppReview", controller.UpdateAppReview)
|
||||
api.POST("/server/updateAppFeishu", controller.UpdateAppFeishu)
|
||||
api.POST("/server/restart", controller.RestartServer)
|
||||
api.POST("/server/reload", controller.ReloadServer)
|
||||
@ -151,11 +159,11 @@ func main() {
|
||||
{
|
||||
scripts.POST("/copywriting", controller.Copywriting) // 下载文案文件
|
||||
}
|
||||
go util.ScheduleDailyTask()
|
||||
//go util.ScheduleDailyTask()
|
||||
go server.Server()
|
||||
go model.InitToken() // 初始化 Token 列表
|
||||
go controller.USSendInfo() // 启动定时任务发送信息
|
||||
go monitor.UserAliveMonitor(0) // 用户存活监控
|
||||
go model.InitToken() // 初始化 Token 列表
|
||||
//go controller.USSendInfo() // 启动定时任务发送信息
|
||||
//go monitor.UserAliveMonitor(0) // 用户存活监控
|
||||
go monitor.ServerInfoMonitor() // 服务器信息监控
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
|
||||
@ -81,19 +81,22 @@ func (m *Mail) SendMail() error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to insert mail: %v", err)
|
||||
}
|
||||
go func() {
|
||||
ws, err := util.GetWebsocket(m.AppId, m.ServerId)
|
||||
if err != nil {
|
||||
log.Printf("failed to get websocket: %v", err)
|
||||
}
|
||||
defer ws.Close()
|
||||
ServerList := util.GetServerInfo(m.AppId, 0)
|
||||
for _, server := range ServerList {
|
||||
go func() {
|
||||
ws, err := util.GetWebsocket(m.AppId, server.ServerId)
|
||||
if err != nil {
|
||||
log.Printf("failed to get websocket: %v", err)
|
||||
}
|
||||
defer ws.Close()
|
||||
|
||||
req := &msg.ReqReloadServerMail{}
|
||||
_, err = util.SendAdminMsg(ws, req)
|
||||
if err != nil {
|
||||
log.Printf("failed to send admin message: %v", err)
|
||||
}
|
||||
}()
|
||||
req := &msg.ReqReloadServerMail{}
|
||||
_, err = util.SendAdminMsg(ws, req)
|
||||
if err != nil {
|
||||
log.Printf("failed to send admin message: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
170
model/server.go
170
model/server.go
@ -2,12 +2,13 @@ package model
|
||||
|
||||
import (
|
||||
"backend/Type"
|
||||
"backend/common"
|
||||
"backend/alibaba"
|
||||
"backend/feishu"
|
||||
"backend/msg"
|
||||
util "backend/util"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/Ullaakut/nmap"
|
||||
)
|
||||
@ -25,6 +26,11 @@ type Server struct {
|
||||
Type int `json:"Type"`
|
||||
Tags string `json:"Tags"`
|
||||
ClientVersion string `json:"ClientVersion"`
|
||||
Host string `json:"Host"`
|
||||
Port int `json:"Port"`
|
||||
WsPort int `json:"WsPort"`
|
||||
WorkDir string `json:"WorkDir"`
|
||||
Ecs int `json:"Ecs"`
|
||||
}
|
||||
|
||||
func (s *Server) AppList() ([]*Type.App, error) {
|
||||
@ -58,8 +64,8 @@ func (s *Server) ServerList() ([]*Type.ServerInfo, error) {
|
||||
func (s *Server) AddServer() error {
|
||||
Db := util.MPool.GetGameDB()
|
||||
defer Db.Close()
|
||||
_, err := Db.Exec("INSERT INTO server (`AppId`, `ServerId`, `ServerName`, `Status`, `CreateTime`, `OpenServerTime`) VALUES (?, ?, ?, ?, ?, ?)",
|
||||
s.AppId, s.ServerId, s.ServerName, s.Status, util.Now(), s.OpenServerTime)
|
||||
_, err := Db.Exec("INSERT INTO server (`AppId`, `ServerId`, `ServerName`, `Status`, `CreateTime`, `OpenServerTime`, `Host`, `Port`, `version`, `ws_port`, `work_dir`, `ecs`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?)",
|
||||
s.AppId, s.ServerId, s.ServerName, s.Status, util.Now(), s.OpenServerTime, s.Host, s.Port, s.ClientVersion, s.WsPort, s.WorkDir, s.Ecs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to insert: %v", err)
|
||||
}
|
||||
@ -78,52 +84,171 @@ func (s *Server) EditServer() error {
|
||||
}
|
||||
|
||||
func (s *Server) UpdateApp() (string, error) {
|
||||
nodeInfo := util.GetNodeByName("devops")
|
||||
AppConfig, err := util.GetAppConfig(s.AppId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ServerConfig, err := common.GetServerConfig(DEVOPS_SERVER)
|
||||
SshClient, err := util.NewSshClient(nodeInfo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
param := Type.AlibabaUpdateCardParam{}
|
||||
|
||||
SshClient, err := NewSshClient(ServerConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer SshClient.client.Close()
|
||||
defer SshClient.Close()
|
||||
_, err = SshClient.RunCommand("cd /data/devops && git pull")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to git pull: %v", err)
|
||||
}
|
||||
now := util.Now()
|
||||
cmd := fmt.Sprintf("ansible-playbook /data/devops/playbook/%s.yml -i /data/devops/playbook/hosts", AppConfig.AppName)
|
||||
output, err := SshClient.RunCommand(cmd)
|
||||
param.UpdateTime = util.NowFormat()
|
||||
param.Duration = fmt.Sprintf("%d 秒", util.Now()-now)
|
||||
param.Server = AppConfig.AppName
|
||||
|
||||
if err != nil {
|
||||
param.SrcGitLog = fmt.Sprintf("- 更新失败: %v\n", err)
|
||||
param.DocGitLog = "- output:\n" + output
|
||||
content := util.ParseTmpl("./template/update.tmpl", param)
|
||||
alibaba.SendStandardMsg("游戏服务更新失败", content, "red")
|
||||
return "", err
|
||||
}
|
||||
// 记录git 更新状态
|
||||
cmd = "cd /codes/pet_home_server && git rev-parse HEAD"
|
||||
srcHead, err := SshClient.RunCommand(cmd)
|
||||
if err != nil {
|
||||
log.Printf("警告: 无法获取源码 git head (目录或git命令可能不存在): %v", err)
|
||||
// 继续执行,不中断流程
|
||||
} else {
|
||||
srcHead = strings.TrimSpace(srcHead)
|
||||
oldSrcHead, _ := util.GetGitHead("src")
|
||||
util.SaveGitHead("src", srcHead)
|
||||
if oldSrcHead != "" && oldSrcHead != srcHead {
|
||||
cmd = fmt.Sprintf("cd /codes/pet_home_server && git log %s..%s --pretty=format:'%%h-%%s'", oldSrcHead, srcHead)
|
||||
commitMsg, _ := SshClient.RunCommand(cmd)
|
||||
if commitMsg != "" {
|
||||
param.SrcGitLog = "- server-git log\n" + commitMsg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmd = "cd /data/docs && git rev-parse HEAD"
|
||||
docHead, err := SshClient.RunCommand(cmd)
|
||||
if err != nil {
|
||||
log.Printf("警告: 无法获取文档 git head (目录或git命令可能不存在): %v", err)
|
||||
// 继续执行,不中断流程
|
||||
} else {
|
||||
docHead = strings.TrimSpace(docHead)
|
||||
oldDocHead, _ := util.GetGitHead("doc")
|
||||
util.SaveGitHead("doc", docHead)
|
||||
if oldDocHead != "" && oldDocHead != docHead {
|
||||
cmd = fmt.Sprintf("cd /data/docs && git log %s..%s --pretty=format:'%%h-%%s'", oldDocHead, docHead)
|
||||
commitMsg, _ := SshClient.RunCommand(cmd)
|
||||
if commitMsg != "" {
|
||||
param.DocGitLog = "- docs-git log\n" + commitMsg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
content := util.ParseTmpl("./template/update.tmpl", param)
|
||||
|
||||
DB := util.MPool.GetGameDB()
|
||||
defer DB.Close()
|
||||
DB.Exec("UPDATE app SET `Update` = ? WHERE `AppId` = ?", util.Now(), s.AppId)
|
||||
feishu.SendFeishuMsg(fmt.Sprintf("AppName: %s, 执行文件更新完成", AppConfig.AppName))
|
||||
|
||||
alibaba.SendStandardMsg("游戏服务更新完成", content, "green")
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func (s *Server) UpdateAppFeishu() (string, error) {
|
||||
func (s *Server) UpdateAppReview() (string, error) {
|
||||
nodeInfo := util.GetNodeByName("devops")
|
||||
AppConfig, err := util.GetAppConfig(s.AppId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ServerConfig, err := common.GetServerConfig(DEVOPS_SERVER)
|
||||
SshClient, err := util.NewSshClient(nodeInfo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
param := Type.AlibabaUpdateCardParam{}
|
||||
|
||||
defer SshClient.Close()
|
||||
_, err = SshClient.RunCommand("cd /data/devops && git pull")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to git pull: %v", err)
|
||||
}
|
||||
now := util.Now()
|
||||
cmd := fmt.Sprintf("ansible-playbook /data/devops/playbook/%s-review.yml -i /data/devops/playbook/hosts", AppConfig.AppName)
|
||||
output, err := SshClient.RunCommand(cmd)
|
||||
param.UpdateTime = util.NowFormat()
|
||||
param.Duration = fmt.Sprintf("%d 秒", util.Now()-now)
|
||||
param.Server = AppConfig.AppName
|
||||
|
||||
if err != nil {
|
||||
param.SrcGitLog = fmt.Sprintf("- 更新失败: %v\n", err)
|
||||
param.DocGitLog = "- output:\n" + output
|
||||
content := util.ParseTmpl("./template/update.tmpl", param)
|
||||
alibaba.SendStandardMsg("游戏服务更新失败", content, "red")
|
||||
return "", err
|
||||
}
|
||||
// 记录git 更新状态
|
||||
cmd = "cd /codes/pet_home_server && git rev-parse HEAD"
|
||||
srcHead, err := SshClient.RunCommand(cmd)
|
||||
if err != nil {
|
||||
log.Printf("警告: 无法获取源码 git head (目录或git命令可能不存在): %v", err)
|
||||
// 继续执行,不中断流程
|
||||
} else {
|
||||
srcHead = strings.TrimSpace(srcHead)
|
||||
oldSrcHead, _ := util.GetGitHead("src")
|
||||
util.SaveGitHead("src", srcHead)
|
||||
if oldSrcHead != "" && oldSrcHead != srcHead {
|
||||
cmd = fmt.Sprintf("cd /codes/pet_home_server && git log %s..%s --pretty=format:'%%h-%%s'", oldSrcHead, srcHead)
|
||||
commitMsg, _ := SshClient.RunCommand(cmd)
|
||||
if commitMsg != "" {
|
||||
param.SrcGitLog = "- server-git log\n" + commitMsg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SshClient, err := NewSshClient(ServerConfig)
|
||||
cmd = "cd /data/docs && git rev-parse HEAD"
|
||||
docHead, err := SshClient.RunCommand(cmd)
|
||||
if err != nil {
|
||||
log.Printf("警告: 无法获取文档 git head (目录或git命令可能不存在): %v", err)
|
||||
// 继续执行,不中断流程
|
||||
} else {
|
||||
docHead = strings.TrimSpace(docHead)
|
||||
oldDocHead, _ := util.GetGitHead("doc")
|
||||
util.SaveGitHead("doc", docHead)
|
||||
if oldDocHead != "" && oldDocHead != docHead {
|
||||
cmd = fmt.Sprintf("cd /data/docs && git log %s..%s --pretty=format:'%%h-%%s'", oldDocHead, docHead)
|
||||
commitMsg, _ := SshClient.RunCommand(cmd)
|
||||
if commitMsg != "" {
|
||||
param.DocGitLog = "- docs-git log\n" + commitMsg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
content := util.ParseTmpl("./template/update.tmpl", param)
|
||||
|
||||
DB := util.MPool.GetGameDB()
|
||||
defer DB.Close()
|
||||
DB.Exec("UPDATE app SET `Update` = ? WHERE `AppId` = ?", util.Now(), s.AppId)
|
||||
alibaba.SendStandardMsg("游戏review服务更新完成", content, "green")
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func (s *Server) UpdateAppFeishu() (string, error) {
|
||||
serverInfo := util.GetServer(s.AppId, s.ServerId)
|
||||
nodeInfo := util.GetNodeById(serverInfo.Ecs)
|
||||
AppConfig, err := util.GetAppConfig(s.AppId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer SshClient.client.Close()
|
||||
SshClient, err := util.NewSshClient(nodeInfo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer SshClient.Close()
|
||||
_, err = SshClient.RunCommand("cd /data/devops && git pull")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to git pull: %v", err)
|
||||
@ -141,22 +266,19 @@ func (s *Server) UpdateAppFeishu() (string, error) {
|
||||
}
|
||||
|
||||
func (s *Server) RestartServer() (string, error) {
|
||||
serverInfo := util.GetServer(s.AppId, s.ServerId)
|
||||
nodeInfo := util.GetNodeById(serverInfo.Ecs)
|
||||
AppConfig, err := util.GetAppConfig(s.AppId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ServerConfig, err := common.GetServerConfig(AppConfig.NodeName)
|
||||
SshClient, err := util.NewSshClient(nodeInfo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
SshClient, err := NewSshClient(ServerConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer SshClient.client.Close()
|
||||
|
||||
cmd := fmt.Sprintf("cd %s && ./tool/tool restart node %d", AppConfig.Path, s.ServerId)
|
||||
defer SshClient.Close()
|
||||
workDir := serverInfo.WorkDir
|
||||
cmd := fmt.Sprintf("cd %s && ./tool/tool restart node %d", workDir, s.ServerId)
|
||||
output, err := SshClient.RunCommand(cmd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
47
model/ssh.go
47
model/ssh.go
@ -1,47 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"backend/common"
|
||||
"backend/util"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type SshClient struct {
|
||||
client *ssh.Client
|
||||
}
|
||||
|
||||
func NewSshClient(config *common.SshConfig) (*SshClient, error) {
|
||||
SP, _ := util.Decrypt(config.Password)
|
||||
sshconfig := &ssh.ClientConfig{
|
||||
User: config.Username,
|
||||
Auth: []ssh.AuthMethod{
|
||||
ssh.Password(SP),
|
||||
},
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
}
|
||||
|
||||
addr := fmt.Sprintf("%s:%d", config.Host, config.Port)
|
||||
client, err := ssh.Dial("tcp", addr, sshconfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SshClient{client: client}, nil
|
||||
}
|
||||
|
||||
func (s *SshClient) RunCommand(cmd string) (string, error) {
|
||||
session, err := s.client.NewSession()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
output, err := session.CombinedOutput(cmd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(output), nil
|
||||
}
|
||||
@ -66,7 +66,6 @@ func ServerInfoMonitor() {
|
||||
now := time.Now()
|
||||
next := now.Truncate(1 * time.Minute).Add(1 * time.Minute)
|
||||
time.Sleep(time.Until(next))
|
||||
|
||||
monitorServerInfo()
|
||||
}
|
||||
}
|
||||
@ -80,7 +79,7 @@ func monitorServerInfo() {
|
||||
return
|
||||
}
|
||||
for _, v := range server {
|
||||
if v.AppId == 5 {
|
||||
if v.Status == 2 || v.Status == 3 { // 维护中或停用跳过
|
||||
continue
|
||||
}
|
||||
go func(v *Type.ServerInfo) {
|
||||
@ -131,5 +130,4 @@ func monitorServerInfo() {
|
||||
tmpDb.Exec("update server set Status=1, Online=?,free_mem=?,cpu=?,weight=? where AppId=? and ServerId=?", util.Int(serverInfo["PlayerNum"]), usage_mem, cpu, weight, v.AppId, v.ServerId)
|
||||
}(v)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
9
template/alibaba_notify.tmpl
Normal file
9
template/alibaba_notify.tmpl
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
- 游戏环境:`{{.NotifyMsg}}`
|
||||
- 报错函数:`{{.FuncName}}`
|
||||
- 发生时间:`{{.AlarmTime}}`
|
||||
------------------------
|
||||
- 堆栈信息:
|
||||
```golang
|
||||
{{.Stack}}
|
||||
```
|
||||
9
template/update.tmpl
Normal file
9
template/update.tmpl
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
- 游戏环境:`{{.Server}}`
|
||||
- 更新时间:`{{.UpdateTime}}`
|
||||
- 耗时:`{{.Duration}}`[鼓掌]
|
||||
------------------------
|
||||
```txt
|
||||
{{.SrcGitLog}}
|
||||
{{.DocGitLog}}
|
||||
```
|
||||
47
unit_test.go
47
unit_test.go
@ -102,3 +102,50 @@ func TestAlibaba(t *testing.T) {
|
||||
version := alibaba.DownloadFile()
|
||||
fmt.Println("version:", version)
|
||||
}
|
||||
|
||||
func TestAlibabaRobot(t *testing.T) {
|
||||
title := "【meowment】订单发货成功"
|
||||
content := `
|
||||
- 玩家账号:test_user_001
|
||||
- 玩家等级:25
|
||||
- 订单号:e50b32601160423c7f
|
||||
|
||||
- 金额 :1.99
|
||||
|
||||
- 发货时间:2026-01-15 18:22:12
|
||||
- 充值总数:10.99 元
|
||||
|
||||
[鼓掌][鼓掌][鼓掌]
|
||||
|
||||
`
|
||||
err := alibaba.SendStandardMsg(title, content, "green")
|
||||
if err != nil {
|
||||
fmt.Println("err:", err)
|
||||
} else {
|
||||
fmt.Println("消息发送成功")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlibabaCard(t *testing.T) {
|
||||
r := Type.NotifyData{
|
||||
NotifyMsg: "测试报警消息内容",
|
||||
Host: "测试主机",
|
||||
EventName: "测试事件名称",
|
||||
Severity: "High",
|
||||
AlarmTime: time.Unix(time.Now().Unix(), 0).Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
err := alibaba.SendZabbixMsg(&r)
|
||||
if err != nil {
|
||||
fmt.Println("err:", err)
|
||||
} else {
|
||||
fmt.Println("卡片发送成功")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerUpdateApp(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestXxxx(t *testing.T) {
|
||||
util.SaveGitHead("src", "7d6a040cec2841c728fc798d720bac30c5084ceb")
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@ -76,3 +77,20 @@ func GetLanguageExportLastUpdate() (int, error) {
|
||||
v, e := getBBolt("language_export_last_update")
|
||||
return Int(v), e
|
||||
}
|
||||
|
||||
func GetGitHead(key string) (string, error) {
|
||||
return getBBolt(fmt.Sprintf("git_head_%s", key))
|
||||
}
|
||||
|
||||
func SaveGitHead(key string, head interface{}) error {
|
||||
return saveBBolt(fmt.Sprintf("git_head_%s", key), head)
|
||||
}
|
||||
|
||||
func GetUserConnectNode(Uid string) (int, error) {
|
||||
v, e := getBBolt(fmt.Sprintf("user_connect_node_%s", Uid))
|
||||
return Int(v), e
|
||||
}
|
||||
|
||||
func SaveUserConnectNode(Uid string, node interface{}) error {
|
||||
return saveBBolt(fmt.Sprintf("user_connect_node_%s", Uid), node)
|
||||
}
|
||||
|
||||
@ -17,6 +17,9 @@ type ServerConfig struct {
|
||||
Version string `db:"version"`
|
||||
Status int `db:"Status"`
|
||||
Weight int `db:"Weight"`
|
||||
WorkDir string `db:"work_dir"`
|
||||
Ecs int `db:"ecs"`
|
||||
Name string `db:"ServerName"`
|
||||
}
|
||||
|
||||
func LoginResponse(c *gin.Context, AppId, AreaCode int, Version string) {
|
||||
@ -185,6 +188,17 @@ func GetServerInfo(AppId, AreaCode int) []ServerConfig {
|
||||
return servers
|
||||
}
|
||||
|
||||
func GetServer(AppId, ServerId int) ServerConfig {
|
||||
Db := MPool.GetGameDB()
|
||||
defer Db.Close()
|
||||
var server ServerConfig
|
||||
err := Db.Get(&server, "SELECT ServerId, Status, Host, Port, MaxOnline, Online, version, ecs, work_dir FROM server WHERE AppId = ? AND ServerId = ?", AppId, ServerId)
|
||||
if err != nil {
|
||||
return ServerConfig{}
|
||||
}
|
||||
return server
|
||||
}
|
||||
|
||||
// VersionDistance 计算两个版本号之间的跨度
|
||||
// 版本号格式为 major.minor.patch (例如: 1.0.0)
|
||||
// 返回值越大表示版本差异越大
|
||||
|
||||
27
util/node.go
Normal file
27
util/node.go
Normal file
@ -0,0 +1,27 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"backend/Type"
|
||||
)
|
||||
|
||||
func GetNodeById(id int) *Type.Node {
|
||||
Db := MPool.GetGameDB()
|
||||
defer Db.Close()
|
||||
node := &Type.Node{}
|
||||
err := Db.Get(node, "SELECT * FROM node WHERE id = ? LIMIT 1", id)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
func GetNodeByName(name string) *Type.Node {
|
||||
Db := MPool.GetGameDB()
|
||||
defer Db.Close()
|
||||
node := &Type.Node{}
|
||||
err := Db.Get(node, "SELECT * FROM node WHERE name = ? LIMIT 1", name)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return node
|
||||
}
|
||||
77
util/ssh.go
Normal file
77
util/ssh.go
Normal file
@ -0,0 +1,77 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"backend/Type"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type SshClient struct {
|
||||
client *ssh.Client
|
||||
}
|
||||
|
||||
func (ssh *SshClient) Close() {
|
||||
ssh.client.Close()
|
||||
}
|
||||
|
||||
func NewSshClient(config *Type.Node) (*SshClient, error) {
|
||||
var authMethods []ssh.AuthMethod
|
||||
|
||||
// 支持证书连接
|
||||
// 从文件读取私钥
|
||||
if config.PrivateKeyPath != "" {
|
||||
keyBytes, err := os.ReadFile(config.PrivateKeyPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read private key file failed: %w", err)
|
||||
}
|
||||
key, err := ssh.ParsePrivateKey(keyBytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse private key failed: %w", err)
|
||||
}
|
||||
authMethods = append(authMethods, ssh.PublicKeys(key))
|
||||
}
|
||||
|
||||
// 支持密码连接
|
||||
if config.Password != "" {
|
||||
SP, err := Decrypt(config.Password)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decrypt password failed: %w", err)
|
||||
}
|
||||
authMethods = append(authMethods, ssh.Password(SP))
|
||||
}
|
||||
|
||||
if len(authMethods) == 0 {
|
||||
return nil, fmt.Errorf("no authentication method provided")
|
||||
}
|
||||
|
||||
sshconfig := &ssh.ClientConfig{
|
||||
User: "root",
|
||||
Auth: authMethods,
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
}
|
||||
|
||||
addr := fmt.Sprintf("%s:22", config.Host)
|
||||
client, err := ssh.Dial("tcp", addr, sshconfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SshClient{client: client}, nil
|
||||
}
|
||||
|
||||
func (s *SshClient) RunCommand(cmd string) (string, error) {
|
||||
session, err := s.client.NewSession()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
output, err := session.CombinedOutput(cmd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(output), nil
|
||||
}
|
||||
@ -209,6 +209,10 @@ func Year() int {
|
||||
return time.Now().Year()
|
||||
}
|
||||
|
||||
func NowFormat() string {
|
||||
return time.Now().Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
func SendAdminMsg(ws *websocket.Conn, req proto.Message) (map[string]interface{}, error) {
|
||||
reqBuf := PackMsg(req)
|
||||
_, err := ws.Write(reqBuf)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user