package service import ( "basic.com/valib/bhomeclient.git" "basic.com/valib/bhomedbapi.git" "basic.com/valib/licence.git" "basic.com/valib/logger.git" "encoding/json" "errors" "fmt" "io/ioutil" "os" "path" "path/filepath" "strconv" "strings" "time" "vamicro/appcenter-service/models" "vamicro/appcenter-service/vo" "vamicro/config" "vamicro/extend/util" ) type SdkInstallService struct { } // inputTxt过滤条件 func (sv SdkInstallService) GetBuyList(inputTxt string) []SdkWithArg { url := "http://" + util.GetShopUrl() + "/data/api-s/sdk/buyList" machineCode := licence.GetMachineCode() logger.Debug("url:", url, "machineCode:", machineCode) var sdkE models.Sdk localSdks, _ := sdkE.FindAll("") //本地已安装所有算法,带顺序 if localSdks == nil { localSdks = make([]models.Sdk, 0) } iv := make(map[string]SdkVB) localSdkIdArr := make([]string, 0) for _, ls := range localSdks { iv[ls.Id] = SdkVB{ Version: ls.Version, BaseVersion: ls.BaseVersion, } localSdkIdArr = append(localSdkIdArr, ls.Id) } paramBody := map[string]interface{}{ "serverId": config.Server.AnalyServerId, "machineCode": machineCode, "localSdkIdArr": localSdkIdArr, "iv": iv, "inputTxt": inputTxt, } header := map[string]string{ "Authorization": token, } respBody, err := util.DoPostRequest(url, util.CONTENT_TYPE_JSON, paramBody, nil, header, time.Second*20) if err != nil { logger.Debug("DoPostRequest err:", err) return nil } var res bhomedbapi.Result if err = json.Unmarshal(respBody, &res); err != nil { logger.Debug("unmarshal err:", err) return nil } bytes, _ := json.Marshal(res.Data) var ss shopSdks if err := json.Unmarshal(bytes, &ss); err != nil { logger.Debug("unmarshal err:", err) return nil } var resultArr []SdkWithArg installSdkM := make(map[string]models.Sdk) if localSdks != nil { for _, is := range localSdks { installSdkM[is.Id] = is } } if ss.Sdks != nil { for _, rs := range ss.Sdks { if _, ok := installSdkM[rs.Id]; !ok { resultArr = append(resultArr, rs) } } } return resultArr } func (sv SdkInstallService) Active(cod string, sdkId string) (interface{}, error) { //使用激活码激活算法 url := "http://" + util.GetShopUrl() + "/data/api-s/sdk/activeByAINode" machineCode := licence.GetMachineCode() if machineCode == "" { logger.Debug("获取机器码失败") return nil, errors.New("获取机器码失败") } paramBody := map[string]interface{}{ "code": cod, "sdkId": sdkId, "machineCode": machineCode, "serverId": config.Server.AnalyServerId, } header := map[string]string{ "Authorization": token, } respBody, err := util.DoPostRequest(url, util.CONTENT_TYPE_JSON, paramBody, nil, header, time.Second*60) if err != nil { logger.Debug("DoPostRequest err:", err) return nil, err } var res bhomedbapi.Result if err = json.Unmarshal(respBody, &res); err != nil { logger.Debug("unmarshal err:", err) return nil, err } if !res.Success { logger.Debug("Active Sdk ret false, res: ", res) return nil, errors.New(res.Msg) } // 激活成功 return res.Data, nil } // 算法(应用)安装包安装 func (sv SdkInstallService) PackInstall(identifier string, filename string, h *bhomeclient.WrapperHandler) (bool, error) { configPatchPath := "" if config.Server.PatchPath != "" { configPatchPath = config.Server.PatchPath } else { configPatchPath = "/opt/vasystem/patch" } filenameWithSuffix := path.Base(filename) ext := path.Ext(filenameWithSuffix) zipFilePath := configPatchPath + "/" + identifier + ext unPackTargetPath := configPatchPath + "/" + identifier + "_basic/" md5DirPath := configPatchPath + "/" + identifier if util.Exists(zipFilePath) { strMd5, e := util.FileMd5(zipFilePath) if e != nil || strMd5 == "" { go os.Remove(zipFilePath) if util.DirExists(unPackTargetPath) { go os.RemoveAll(unPackTargetPath) } if util.DirExists(md5DirPath) { go os.RemoveAll(md5DirPath) } return false, errors.New("获取安装包md5失败") } if strMd5 == identifier { if _, insE := installPack(identifier, ext, h); insE != nil { logger.Error("PackInstall insE:", insE) return false, insE } return true, nil } else { go os.Remove(zipFilePath) if util.DirExists(unPackTargetPath) { go os.RemoveAll(unPackTargetPath) } if util.DirExists(md5DirPath) { go os.RemoveAll(md5DirPath) } logger.Debug("strMd5 is", strMd5, "identifier is", identifier, "not equal") return false, errors.New("校验安装文件失败") } } else { return false, errors.New("安装包已丢失,请重新上传") } } func (sv SdkInstallService) PackUninstall(appId string) error { uninstallFile := "/opt/vasystem/package/" + appId + "/uninstall.sh" if util.Exists(uninstallFile) { _, err := ExecCmd(uninstallFile) if err != nil { logger.Error("安装脚本执行失败:", err.Error()) return err } } return nil } // 解压上传的算法安装包 func unPackPatchPackage(identifier string, ext string) (bool, error) { if ext != ".gz" { return false, errors.New("非法的安装包文件,安装包为.tar.gz文件") } configPatchPath := "" if config.Server.PatchPath != "" { configPatchPath = config.Server.PatchPath } else { configPatchPath = "/opt/vasystem/patch" } //1.解压缩更新包 unPackTargetPath := configPatchPath + "/" + identifier + "_basic/" unPackFilePath := configPatchPath + "/" + identifier + ext if util.Exists(unPackTargetPath) { //此版本已经更新过 rmErr := os.RemoveAll(unPackTargetPath) if rmErr != nil { return false, rmErr } } if !util.CreateDirectory(unPackTargetPath) { return false, errors.New("创建压缩文件夹失败") } logger.Debug("unPackFilePath:", unPackFilePath, "unPackPath:", unPackTargetPath) _, err := util.UnTarGzByCmd(unPackFilePath, unPackTargetPath) if err != nil { logger.Debug("UnPack err:", err, "unPackFile:", unPackFilePath) return false, err } return true, nil } func (sv SdkInstallService) ShowInstallInfo(identifier string, filename string) (bool, map[string]interface{}, error) { configPatchPath := "" if config.Server.PatchPath != "" { configPatchPath = config.Server.PatchPath } else { configPatchPath = "/opt/vasystem/patch" } unPackTargetPath := configPatchPath + "/" + identifier + "_basic/" isValid := false defer func() { if !isValid { filenameWithSuffix := path.Base(filename) ext := path.Ext(filenameWithSuffix) unPackFilePath := configPatchPath + "/" + identifier + ext md5DirPath := configPatchPath + "/" + identifier if util.Exists(unPackTargetPath) { os.RemoveAll(unPackTargetPath) } if util.Exists(unPackFilePath) { os.RemoveAll(unPackFilePath) } if util.DirExists(md5DirPath) { go os.RemoveAll(md5DirPath) } } }() if util.Exists(unPackTargetPath) { targetFileName := "" err := filepath.Walk(unPackTargetPath, func(path string, f os.FileInfo, err error) error { if f == nil { return err } if f.IsDir() { targetFileName = f.Name() } return nil }) if err != nil { return isValid, nil, errors.New("非法的安装包") } else { unPackPath := unPackTargetPath + targetFileName + "/" //解压完成,获取安装包中的文件,开始安装 //1.解析安装说明ins.inc incPath := unPackPath + "ins.inc" if util.Exists(incPath) { if incB, err := ioutil.ReadFile(incPath); err == nil { var ins InsInc if err = json.Unmarshal(incB, &ins); err == nil { showInfo := map[string]interface{}{ "productName": ins.ProductName, "installContent": ins.InstallContent, } sdkInfo := make([]map[string]interface{}, 0) appInfo := make([]map[string]interface{}, 0) if ins.Sdks != nil { for _, is := range ins.Sdks { sdkInfo = append(sdkInfo, map[string]interface{}{ "sdkId": is.SdkId, "sdkName": is.SdkName, "version": is.Version, }) } } if ins.Modules != nil { for _, ia := range ins.Modules { appInfo = append(appInfo, map[string]interface{}{ "appId": ia.AppId, "appName": ia.AppName, "version": ia.Version, }) } } showInfo["sdks"] = sdkInfo showInfo["apps"] = appInfo isValid = true return true, showInfo, nil } else { return false, nil, errors.New("非法的安装包") } } else { return false, nil, errors.New("非法的安装包") } } else { return false, nil, errors.New("非法的安装包") } } } else { return isValid, nil, errors.New("非法的安装包格式,安装包已删除") } } // 安装sdk(app) func installPack(identifier string, ext string, h *bhomeclient.WrapperHandler) (bool, error) { configPatchPath := "" if config.Server.PatchPath != "" { configPatchPath = config.Server.PatchPath } else { configPatchPath = "/opt/vasystem/patch" } //1.解压缩更新包 unPackTargetPath := configPatchPath + "/" + identifier + "_basic/" unPackFilePath := configPatchPath + "/" + identifier + ext md5DirPath := configPatchPath + "/" + identifier defer func() { if util.Exists(unPackTargetPath) { os.RemoveAll(unPackTargetPath) } if util.Exists(unPackFilePath) { os.RemoveAll(unPackFilePath) } if util.DirExists(md5DirPath) { go os.RemoveAll(md5DirPath) } }() if !util.Exists(unPackTargetPath) { //安装包不存在 return false, errors.New("解压后的安装文件已不存在") } // 查找下一级目录 targetDir := "" files, err := ioutil.ReadDir(unPackTargetPath) if err != nil { return false, err } for _, f := range files { if f.IsDir() && f.Name() != "." && f.Name() != ".." { targetDir = f.Name() } } if targetDir == "" { return false, errors.New("安装目录不存在") } unPackPath := unPackTargetPath + targetDir + "/" if !util.Exists(unPackPath) { return false, errors.New("安装文件已不存在") } //解压完成,获取安装包中的文件,开始安装 //1.解析安装说明ins.inc incPath := unPackPath + "ins.inc" if util.Exists(incPath) { if incB, err := ioutil.ReadFile(incPath); err == nil { var ins InsInc if err = json.Unmarshal(incB, &ins); err == nil { // 定制手动安装 if ins.ActivateCode != "*" { //处理授权信息,看当前安装包是否适用这台机器 curMc := licence.GetMachineCode() curServerId := config.Server.AnalyServerId devMatch := false for _, mc := range ins.Devs { if mc.DevId == curServerId || mc.MachineCode == curMc { devMatch = true break } } if !devMatch { logger.Debug("curServerId:", curServerId, "curMc:", curMc, "ins.Devs:", ins.Devs) return false, errors.New("此安装包与当前设备不匹配,请检查") } } //安装算法,如果有算法包 if len(ins.Sdks) > 0 { if ie := installSDKInPack(unPackPath, ins.Sdks, h); ie != nil { return false, errors.New("算法安装失败,失败原因:" + ie.Error() + "") } //如果有依赖文件则安装依赖 if depErr := installDepend(unPackPath); depErr != nil { logger.Error("installDepend depErr:", depErr) //如果安装包里没有带依赖或依赖安装失败,则尝试在线下载依赖 depErr = downloadDepend(ins.Sdks) if depErr != nil { logger.Error("downloadDepend err:", depErr) } } } //安装应用包,如果有应用 if len(ins.Modules) > 0 { if ie := installAppInPack(unPackPath, ins.Modules, h); ie != nil { return false, errors.New("应用安装失败,失败原因:" + ie.Error() + "") } } } else { logger.Debug("反序列化授权信息失败") return false, errors.New("错误的安装包") } } else { logger.Debug("读取授权文件失败") return false, errors.New("错误的安装包") } } else { return false, errors.New("错误的安装包") } return true, nil } // 安装安装包中的算法 func installSDKInPack(unPackPath string, sdkDefs []SdkIns, h *bhomeclient.WrapperHandler) error { sv := NewSdkService(h.Bk) var insErr error var insSdkIds []string defer func() { if insErr != nil { //todo 回滚 logger.Debug("installSDKInPack err:", insErr, "sdkIds:", insSdkIds) if len(insSdkIds) > 0 { //删除算法 //for _,id := range insSdkIds { // //} } } }() defSDKPath := unPackPath + "sdk.def" if util.Exists(defSDKPath) { if defB, err := ioutil.ReadFile(defSDKPath); err == nil { //3.将算法so、依赖文件、zconf、 var skDefArr []SdkDef if err = json.Unmarshal(defB, &skDefArr); err == nil { exedFiles := make(map[string]string) for _, sd := range sdkDefs { //先校验platform是否匹配 if sd.Platform == "" { insErr = errors.New("非法的安装包,无platform信息,请下载最新安装包") return insErr } if !util.PlatformMatch(sd.Platform) { insErr = errors.New("算法platform不匹配,非法的安装包") return insErr } if sd.SdkBaseComponentPath != "" { bPath := path.Base(sd.SdkBaseComponentPath) if util.Exists(unPackPath + bPath) { if _, nIn := exedFiles[bPath]; !nIn { //未安装过,才安装 //检查算法支持的显卡型号是否和本机匹配 if !util.GpuMatch(sd.VGpus) { insErr = errors.New("算法支持的显卡型号(" + sd.VGpus + ")与当前设备不匹配") return insErr } if insErr = installComponent(unPackPath, bPath); insErr != nil { return insErr } else { exedFiles[bPath] = bPath } } } else { insErr = errors.New("基础算法包" + bPath + "丢失,请检查安装包") return insErr } } if sd.ComponentPath != "" { oPath := path.Base(sd.ComponentPath) if util.Exists(unPackPath + oPath) { if _, nIn := exedFiles[oPath]; !nIn { //未安装过,才安装 if insErr = installComponent(unPackPath, oPath); insErr != nil { return insErr } else { exedFiles[oPath] = oPath } } } else { insErr = errors.New("组件" + oPath + "丢失,请检查") return insErr } } } for _, skd := range skDefArr { srv := vo.SdkRegisterVo{} srv.Id = skd.Def.Id srv.SdkType = skd.Def.SdkType srv.SdkName = skd.Def.SdkName srv.Icon = skd.Def.Icon srv.Url = skd.Def.Url srv.IconBlob = skd.Def.IconBlob srv.IconBlob2 = skd.Def.IconBlob2 srv.Version = skd.Def.Version srv.EnTrack = skd.Def.EnTrack srv.ArgDef = skd.Def.ArgDef srv.RuleSo = skd.Def.RuleSo srv.BaseVersion = skd.Def.BaseVersion for _, ag := range skd.Args { sra := vo.SdkRegisterArgVo{ Scope: ag.Scope, } sra.SdkArg = models.SdkArg{ Alias: ag.Alias, Name: ag.Name, Type: ag.Type, ArgType: ag.ArgType, Must: ag.Must, Unit: ag.Unit, Range: ag.Range, DefaultValue: ag.DefaultValue, DefaultOperator: ag.DefaultOperator, Sort: ag.Sort, } srv.Args = append(srv.Args, sra) } //将算法注册到数据库中 if sv.Register(&srv) { logger.Debug("注册成功,sdkId:", skd.Def.Id) insSdkIds = append(insSdkIds, skd.Def.Id) } else { insErr = errors.New("sdk注册失败,算法id:" + skd.Def.Id + "") logger.Debug(insErr.Error()) return insErr } } //zconfPath := "./zconf/" //libPath := "../libs/" //if !util.DirExists(zconfPath) { // os.MkdirAll(zconfPath, 0777) //} //if !util.DirExists(libPath) { // os.MkdirAll(libPath, 0777) //} //for sdkType,_ := range soM { // if _,iOk := nInsM[sdkType];iOk { // //先解压SdkType.tar.gz文件 // if unTarGzE := util.UnTarGz(unPackPath+sdkType+".tar.gz", unPackPath);unTarGzE == nil { // //复制json启动文件 // if util.Exists(unPackPath+sdkType+"/zconf/"+sdkType+".json") { // util.CopyFile(unPackPath+sdkType+"/zconf/"+sdkType+".json", zconfPath+sdkType+".json") // } // if util.DirExists(unPackPath+sdkType) { // if _,cE := util.CopyDirByCmd(unPackPath+sdkType, libPath);cE != nil { // insErr = cE // return insErr // } // } // if util.DirExists(unPackPath+sdkType+"/models") { // if _,cE := util.CopyDirByCmd(unPackPath+sdkType+"/models", "./"); cE != nil { // insErr = cE // return insErr // } // //拷贝完成后删除libs下sdkType文件夹下models // } // if util.DirExists(libPath+sdkType+"/models") { // os.RemoveAll(libPath+sdkType+"/models") // } // if util.DirExists(libPath+sdkType+"/zconf") { // os.RemoveAll(libPath+sdkType+"/zconf") // } // } else { // logger.Debug("unTarGzE sdkType.tar.gz err:", unTarGzE) // } // } else { // logger.Debug("upper version has been installed") // } //} } else { logger.Debug("反序列化算法定义信息失败") insErr = errors.New("错误的安装包") return insErr } } else { logger.Debug("读取算法定义信息失败,err:", err) insErr = errors.New("错误的安装包") return insErr } } else { insErr = errors.New("错误的安装包,算法定义文件不存在") return insErr } return insErr } func installAppInPack(unPackPath string, appDefs []AppIns, h *bhomeclient.WrapperHandler) error { //1.写入数据库 var appApi models.App var insErr error var insAppIds []string defer func() { if insErr != nil { //todo 回滚 logger.Debug("installAppInPack err:", insErr, "appIds:", insAppIds) if len(insAppIds) > 0 { //删除应用 for _, id := range insAppIds { appApi.DeleteById(id) } } } }() defAppPath := unPackPath + "app.def" if util.Exists(defAppPath) { if defB, err := ioutil.ReadFile(defAppPath); err == nil { //3.将算法so、依赖文件、zconf、 var appDefArr []models.App if err = json.Unmarshal(defB, &appDefArr); err == nil { var appId = "" for _, ap := range appDefArr { appId = ap.Id if !SaveApp(ap) { insErr = errors.New("注册应用失败,应用id:" + ap.Id + "") return insErr } else { insAppIds = append(insAppIds, ap.Id) } } //2.处理app文件内容 exedFiles := make(map[string]string) for _, sd := range appDefs { if sd.ComponentPath != "" { oPath := path.Base(sd.ComponentPath) if util.Exists(unPackPath + oPath) { if _, nIn := exedFiles[oPath]; !nIn { //未安装过,才安装 insErr = installComponent(unPackPath, oPath) if insErr != nil { return insErr } else { exedFiles[oPath] = oPath } } } else { insErr = errors.New("组件" + oPath + "丢失,请检查") return insErr } } } // 3 手动安装 installFile := path.Join(unPackPath, "install.sh") if util.Exists(installFile) { // 切换到当前运行目录 os.Chdir(unPackPath) b, err := ExecCmd(installFile) if err != nil { logger.Error("安装脚本执行失败:", err.Error()) return err } logger.Debug("install component result:", string(b)) // 复制安装文件到package目录, 卸载时调用 uninstall pkgDir := "/opt/vasystem/package/" + appId ExecCmd(fmt.Sprintf("mkdir -p %s", pkgDir)) ExecCmd(fmt.Sprintf("cp -rf %s/* %s/", unPackPath, pkgDir)) return nil } } else { logger.Debug("反序列化应用定义信息失败") insErr = errors.New("错误的安装包") return insErr } } else { insErr = errors.New("读取应用定义文件失败") return insErr } } else { insErr = errors.New("错误的安装包,应用定义文件不存在") return insErr } return nil } func installComponent(unPackPath string, componentFileName string) error { ext := path.Ext(componentFileName) if ext == "" { return errors.New("非法的安装包后缀") } cName := strings.ReplaceAll(componentFileName, ext, "") targetPath := unPackPath + cName + "/" logger.Debug("installComponent targetPath:", targetPath) if util.Exists(targetPath) { rmErr := os.RemoveAll(targetPath) if rmErr != nil { return rmErr } } if !util.CreateDirectory(targetPath) { return errors.New("创建压缩文件夹失败") } if utzOut, unTarGzE := util.UnTarGzByCmd(unPackPath+componentFileName, targetPath); unTarGzE == nil { //使用安装脚本执行 //targetFileName := "" //err := filepath.Walk(targetPath, func(path string, f os.FileInfo, err error) error { // if f == nil { // return err // } // if f.IsDir() { // targetFileName = f.Name() // } // return nil //}) //if err != nil { // return errors.New("安装包不合法,请检查,err:"+err.Error()+"") //} //logger.Debug("targetFileName:", targetFileName) if util.Exists(targetPath + "install.sh") { cmdPath := fmt.Sprintf("%sinstall.sh %s", targetPath, targetPath) b, err := ExecCmd(cmdPath) if err != nil { return err } logger.Debug("install component ", componentFileName, " result:", string(b)) return nil } else { return errors.New("安装执行文件不存在,请检查") } } else { logger.Error("UnTarGzByCmd out:", utzOut) return unTarGzE } } func shouldVersionBeUpgrade(curVersion, dstVersion string) bool { if curVersion == "" { return true } if dstVersion == "" { return false } curIVArr := strings.Split(curVersion, ".") dstIVArr := strings.Split(dstVersion, ".") if len(curIVArr) != 3 || len(dstIVArr) != 3 { return false } cH, cEH := strconv.Atoi(curIVArr[0]) cM, cEM := strconv.Atoi(curIVArr[1]) cL, cEL := strconv.Atoi(curIVArr[2]) dH, dEH := strconv.Atoi(dstIVArr[0]) dM, dEM := strconv.Atoi(dstIVArr[1]) dL, dEL := strconv.Atoi(dstIVArr[2]) if cEH != nil || cEM != nil || cEL != nil || dEH != nil || dEM != nil || dEL != nil { return false } if cH > dH { return false } else if cH == dH { if cM > dM { return false } else if cM == dM { if cL > dL { return false } else if cL == dL { return false } else { return true } } else { return true } } else { return true } } type InsInc struct { OrderId string `json:"orderId"` //订单id ProductId string `json:"productId"` //产品id ActivateCode string `json:"activateCode"` //激活码 Devs []InsDev `json:"devs"` //安装包给哪些设备使用 UserId string `json:"userId"` //用户id Sdks []SdkIns `json:"sdks"` //算法模块 Modules []AppIns `json:"modules"` //应用模块 ChCount int `json:"chCount"` //通道数量 AuthCount int `json:"authCount"` //授权数量 ServeYear int `json:"serveYear"` //服务时长 ProductName string `json:"productName"` InstallContent string `json:"installContent"` } type InsDev struct { DevId string `json:"devId"` MachineCode string `json:"machineCode"` } type SdkIns struct { SdkId string `json:"sdkId"` SdkName string `json:"sdkName"` SdkType string `json:"sdkType"` Version string `json:"version"` BaseVersion string `json:"baseVersion"` SdkBaseComponentPath string `json:"sdkBase_component_path"` SdkBaseComponentName string `json:"sdkBase_component_name"` ComponentPath string `json:"component_path"` ComponentName string `json:"component_name"` VGpus string `json:"vGpus"` //此算法支持的显卡型号 Platform string `json:"platform"` } type AppIns struct { AppId string `json:"appId"` AppName string `json:"appName"` Version string `json:"version"` ComponentPath string `json:"component_path"` ComponentName string `json:"component_name"` } // 算法和参数定义 type SdkDef struct { Def models.Sdk `json:"def"` Args []models.SdkArgEntity `json:"args"` } type SdkWithArg struct { models.Sdk Args []models.SdkArgEntity `json:"args"` CanUpOrIns bool `json:"canUpOrIns"` Platforms []models.PtIns `json:"platforms"` //可适配的平台信息 } type SdkInsOrUpgrade struct { SdkWithArg RemoteVersion string `json:"remoteVersion"` //商城仓库版本号 Installed bool `json:"installed"` //是否已安装 IsUpgrade bool `json:"isUpgrade"` //是否需要升级 ProgressMsg string `json:"progressMsg"` //安装或升级进度 ProtoRuleSo string `json:"ruleSo"` //适配protomsg中的ruleSo }