liuxiaolong
2020-01-06 2fdef0f732a5d6549d2c42a116dfdd3dc75a0b48
merge ynPatch
5个文件已添加
10个文件已修改
1022 ■■■■■ 已修改文件
config/dev.yaml 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
config/pro.yaml 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
config/test.yaml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/syssetcont.go 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
extend/code/code.go 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
extend/config/config.go 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
extend/util/util.go 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
extend/util/zip.go 314 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
go.mod 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
go.sum 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
mergeAll.sh 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
router/router.go 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/SysService.go 286 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sysComeBack.sh 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
updatePatch.sh 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
config/dev.yaml
@@ -19,6 +19,19 @@
    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
config/pro.yaml
@@ -19,6 +19,19 @@
    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
config/test.yaml
@@ -35,6 +35,7 @@
    value: 100
    color: '#5d0000'
  ptzSpeed: 50
  patchPath: /opt/vasystem/patch
database:
  driver: sqlite
  name: sqlite3
controllers/syssetcont.go
@@ -1,11 +1,15 @@
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"
@@ -483,14 +487,150 @@
    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())
    }
}
extend/code/code.go
@@ -65,4 +65,7 @@
    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, "升级失败"}
)
extend/config/config.go
@@ -29,6 +29,8 @@
    SudoPassword  string      `mapstructure: "sudoPassword"` //系统密码
    SysThresholds []threshold `mapstructure: "sysThresholds"`
    PTZSpeed      int         `mapstructure: "ptzSpeed"` // 云台移动速度
    PatchPath       string `mapstructure:"patchPath"`//系统更新包路径
    BakPath         string `mapstructure:"bakPath"`//系统更新包路径
}
var Server = &server{}
extend/util/util.go
@@ -1,12 +1,19 @@
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"
@@ -206,3 +213,116 @@
    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
}
extend/util/zip.go
New file
@@ -0,0 +1,314 @@
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.mod
@@ -3,12 +3,12 @@
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
go.sum
@@ -1,5 +1,5 @@
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=
@@ -8,8 +8,8 @@
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=
mergeAll.sh
New file
@@ -0,0 +1,21 @@
#!/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"
router/router.go
@@ -235,6 +235,9 @@
        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)
    }
    //算法库操作
service/SysService.go
New file
@@ -0,0 +1,286 @@
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()
}
sysComeBack.sh
New file
@@ -0,0 +1,15 @@
#!/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
updatePatch.sh
New file
@@ -0,0 +1,71 @@
#!/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