| @@ -61,7 +61,7 @@ type TemplateValue struct { | |||||
| Color string `json:"color"` | Color string `json:"color"` | ||||
| } | } | ||||
| type CloudbrainTaskData struct { | |||||
| type DefaultWechatTemplate struct { | |||||
| First TemplateValue `json:"first"` | First TemplateValue `json:"first"` | ||||
| Keyword1 TemplateValue `json:"keyword1"` | Keyword1 TemplateValue `json:"keyword1"` | ||||
| Keyword2 TemplateValue `json:"keyword2"` | Keyword2 TemplateValue `json:"keyword2"` | ||||
| @@ -0,0 +1,155 @@ | |||||
| package wechat | |||||
| import ( | |||||
| "code.gitea.io/gitea/models" | |||||
| "code.gitea.io/gitea/modules/log" | |||||
| "code.gitea.io/gitea/modules/setting" | |||||
| "fmt" | |||||
| "time" | |||||
| ) | |||||
| type JobOperateType string | |||||
| const ( | |||||
| JobOperateTypeStart JobOperateType = "start" | |||||
| JobOperateTypeStop JobOperateType = "stop" | |||||
| ) | |||||
| type CloudbrainStartMsg struct { | |||||
| } | |||||
| func (CloudbrainStartMsg) Data(ctx *TemplateContext) *DefaultWechatTemplate { | |||||
| return &DefaultWechatTemplate{ | |||||
| First: TemplateValue{Value: setting.CloudbrainStartedTitle}, | |||||
| Keyword1: TemplateValue{Value: ctx.Cloudbrain.DisplayJobName}, | |||||
| Keyword2: TemplateValue{Value: getJobTypeDisplayName(ctx.Cloudbrain.JobType)}, | |||||
| Keyword3: TemplateValue{Value: time.Unix(int64(ctx.Cloudbrain.CreatedUnix), 0).Format("2006-01-02 15:04:05")}, | |||||
| Remark: TemplateValue{Value: setting.CloudbrainStartedRemark}, | |||||
| } | |||||
| } | |||||
| func (CloudbrainStartMsg) ShouldSend(ctx *TemplateContext) bool { | |||||
| if len(setting.CloudbrainStartedNotifyList) == 0 { | |||||
| return false | |||||
| } | |||||
| for _, v := range setting.CloudbrainStartedNotifyList { | |||||
| if v == ctx.Cloudbrain.JobType { | |||||
| return true | |||||
| } | |||||
| } | |||||
| return false | |||||
| } | |||||
| func (CloudbrainStartMsg) MsgId(ctx *TemplateContext) string { | |||||
| return string(JobOperateTypeStart) + "_" + fmt.Sprint(ctx.Cloudbrain.ID) | |||||
| } | |||||
| func (CloudbrainStartMsg) Url(ctx *TemplateContext) string { | |||||
| repo, err := models.GetRepositoryByID(ctx.Cloudbrain.RepoID) | |||||
| if err != nil { | |||||
| log.Error("CloudbrainStartMsg GetRepositoryByID error,%v", err) | |||||
| return "" | |||||
| } | |||||
| return getCloudbrainTemplateUrl(*ctx.Cloudbrain, repo) | |||||
| } | |||||
| type CloudbrainStopMsg struct { | |||||
| } | |||||
| func (CloudbrainStopMsg) Data(ctx *TemplateContext) *DefaultWechatTemplate { | |||||
| return &DefaultWechatTemplate{ | |||||
| First: TemplateValue{Value: setting.CloudbrainStoppedTitle}, | |||||
| Keyword1: TemplateValue{Value: ctx.Cloudbrain.DisplayJobName}, | |||||
| Keyword2: TemplateValue{Value: getJobTypeDisplayName(ctx.Cloudbrain.JobType)}, | |||||
| Keyword3: TemplateValue{Value: time.Unix(int64(ctx.Cloudbrain.CreatedUnix), 0).Format("2006-01-02 15:04:05")}, | |||||
| Remark: TemplateValue{Value: setting.CloudbrainStoppedRemark}, | |||||
| } | |||||
| } | |||||
| func (CloudbrainStopMsg) ShouldSend(ctx *TemplateContext) bool { | |||||
| if len(setting.CloudbrainStoppedNotifyList) == 0 { | |||||
| return false | |||||
| } | |||||
| for _, v := range setting.CloudbrainStoppedNotifyList { | |||||
| if v == ctx.Cloudbrain.JobType { | |||||
| return true | |||||
| } | |||||
| } | |||||
| return false | |||||
| } | |||||
| func (CloudbrainStopMsg) MsgId(ctx *TemplateContext) string { | |||||
| return string(JobOperateTypeStop) + "_" + fmt.Sprint(ctx.Cloudbrain.ID) | |||||
| } | |||||
| func (CloudbrainStopMsg) Url(ctx *TemplateContext) string { | |||||
| repo, err := models.GetRepositoryByID(ctx.Cloudbrain.RepoID) | |||||
| if err != nil { | |||||
| log.Error("CloudbrainStopMsg GetRepositoryByID error,%v", err) | |||||
| return "" | |||||
| } | |||||
| return getCloudbrainTemplateUrl(*ctx.Cloudbrain, repo) | |||||
| } | |||||
| var startMsg = &CloudbrainStartMsg{} | |||||
| var stopMsg = &CloudbrainStopMsg{} | |||||
| func GetTemplateFromOperateType(operate JobOperateType) Template { | |||||
| switch operate { | |||||
| case JobOperateTypeStart: | |||||
| return startMsg | |||||
| case JobOperateTypeStop: | |||||
| return stopMsg | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func GetJobOperateTypeFromCloudbrainStatus(cloudbrain *models.Cloudbrain) JobOperateType { | |||||
| if cloudbrain.IsTerminal() { | |||||
| return JobOperateTypeStop | |||||
| } | |||||
| if cloudbrain.IsRunning() { | |||||
| return JobOperateTypeStart | |||||
| } | |||||
| return "" | |||||
| } | |||||
| func getCloudbrainTemplateUrl(cloudbrain models.Cloudbrain, repo *models.Repository) string { | |||||
| url := setting.AppURL + repo.FullName() | |||||
| switch cloudbrain.JobType { | |||||
| case string(models.JobTypeDebug): | |||||
| if cloudbrain.ComputeResource == "CPU/GPU" { | |||||
| url += "/cloudbrain/" + fmt.Sprint(cloudbrain.ID) | |||||
| } else { | |||||
| url += "/modelarts/notebook/" + fmt.Sprint(cloudbrain.ID) | |||||
| } | |||||
| case string(models.JobTypeBenchmark): | |||||
| url += "/cloudbrain/benchmark/" + fmt.Sprint(cloudbrain.ID) | |||||
| case string(models.JobTypeTrain): | |||||
| if cloudbrain.Type == models.TypeCloudBrainOne { | |||||
| url += "/cloudbrain/train-job/" + fmt.Sprint(cloudbrain.JobID) | |||||
| } else if cloudbrain.Type == models.TypeCloudBrainTwo { | |||||
| url += "/modelarts/train-job/" + fmt.Sprint(cloudbrain.JobID) | |||||
| } else if cloudbrain.Type == models.TypeC2Net { | |||||
| url += "/grampus/train-job/" + fmt.Sprint(cloudbrain.JobID) | |||||
| } | |||||
| case string(models.JobTypeInference): | |||||
| url += "/modelarts/inference-job/" + fmt.Sprint(cloudbrain.JobID) | |||||
| } | |||||
| return url | |||||
| } | |||||
| func getJobTypeDisplayName(jobType string) string { | |||||
| switch jobType { | |||||
| case string(models.JobTypeDebug): | |||||
| return "调试任务" | |||||
| case string(models.JobTypeBenchmark): | |||||
| return "评测任务" | |||||
| case string(models.JobTypeTrain): | |||||
| return "训练任务" | |||||
| case string(models.JobTypeInference): | |||||
| return "推理任务" | |||||
| } | |||||
| return "" | |||||
| } | |||||
| @@ -6,140 +6,55 @@ import ( | |||||
| "code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
| "errors" | "errors" | ||||
| "fmt" | "fmt" | ||||
| "time" | |||||
| ) | ) | ||||
| type JobOperateType string | |||||
| const ( | |||||
| JobOperateTypeStart JobOperateType = "start" | |||||
| JobOperateTypeStop JobOperateType = "stop" | |||||
| ) | |||||
| type Template interface { | |||||
| ShouldSend(ctx *TemplateContext) bool | |||||
| Data(ctx *TemplateContext) *DefaultWechatTemplate | |||||
| MsgId(ctx *TemplateContext) string | |||||
| Url(ctx *TemplateContext) string | |||||
| } | |||||
| func GetJobOperateTypeFromCloudbrainStatus(cloudbrain *models.Cloudbrain) JobOperateType { | |||||
| if cloudbrain.IsTerminal() { | |||||
| return JobOperateTypeStop | |||||
| } | |||||
| if cloudbrain.IsRunning() { | |||||
| return JobOperateTypeStart | |||||
| } | |||||
| return "" | |||||
| type TemplateContext struct { | |||||
| Cloudbrain *models.Cloudbrain | |||||
| } | } | ||||
| func SendCloudbrainStartedMsg(operateType JobOperateType, cloudbrain models.Cloudbrain) error { | |||||
| func SendTemplateMsg(template Template, ctx *TemplateContext, userId int64) error { | |||||
| defer func() { | defer func() { | ||||
| if err := recover(); err != nil { | if err := recover(); err != nil { | ||||
| combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2)) | combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2)) | ||||
| log.Error("PANIC:", combinedErr) | log.Error("PANIC:", combinedErr) | ||||
| } | } | ||||
| }() | }() | ||||
| repo, err := models.GetRepositoryByID(cloudbrain.RepoID) | |||||
| if err != nil { | |||||
| log.Error("SendCloudbrainStartedMsg GetRepositoryByID error,%v", err) | |||||
| } | |||||
| if setting.CloudbrainStartedTemplateId == "" { | |||||
| if !template.ShouldSend(ctx) { | |||||
| return nil | return nil | ||||
| } | } | ||||
| openId := models.GetUserWechatOpenId(cloudbrain.UserID) | |||||
| openId := models.GetUserWechatOpenId(userId) | |||||
| if openId == "" { | if openId == "" { | ||||
| return errors.New("Wechat openId not exist") | return errors.New("Wechat openId not exist") | ||||
| } | } | ||||
| data := CloudbrainTaskData{ | |||||
| First: TemplateValue{Value: getCloudbrainTemplateTitle(operateType)}, | |||||
| Keyword1: TemplateValue{Value: cloudbrain.DisplayJobName}, | |||||
| Keyword2: TemplateValue{Value: getJobTypeDisplayName(cloudbrain.JobType)}, | |||||
| Keyword3: TemplateValue{Value: time.Unix(int64(cloudbrain.CreatedUnix), 0).Format("2006-01-02 15:04:05")}, | |||||
| Remark: TemplateValue{Value: getCloudbrainTemplateRemark(operateType)}, | |||||
| } | |||||
| req := TemplateMsgRequest{ | req := TemplateMsgRequest{ | ||||
| ToUser: openId, | ToUser: openId, | ||||
| TemplateId: setting.CloudbrainStartedTemplateId, | TemplateId: setting.CloudbrainStartedTemplateId, | ||||
| Url: getCloudbrainTemplateUrl(cloudbrain, repo), | |||||
| ClientMsgId: string(operateType) + "_" + fmt.Sprint(cloudbrain.ID), | |||||
| Data: data, | |||||
| Url: template.Url(ctx), | |||||
| ClientMsgId: template.MsgId(ctx), | |||||
| Data: template.Data(ctx), | |||||
| } | } | ||||
| err, retryFlag := sendTemplateMsg(req) | err, retryFlag := sendTemplateMsg(req) | ||||
| if retryFlag { | if retryFlag { | ||||
| log.Info("retrySendCloudbrainTemplateMsg calling") | |||||
| log.Info("SendTemplateMsg calling") | |||||
| refreshAccessToken() | refreshAccessToken() | ||||
| err, _ = sendTemplateMsg(req) | err, _ = sendTemplateMsg(req) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("SendCloudbrainStartedMsg err. %v", err) | |||||
| log.Error("SendTemplateMsg err. %v", err) | |||||
| return err | return err | ||||
| } | } | ||||
| return nil | return nil | ||||
| } | } | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("SendCloudbrainStartedMsg err. %v", err) | |||||
| log.Error("SendTemplateMsg err. %v", err) | |||||
| return err | return err | ||||
| } | } | ||||
| return nil | return nil | ||||
| } | } | ||||
| func getCloudbrainTemplateUrl(cloudbrain models.Cloudbrain, repo *models.Repository) string { | |||||
| url := setting.AppURL + repo.FullName() | |||||
| switch cloudbrain.JobType { | |||||
| case string(models.JobTypeDebug): | |||||
| if cloudbrain.ComputeResource == "CPU/GPU" { | |||||
| url += "/cloudbrain/" + fmt.Sprint(cloudbrain.ID) | |||||
| } else { | |||||
| url += "/modelarts/notebook/" + fmt.Sprint(cloudbrain.ID) | |||||
| } | |||||
| case string(models.JobTypeBenchmark): | |||||
| url += "/cloudbrain/benchmark/" + fmt.Sprint(cloudbrain.ID) | |||||
| case string(models.JobTypeTrain): | |||||
| if cloudbrain.Type == models.TypeCloudBrainOne { | |||||
| url += "/cloudbrain/train-job/" + fmt.Sprint(cloudbrain.JobID) | |||||
| } else if cloudbrain.Type == models.TypeCloudBrainTwo { | |||||
| url += "/modelarts/train-job/" + fmt.Sprint(cloudbrain.JobID) | |||||
| } else if cloudbrain.Type == models.TypeC2Net { | |||||
| url += "/grampus/train-job/" + fmt.Sprint(cloudbrain.JobID) | |||||
| } | |||||
| case string(models.JobTypeInference): | |||||
| url += "/modelarts/inference-job/" + fmt.Sprint(cloudbrain.JobID) | |||||
| } | |||||
| return url | |||||
| } | |||||
| func getCloudbrainTemplateTitle(operateType JobOperateType) string { | |||||
| var title string | |||||
| switch operateType { | |||||
| case JobOperateTypeStart: | |||||
| title = "您好,您提交的算力资源申请已通过,任务已启动,请您关注运行情况。" | |||||
| case JobOperateTypeStop: | |||||
| title = "您好,您提交的任务已运行结束。" | |||||
| } | |||||
| return title | |||||
| } | |||||
| func getCloudbrainTemplateRemark(operateType JobOperateType) string { | |||||
| var remark string | |||||
| switch operateType { | |||||
| case JobOperateTypeStart: | |||||
| remark = "感谢您的耐心等待。" | |||||
| case JobOperateTypeStop: | |||||
| remark = "点击可查看运行结果" | |||||
| } | |||||
| return remark | |||||
| } | |||||
| func getJobTypeDisplayName(jobType string) string { | |||||
| switch jobType { | |||||
| case string(models.JobTypeDebug): | |||||
| return "调试任务" | |||||
| case string(models.JobTypeBenchmark): | |||||
| return "评测任务" | |||||
| case string(models.JobTypeTrain): | |||||
| return "训练任务" | |||||
| case string(models.JobTypeInference): | |||||
| return "推理任务" | |||||
| } | |||||
| return "" | |||||
| } | |||||
| @@ -8,7 +8,6 @@ import ( | |||||
| "code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
| "code.gitea.io/gitea/modules/auth/wechat" | "code.gitea.io/gitea/modules/auth/wechat" | ||||
| "code.gitea.io/gitea/modules/notification/base" | "code.gitea.io/gitea/modules/notification/base" | ||||
| "code.gitea.io/gitea/modules/setting" | |||||
| ) | ) | ||||
| type wechatNotifier struct { | type wechatNotifier struct { | ||||
| @@ -29,16 +28,6 @@ func (*wechatNotifier) NotifyChangeCloudbrainStatus(cloudbrain *models.Cloudbrai | |||||
| if operateType == "" { | if operateType == "" { | ||||
| return | return | ||||
| } | } | ||||
| switch operateType { | |||||
| case wechat.JobOperateTypeStart: | |||||
| if len(setting.CloudbrainStartedNotifyList) == 0 { | |||||
| return | |||||
| } | |||||
| for _, v := range setting.CloudbrainStartedNotifyList { | |||||
| if v == cloudbrain.JobType { | |||||
| go wechat.SendCloudbrainStartedMsg(operateType, *cloudbrain) | |||||
| return | |||||
| } | |||||
| } | |||||
| } | |||||
| template := wechat.GetTemplateFromOperateType(operateType) | |||||
| go wechat.SendTemplateMsg(template, &wechat.TemplateContext{Cloudbrain: cloudbrain}, cloudbrain.UserID) | |||||
| } | } | ||||
| @@ -586,6 +586,12 @@ var ( | |||||
| //wechat template msg config | //wechat template msg config | ||||
| CloudbrainStartedTemplateId string | CloudbrainStartedTemplateId string | ||||
| CloudbrainStartedNotifyList []string | CloudbrainStartedNotifyList []string | ||||
| CloudbrainStartedTitle string | |||||
| CloudbrainStartedRemark string | |||||
| CloudbrainStoppedTemplateId string | |||||
| CloudbrainStoppedNotifyList []string | |||||
| CloudbrainStoppedTitle string | |||||
| CloudbrainStoppedRemark string | |||||
| //nginx proxy | //nginx proxy | ||||
| PROXYURL string | PROXYURL string | ||||
| @@ -1448,6 +1454,12 @@ func NewContext() { | |||||
| TreePathOfSubscribe = sec.Key("SUBSCRIBE_TREE_PATH").MustString("wechat/subscribe_reply.json") | TreePathOfSubscribe = sec.Key("SUBSCRIBE_TREE_PATH").MustString("wechat/subscribe_reply.json") | ||||
| CloudbrainStartedTemplateId = sec.Key("CLOUDBRAIN_STARTED_TEMPLATE_ID").MustString("") | CloudbrainStartedTemplateId = sec.Key("CLOUDBRAIN_STARTED_TEMPLATE_ID").MustString("") | ||||
| CloudbrainStartedNotifyList = strings.Split(sec.Key("CLOUDBRAIN_STARTED_NOTIFY_LIST").MustString("DEBUG"), ",") | CloudbrainStartedNotifyList = strings.Split(sec.Key("CLOUDBRAIN_STARTED_NOTIFY_LIST").MustString("DEBUG"), ",") | ||||
| CloudbrainStartedTitle = sec.Key("CLOUDBRAIN_STARTED_TITLE").MustString("您好,您提交的算力资源申请已通过,任务已启动,请您关注运行情况。") | |||||
| CloudbrainStartedRemark = sec.Key("CLOUDBRAIN_STARTED_REMARK").MustString("感谢您的耐心等待。") | |||||
| CloudbrainStoppedTemplateId = sec.Key("CLOUDBRAIN_STOPPED_TEMPLATE_ID").MustString("") | |||||
| CloudbrainStoppedNotifyList = strings.Split(sec.Key("CLOUDBRAIN_STOPPED_NOTIFY_LIST").MustString("TRAIN"), ",") | |||||
| CloudbrainStoppedTitle = sec.Key("CLOUDBRAIN_STOPPED_TITLE").MustString("您好,您申请的算力资源已结束使用,任务已完成运行,请您关注运行结果。") | |||||
| CloudbrainStoppedRemark = sec.Key("CLOUDBRAIN_STOPPED_REMARK").MustString("感谢您的耐心等待。") | |||||
| SetRadarMapConfig() | SetRadarMapConfig() | ||||