From 54791e3c2cfeada8650b1e1fb7133227a4251c36 Mon Sep 17 00:00:00 2001 From: luziqi Date: Fri, 31 Mar 2023 11:26:41 +0800 Subject: [PATCH] update --- common/notify.go | 80 ++++++++++++++++++++++++------- common/push.go | 5 +- crontask/monkey.go | 12 +++++ device/devices.go | 16 +++---- device/opt.go | 115 +++++++++++++++++++++++++++++++++++++++++++++ docs/docs.go | 43 +++++++++++++++++ docs/swagger.json | 43 +++++++++++++++++ docs/swagger.yaml | 29 ++++++++++++ main.go | 12 +++++ models/http.go | 15 +++--- models/notify.go | 15 ++++++ monkey/task.go | 68 +++++++++++++++------------ test/test.go | 19 ++++---- 13 files changed, 401 insertions(+), 71 deletions(-) create mode 100644 device/opt.go create mode 100644 models/notify.go diff --git a/common/notify.go b/common/notify.go index 2593dd0..5ebbf54 100644 --- a/common/notify.go +++ b/common/notify.go @@ -2,33 +2,79 @@ package common import ( "errors" - "fmt" "goqs/dbsql" + "goqs/models" + + "gorm.io/gorm" ) -type notify struct { - ID int `json:"id" gorm:"column:id"` - Section string `json:"section" gorm:"column:section"` - Name string `json:"name" gorm:"column:name"` - Token string `json:"token" gorm:"column:token"` - Secret string `json:"secret" gorm:"column:secret"` - IsDel int `json:"-" gorm:"column:is_del"` -} +var NotifyList []models.Notify -func (t *notify) TableName() string { - return "notify" +func InitNotifyInfos() error { + var list []models.Notify + + db, err := dbsql.GetConn(dbsql.DSN) + if err != nil { + return err + } + defer dbsql.Close(db) + + db.Find(&list) + if db.Error != nil { + return db.Error + } + + NotifyList = list + + return nil } -func GetNotifyConfig(section, name string) (notify, error) { +// 根据section和name获取通知信息 +func GetNotifyInfo(section, name string) (models.Notify, error) { + var n models.Notify + db, err := dbsql.GetConn(dbsql.DSN) if err != nil { - fmt.Println(err) + return n, err } defer dbsql.Close(db) - var n notify - db.Model(notify{}).Where("section = ? AND name = ?", section, name).Last(&n) - if n.ID < 1 { - return n, errors.New("没找到对应的通知设置") + + db.Where("section = ? AND name = ?", section, name).Last(&n) + if db.Error != nil { + return n, db.Error } + if n.ID < 0 { + return n, errors.New("没有找到notify配置") + } + return n, nil } + +// 创建通知 +func createNotify(db *gorm.DB, n *models.Notify) error { + return db.Create(n).Error +} + +// 查询所有通知 +func getAllNotifys(db *gorm.DB) ([]models.Notify, error) { + var ns []models.Notify + err := db.Find(&ns).Error + return ns, err +} + +// 根据 ID 查询通知 +func getNotifyByID(db *gorm.DB, id uint) (models.Notify, error) { + var n models.Notify + err := db.First(&n, id).Error + return n, err +} + +// 更新通知 +func updateNotify(db *gorm.DB, n *models.Notify) error { + return db.Updates(n).Error +} + +// 删除通知 +func deleteNotify(db *gorm.DB, id uint) error { + return db.Delete(&models.Notify{}, id).Error +} diff --git a/common/push.go b/common/push.go index 22fa48d..5e7ecbb 100644 --- a/common/push.go +++ b/common/push.go @@ -35,8 +35,9 @@ func PushCorntaskLog(str string) { func PushMonkeyResult(task models.MonkeyTask) { cli := dingtalk.InitDingTalkWithSecret(Bot_Test_Token, Bot_Test_Secret) if task.Remark != "debug" { - if task.Project == "hising" { - cli = dingtalk.InitDingTalkWithSecret(Bot_Hising_Token, Bot_Hising_Secret) + n, err := GetNotifyInfo("monkey", task.Project) + if err == nil { + cli = dingtalk.InitDingTalkWithSecret(n.Token, n.Secret) } } diff --git a/crontask/monkey.go b/crontask/monkey.go index dec317f..42b9902 100644 --- a/crontask/monkey.go +++ b/crontask/monkey.go @@ -27,4 +27,16 @@ func CheckMonkeyTasks() { go monkey.RunAndroidMonkeyCmd(task, device.Udid) common.PushCorntaskLog("执行Monkey任务:" + task.Project + "-" + device.Udid) } + db.Model(models.MonkeyTask{}).Where("status = ? AND is_del = 0", "RUNNING").Find(&list) + for _, task := range list { + var pids []models.MonkeyPid + db.Model(models.MonkeyPid{}).Where("task_id = ?", task.Id).Find(&pids) + if code := checkTaskPids(pids); code == 0 { + task.Status = "RUNNING" + } else if code == 1 { + task.Status = "FINISH" + db.Model(models.MonkeyTask{}).Where("id = ?", task.Id).Update("status", task.Status) + common.PushMonkeyResult(task) + } + } } diff --git a/device/devices.go b/device/devices.go index 7b0e536..8cc6c38 100644 --- a/device/devices.go +++ b/device/devices.go @@ -28,8 +28,8 @@ func GetDeviceByUdid(c *gin.Context) { return } db, err := dbsql.GetConn(dbsql.DSN) - if rsp.CheckErr(err) { - c.JSON(http.StatusOK, rsp) + if err != nil { + c.JSON(http.StatusOK, rsp.Error(err.Error())) return } defer dbsql.Close(db) @@ -62,21 +62,21 @@ func GetDevices(c *gin.Context) { var p models.Page pageIndex, err := strconv.Atoi(c.DefaultQuery("page_index", "1")) - if rsp.CheckErr(err) { - c.JSON(http.StatusOK, rsp) + if err != nil { + c.JSON(http.StatusOK, rsp.Error(err.Error())) return } p.Index = pageIndex pageSize, err := strconv.Atoi(c.DefaultQuery("page_size", "10")) - if rsp.CheckErr(err) { - c.JSON(http.StatusOK, rsp) + if err != nil { + c.JSON(http.StatusOK, rsp.Error(err.Error())) return } p.Size = pageSize db, err := dbsql.GetConn(dbsql.DSN) - if rsp.CheckErr(err) { - c.JSON(http.StatusOK, rsp) + if err != nil { + c.JSON(http.StatusOK, rsp.Error(err.Error())) return } defer dbsql.Close(db) diff --git a/device/opt.go b/device/opt.go new file mode 100644 index 0000000..1565820 --- /dev/null +++ b/device/opt.go @@ -0,0 +1,115 @@ +package device + +import ( + "goqs/controllers" + "goqs/dbsql" + "goqs/models" + "net/http" + "os/exec" + "time" + + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" + "github.com/spf13/cast" +) + +// @Tags 设备相关 /api/device/v1/ +// @Summary 安装应用 +// @Description 传入安装包链接并指定设备安装 +// @accept x-www-form-urlencoded +// @Param udid formData string true "设备udid" +// @Param pf formData string true "安装平台" +// @Param pkg_url formData string true "安装包下载链接" +// @Success 200 {object} models.Response "返回结果" +// @Router /api/device/v1/opt/install [post] +func InstallApp(c *gin.Context) { + rsp := controllers.NewResponse() + + udid := c.PostForm("udid") // 获取 udid 参数 + pf := c.PostForm("pf") // 获取 pf 参数 + pkg_url := c.PostForm("pkg_url") // 获取 pkg_url 参数 + + if udid == "" { + rsp.Error("参数udid错误:" + udid) + c.JSON(http.StatusOK, rsp) + return + } + if pf == "" { + rsp.Error("参数pf错误:" + pf) + c.JSON(http.StatusOK, rsp) + return + } + if pkg_url == "" { + rsp.Error("参数pkgUrl错误:" + pkg_url) + c.JSON(http.StatusOK, rsp) + return + } + + db, err := dbsql.GetConn(dbsql.DSN) + if err != nil { + rsp.Error(err.Error()) + c.JSON(http.StatusOK, rsp) + } + defer dbsql.Close(db) + + var device models.Device + db.Model(models.Device{}).Where("udid = ?", udid).Find(&device) + if device.ID < 1 { + rsp.Error("找不到该设备:" + udid) + c.JSON(http.StatusOK, rsp) + return + } + if device.Status == "offline" { + rsp.Error("设备不在线:" + udid) + c.JSON(http.StatusOK, rsp) + return + } + if device.Status == "busy" { + rsp.Error("设备正在被占用,无法执行安装操作") + c.JSON(http.StatusOK, rsp) + return + } + + if pf == "adr" { + // 下载app到服务器 + go DownloadAndInstallApp(udid, pkg_url) + + } else { + rsp.Error("未支持的平台:" + pf) + c.JSON(http.StatusOK, rsp) + return + } + + rsp.Success() + rsp.Data = "已执行" + c.JSON(http.StatusOK, rsp) +} + +func DownloadAndInstallApp(udid, pkg_url string) error { + pkg_path := "/home/tmp/pkg/" + cast.ToString(time.Now().Unix()) + ".apk" + log.Debug("正在下载:", pkg_url) + err := exec.Command("wget", pkg_url, "-O", pkg_path).Run() + if err != nil { + log.Error(err) + return err + } + log.Debug("下载完毕,路径:", pkg_path) + err = AdbInstall(udid, pkg_path) + if err != nil { + log.Error(err) + return err + } + return nil +} + +func AdbInstall(udid, filepath string) error { + // 通过 adb 安装 APK + cmd := exec.Command("adb", "-s", udid, "install", "-r", filepath) + output, err := cmd.CombinedOutput() + if err != nil { + log.Error("安装失败:", err) + return err + } + log.Debug("安装成功:", string(output)) + return nil +} diff --git a/docs/docs.go b/docs/docs.go index 296be78..cae93eb 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -178,6 +178,49 @@ var doc = `{ } } }, + "/api/device/v1/opt/install": { + "post": { + "description": "传入安装包链接并指定设备安装", + "consumes": [ + "application/x-www-form-urlencoded" + ], + "tags": [ + "设备相关 /api/device/v1/" + ], + "summary": "安装应用", + "parameters": [ + { + "type": "string", + "description": "设备udid", + "name": "udid", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "安装平台", + "name": "pf", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "安装包下载链接", + "name": "pkg_url", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "返回结果", + "schema": { + "$ref": "#/definitions/models.Response" + } + } + } + } + }, "/api/device/v1/update": { "post": { "description": "根据主键更新设备", diff --git a/docs/swagger.json b/docs/swagger.json index 983a6b2..b54e524 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -159,6 +159,49 @@ } } }, + "/api/device/v1/opt/install": { + "post": { + "description": "传入安装包链接并指定设备安装", + "consumes": [ + "application/x-www-form-urlencoded" + ], + "tags": [ + "设备相关 /api/device/v1/" + ], + "summary": "安装应用", + "parameters": [ + { + "type": "string", + "description": "设备udid", + "name": "udid", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "安装平台", + "name": "pf", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "安装包下载链接", + "name": "pkg_url", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "返回结果", + "schema": { + "$ref": "#/definitions/models.Response" + } + } + } + } + }, "/api/device/v1/update": { "post": { "description": "根据主键更新设备", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 5747ce4..84a2874 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -113,6 +113,35 @@ paths: summary: 获取设备列表 tags: - 设备相关 /api/device/v1/ + /api/device/v1/opt/install: + post: + consumes: + - application/x-www-form-urlencoded + description: 传入安装包链接并指定设备安装 + parameters: + - description: 设备udid + in: formData + name: udid + required: true + type: string + - description: 安装平台 + in: formData + name: pf + required: true + type: string + - description: 安装包下载链接 + in: formData + name: pkg_url + required: true + type: string + responses: + "200": + description: 返回结果 + schema: + $ref: '#/definitions/models.Response' + summary: 安装应用 + tags: + - 设备相关 /api/device/v1/ /api/device/v1/update: post: consumes: diff --git a/main.go b/main.go index 7f69db5..4f04910 100644 --- a/main.go +++ b/main.go @@ -28,6 +28,17 @@ func init() { } func main() { + // dbsql.DSN = dbsql.DSN_local + // db, err := dbsql.GetConn(dbsql.DSN) + // if err != nil { + // fmt.Println(err) + // return + // } + // defer dbsql.Close(db) + // var task models.MonkeyTask + // db.Last(&task) + // common.PushMonkeyResult(task) + // return go crontask.Run() env.InitDB() @@ -82,6 +93,7 @@ func main() { r.POST("/api/device/v1/update", device.UpdateDevice) r.DELETE("/api/device/v1/delete/:id", device.DeleteDevice) r.POST("/api/device/v1/update_status", device.UpdateDeviceStatus) + r.POST("/api/device/v1/opt/install", device.InstallApp) r.Run(port) diff --git a/models/http.go b/models/http.go index 1a033d0..fbdd85f 100644 --- a/models/http.go +++ b/models/http.go @@ -6,26 +6,29 @@ type Response struct { Data interface{} `form:"data" json:"data" uri:"data" xml:"data"` } -func (r *Response) Init() { +func (r *Response) Init() *Response { r.Code = 500 r.Msg = "none" + return r } -func (r *Response) Success() { +func (r *Response) Success() *Response { r.Code = 200 r.Msg = "success" + return r } -func (r *Response) Error(msg string) { +func (r *Response) Error(msg string) *Response { r.Code = 500 r.Msg = msg + return r } -func (r *Response) CheckErr(err error) bool { +func (r *Response) CheckErr(err error) *Response { if err != nil { r.Code = 500 r.Msg = err.Error() - return true + return r } - return false + return r } diff --git a/models/notify.go b/models/notify.go new file mode 100644 index 0000000..8cd32f5 --- /dev/null +++ b/models/notify.go @@ -0,0 +1,15 @@ +package models + +type Notify struct { + ID int `json:"id" gorm:"primaryKey;column:id;type:int unsigned;not null"` + Name string `json:"name" gorm:"column:name;type:varchar(255);not null"` + Section string `json:"section" gorm:"column:section;type:varchar(255);not null"` + Type string `json:"type" gorm:"column:type;type:varchar(255);not null"` + Token string `json:"token" gorm:"column:token;type:varchar(255);not null"` + Secret string `json:"secret" gorm:"column:secret;type:varchar(255);"` + IsDel int `json:"is_del" gorm:"column:is_del;type:int;not null"` +} + +func (Notify) TableName() string { + return "notify" +} diff --git a/monkey/task.go b/monkey/task.go index 8be0aa5..2422ea3 100644 --- a/monkey/task.go +++ b/monkey/task.go @@ -128,6 +128,7 @@ func UpdateTaskStatus(c *gin.Context) { } task.Status = status db.Save(&task) + fmt.Println("更新设备状态为", status) if status == "FINISH" { common.PushMonkeyResult(task) @@ -198,21 +199,21 @@ func GetTasks(c *gin.Context) { var p models.Page pageIndex, err := strconv.Atoi(c.DefaultQuery("page_index", "1")) - if rsp.CheckErr(err) { - c.JSON(http.StatusOK, rsp) + if err != nil { + c.JSON(http.StatusOK, rsp.Error(err.Error())) return } p.Index = pageIndex pageSize, err := strconv.Atoi(c.DefaultQuery("page_size", "10")) - if rsp.CheckErr(err) { - c.JSON(http.StatusOK, rsp) + if err != nil { + c.JSON(http.StatusOK, rsp.Error(err.Error())) return } p.Size = pageSize db, err := dbsql.GetConn(dbsql.DSN) - if rsp.CheckErr(err) { - c.JSON(http.StatusOK, rsp) + if err != nil { + c.JSON(http.StatusOK, rsp.Error(err.Error())) return } defer dbsql.Close(db) @@ -228,26 +229,26 @@ func GetTasks(c *gin.Context) { dbsql.Close(db) db, _ = dbsql.GetConn(dbsql.DSN) - for i, v := range list { + for i, _ := range list { var count int64 db.Model(models.MonkeyActivity{}).Where("task_id = ?", list[i].Id).Count(&count) list[i].CoveredAcitvities = int(count) // 如果状态在 进行中 or 取消中,则检查进程状态 - if v.Status == "RUNNING" || v.Status == "CANCELING" { - var pids []models.MonkeyPid - db.Model(models.MonkeyPid{}).Where("task_id = ?", v.Id).Find(&pids) - if code := checkTaskPids(pids); code == 0 { - list[i].Status = "RUNNING" - } else if code == 1 { - if v.Status == "CANCELING" { - list[i].Status = "CANCEL" - db.Model(models.MonkeyTask{}).Where("id = ?", v.Id).Update("status", list[i].Status) - } else if v.Status == "RUNNING" { - list[i].Status = "FINISH" - db.Model(models.MonkeyTask{}).Where("id = ?", v.Id).Update("status", list[i].Status) - } - } - } + // if v.Status == "RUNNING" || v.Status == "CANCELING" { + // var pids []models.MonkeyPid + // db.Model(models.MonkeyPid{}).Where("task_id = ?", v.Id).Find(&pids) + // if code := checkTaskPids(pids); code == 0 { + // list[i].Status = "RUNNING" + // } else if code == 1 { + // if v.Status == "CANCELING" { + // list[i].Status = "CANCEL" + // db.Model(models.MonkeyTask{}).Where("id = ?", v.Id).Update("status", list[i].Status) + // } else if v.Status == "RUNNING" { + // list[i].Status = "FINISH" + // db.Model(models.MonkeyTask{}).Where("id = ?", v.Id).Update("status", list[i].Status) + // } + // } + // } } dbsql.Close(db) @@ -275,8 +276,8 @@ func GetTaskById(c *gin.Context) { var rsp models.Response db, err := dbsql.GetConn(dbsql.DSN) - if rsp.CheckErr(err) { - c.JSON(http.StatusOK, rsp) + if err != nil { + c.JSON(http.StatusOK, rsp.Error(err.Error())) return } defer dbsql.Close(db) @@ -340,8 +341,8 @@ func UpdatePids(c *gin.Context) { var rsp models.Response db, err := dbsql.GetConn(dbsql.DSN) - if rsp.CheckErr(err) { - c.JSON(http.StatusOK, rsp) + if err != nil { + c.JSON(http.StatusOK, rsp.Error(err.Error())) return } defer dbsql.Close(db) @@ -392,8 +393,8 @@ func UpdateDevices(c *gin.Context) { } db, err := dbsql.GetConn(dbsql.DSN) - if rsp.CheckErr(err) { - c.JSON(http.StatusOK, rsp) + if err != nil { + c.JSON(http.StatusOK, rsp.Error(err.Error())) return } defer dbsql.Close(db) @@ -429,8 +430,8 @@ func StopMonkeyTask(c *gin.Context) { if task_id := cast.ToInt(c.PostForm("task_id")); task_id > 0 { db, err := dbsql.GetConn(dbsql.DSN) - if rsp.CheckErr(err) { - c.JSON(http.StatusOK, rsp) + if err != nil { + c.JSON(http.StatusOK, rsp.Error(err.Error())) return } defer dbsql.Close(db) @@ -462,6 +463,13 @@ func StopMonkeyTask(c *gin.Context) { killPid(v.PId) pids = append(pids, v.PId) } + //判断是否停止成功 + var pids []models.MonkeyPid + db.Table("monkey_pid").Model(models.MonkeyPid{}).Where("task_id = ?", task.Id).Find(&pids) + if code := checkTaskPids(pids); code == 1 { + task.Status = "CANCEL" + db.Model(models.MonkeyTask{}).Where("id = ?", task.Id).Update("status", task.Status) + } } rsp.Success() diff --git a/test/test.go b/test/test.go index 0c89512..01d34e9 100644 --- a/test/test.go +++ b/test/test.go @@ -9,14 +9,6 @@ import ( ) func main() { - var task models.MonkeyTask - task.Project = "Hising" - task.Version = "1.00.04_10004006" - task.Platform = "adr" - task.Branch = "xxx/bbb/vasd_sdds" - task.PackageName = "music.hising.live.dev" - common.PushMonkeyResult(task) - return dbsql.DSN = dbsql.DSN_local db, err := dbsql.GetConn(dbsql.DSN) if err != nil { @@ -24,6 +16,17 @@ func main() { return } defer dbsql.Close(db) + var task models.MonkeyTask + db.Last(&task) + common.PushMonkeyResult(task) + return + // dbsql.DSN = dbsql.DSN_local + // db, err := dbsql.GetConn(dbsql.DSN) + // if err != nil { + // fmt.Println(err) + // return + // } + // defer dbsql.Close(db) var list []models.MonkeyTask db.Model(models.MonkeyTask{}).Order("id DESC").Find(&list)