package service import ( "basic.com/dbapi.git" "basic.com/pubsub/protomsg.git" "basic.com/valib/licence.git" "basic.com/valib/logger.git" "encoding/json" "errors" "io/ioutil" "os" "path" "path/filepath" "strconv" "strings" "webserver/extend/config" "webserver/extend/util" reqUtil "webserver/extend/util" ) type SdkInstallService struct { } func (sv SdkInstallService) Active(cod string, sdkId string) (interface{},error) { //使用激活码激活算法 url := "http://"+config.ShopConf.Url+"/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, } header := map[string]string { "Authorization": token, } respBody, err := reqUtil.DoPostRequest(url, reqUtil.CONTENT_TYPE_JSON, paramBody, nil, header) if err != nil { logger.Debug("DoPostRequest err:", err) return nil, err } var res dbapi.Result if err = json.Unmarshal(respBody, &res); err != nil { logger.Debug("unmarshal err:", err) return nil, err } if !res.Success { logger.Debug("res.Data:", res.Data) return nil, errors.New("请求商城失败") } return res.Data, nil } //算法安装包安装 func (sv SdkInstallService) SdkInstall(identifier string,filename string) (bool,error) { configPatchPath := "" if config.Server.PatchPath != "" { configPatchPath = config.Server.PatchPath } else { configPatchPath = "../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 := installSdk(identifier, ext); insE != nil { 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 unPackPatchPackage(identifier string, ext string) (bool,error) { configPatchPath := "" if config.Server.PatchPath != "" { configPatchPath = config.Server.PatchPath } else { configPatchPath = "../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 = "../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 { return true, map[string]interface{} { "sdkName": ins.ProductName, "installVersion": ins.InstallVersion, "installContent": ins.InstallContent, }, 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 func installSdk(identifier string, ext string) (bool, error) { configPatchPath := "" if config.Server.PatchPath != "" { configPatchPath = config.Server.PatchPath } else { configPatchPath = "../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("安装文件已不存在") } 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 false, err } unPackPath := unPackTargetPath + targetFileName +"/" 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 { //处理授权信息 curMc := "" if ins.MachineCode != curMc { } //2.解析sdk.def,将so和zconf复制到/opt/vasystem/libs/文件夹下 defPath := unPackPath + "sdk.def" if util.Exists(defPath) { if defB, err := ioutil.ReadFile(defPath); err == nil { //3.将算法so、依赖文件、zconf、 soM := make(map[string]SdkDef) var skDefArr []SdkDef nInsM := make(map[string]string) aInsM := make(map[string]string) if err = json.Unmarshal(defB, &skDefArr);err == nil { var sdkApi dbapi.SdkApi for _,skd := range skDefArr { //注册算法信息和算法参数到dbserver //先看此算法有没有注册,如果已安装,比对版本号 bf, curDbSdk := sdkApi.GetById(skd.Def.Id) if bf { bytes, _ := json.Marshal(curDbSdk) var sm map[string]interface{} unE := json.Unmarshal(bytes, &sm) if unE != nil { continue } sdkVersion, ok := sm["version"] if ok { //有版本号 vStr := sdkVersion.(string) if shouldVersionBeUpgrade(vStr, skd.Def.Version) { //比对版本号确定是否需要安装 nInsM[skd.Def.SdkType] = skd.Def.SdkType aInsM[skd.Def.Id] = skd.Def.Id } } else { nInsM[skd.Def.SdkType] = skd.Def.SdkType aInsM[skd.Def.Id] = skd.Def.Id } } else { nInsM[skd.Def.SdkType] = skd.Def.SdkType aInsM[skd.Def.Id] = skd.Def.Id } if _,ok := soM[skd.Def.SdkType];!ok { soM[skd.Def.SdkType] = skd } if _,ok := aInsM[skd.Def.Id]; ok { srv := SdkRegisterVo{} srv.SdkCommon = skd.Def.SdkCommon for _,ag := range skd.Args { sra := SdkRegisterArgVo{ Scope: ag.Scope, } sra.SdkArg = 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) } paramBody := util.Struct2Map(srv) logger.Debug("sdkApi.Register paramBody:", paramBody) sdkApi.Register(paramBody) //将算法注册到数据库中 } } 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 { return false, cE } } if util.DirExists(unPackPath+sdkType+"/models") { if _,cE := util.CopyDirByCmd(unPackPath+sdkType+"/models", "./"); cE != nil { return false, cE } //拷贝完成后删除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("反序列化算法定义信息失败") return false, errors.New("错误的安装包") } } else { logger.Debug("读取算法定义信息失败") return false, errors.New("错误的安装包") } } else { logger.Debug("算法定义信息丢失") return false, errors.New("错误的安装包") } } else { logger.Debug("反序列化授权信息失败") return false, errors.New("错误的安装包") } } else { logger.Debug("读取授权文件失败") return false, errors.New("错误的安装包") } } else { return false, errors.New("错误的安装包") } return true, nil } 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"` ProductId string `json:"productId"` ActivateCode string `json:"activateCode"` MachineCode string `json:"machineCode"` UserId string `json:"userId"` SdkIds []string `json:"sdkIds"` ModuleIds []string `json:"moduleIds"` ChCount int `json:"chCount"` AuthCount int `json:"authCount"` ServeYear int `json:"serveYear"` ProductName string `json:"productName"` InstallVersion string `json:"installVersion"` InstallContent string `json:"installContent"` } //算法和参数定义 type SdkDef struct { Def Sdk `json:"def"` Args []SdkArgEntity `json:"args"` } type Sdk struct { SdkCommon CreateTime string `gorm:"column:create_time" json:"create_time"` CreateBy string `gorm:"column:create_by" json:"create_by"` UpdateTime string `gorm:"column:update_time" json:"update_time"` Enable bool `gorm:"column:enable;default:1" json:"enable"` DelFlag int `gorm:"column:del_flag;default:0" json:"del_flag"` Args []SdkArg `json:"args"` } func (sc *SdkCommon) copyFromProto(pSdk protomsg.Sdk) { sc.Id = pSdk.Id sc.IpcId = pSdk.IpcId sc.SdkType = pSdk.SdkType sc.SdkName = pSdk.SdkName sc.Icon = pSdk.Icon sc.Url = pSdk.Url sc.IconBlob = pSdk.IconBlob sc.Version = pSdk.Version sc.ArgDef = pSdk.ArgDef sc.RuleSo = pSdk.RuleSo } type SdkCommon struct { Id string `json:"id"` IpcId string `json:"ipc_id"` SdkType string `json:"sdk_type"`//人脸检测:FaceDetect,人脸提取:FaceExtract,人脸比对:FaceCompare,行为:Yolo SdkName string `json:"sdk_name"` //算法名称 Icon string `json:"icon"` //算法图标 Url string `json:"url"` //算法下载地址 IconBlob string `json:"iconBlob"` //图片 Version string `json:"version"` //版本号 EnTrack bool `json:"enTrack"` //是否开启跟踪 ArgDef string `json:"argDef"` //算法默认参数定义 RuleSo string `json:"rule_so"` } type SdkInsOrUpgrade struct { Sdk RemoteVersion string `json:"remoteVersion"` //商城仓库版本号 Installed bool `json:"installed"` //是否已安装 IsUpgrade bool `json:"isUpgrade"` //是否需要升级 } type SdkArgEntity struct { Id string `gorm:"primary_key;column:id" json:"id"` SdkId string `gorm:"column:sdk_id" json:"sdk_id"` Scope string `gorm:"column:scope" json:"scope"` SdkArg } type SdkArg struct { Alias string `gorm:"column:alias" json:"alias"` //参数的别名 Name string `gorm:"column:name" json:"name"` //参数名称 Type string `gorm:"column:type" json:"type"` //参数类型(整数,字符串或数组) ArgType string `gorm:"column:arg_type" json:"arg_type"` Must bool `gorm:"column:must" json:"must"` //是否必填 Unit string `gorm:"column:unit" json:"unit"` //单位 Range string `gorm:"column:range" json:"range"` //值的范围,eg:0,100表示从0到100 DefaultValue string `gorm:"column:default_value" json:"default_value"` DefaultOperator string `gorm:"column:default_operator" json:"default_operator"` Sort int `gorm:"column:sort;default:1" json:"sort"` } type SdkRegisterVo struct { SdkCommon Args []SdkRegisterArgVo `json:"args"` //算法参数 } type SdkRegisterArgVo struct { Scope string `json:"scope"` SdkArg Dics []SdkArgDic `json:"dics"` //如果此算法参数是被选项,需要将参数枚举值写入到字典表中 } type SdkArgDic struct { Value string `json:"value"` Name string `json:"name"` Sort int `json:"sort"` }