| | |
| | | channelCount: 0 |
| | | #硬盘个数 |
| | | diskCount: 2 |
| | | #Exec root command |
| | | sudoPassword: 123 |
| | | sysThresholds: |
| | | - value: 60 |
| | | color: '#13ce66' |
| | | - value: 80 |
| | | color: '#FF9C4A' |
| | | - value: 95 |
| | | color: '#f53d3d' |
| | | - value: 100 |
| | | color: '#5d0000' |
| | | ptzSpeed: 50 |
| | | patchPath: /opt/vasystem/patch |
| | | database: |
| | | driver: sqlite |
| | | name: sqlite3 |
| | |
| | | channelCount: 0 |
| | | #硬盘个数 |
| | | diskCount: 2 |
| | | #Exec root command |
| | | sudoPassword: 123 |
| | | sysThresholds: |
| | | - value: 60 |
| | | color: '#13ce66' |
| | | - value: 80 |
| | | color: '#FF9C4A' |
| | | - value: 95 |
| | | color: '#f53d3d' |
| | | - value: 100 |
| | | color: '#5d0000' |
| | | ptzSpeed: 50 |
| | | patchPath: /opt/vasystem/patch |
| | | database: |
| | | driver: sqlite |
| | | name: sqlite3 |
| | |
| | | value: 100 |
| | | color: '#5d0000' |
| | | ptzSpeed: 50 |
| | | patchPath: /opt/vasystem/patch |
| | | database: |
| | | driver: sqlite |
| | | name: sqlite3 |
| | |
| | | package controllers |
| | | |
| | | import ( |
| | | "net/http" |
| | | "regexp" |
| | | "strconv" |
| | | "webserver/extend/code" |
| | | "webserver/extend/config" |
| | | "webserver/extend/sys" |
| | | "webserver/extend/util" |
| | | "webserver/middlewares/auth" |
| | | "webserver/service" |
| | | |
| | | "basic.com/dbapi.git" |
| | | "github.com/gin-gonic/gin" |
| | |
| | | var reqBody ResourceConfigVo |
| | | c.BindJSON(&reqBody) |
| | | if reqBody.ServiceIp == "" && reqBody.Domain == "" { |
| | | util.ResponseFormat(c,code.RequestParamError,"") |
| | | util.ResponseFormat(c, code.RequestParamError, "") |
| | | return |
| | | } |
| | | var sysApi dbapi.SysSetApi |
| | | paramBody := util.Struct2Map(reqBody) |
| | | if b,_ := sysApi.SaveResourceConfig(paramBody); b { |
| | | util.ResponseFormat(c,code.Success,"") |
| | | if b, _ := sysApi.SaveResourceConfig(paramBody); b { |
| | | util.ResponseFormat(c, code.Success, "") |
| | | } else { |
| | | util.ResponseFormat(c,code.ComError,"") |
| | | util.ResponseFormat(c, code.ComError, "") |
| | | } |
| | | } |
| | | // @Summary 系统更新包上传(分块检查) |
| | | // @Description 系统更新包上传(分块检查) |
| | | // @Accept multipart/form-data |
| | | // @Produce json |
| | | // @Tags sysset |
| | | // @Param chunkNumber formData int true "当前是第几个分块" |
| | | // @Param chunkSize formData int true "每一块的大小" |
| | | // @Param currentChunkSize formData int true "当前块的大小" |
| | | // @Param identifier formData string true "整个文件的唯一标识,目前是md5" |
| | | // @Param filename formData string true "文件名称" |
| | | // @Param relativePath formData string true "文件在客户端电脑的路径" |
| | | // @Param totalChunks formData int true "文件总块数" |
| | | // @Success 200 {string} json "{"code":200, msg:"", success:true}" |
| | | // @Failure 500 {string} json "{"code":500, msg:"", success:false}" |
| | | // @Router /data/api-v/sysset/patchUpdate [get] |
| | | func (sset SysSetController) PatchUpdateCheck(c *gin.Context) { |
| | | authDriver := auth.GenerateAuthDriver() |
| | | userM := (*authDriver).User(c) |
| | | if userM ==nil { |
| | | util.ResponseFormat(c,code.TokenNotFound,"登录过期,请登录") |
| | | return |
| | | } |
| | | chunkNumber, e1 := strconv.Atoi(c.Request.FormValue("chunkNumber")) |
| | | chunkSize, e2 := strconv.Atoi(c.Request.FormValue("chunkSize")) |
| | | currentChunkSize, e3 := strconv.Atoi(c.Request.FormValue("currentChunkSize")) |
| | | identifier := c.Request.FormValue("identifier") |
| | | filename := c.Request.FormValue("filename") |
| | | relativePath := c.Request.FormValue("relativePath") |
| | | totalChunks, e5 := strconv.Atoi(c.Request.FormValue("totalChunks")) |
| | | if identifier == "" || e1 != nil || e2 != nil || e3 != nil || e5 !=nil { |
| | | util.ResponseFormat(c,code.RequestParamError,"参数有误") |
| | | return |
| | | } |
| | | var arg = service.FileChunkCheckVo { |
| | | UserId: userM["id"].(string), |
| | | FileName: filename, |
| | | Identifier: identifier, |
| | | RelativePath: relativePath, |
| | | TotalChunks: totalChunks, |
| | | ChunkNumber: chunkNumber, |
| | | ChunkSize: chunkSize, |
| | | CurrentChunkSize:currentChunkSize, |
| | | } |
| | | var sv service.SysService |
| | | if b := sv.CheckUpdateFile(&arg);b { |
| | | c.String(http.StatusOK,"found") |
| | | } else { |
| | | c.String(http.StatusNoContent,"") |
| | | } |
| | | } |
| | | |
| | | // @Security ApiKeyAuth |
| | | // @Summary 系统更新包上传 |
| | | // @Description 系统更新包上传 |
| | | // @Accept multipart/form-data |
| | | // @Produce json |
| | | // @Tags sysset |
| | | // @Param chunkNumber formData int true "当前是第几个分块" |
| | | // @Param chunkSize formData int true "每一块的大小" |
| | | // @Param currentChunkSize formData int true "当前块的大小" |
| | | // @Param totalSize formData string true "文件总大小" |
| | | // @Param identifier formData string true "整个文件的唯一标识,目前是md5" |
| | | // @Param filename formData string true "文件名称" |
| | | // @Param relativePath formData string true "文件在客户端电脑的路径" |
| | | // @Param totalChunks formData int true "文件总块数" |
| | | // @Param file formData file true "文件分片内容" |
| | | // @Success 200 {string} json "{"code":200, msg:"", success:true}" |
| | | // @Failure 500 {string} json "{"code":500, msg:"", success:false}" |
| | | // @Router /data/api-v/sysset/patchUpdate [post] |
| | | func (sset SysSetController) PatchUpdate(c *gin.Context) { |
| | | authDriver := auth.GenerateAuthDriver() |
| | | userM := (*authDriver).User(c) |
| | | if userM == nil { |
| | | util.ResponseFormat(c, code.TokenNotFound, "登录过期,请登录") |
| | | return |
| | | } |
| | | chunkNumber, e1 := strconv.Atoi(c.Request.FormValue("chunkNumber")) |
| | | chunkSize, e2 := strconv.Atoi(c.Request.FormValue("chunkSize")) |
| | | currentChunkSize, e3 := strconv.Atoi(c.Request.FormValue("currentChunkSize")) |
| | | totalSize, e4 := strconv.ParseInt(c.Request.FormValue("totalSize"), 10, 64) |
| | | identifier := c.Request.FormValue("identifier") |
| | | filename := c.Request.FormValue("filename") |
| | | relativePath := c.Request.FormValue("relativePath") |
| | | totalChunks, e5 := strconv.Atoi(c.Request.FormValue("totalChunks")) |
| | | file, header, e6 := c.Request.FormFile("file") |
| | | if identifier == "" || e1 != nil || e2 != nil || e3 != nil || e4 != nil || e5 != nil || e6 != nil { |
| | | util.ResponseFormat(c, code.RequestParamError, "参数有误") |
| | | return |
| | | } |
| | | var arg = service.FileUploadVo{ |
| | | UserId: userM["id"].(string), |
| | | FileName: filename, |
| | | Identifier: identifier, |
| | | RelativePath: relativePath, |
| | | TotalSize: totalSize, |
| | | TotalChunks: totalChunks, |
| | | ChunkNumber: chunkNumber, |
| | | ChunkSize: chunkSize, |
| | | CurrentChunkSize: currentChunkSize, |
| | | File: &file, |
| | | Header: header, |
| | | } |
| | | var sv service.SysService |
| | | if b := sv.PatchUpload(&arg); b { |
| | | util.ResponseFormat(c, code.Success, "") |
| | | } else { |
| | | util.ResponseFormat(c, code.ComError, "") |
| | | } |
| | | } |
| | | |
| | | |
| | | // @Security ApiKeyAuth |
| | | // @Summary 开始升级 |
| | | // @Description 开始升级 |
| | | // @Accept multipart/form-data |
| | | // @Produce json |
| | | // @Tags sysset |
| | | // @Param identifier formData string true "整个文件的唯一标识,目前是md5" |
| | | // @Param filename formData string true "文件名称" |
| | | // @Success 200 {string} json "{"code":200, msg:"", success:true}" |
| | | // @Failure 500 {string} json "{"code":500, msg:"", success:false}" |
| | | // @Router /data/api-v/sysset/upgrade [post] |
| | | func (sset SysSetController) Upgrade(c *gin.Context) { |
| | | identifier := c.Request.FormValue("identifier") |
| | | filename := c.Request.FormValue("filename") |
| | | if identifier == "" || filename == "" { |
| | | util.ResponseFormat(c,code.RequestParamError,"") |
| | | return |
| | | } |
| | | var sv service.SysService |
| | | if b,err := sv.Upgrade(identifier, filename);b { |
| | | util.ResponseFormat(c,code.UpgradeSuccess,"升级成功") |
| | | } else { |
| | | util.ResponseFormat(c,code.UpgradeFail,err.Error()) |
| | | } |
| | | } |
| | |
| | | CreateFirstNodeErr = &Code{http.StatusInternalServerError, false, "创建节点失败!"} |
| | | QueryClusterInfoErr = &Code{http.StatusInternalServerError, false, "查询失败,请确认您的ip是正确的!"} |
| | | AddClusterInfoErr = &Code{http.StatusInternalServerError, false, "加入节点失败!"} |
| | | |
| | | UpgradeSuccess = &Code{http.StatusOK, true, "升级成功"} |
| | | UpgradeFail = &Code{http.StatusInternalServerError, false, "升级失败"} |
| | | ) |
| | |
| | | SudoPassword string `mapstructure: "sudoPassword"` //系统密码 |
| | | SysThresholds []threshold `mapstructure: "sysThresholds"` |
| | | PTZSpeed int `mapstructure: "ptzSpeed"` // 云台移动速度 |
| | | PatchPath string `mapstructure:"patchPath"`//系统更新包路径 |
| | | BakPath string `mapstructure:"bakPath"`//系统更新包路径 |
| | | } |
| | | |
| | | var Server = &server{} |
| | |
| | | package util |
| | | |
| | | import ( |
| | | "archive/zip" |
| | | "bytes" |
| | | "crypto/md5" |
| | | "encoding/hex" |
| | | "encoding/json" |
| | | "image" |
| | | "io" |
| | | "io/ioutil" |
| | | "net/http" |
| | | "os" |
| | | "path/filepath" |
| | | "strconv" |
| | | "time" |
| | | "webserver/extend/code" |
| | | |
| | | "basic.com/pubsub/protomsg.git" |
| | |
| | | out = out[:n] // compressed data |
| | | return out, nil |
| | | } |
| | | |
| | | // 判断所给路径文件/文件夹是否存在 |
| | | func Exists(path string) bool { |
| | | if path == "" { |
| | | return false |
| | | } |
| | | _, err := os.Stat(path) //os.Stat获取文件信息 |
| | | if err != nil { |
| | | if os.IsExist(err) { |
| | | return true |
| | | } |
| | | return false |
| | | } |
| | | return true |
| | | } |
| | | func CreateDirectory(path string) bool { |
| | | if path == "" { |
| | | return false |
| | | } |
| | | if Exists(path) { |
| | | return true |
| | | } |
| | | err := os.MkdirAll(path,os.ModePerm) |
| | | if err !=nil { |
| | | return false |
| | | } |
| | | return true |
| | | } |
| | | |
| | | //日期转字符串 |
| | | func FormatDate(date time.Time, layout string) string { |
| | | layout = strings.Replace(layout, "yyyy", "2006", 1) |
| | | layout = strings.Replace(layout, "yy", "06", 1) |
| | | layout = strings.Replace(layout, "MM", "01", 1) |
| | | layout = strings.Replace(layout, "dd", "02", 1) |
| | | layout = strings.Replace(layout, "HH", "15", 1) |
| | | layout = strings.Replace(layout, "mm", "04", 1) |
| | | layout = strings.Replace(layout, "ss", "05", 1) |
| | | layout = strings.Replace(layout, "SSS", "000", -1) |
| | | return date.Format(layout) |
| | | } |
| | | func ZipCheck(zipPath string) bool { |
| | | f, err := os.Open(zipPath) |
| | | if err != nil { |
| | | return false |
| | | } |
| | | defer f.Close() |
| | | buf := make([]byte, 4) |
| | | if n, err := f.Read(buf); err != nil || n < 4 { |
| | | return false |
| | | } |
| | | return bytes.Equal(buf, []byte("PK\x03\x04")) |
| | | } |
| | | func UnZip(archive, target string) error { |
| | | reader, err := zip.OpenReader(archive) |
| | | if err != nil { |
| | | return err |
| | | } |
| | | if err := os.MkdirAll(target, 0755); err != nil { |
| | | return err |
| | | } |
| | | for _, file := range reader.File { |
| | | path := filepath.Join(target, file.Name) |
| | | if file.FileInfo().IsDir() { |
| | | os.MkdirAll(path, file.Mode()) |
| | | continue |
| | | } |
| | | fileReader, err := file.Open() |
| | | if err != nil { |
| | | return err |
| | | } |
| | | defer fileReader.Close() |
| | | targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode()) |
| | | if err != nil { |
| | | return err |
| | | } |
| | | defer targetFile.Close() |
| | | if _, err := io.Copy(targetFile, fileReader); err != nil { |
| | | return err |
| | | } |
| | | } |
| | | |
| | | return nil |
| | | } |
| | | |
| | | func FormatNum(oNum int,n int) string { |
| | | m := 0 |
| | | for { |
| | | oNum = oNum / 10 |
| | | m++ |
| | | if oNum == 0 { |
| | | break |
| | | } |
| | | } |
| | | fmtStr := "%0"+strconv.Itoa(m)+"d" |
| | | return fmt.Sprintf(fmtStr, n) |
| | | } |
| | | |
| | | func FileMd5(path string) (string,error){ |
| | | file, err := os.Open(path) |
| | | if err !=nil { |
| | | return "",err |
| | | } |
| | | |
| | | defer file.Close() |
| | | |
| | | _md5 := md5.New() |
| | | if _,err := io.Copy(_md5, file);err != nil { |
| | | return "",err |
| | | } |
| | | |
| | | return hex.EncodeToString(_md5.Sum(nil)),nil |
| | | } |
New file |
| | |
| | | package util |
| | | |
| | | import ( |
| | | "archive/tar" |
| | | "basic.com/valib/logger.git" |
| | | "compress/gzip" |
| | | "errors" |
| | | "io" |
| | | "io/ioutil" |
| | | "os" |
| | | "path" |
| | | "strings" |
| | | ) |
| | | |
| | | //FileName 待压缩的文件名 |
| | | //DesPathName 压缩完之后存放的目录名 |
| | | func Gzip(FilePathName, DesPathName string) error { |
| | | // 清理路径字符串 |
| | | FilePathName = path.Clean(FilePathName) |
| | | // 要解压的文件名字 |
| | | FileName := FilePathName |
| | | index := strings.LastIndex(FilePathName, "\\") |
| | | if index != -1 { |
| | | FileName = FilePathName[index+1:] |
| | | } |
| | | logger.Debug("文件名称是", FileName) |
| | | //创建存放压缩文件的路径(如果文件夹不存在) |
| | | |
| | | if !dirExists(DesPathName) { |
| | | os.MkdirAll(DesPathName, 0777) |
| | | } |
| | | logger.Debug("创建文件") |
| | | //创建压缩文件 |
| | | DesFileName := DesPathName + "\\" + FileName + ".gz" |
| | | fw, er := os.Create(DesFileName) |
| | | if er != nil { |
| | | return er |
| | | } |
| | | defer fw.Close() |
| | | gw := gzip.NewWriter(fw) |
| | | defer gw.Close() |
| | | |
| | | //读取文件内容 |
| | | rd := make([]byte, 1024*1024) |
| | | rd, err := ioutil.ReadFile(FilePathName) |
| | | if err != nil { |
| | | logger.Debug("读取文件内的数据出错 err:", err) |
| | | return err |
| | | } |
| | | // 获取文件或目录信息 |
| | | fi, err := os.Stat(FilePathName) |
| | | if err != nil { |
| | | logger.Debug("获取文件的详细信息出错 err :", err) |
| | | return nil |
| | | } |
| | | gw.Name = fi.Name() |
| | | gw.ModTime = fi.ModTime() |
| | | _, err = gw.Write(rd) |
| | | if err != nil { |
| | | logger.Debug("写入压缩文件出错 err:", err) |
| | | return err |
| | | } |
| | | err = gw.Flush() |
| | | if err != nil { |
| | | logger.Debug("gw.Flush() 出错 err:", err) |
| | | return err |
| | | } |
| | | return nil |
| | | } |
| | | func UnGz(srcGz string, filePath string) error { |
| | | fr, err := os.Open(srcGz) |
| | | if err != nil { |
| | | logger.Debug("open secGZ failed. err:%v", err) |
| | | return err |
| | | } |
| | | gr, err := gzip.NewReader(fr) |
| | | if err != nil { |
| | | fr.Close() |
| | | logger.Debug("create gzip.reader failed. err:%v", err) |
| | | return err |
| | | } |
| | | index := strings.LastIndex(srcGz, ".") |
| | | if index == -1 { |
| | | gr.Close() |
| | | fr.Close() |
| | | logger.Debug("find . failed. err:%v", err) |
| | | return err |
| | | } |
| | | fw, err := os.Create(filePath) |
| | | if err != nil { |
| | | gr.Close() |
| | | fr.Close() |
| | | logger.Debug("create file failed. err:%v", err) |
| | | return err |
| | | } |
| | | // 写文件 |
| | | _, err = io.Copy(fw, gr) |
| | | if err != nil { |
| | | fw.Close() |
| | | gr.Close() |
| | | fr.Close() |
| | | logger.Debug("write file failed. err:%v", err) |
| | | return err |
| | | } |
| | | fw.Close() |
| | | gr.Close() |
| | | fr.Close() |
| | | //删除gz压缩文件 |
| | | err = os.Remove(srcGz) |
| | | if err != nil { |
| | | logger.Debug("remove file failed. err:%v", err) |
| | | return err |
| | | } |
| | | return nil |
| | | } |
| | | // 将文件或目录打包成 .tar 文件 |
| | | // src 是要打包的文件或目录的路径 |
| | | // dstTar 是要生成的 .tar 文件的路径 |
| | | // failIfExiBst 标记如果 dstTar 文件存在,是否放弃打包,如果否,则会覆盖已存在的文件 |
| | | func TarGz(src string, dstTar string, failIfExist bool) error { |
| | | // 清理路径字符串 |
| | | src = path.Clean(src) |
| | | // 判断要打包的文件或目录是否存在 |
| | | if !exists(src) { |
| | | return errors.New("要打包的文件或目录不存在:" + src) |
| | | } |
| | | // 判断目标文件是否存在 |
| | | if fileExists(dstTar) { |
| | | if failIfExist { // 不覆盖已存在的文件 |
| | | return errors.New("目标文件已经存在:" + dstTar) |
| | | } else { // 覆盖已存在的文件 |
| | | if er := os.Remove(dstTar); er != nil { |
| | | return er |
| | | } |
| | | } |
| | | } |
| | | // 创建空的目标文件 |
| | | fw, er := os.Create(dstTar) |
| | | if er != nil { |
| | | return er |
| | | } |
| | | defer fw.Close() |
| | | gw := gzip.NewWriter(fw) |
| | | defer gw.Close() |
| | | // 创建 tar.Writer,执行打包操作 |
| | | tw := tar.NewWriter(gw) |
| | | var err error |
| | | defer func() { |
| | | // 这里要判断 tw 是否关闭成功,如果关闭失败,则 .tar 文件可能不完整 |
| | | if er := tw.Close(); er != nil { |
| | | err = er |
| | | } |
| | | }() |
| | | // 获取文件或目录信息 |
| | | fi, er := os.Stat(src) |
| | | if er != nil { |
| | | return er |
| | | } |
| | | // 获取要打包的文件或目录的所在位置和名称 |
| | | srcBase, srcRelative := path.Split(path.Clean(src)) |
| | | // 开始打包 |
| | | if fi.IsDir() { |
| | | logger.Debug("第一层目录:", srcRelative) |
| | | tarDir(srcBase, srcRelative, tw, fi) |
| | | } else { |
| | | tarFile(srcBase, srcRelative, tw, fi) |
| | | } |
| | | return nil |
| | | } |
| | | // 因为要执行遍历操作,所以要单独创建一个函数 |
| | | func tarDir(srcBase, srcRelative string, tw *tar.Writer, fi os.FileInfo) (err error) { |
| | | // 获取完整路径 |
| | | srcFull := srcBase + srcRelative |
| | | logger.Debug("srcFull:", srcFull) |
| | | // 在结尾添加 "/" |
| | | last := len(srcRelative) - 1 |
| | | if srcRelative[last] != os.PathSeparator { |
| | | srcRelative += string(os.PathSeparator) |
| | | } |
| | | // 获取 srcFull 下的文件或子目录列表 |
| | | fis, er := ioutil.ReadDir(srcFull) |
| | | if er != nil { |
| | | return er |
| | | } |
| | | // 开始遍历 |
| | | for _, fi := range fis { |
| | | if fi.IsDir() { |
| | | logger.Debug("下层目录") |
| | | tarDir(srcBase, srcRelative+fi.Name(), tw, fi) |
| | | } else { |
| | | logger.Debug("是文件") |
| | | tarFile(srcBase, srcRelative+fi.Name(), tw, fi) |
| | | } |
| | | } |
| | | return nil |
| | | } |
| | | // 因为要在 defer 中关闭文件,所以要单独创建一个函数 |
| | | func tarFile(srcBase, srcRelative string, tw *tar.Writer, fi os.FileInfo) (err error) { |
| | | // 获取完整路径 |
| | | srcFull := srcBase + srcRelative |
| | | logger.Debug("文件的全路径", srcFull) |
| | | // 写入文件信息 |
| | | hdr, er := tar.FileInfoHeader(fi, "") |
| | | if er != nil { |
| | | return er |
| | | } |
| | | logger.Debug(srcRelative) |
| | | hdr.Name = srcRelative |
| | | logger.Debug("文件hdr.name", hdr.Name) |
| | | if er = tw.WriteHeader(hdr); er != nil { |
| | | return er |
| | | } |
| | | // 打开要打包的文件,准备读取 |
| | | fr, er := os.Open(srcFull) |
| | | if er != nil { |
| | | return er |
| | | } |
| | | defer fr.Close() |
| | | // 将文件数据写入 tw 中 |
| | | if _, er = io.Copy(tw, fr); er != nil { |
| | | return er |
| | | } |
| | | return nil |
| | | } |
| | | |
| | | //解包 可以解压,压缩文件里有文件夹的,也可以解压压缩文件里全是文件的 |
| | | //srcGz待解包文件 |
| | | //dstDir 解包之后存放的目录 |
| | | func UnTarGz(srcGz string, dstDir string) error { |
| | | dstDir = path.Clean(dstDir) + string(os.PathSeparator) |
| | | //打开压缩文件 |
| | | fr, err := os.Open(srcGz) |
| | | if err != nil { |
| | | return err |
| | | } |
| | | defer fr.Close() |
| | | gw, err := gzip.NewReader(fr) |
| | | defer gw.Close() |
| | | // 创建 tar.Reader 对象,准备执行解包操作 |
| | | // 可以用 tr.Next() 来遍历包中的文件 |
| | | tr := tar.NewReader(gw) |
| | | // 遍历包中的文件 |
| | | for hdr, er := tr.Next(); er != io.EOF; hdr, er = tr.Next() { |
| | | if er != nil { |
| | | logger.Debug("--------- er:", er) |
| | | return er |
| | | } |
| | | // 获取文件信息 |
| | | fi := hdr.FileInfo() |
| | | // 获取绝对路径 |
| | | dstFullPath := dstDir + hdr.Name |
| | | logger.Debug("--- dstFullPath:", dstFullPath) |
| | | if hdr.Typeflag == tar.TypeDir { |
| | | logger.Debug("--- type is floder") |
| | | // 创建目录 |
| | | os.MkdirAll(dstFullPath, fi.Mode().Perm()) |
| | | // 设置目录权限 |
| | | os.Chmod(dstFullPath, fi.Mode().Perm()) |
| | | } else { |
| | | logger.Debug(dstFullPath, "--- type is file") |
| | | // 创建文件所在的目录 |
| | | |
| | | strtemp := dstFullPath[:strings.LastIndex(dstFullPath, "\\")+1] |
| | | //os.MkdirAll(path.Dir(dstFullPath), os.ModePerm) |
| | | |
| | | os.MkdirAll(strtemp, os.ModePerm) |
| | | // 将 tr 中的数据写入文件中 |
| | | if er := unTarFile(dstFullPath, tr); er != nil { |
| | | logger.Debug("unTarFile:",er) |
| | | return er |
| | | } |
| | | // 设置文件权限 |
| | | os.Chmod(dstFullPath, fi.Mode().Perm()) |
| | | } |
| | | } |
| | | |
| | | return nil |
| | | } |
| | | |
| | | // 因为要在 defer 中关闭文件,所以要单独创建一个函数 |
| | | func unTarFile(dstFile string, tr *tar.Reader) error { |
| | | // 创建空文件,准备写入解包后的数据 |
| | | fw, er := os.Create(dstFile) |
| | | if er != nil { |
| | | return er |
| | | } |
| | | defer fw.Close() |
| | | |
| | | // 写入解包后的数据 |
| | | _, er = io.Copy(fw, tr) |
| | | if er != nil { |
| | | return er |
| | | } |
| | | |
| | | return nil |
| | | } |
| | | |
| | | // 判断档案是否存在 |
| | | func exists(name string) bool { |
| | | _, err := os.Stat(name) |
| | | return err == nil || os.IsExist(err) |
| | | } |
| | | |
| | | // 判断文件是否存在 |
| | | func fileExists(filename string) bool { |
| | | fi, err := os.Stat(filename) |
| | | return (err == nil || os.IsExist(err)) && !fi.IsDir() |
| | | } |
| | | |
| | | // 判断目录是否存在 |
| | | func dirExists(dirname string) bool { |
| | | fi, err := os.Stat(dirname) |
| | | return (err == nil || os.IsExist(err)) && fi.IsDir() |
| | | } |
| | |
| | | go 1.12 |
| | | |
| | | require ( |
| | | basic.com/dbapi.git v0.0.0-20191216030028-03153c1f1f30 // indirect |
| | | basic.com/dbapi.git v0.0.0-20191224083228-8018a323ebc3 // indirect |
| | | basic.com/fileServer/WeedFSClient.git v0.0.0-20190919054037-0182b6c3f5cb // indirect |
| | | basic.com/gb28181api.git v0.0.0-20191028082253-472438a8407b // indirect |
| | | basic.com/pubsub/cache.git v0.0.0-20190718093725-6a413e1d7d48 // indirect |
| | | basic.com/pubsub/esutil.git v0.0.0-20191120125514-865efa73a9ae // indirect |
| | | basic.com/pubsub/protomsg.git v0.0.0-20191217114717-83e84039a99d // indirect |
| | | basic.com/pubsub/protomsg.git v0.0.0-20191223033758-3fd9a59b8137 // indirect |
| | | basic.com/valib/capture.git v0.0.0-20191204103802-89c923cf2abe // indirect |
| | | basic.com/valib/deliver.git v0.0.0-20190531095353-25d8c3b20051 |
| | | basic.com/valib/godraw.git v0.0.0-20191122082247-26e9987cd183 // indirect |
| | |
| | | basic.com/dbapi.git v0.0.0-20191216030028-03153c1f1f30 h1:nesVta2Rf3LAqyFtGAqNOI+Mf9SqHa4gz1Dj38nm5bk= |
| | | basic.com/dbapi.git v0.0.0-20191216030028-03153c1f1f30/go.mod h1:eDXPnxaz6jZPDvBSk7ya7oSASWPCuUEgRTJCjsfKt/Q= |
| | | basic.com/dbapi.git v0.0.0-20191224083228-8018a323ebc3 h1:sW+KVl8NguOKbafPou8uNoEBHRcmiKM1lIqB45jucFc= |
| | | basic.com/dbapi.git v0.0.0-20191224083228-8018a323ebc3/go.mod h1:eDXPnxaz6jZPDvBSk7ya7oSASWPCuUEgRTJCjsfKt/Q= |
| | | basic.com/fileServer/WeedFSClient.git v0.0.0-20190919054037-0182b6c3f5cb h1:fM6DojeInFSCFO+wkba1jtyPiSDqw0jYKi4Tk+e+ka4= |
| | | basic.com/fileServer/WeedFSClient.git v0.0.0-20190919054037-0182b6c3f5cb/go.mod h1:FTryK8BsVLfUplx8a3+l8hJWub6VbAWZCUH7sPRZaso= |
| | | basic.com/gb28181api.git v0.0.0-20191028082253-472438a8407b h1:Qh7x2PY3HA9B404Llq+olY5/YlGYrM58bpOHa2CGcro= |
| | |
| | | basic.com/pubsub/cache.git v0.0.0-20190718093725-6a413e1d7d48/go.mod h1:gHLJZz2ee1cGL0X0ae69fs56bAxkDgEQwDhhXZJNUcY= |
| | | basic.com/pubsub/esutil.git v0.0.0-20191120125514-865efa73a9ae h1:/j1dIDLxzEp51N+ZHZIq1xeYVK9zz8epWEAfw01uWe8= |
| | | basic.com/pubsub/esutil.git v0.0.0-20191120125514-865efa73a9ae/go.mod h1:yIvppFPFGC61DOdm71ujnsxZBMFUu2yKjr5O43bMWCw= |
| | | basic.com/pubsub/protomsg.git v0.0.0-20191217114717-83e84039a99d h1:8dxtZCRIBdaZwCbqREyRdgXkBqyufK8WJxbrWbNweEA= |
| | | basic.com/pubsub/protomsg.git v0.0.0-20191217114717-83e84039a99d/go.mod h1:un5NV5VWQoblVLZfx1Rt5vyLgwR0jI92d3VJhfrJhWU= |
| | | basic.com/pubsub/protomsg.git v0.0.0-20191223033758-3fd9a59b8137 h1:bvAnC34X/0CjLcubBj2sfHKzYXZXDjnd0LD7pyp1pH0= |
| | | basic.com/pubsub/protomsg.git v0.0.0-20191223033758-3fd9a59b8137/go.mod h1:un5NV5VWQoblVLZfx1Rt5vyLgwR0jI92d3VJhfrJhWU= |
| | | basic.com/valib/capture.git v0.0.0-20191204103802-89c923cf2abe h1:uh3u7DuSOw6AwzvPC1EM19sw1Skks1EUJddcbHDKI9M= |
| | | basic.com/valib/capture.git v0.0.0-20191204103802-89c923cf2abe/go.mod h1:y+h7VUnoSQ3jOtf2K3twXNA8fYDfyUsifSswcyKLgNw= |
| | | basic.com/valib/deliver.git v0.0.0-20190531095353-25d8c3b20051/go.mod h1:bkYiTUGzckyNOjAgn9rB/DOjFzwoSHJlruuWQ6hu6IY= |
New file |
| | |
| | | #!/bin/bash |
| | | |
| | | filepath=$1 |
| | | filestore=$2 |
| | | |
| | | echo "filepath: " $filepath |
| | | echo "filestorepath: " $filestore |
| | | |
| | | if [ ! -f $filestore ]; then |
| | | echo "$filestore not exist" |
| | | else |
| | | rm -f $filestore |
| | | fi |
| | | |
| | | for item in `ls $filepath | sort -n` |
| | | do |
| | | `cat ${filepath}/${item} >> ${filestore}` |
| | | echo "merge ${filepath}/${item} to $filestore ok" |
| | | done |
| | | |
| | | echo "file store ok" |
| | |
| | | |
| | | vsset.GET("/getResourceConfig",ssController.GetResourceConfig) |
| | | vsset.POST("/saveResourceConfig",ssController.SaveResourceConfig) |
| | | vsset.GET("/patchUpdate", ssController.PatchUpdateCheck) |
| | | vsset.POST("/patchUpdate", ssController.PatchUpdate) |
| | | vsset.POST("/upgrade", ssController.Upgrade) |
| | | } |
| | | |
| | | //算法库操作 |
New file |
| | |
| | | package service |
| | | |
| | | import ( |
| | | "basic.com/valib/logger.git" |
| | | "bufio" |
| | | "errors" |
| | | "fmt" |
| | | "io/ioutil" |
| | | "mime/multipart" |
| | | "os" |
| | | "os/exec" |
| | | "path" |
| | | "strings" |
| | | "webserver/extend/config" |
| | | "webserver/extend/util" |
| | | ) |
| | | |
| | | type SysService struct { |
| | | |
| | | } |
| | | |
| | | type FileChunkCheckVo struct { |
| | | UserId string |
| | | ChunkNumber int //当前分片下标,从1开始 |
| | | ChunkSize int //每一块的大小 |
| | | CurrentChunkSize int //当前分块的大小 |
| | | FileName string //文件名称 |
| | | Identifier string //整个文件唯一标识,md5 |
| | | RelativePath string //文件客户端路径 |
| | | TotalSize int64 //文件总大小 |
| | | TotalChunks int //总分片数量 |
| | | } |
| | | |
| | | type FileUploadVo struct { |
| | | Id string |
| | | UserId string |
| | | ChunkNumber int //当前分片下标,从1开始 |
| | | ChunkSize int //每一块的大小 |
| | | CurrentChunkSize int //当前分块的大小 |
| | | FileName string //文件名称 |
| | | Identifier string //整个文件唯一标识,md5 |
| | | RelativePath string //文件客户端路径 |
| | | TotalSize int64 //文件总大小 |
| | | TotalChunks int //总分片数量 |
| | | File *multipart.File //当前分片的文件内容 |
| | | Header *multipart.FileHeader |
| | | } |
| | | |
| | | func (sv SysService) CheckUpdateFile(arg *FileChunkCheckVo) bool { |
| | | configPatchPath := "" |
| | | if config.Server.PatchPath != "" { |
| | | configPatchPath = config.Server.PatchPath |
| | | } else { |
| | | configPatchPath = "/opt/vasystem/patch" |
| | | } |
| | | fileTmpPath := configPatchPath + "/"+arg.Identifier |
| | | if !util.Exists(fileTmpPath) { |
| | | return false |
| | | } |
| | | //判断合成的文件是否存在 |
| | | index := strings.LastIndex(arg.FileName, ".") |
| | | subfix := "" |
| | | if index >-1 {//有后缀 |
| | | subfix = arg.FileName[index:] |
| | | } |
| | | mergedFilePath := fileTmpPath+subfix |
| | | if util.Exists(mergedFilePath) { |
| | | return true |
| | | } |
| | | //判断分块文件是否存在 |
| | | chunkAlignNum := util.FormatNum(arg.TotalChunks, arg.ChunkNumber) |
| | | chunkFilePath := fileTmpPath+"/"+arg.Identifier+"_"+chunkAlignNum |
| | | if !util.Exists(chunkFilePath) { |
| | | return false |
| | | } |
| | | if arg.ChunkNumber == arg.TotalChunks { |
| | | dirFiles, _ := ioutil.ReadDir(fileTmpPath) |
| | | if dirFiles != nil && len(dirFiles) == arg.TotalChunks { |
| | | //表示所有分块都上传了,需要merge |
| | | if !sv.MergeChunks(fileTmpPath, mergedFilePath) { |
| | | return false |
| | | } |
| | | } |
| | | } |
| | | return true |
| | | } |
| | | |
| | | func (sv SysService) PatchUpload(arg *FileUploadVo) bool { |
| | | configPatchPath := "" |
| | | if config.Server.PatchPath != "" { |
| | | configPatchPath = config.Server.PatchPath |
| | | } else { |
| | | configPatchPath = "/opt/vasystem/patch" |
| | | } |
| | | defer (*arg.File).Close() |
| | | if !util.CreateDirectory(configPatchPath) { |
| | | return false |
| | | } |
| | | |
| | | filenameWithSuffix := path.Base(arg.Header.Filename) |
| | | subfix := path.Ext(filenameWithSuffix) |
| | | MD5Str := arg.Identifier |
| | | logger.Debug("Identifier:",MD5Str) |
| | | fileTmpPath := configPatchPath + "/"+MD5Str |
| | | if !util.Exists(fileTmpPath) { |
| | | if !util.CreateDirectory(fileTmpPath) { |
| | | return false |
| | | } |
| | | } |
| | | chunkAlignNum := util.FormatNum(arg.TotalChunks, arg.ChunkNumber) |
| | | fileSavePath := fileTmpPath+"/"+MD5Str+"_"+chunkAlignNum |
| | | if util.Exists(fileSavePath) { |
| | | rmErr := os.Remove(fileSavePath) |
| | | if rmErr != nil { |
| | | logger.Debug("rmErr:",rmErr) |
| | | return false |
| | | } |
| | | } |
| | | file, e := os.Create(fileSavePath) |
| | | if e !=nil { |
| | | logger.Debug("os.Create err:",e,"fileSavePath:",fileSavePath) |
| | | return false |
| | | } |
| | | defer file.Close() |
| | | writer := bufio.NewWriter(file) |
| | | chunkData := make([]byte, arg.Header.Size) |
| | | n, err := (*arg.File).ReadAt(chunkData, 0) |
| | | if n ==0 || err !=nil { |
| | | logger.Debug("read chunkData err:",err,"n:",n) |
| | | return false |
| | | } |
| | | nn, err2 := writer.Write(chunkData) |
| | | if nn ==0 || err2 !=nil { |
| | | logger.Debug("write chunkData err:",err2,"nn:",nn) |
| | | return false |
| | | } |
| | | if err = writer.Flush(); err != nil { |
| | | logger.Debug("write flush err:",err) |
| | | } |
| | | isComplete := false |
| | | dirFiles, _ := ioutil.ReadDir(fileTmpPath) |
| | | if dirFiles != nil && len(dirFiles) == arg.TotalChunks { |
| | | isComplete = true |
| | | } |
| | | if isComplete { |
| | | if sv.MergeChunks(fileTmpPath,fileTmpPath + subfix) { |
| | | logger.Debug("merge all chunks success,identifier:",MD5Str,"fileName:",arg.FileName) |
| | | } else { |
| | | return false |
| | | } |
| | | } |
| | | return true |
| | | } |
| | | |
| | | //upgrade |
| | | func (sv SysService) Upgrade(identifier string,filename string) (bool,error) { |
| | | if !bakBeforeUpgrade() { |
| | | return false,errors.New("更新前备份失败") |
| | | } |
| | | 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 |
| | | if util.Exists(zipFilePath) { |
| | | //校验md5 |
| | | strMd5, e := util.FileMd5(zipFilePath) |
| | | if e !=nil || strMd5 == "" { |
| | | return false,errors.New("获取升级压缩包md5失败") |
| | | } |
| | | if strMd5 == identifier { |
| | | if !updatePatch(identifier, ext) { |
| | | return false,errors.New("执行升级过程异常,请确定上传的补丁是tar.gz格式") |
| | | } |
| | | return true,nil |
| | | |
| | | } else { |
| | | logger.Debug("strMd5 is", strMd5,"identifier is",identifier,"not equal") |
| | | return false,errors.New("校验升级文件失败") |
| | | } |
| | | } else { |
| | | return false,errors.New("升级文件已丢失,请重新上传") |
| | | } |
| | | } |
| | | |
| | | func bakBeforeUpgrade() bool { |
| | | configBakPath := "" |
| | | if config.Server.BakPath != "" { |
| | | configBakPath = config.Server.BakPath |
| | | } else { |
| | | configBakPath = "/opt/vasystem/bak" |
| | | } |
| | | if util.Exists(configBakPath) { |
| | | //只保留最新的版本 |
| | | if err := os.RemoveAll(configBakPath);err != nil { |
| | | return false |
| | | } |
| | | } |
| | | if !util.CreateDirectory(configBakPath) { |
| | | return false |
| | | } |
| | | b, err := ExecCmd("cp -r /opt/vasystem/bin /opt/vasystem/bak") |
| | | if err != nil { |
| | | logger.Debug("bakBeforeUpgrade result:",string(b),"err:",err) |
| | | return false |
| | | } |
| | | return true |
| | | } |
| | | |
| | | //更新系统程序 |
| | | func updatePatch(identifier string, ext string) bool { |
| | | configPatchPath := "" |
| | | if config.Server.PatchPath != "" { |
| | | configPatchPath = config.Server.PatchPath |
| | | } else { |
| | | configPatchPath = "/opt/vasystem/patch" |
| | | } |
| | | //1.解压缩更新包 |
| | | unPackPath := configPatchPath+"/"+identifier+"_basic/" |
| | | if util.Exists(unPackPath) { |
| | | //此版本已经更新过 |
| | | rmErr := os.RemoveAll(unPackPath) |
| | | if rmErr !=nil { |
| | | return false |
| | | } |
| | | } |
| | | if !util.CreateDirectory(unPackPath) { |
| | | return false |
| | | } |
| | | |
| | | unPackFilePath := configPatchPath+"/"+identifier+ext |
| | | err := util.UnTarGz(unPackFilePath, unPackPath) |
| | | if err !=nil { |
| | | logger.Debug("UnPack err:",err,"unPackFile:",unPackFilePath) |
| | | return false |
| | | } |
| | | |
| | | //如果通用脚本有更新,则更新通用脚本 |
| | | if util.Exists(unPackPath+"updatePatch.sh") { |
| | | cpStr := fmt.Sprintf("cp %s /opt/vasystem/bin",unPackPath+"updatePatch.sh") |
| | | b, err := ExecCmd(cpStr) |
| | | if err != nil { |
| | | logger.Debug("cp updatePatch.sh to bin err:",err,"result:",string(b)) |
| | | return false |
| | | } |
| | | } |
| | | |
| | | //判断更新包里是否有补丁脚本,如果有则执行,否则执行updatePatch.sh |
| | | updateCmd := fmt.Sprintf("./updatePatch.sh %s %s %s &",unPackPath,unPackFilePath,configPatchPath+"/"+identifier) |
| | | if util.Exists(unPackPath+"upgrade.sh") { |
| | | updateCmd = fmt.Sprintf("%supgrade.sh %s %s %s &",unPackPath,unPackPath,unPackFilePath,configPatchPath+"/"+identifier) |
| | | } |
| | | //2.更新系统 |
| | | b,err := ExecCmd(updateCmd) |
| | | if err != nil { |
| | | logger.Debug("upgrade err:",err,"result:",string(b),"cmd:",updateCmd) |
| | | return false |
| | | } else { |
| | | logger.Debug("upgrade result:",string(b),"cmd:",updateCmd) |
| | | } |
| | | return true |
| | | } |
| | | |
| | | func (sv SysService) MergeChunks(chunkPath string, storePath string) bool { |
| | | var cmd *exec.Cmd |
| | | cmd = exec.Command("/bin/sh", "-c", fmt.Sprintf("./mergeAll.sh %s %s", chunkPath, storePath)) |
| | | if b, err := cmd.Output(); err != nil { |
| | | logger.Debug("mergeChunks err:", err, "result:", string(b)) |
| | | return false |
| | | } else { |
| | | logger.Debug("mergeChunks result:",string(b),"cmd: ./mergeAll.sh ", chunkPath, storePath) |
| | | return true |
| | | } |
| | | } |
| | | |
| | | func ExecCmd(cmdStr string) ([]byte,error) { |
| | | var cmd *exec.Cmd |
| | | cmd = exec.Command("/bin/sh", "-c",cmdStr) |
| | | return cmd.Output() |
| | | } |
New file |
| | |
| | | #!/bin/bash |
| | | |
| | | cd /opt/vasystem/ |
| | | |
| | | ./kill.sh |
| | | sleep 2 |
| | | |
| | | cp -r /opt/vasystem/bak/bin /opt/vasystem/bin |
| | | |
| | | ./daemon.sh -shm |
| | | |
| | | sleep 2 |
| | | echo "backup success" |
| | | |
| | | exit 0 |
New file |
| | |
| | | #!/bin/bash |
| | | |
| | | #stop proc |
| | | killP() { |
| | | pkill $1 |
| | | ps aux | grep "$1" | grep -q -v grep |
| | | PROCESS_STATUS=$? |
| | | if [ $PROCESS_STATUS -ne 0 ]; then |
| | | pkill $1 |
| | | fi |
| | | } |
| | | startSdkCompareWithOneParam(){ |
| | | number=`ps -ef | grep "sdkCompare" | grep -v grep | wc -l` |
| | | if [ $number -ne 2 ]; then |
| | | killP sdkCompare |
| | | sleep 2 |
| | | date +%D-%T" sdkCompare start" |
| | | nohup ./sdkCompare $1 >/dev/null 2>&1 & |
| | | nohup ./sdkCompare $1 -target=es >/dev/null 2>&1 & |
| | | return 1 |
| | | else |
| | | echo "sdkCompare is exists">>upgrade.out |
| | | return 0 |
| | | fi |
| | | |
| | | } |
| | | cd /opt/vasystem/bin |
| | | patchPath=$1 |
| | | zipPath=$2 |
| | | chunkPath=$3 |
| | | files=$(ls $patchPath) |
| | | echo "patchPath: " $patchPath >> upgrade.out |
| | | if [ ! -d $patchPath ]; then |
| | | echo "$patchPath not exist,patch update fail" >> upgrade.out |
| | | else |
| | | for item in $files |
| | | do |
| | | if [ -f $patchPath/$item ]; then |
| | | echo "start update proc ${item}" >> upgrade.out |
| | | killP $item |
| | | sleep 2 |
| | | cp $patchPath/$item /opt/vasystem/bin |
| | | chmod +x /opt/vasystem/bin/$item |
| | | if [ "$item" = "sdkCompare" ]; then |
| | | startSdkCompareWithOneParam -e=pro |
| | | echo "update ${item} success" >> upgrade.out |
| | | elif [ "$item" = "ruleprocess" ]; then |
| | | echo "update algorithm" >> upgrade.out |
| | | #update algorithm |
| | | if [ -d $patchPath/algorithm ]; then |
| | | cp -r $patchPath/algorithm /opt/vasystem/bin |
| | | fi |
| | | nohup ./ruleprocess >/dev/null 2>&1 & |
| | | else |
| | | nohup ./$item >/dev/null 2>&1 & |
| | | echo "update ${item} success" >> upgrade.out |
| | | fi |
| | | else |
| | | if [ "$item" = "dist" ]; then |
| | | echo "update web dist" >> upgrade.out |
| | | cp -r $patchPath/$item /opt/vasystem/web |
| | | else |
| | | echo "unknown directory ${item}" >> upgrade.out |
| | | fi |
| | | fi |
| | | done |
| | | fi |
| | | echo "exec rm -rf ${patchPath} ${zipPath} ${chunkPath}" >> upgrade.out |
| | | rm -rf $patchPath $zipPath $chunkPath |
| | | echo "rm success" >> upgrade.out |
| | | exit 0 |