package service
|
|
import (
|
"basic.com/dbapi.git"
|
"basic.com/valib/logger.git"
|
"encoding/json"
|
"errors"
|
"io/ioutil"
|
"os"
|
"path"
|
"path/filepath"
|
"strconv"
|
"strings"
|
"webserver/extend/config"
|
"webserver/extend/util"
|
)
|
|
type SdkInstallService struct {
|
|
}
|
|
//算法安装包安装
|
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/"
|
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)
|
}
|
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)
|
}
|
logger.Debug("strMd5 is", strMd5,"identifier is",identifier,"not equal")
|
return false,errors.New("校验安装文件失败")
|
}
|
} else {
|
return false,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
|
defer func() {
|
if util.Exists(unPackTargetPath) {
|
os.RemoveAll(unPackTargetPath)
|
}
|
if util.Exists(unPackFilePath) {
|
os.RemoveAll(unPackFilePath)
|
}
|
}()
|
|
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
|
}
|
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 +"/"
|
//解压完成,获取安装包中的文件,开始安装
|
//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{
|
Id: skd.Def.Id,
|
SdkType: skd.Def.SdkType,
|
SdkName: skd.Def.SdkName,
|
Icon: skd.Def.Icon,
|
Url: skd.Def.Url,
|
IconBlob: skd.Def.IconBlob,
|
Version: skd.Def.Version,
|
}
|
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", "./zconf"); cE != nil {
|
return false, cE
|
}
|
}
|
} else {
|
logger.Debug("unTarGzE sdkType.tar.gz err:", unTarGzE)
|
}
|
} else {
|
logger.Debug("upper version has been installed")
|
}
|
}
|
|
} else {
|
return false, errors.New("反序列化算法定义信息失败")
|
}
|
} else {
|
return false, errors.New("读取算法定义信息失败")
|
}
|
} else {
|
return false, errors.New("算法定义信息丢失")
|
}
|
} else {
|
return false, errors.New("反序列化授权信息失败")
|
}
|
} else {
|
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(curIVArr[0])
|
dM,dEM := strconv.Atoi(curIVArr[1])
|
dL,dEL := strconv.Atoi(curIVArr[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"`
|
}
|
|
//算法和参数定义
|
type SdkDef struct {
|
Def Sdk `json:"def"`
|
Args []SdkArgEntity `json:"args"`
|
}
|
|
type Sdk struct {
|
Id string `gorm:"column:id;primary_key;type:varchar(50);unique;not null;" json:"id"`
|
IpcId string `gorm:"column:ipc_id" json:"ipc_id"`
|
SdkType string `gorm:"column:sdk_type" json:"sdk_type"`
|
SdkName string `gorm:"column:sdk_name" json:"sdk_name" example:"人脸检测"`
|
Icon string `gorm:"column:icon" json:"icon,omitempty"`
|
Url string `gorm:"column:url" json:"url,omitempty" example:"http://ip:port/govideo/sdk/1"`
|
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"`
|
Env string `gorm:"column:env" json:"env"` //运行环境及结果说明,json格式,包含so_file_path,runtime,param,depends(cuda版本,opencv版本,tensorflow版本等)
|
IconBlob string `gorm:"column:iconBlob;type:text;" json:"iconBlob"` //图片
|
Version string `gorm:"column:version;type:varchar(50);default:'1.0';" json:"version"` //版本号
|
}
|
|
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 {
|
Id string `json:"id"`
|
SdkType string `json:"sdk_type"`//人脸检测:FaceDetect,人脸提取:FaceExtract,人脸比对:FaceCompare,行为:Yolo
|
SdkName string `json:"sdk_name"` //算法名称
|
Args []SdkRegisterArgVo `json:"args"` //算法参数
|
Icon string `json:"icon"` //算法图标
|
Url string `json:"url"` //算法下载地址
|
IconBlob string `json:"iconBlob"` //图片
|
Version string `json:"version"` //版本号
|
}
|
|
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"`
|
}
|