package service import ( "bytes" "errors" "log" "os/exec" "strings" "time" "videoplayer/dao" "videoplayer/proto" "videoplayer/worker" ) func CreateShell(shellName, shellContent, server string, uid int) uint { id := dao.CreateShell(shellName, shellContent, server, uint(uid)) return id } func FindShellByAuthID(id int) []dao.Shell { return dao.FindShellByAuthID(id) } func DeleteShellByID(id, authId uint) bool { user := GetUserByIDFromUserCenter(int(authId)) if user.Role == "admin" { return dao.DeleteShellByIDV2(id) } return dao.DeleteShellByID(id, authId) } func UpdateShellByID(id, authId uint, shellName, shellContent, server string, status int, shellResult string) bool { return dao.UpdateShellByID(id, authId, shellName, shellContent, status, shellResult, 0, 0) } func UpdateShellByIDV2(id, authId uint, shellName, shellContent, server string, status int, shellResult string, shellRuntime float64) bool { //查看shell是否存在 pd := dao.FindShellByID(id, authId) if len(pd) < 1 && pd[0].ID == 0 { return false } shell := pd[0] //如果状态为2,3转为0,1是不允许的,为了防止出现1确认包阻塞问题 if (shell.Status == 2 || shell.Status == 3) && (status == 0 || status == 1) { log.Println("UpdateShellByIDV2: status change from 2/3 to 0/1 is not allowed, shell id:", id) return false } var elapsed float64 //持续时间 if (shell.Status == 0 || shell.Status == 1) && (status == 2 || status == 3) { //如果状态为执行中,且新更新时间状态为2或3,则获取持续时间 elapsed = time.Since(shell.CreatedAt).Seconds() } return dao.UpdateShellByID(id, authId, shellName, shellContent, status, shellResult, shellRuntime, elapsed) } func FindShellWillRunByServer(server string, uid int) ([]dao.Shell, error) { var shells []dao.Shell var err error if server == "" { //err设置为server为空 err = errors.New("server is empty") return shells, err } shells = dao.FindShellWillRunByServer(server, uint(uid)) //设置状态为执行中 for _, v := range shells { dao.UpdateShellByID(v.ID, uint(uid), v.ShellName, v.ShellContent, v.Status+1, v.ShellResult, 0, 0) //将状态设置为执行中 } return shells, err } // 从服务器定时获取shell、执行并返回结果 func ShellWillRunFromServer() { shells, err := GetShellWillRunFromMaster(proto.Config.SERVER_NAME) if err != nil { return } var resp []proto.UpdateShellReq for _, v := range shells { //执行shell脚本,go执行命令 start := time.Now() res, err2 := RunShell(v.ShellContent) //执行时间,转成秒 shellRuntime := time.Since(start).Seconds() if err2 != "" { resp = append(resp, proto.UpdateShellReq{ID: v.ID, Server: v.Server, Status: 3, ShellResult: "err:" + err2 + "\nresult:" + res, ShellRuntime: shellRuntime}) //执行出错 } else { resp = append(resp, proto.UpdateShellReq{ID: v.ID, Server: v.Server, Status: 2, ShellResult: res, ShellRuntime: shellRuntime}) //执行成功 } } if len(resp) == 0 { return } //返回执行结果 url := "https://" + proto.Config.MASTER_SERVER_DOMAIN + "/shell/update?super_id=1" var req proto.SyncUserShellResp req.Token = worker.GetRedisSetMembers("super_permission_tokens")[0] req.Shells = resp resp_data, err := worker.SyncDataFromMasterShellReq3(url, req) if err != nil { return } //更新执行结果 for _, v := range resp_data { if v.Status < 0 { log.Fatalln("update shell failed:", v.ID, v.Status) } } } // 从服务器从主服务器获取待执行的shell func GetShellWillRunFromMaster(server string) ([]dao.Shell, error) { master := proto.Config.MASTER_SERVER_DOMAIN //发起请求获取待执行的shell url := "https://" + master + "/shell/server_will_run_list?super_id=1" var req proto.SyncUserShellReq req.Server = server superPermissions := worker.GetRedisSetMembers("super_permission_tokens") if len(superPermissions) == 0 { log.Println("get shell will run from master error: no super permission tokens found, please check the configuration or redis!") return nil, errors.New("no super permission tokens found") } req.Token = superPermissions[0] shells, err := worker.SyncDataFromMasterShellReq2(url, req) if err != nil { return nil, err } return shells, nil } func RunShell(script string) (res, err string) { cmd := exec.Command("/bin/bash", "-c", script) // 使用bytes.Buffer捕获输出 var out bytes.Buffer cmd.Stdout = &out err3 := cmd.Run() err3_info := "" if err3 != nil { err3_info = err3.Error() } return strings.TrimSpace(out.String()), err3_info }