分享一个小东西,自动到指定的地方下载动态版本的命令,然后根据配置循环执行调用.

前端之家收集整理的这篇文章主要介绍了分享一个小东西,自动到指定的地方下载动态版本的命令,然后根据配置循环执行调用.前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

写此小程序的原因是,研究小米的open-falcon的时候用他们的插件管理感觉不适合我们公司,就自动动手写了个基于服务端的版本控制的,命令下载时基于http的所以也比较方便.

代码写的比较紧急有点乱,先这样吧,回头用起来再调优一下.

先发下执行的结果:

开始解析cfg.json配置文件.解析配置文件成功:  {gyc D:/code/20151117/src/ssh true
27.0.0.1:2789 http://127.0.0.1:1789/pkg/ :1789 true 60}
开始初始化本地命令...
初始化本地命令完成...
[{client.go D:\code\20151117\src\ssh\client.go 256034f7168a3937b124ad89227f0ea9
 {sshd D:\code\20151117\src\ssh\sshd af7ec72582c33ecd97dc5abf0e747e92}]
D:/code/20151117/src/ssh
2015-11-18 17:46:29获取服务端版本!
{fmt.exe fe117de8dbf1a460e66d2a799bde17cf 30 }
2015-11-18 17:46:29开始验证本地!
{Test01.exe e6a54c6f478d93828cb635e97d710ba6 30 }
2015-11-18 17:46:29开始验证本地!
开始下载:http://127.0.0.1:1789/pkg/fmt.exe
开始下载:http://127.0.0.1:1789/pkg/Test01.exe
tmp/Test01.exe D:/code/20151117/src/ssh/Test01.exe
tmp/fmt.exe D:/code/20151117/src/ssh/fmt.exe
2015-11-18 17:46:29 开始执行Test01.exe
2015-11-18 17:46:29 开始执行fmt.exe
命令Test01.exe结果:This is Test01
命令fmt.exe结果:2015-11-18 17:46:29.3219182 +0800 CST
命令Test01.exe结果:This is Test01
命令fmt.exe结果:2015-11-18 17:46:59.3536359 +0800 CST
2015-11-18 17:47:29获取服务端版本!
清除过期的命令:Test01.exe.
{fmt.exe fe117de8dbf1a460e66d2a799bde17cf 30 }
2015-11-18 17:47:29 退出执行Test01.exe
命令fmt.exe结果:2015-11-18 17:47:29.3933541 +0800 CST

废话不多说直接上源码:

服务端简单的代码小例子:

server.go

package main

import (
	"encoding/json"
	"fmt"
	"net"
)

type versionInfo struct {
	Name     string `json:name`
	Md5      string `json:md5`
	Interval int    `json:interval`
	Args     string `json:args`
}

//测试代码.服务端可以自己按需求定义.
func main() {
	var list []versionInfo
	list = []versionInfo{{"fmt.exe","fe117de8dbf1a460e66d2a799bde17cf",30,""},{"Test01.exe","e6a54c6f478d93828cb635e97d710ba6",""}}
	//这些内容命令版本多的时候可以用数据库来控制,不多就随便自己搞搞吧,b,err := json.Marshal(list)
	if err != nil {
		fmt.Printf("初始话数据失败:%s\n",err)
		return
	}
	lis,err := net.Listen("tcp",":2789")
	if err != nil {
		fmt.Printf("初始化服务端失败:%s\n",err)
		return
	}
	defer lis.Close()
	for {
		con,err := lis.Accept()
		if err != nil {
			fmt.Println(err)
			continue
		}
		go func(con net.Conn) {
			defer con.Close()
			buf := make([]byte,512)
			n,err := con.Read(buf)
			if err != nil {
				fmt.Println(err)
				return
			}
			if string(buf[:n]) != "gyc" { //这里的值需要根据自己来控制,比如每次收到的请求到数据库查询来取版本返回.
				con.Write([]byte("No this group!"))
				return
			}
			con.Write(b)
		}(con)
	}
}

下面是每个实例的代码.

我得用目录是:new

getServerVersion.go

package new

import (
	"encoding/json"
	"fmt"
	"io/IoUtil"
	"net"
	"os"
	"time"
)

func GetVersion(group string) []RemoteVersionInfo {
	var list []RemoteVersionInfo
This:
	con,err := net.Dial("tcp",Getconfig().GetVersionServer)
	if err != nil {
		fmt.Printf("%s 从%s获取命令版本信息错误: %s\n",GetNowTime(),Getconfig().GetVersionServer,err)
		time.Sleep(60e9)
		goto This
	}
	defer con.Close()
	_,err = con.Write([]byte(group))
	if err != nil {
		fmt.Printf("发送%s的version请求失败:%s\n",group,err)
		time.Sleep(60e9)
		goto This
	}
	buf,err := IoUtil.ReadAll(con)
	if err != nil {
		fmt.Printf("%s 获取命令版本信息错误: %s\n",err)
		time.Sleep(60e9)
		goto This
	}
	if string(buf) == "No this group!" {
		fmt.Printf("版本库找不到此分组:%s\n",group)
		os.Exit(1)
	}
	err = json.Unmarshal(buf,&list)
	if err != nil {
		fmt.Printf("%s 解析获取的版本消息错误: %s\n",err)
		time.Sleep(60e9)
		goto This
	}
	return list
}
init_var.go
package new

import (
	"encoding/json"
	"fmt"
	"io/IoUtil"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

var CmdPath string
var config ConfigJson
var Lock *sync.RWMutex = new(sync.RWMutex)
var CmdFuncMap *FuncMap

func Getconfig() *ConfigJson {
	Lock.RLock()
	defer Lock.RUnlock()
	return &config
}

func init() {
	err := parseConfig("cfg.json")
	if err != nil {
		os.Exit(1)
	}
	info,err := os.Lstat(Getconfig().CmdDirPath)
	CmdPath = Getconfig().CmdDirPath
	if err != nil || !info.IsDir() {
		fmt.Printf("校验目录失败: %s \n",err)
		err := initDir()
		if err != nil {
			os.Exit(1)
		}
		fmt.Printf("使用默认配置做根目录: %s\n",CmdPath)
	}
	initBaseCmdInfo(CmdPath)
	CmdFuncMap = &FuncMap{make(map[string]*ExecCmdInfo),new(sync.RWMutex)}
}

func parseConfig(configPath string) error {
	fmt.Printf("开始解析%s配置文件.",configPath)
	b,err := IoUtil.ReadFile(configPath)
	if err != nil {
		fmt.Printf("读取配置文件出错: %s\n",err)
		return err
	}
	err = json.Unmarshal(b,&config)
	if err != nil {
		fmt.Printf("解析配置出错: %s\n",err)
		return err
	}
	fmt.Println("解析配置文件成功: ",config)
	return nil
}

func initDir() error {
	fmt.Println("初始化默认路径.")
	p,err := os.Getwd()
	if err != nil {
		fmt.Printf("获取当前目录错误: %s\n",err)
		return err
	}
	info,err := os.Lstat("cmd")
	if err == nil && info.IsDir() {
		CmdPath = strings.Replace(p,`\`,`/`,20) + `/cmd`
		return nil
	}
	err = os.Mkdir("cmd",0644)
	if err != nil {
		fmt.Printf("初始化文件夹失败: %s\n",err)
		return err
	}
	CmdPath = strings.Replace(p,20) + `/cmd`
	return nil
}

func initBaseCmdInfo(path string) {
	fmt.Println("开始初始化本地命令...")
	err := filepath.Walk(path,run)
	if err != nil {
		fmt.Printf("%s 初始化命令列表出错: %s",err)
		os.Exit(1)
	}
	fmt.Println("初始化本地命令完成...")
}
run.go
package new

import (
	"fmt"
	"os/exec"
	"strings"
	"time"
)

func R() {
	if Getconfig().Debug {
		fmt.Printf("%s获取服务端版本!\n",GetNowTime())
	}
	list := GetVersion(Getconfig().Group)
	CmdFuncMap.Lock.Lock()
	for k,m := range CmdFuncMap.Map {
		if !Contain(k,list) {
			fmt.Printf("清除过期的命令:%s.\n",k)
			m.Exit <- true
			delete(CmdFuncMap.Map,k)
		}
	}
	CmdFuncMap.Lock.Unlock()
	for _,cmdVersion := range list {
		fmt.Println(cmdVersion)
		CmdFuncMap.Lock.RLock()
		k,ok := CmdFuncMap.Map[cmdVersion.Name]
		CmdFuncMap.Lock.RUnlock()
		if ok {
			if k.M5 == cmdVersion.Md5 {
				continue
			}
			loadcmdbaseinfo := LoadCmdBaseInfo{k.Name,k.Path,k.M5}
			go Update(loadcmdbaseinfo,cmdVersion)
			continue
		}
		cmd := index(cmdVersion)
		if cmd != nil {
			CmdFuncMap.Lock.Lock()
			CmdFuncMap.Map[cmd.Name] = cmd
			go cmd.Run()
			CmdFuncMap.Lock.Unlock()
		}
	}
}

func index(r RemoteVersionInfo) *ExecCmdInfo {
	if Getconfig().Debug {
		fmt.Printf("%s开始验证本地!\n",GetNowTime())
	}
	var g chan bool = make(chan bool,1)
	for _,v := range LocalCmdList {
		if v.Name == r.Name && v.Md5 == r.Md5 {
			return &ExecCmdInfo{r.Name,v.Path,r.Md5,r.Interval,split(r.Args),g}
		}
	}
	v := LoadCmdBaseInfo{r.Name,fmt.Sprintf("%s/%s",CmdPath,r.Name),r.Md5}
	go Update(v,r)
	return nil
}

func Update(v LoadCmdBaseInfo,r RemoteVersionInfo) {
	var url string = Getconfig().GetCmdAddr
	if !strings.HasSuffix(url,"/") {
		url = url + "/"
	}
	url = url + r.Name
	str := Download(r.Name,url)
	if str != strings.ToLower(r.Md5) {
		return
	}
	CmdFuncMap.Lock.Lock()
	defer CmdFuncMap.Lock.Unlock()
	k,ok := CmdFuncMap.Map[r.Name]
	if ok {
		k.Exit <- true
		time.Sleep(1e9)
	}
	if !MoveFile(fmt.Sprintf("%s/%s","tmp",v.Path) {
		return
	}
	var g chan bool = make(chan bool,1)
	E := &ExecCmdInfo{r.Name,g}
	CmdFuncMap.Map[r.Name] = E
	go E.Run()
}

func (this *ExecCmdInfo) Run() {
	fmt.Printf("%s 开始执行%s\n",this.Name)
	var exit bool = false
	go func() {
		b := <-this.Exit
		if b {
			exit = b
		}
	}()
	for {
		if exit {
			break
		}
		cmd := exec.Command(this.Path,this.Args...)
		//err := cmd.Run()
		b,err := cmd.Output()
		if err != nil {
			fmt.Printf("执行%s出错:%s\n",this.Name,err)
		}
		if Getconfig().Debug {
			fmt.Printf("命令%s结果:%s",string(b))
		}
		time.Sleep(time.Second * time.Duration(this.Interval))
	}
	fmt.Printf("%s 退出执行%s\n",this.Name)
}


type.go
package new

import "sync"

type ConfigJson struct {
	Group            string `json:group`
	CmdDirPath       string `json:cmddirpath`
	AutoUpdate       bool   `json:autoupdate`
	GetVersionServer string `json:vetversionserver`
	GetCmdAddr       string `json:getcmdaddr`
	Listen           string `json:listen`
	Debug            bool   `json:debug`
	Update           int    `json:update`
}

type RemoteVersionInfo struct {
	Name     string `json:name`
	Md5      string `json:md5`
	Interval int    `json:interval`
	Args     string `json:args`
}

type ExecCmdInfo struct {
	Name     string
	Path     string
	M5       string
	Interval int
	Args     []string
	Exit     chan bool
}

type LoadCmdBaseInfo struct {
	Name string
	Path string
	Md5  string
}

type FuncMap struct {
	Map  map[string]*ExecCmdInfo
	Lock *sync.RWMutex
}

usefunc.go
package new

import (
	"crypto/md5"
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

var LocalCmdList []LoadCmdBaseInfo

func run(path string,info os.FileInfo,err error) error {
	if err != nil {
		return err
	}
	if info.IsDir() {
		return nil
	}

	m5 := Md5(path)
	if m5 != "" {
		LocalCmdList = append(LocalCmdList,LoadCmdBaseInfo{info.Name(),path,m5})
	}
	return nil
}

func Md5(path string) string {
	File,err := os.Open(path)
	if err != nil {
		fmt.Printf("%s 校验%s的md5出错:%s\n",err)
		return ""
	}
	M := md5.New()
	io.Copy(M,File)
	b := M.Sum([]byte{})
	return fmt.Sprintf("%x",b)
}

func GetNowTime() string {
	return time.Now().Format("2006-01-02 15:04:05")
}

func Download(name,url string) string {
	resp,err := http.Get(url)
	fmt.Printf("开始下载:%s\n",url)
	if err != nil || resp.StatusCode != 200 {
		fmt.Printf("%s 下载%s出错: %s\n",url,err)
		return ""
	}
	os.Mkdir("tmp",0644)
	defer resp.Body.Close()
	name = "tmp/" + name
	File,err := os.Create(name)
	if err != nil {
		fmt.Printf("%s 创建文件%s错误: %s\n",name,err)
		return ""
	}
	io.Copy(File,resp.Body)
	File.Close()
	return Md5(name)
}
func split(str string) []string {
	var l []string
	list := strings.Split(str," ")
	for _,v := range list {
		if len(v) == 0 {
			continue
		}
		if strings.Contains(v,"	") {
			list := strings.Split(v,"	")
			for _,v := range list {
				if len(v) == 0 {
					continue
				}
				l = append(l,v)
			}
			continue
		}
		l = append(l,v)
	}
	return l
}

func MoveFile(s,d string) bool {
	fmt.Println(s,d)
	sFile,err := os.Open(s)
	if err != nil {
		fmt.Printf("移动文件%s出错:%s\n",s,err)
		return false
	}
	defer sFile.Close()
	dFile,err := os.Create(d)
	if err != nil {
		fmt.Printf(" 新建文件%s出错:%s\n",err)
		return false
	}
	defer dFile.Close()
	io.Copy(dFile,sFile)
	return true
}

func Contain(k string,list []RemoteVersionInfo) bool {
	for _,v := range list {
		if k == v.Name {
			return true
		}
	}
	return false
}


下面是入口函数:

main.go

package main

import (
	"fmt"
	"new"
	"time"
)

func main() {
	j := new.Getconfig()
	go func() {
		for {
			new.R()
			time.Sleep(time.Second * time.Duration(j.Update))
		}
	}()
	select {}
}
下面是:实例的配置文件:cfg.json
{"Group":"gyc",
"CmdDirPath":"D:/code/201508221",
"AutoUpdate":true,
"GetVersionServer":"127.0.0.1:2789",
"GetCmdAddr":"http://127.0.0.1:1789/pkg/",
"Listen":":1789",
"Debug":true,
"Update":60}
原文链接:https://www.f2er.com/go/190088.html

猜你在找的Go相关文章