Просмотр исходного кода

golang 的工具类 初始版本

fly 1 год назад
Сommit
8ca67c377b
9 измененных файлов с 550 добавлено и 0 удалено
  1. 1 0
      .gitignore
  2. 9 0
      algorithm/checksum/checksum.go
  3. 23 0
      algorithm/checksum/crc/modbus.go
  4. 36 0
      algorithm/hash/sha.go
  5. 54 0
      config/config.go
  6. 164 0
      files/file.go
  7. 35 0
      go.mod
  8. 66 0
      go.sum
  9. 162 0
      protocol/mqtt/mqtt.go

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+vendor/

+ 9 - 0
algorithm/checksum/checksum.go

@@ -0,0 +1,9 @@
+package checksum
+
+func Xor(buf []byte, len int) byte {
+	temp := buf[0]
+	for i := 1; i < len; i++ {
+		temp ^= buf[i]
+	}
+	return temp
+}

+ 23 - 0
algorithm/checksum/crc/modbus.go

@@ -0,0 +1,23 @@
+package crc
+
+func ModbusCrc16(data []byte, len int) uint16 {
+	var crc uint16 = 0xFFFF
+	var polynomial uint16 = 0xA001
+
+	if len == 0 {
+		return 0
+	}
+
+	for i := 0; i < len; i++ {
+		crc ^= uint16(data[i]) & 0x00FF
+		for j := 0; j < 8; j++ {
+			if (crc & 0x0001) != 0 {
+				crc >>= 1
+				crc ^= polynomial
+			} else {
+				crc >>= 1
+			}
+		}
+	}
+	return crc
+}

+ 36 - 0
algorithm/hash/sha.go

@@ -0,0 +1,36 @@
+package sha
+
+import (
+	"crypto/hmac"
+	"crypto/md5"
+	"crypto/sha1"
+	"crypto/sha256"
+	"fmt"
+	"io"
+)
+
+func ComputeSHA1(data string) string {
+	t := sha1.New()
+	_, _ = io.WriteString(t, data)
+	return fmt.Sprintf("%x", t.Sum(nil))
+}
+
+func ComputeMD5(data string) string {
+	t := md5.New()
+	_, _ = io.WriteString(t, data)
+	return fmt.Sprintf("%x", t.Sum(nil))
+}
+
+func ComputeHmacSha256(message string, secret string) string {
+	key := []byte(secret)
+	h := hmac.New(sha256.New, key)
+	h.Write([]byte(message))
+	return fmt.Sprintf("%x", h.Sum(nil))
+}
+
+func ComputeSha256(message string) []byte {
+	p := []byte(message)
+	h := sha256.New()
+	h.Write(p)
+	return h.Sum(nil)
+}

+ 54 - 0
config/config.go

@@ -0,0 +1,54 @@
+package config
+
+import (
+	"github.com/spf13/viper"
+)
+
+type any interface{}
+
+func init() {
+	//引入viper配置文件
+	viper.SetConfigName("iot-master") //name := lib.AppName()
+	viper.SetConfigType("yaml")
+	viper.AddConfigPath(".")
+	//viper.SetEnvPrefix("database")
+
+	//绑定命令行参数
+	//_ = viper.BindPFlags(pflag.CommandLine)
+
+	//数据目录
+	viper.SetDefault("data", "data")
+}
+
+func Load() error {
+	return viper.ReadInConfig()
+}
+
+func Store() error {
+	return viper.SafeWriteConfig()
+}
+
+func Register(module string, key string, value any) {
+	viper.SetDefault(module+"."+key, value)
+}
+
+func GetBool(module string, key string) bool {
+	return viper.GetBool(module + "." + key)
+}
+
+func GetString(module string, key string) string {
+	return viper.GetString(module + "." + key)
+}
+
+func GetInt(module string, key string) int {
+	return viper.GetInt(module + "." + key)
+}
+
+func GetFloat(module string, key string) float64 {
+	return viper.GetFloat64(module + "." + key)
+}
+
+func GetStringSlice(module string, key string) []string {
+	return viper.GetStringSlice(module + "." + key)
+
+}

+ 164 - 0
files/file.go

@@ -0,0 +1,164 @@
+package files
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+)
+
+// 按文件名排序,可扩展至文件时间
+type byName []os.FileInfo
+
+//func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() } // 文件名升序,默认方式
+func (f byName) Less(i, j int) bool { return f[i].Name() > f[j].Name() } // 文件名倒序
+func (f byName) Len() int           { return len(f) }
+func (f byName) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
+
+// GetFileListBySuffix returns an ordered list of file paths.
+// It recognize if given path is a file, and don't do recursive find.
+func GetFileListBySuffix(dirPath, suffix string, needDir bool, isDescend bool, num int) ([]string, error) {
+	if !IsExist(dirPath) {
+		return nil, fmt.Errorf("given path does not exist: %s", dirPath)
+	} else if IsFile(dirPath) {
+		return []string{dirPath}, nil
+	}
+
+	// Given path is a directory.
+	dir, err := os.Open(dirPath)
+	if err != nil {
+		return nil, err
+	}
+
+	fis, err := dir.Readdir(0)
+	if err != nil {
+		return nil, err
+	}
+
+	if isDescend {
+		sort.Sort(byName(fis))
+	}
+
+	if num == 0 {
+		num = len(fis)
+	}
+	files := make([]string, 0, num)
+	for i := 0; i < num; i++ {
+		fi := fis[i]
+		if strings.HasSuffix(fi.Name(), suffix) {
+			if needDir {
+				files = append(files, filepath.Join(dirPath, fi.Name()))
+			} else {
+				files = append(files, fi.Name())
+			}
+		}
+	}
+
+	return files, nil
+}
+
+// as GetFileListBySuffix, but for Prefix
+func GetFileListByPrefix(dirPath, suffix string, needDir bool, isDescend bool, num int) ([]string, error) {
+	if !IsExist(dirPath) {
+		return nil, fmt.Errorf("given path does not exist: %s", dirPath)
+	} else if IsFile(dirPath) {
+		return []string{dirPath}, nil
+	}
+
+	// Given path is a directory.
+	dir, err := os.Open(dirPath)
+	if err != nil {
+		return nil, err
+	}
+
+	fis, err := dir.Readdir(0)
+	if err != nil {
+		return nil, err
+	}
+
+	if isDescend {
+		sort.Sort(byName(fis))
+	}
+
+	if num == 0 {
+		num = len(fis)
+	}
+	files := make([]string, 0, num)
+	for i := 0; i < num; i++ {
+		fi := fis[i]
+		if strings.HasPrefix(fi.Name(), suffix) {
+			if needDir {
+				files = append(files, filepath.Join(dirPath, fi.Name()))
+			} else {
+				files = append(files, fi.Name())
+			}
+		}
+	}
+
+	return files, nil
+}
+
+// 根据关键字查找
+func GetFileListByKey(dirPath, key string, needDir bool, isDescend bool, num int) ([]string, error) {
+	if !IsExist(dirPath) {
+		return nil, fmt.Errorf("given path does not exist: %s", dirPath)
+	} else if IsFile(dirPath) {
+		return []string{dirPath}, nil
+	}
+
+	// Given path is a directory.
+	dir, err := os.Open(dirPath)
+	if err != nil {
+		return nil, err
+	}
+
+	fis, err := dir.Readdir(0)
+	if err != nil {
+		return nil, err
+	}
+
+	if isDescend {
+		sort.Sort(byName(fis))
+	}
+
+	if num == 0 {
+		num = len(fis)
+	}
+	files := make([]string, 0, num)
+	for i := 0; i < num; i++ {
+		fi := fis[i]
+		if strings.Contains(fi.Name(), key) {
+			if needDir {
+				files = append(files, filepath.Join(dirPath, fi.Name()))
+			} else {
+				files = append(files, fi.Name())
+			}
+		}
+	}
+
+	return files, nil
+}
+
+func IsDir(path string) bool {
+	s, err := os.Stat(path)
+	if err != nil {
+		return false
+	}
+	return s.IsDir()
+}
+
+func IsFile(path string) bool {
+	return !IsDir(path)
+}
+
+func IsExist(path string) bool {
+	_, err := os.Stat(path)
+	if err != nil {
+		if os.IsExist(err) {
+			return true
+		}
+		return false
+	}
+	return true
+}

+ 35 - 0
go.mod

@@ -0,0 +1,35 @@
+module onedev.familybaby.top/utils
+
+go 1.17
+
+require (
+	github.com/eclipse/paho.mqtt.golang v1.4.3
+	github.com/satori/go.uuid v1.2.0
+	github.com/sirupsen/logrus v1.9.3
+	github.com/spf13/viper v1.18.2
+)
+
+require (
+	github.com/fsnotify/fsnotify v1.7.0 // indirect
+	github.com/gorilla/websocket v1.5.0 // indirect
+	github.com/hashicorp/hcl v1.0.0 // indirect
+	github.com/magiconair/properties v1.8.7 // indirect
+	github.com/mitchellh/mapstructure v1.5.0 // indirect
+	github.com/pelletier/go-toml/v2 v2.1.0 // indirect
+	github.com/sagikazarmark/locafero v0.4.0 // indirect
+	github.com/sagikazarmark/slog-shim v0.1.0 // indirect
+	github.com/sourcegraph/conc v0.3.0 // indirect
+	github.com/spf13/afero v1.11.0 // indirect
+	github.com/spf13/cast v1.6.0 // indirect
+	github.com/spf13/pflag v1.0.5 // indirect
+	github.com/subosito/gotenv v1.6.0 // indirect
+	go.uber.org/atomic v1.9.0 // indirect
+	go.uber.org/multierr v1.9.0 // indirect
+	golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
+	golang.org/x/net v0.19.0 // indirect
+	golang.org/x/sync v0.5.0 // indirect
+	golang.org/x/sys v0.15.0 // indirect
+	golang.org/x/text v0.14.0 // indirect
+	gopkg.in/ini.v1 v1.67.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+)

+ 66 - 0
go.sum

@@ -0,0 +1,66 @@
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik=
+github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
+github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
+github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
+github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
+github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
+github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
+github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
+github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
+github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
+github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
+github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
+github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
+github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
+github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
+go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
+go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
+go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
+golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
+golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
+golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
+golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
+golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
+golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
+golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 162 - 0
protocol/mqtt/mqtt.go

@@ -0,0 +1,162 @@
+package mqtt
+
+import (
+	mqtts "github.com/eclipse/paho.mqtt.golang"
+	"github.com/satori/go.uuid"
+	"github.com/sirupsen/logrus"
+	"strconv"
+	"time"
+)
+
+var log = logrus.WithField("module", "mqtt")
+
+type MqttTopicStore struct {
+	qos byte
+	fun func(topic string, payload []byte)
+}
+type MqttClient struct {
+	Host     string                    //mqtt服务器地址
+	Port     int                       //mqtt 端口
+	Id       string                    //clientId
+	Username string                    //mqtt 登录用户名
+	Password string                    //mqtt 登录密码
+	Timeout  int                       //超时时间
+	Retry    int                       //重试次数
+	topics   map[string]MqttTopicStore //订阅的主题
+	client   mqtts.Client              //客户端
+}
+
+func NewMqttClient(host string, port int, username, password string) *MqttClient {
+	return &MqttClient{
+		Host:     host,
+		Port:     port,
+		Username: username,
+		Password: password,
+		Timeout:  30,
+		topics:   make(map[string]MqttTopicStore),
+		Retry:    3,
+	}
+}
+func NewMqttClientWithId(host string, port int, username, password, id string) *MqttClient {
+	return &MqttClient{
+		Host:     host,
+		Port:     port,
+		Username: username,
+		Password: password,
+		Id:       id,
+		Timeout:  30,
+		topics:   make(map[string]MqttTopicStore),
+		Retry:    3,
+	}
+}
+
+// 创建全局mqtt publish消息处理 handler
+var messagePubHandler mqtts.MessageHandler = func(client mqtts.Client, msg mqtts.Message) {
+	log.Debug("Push Message:")
+	log.Debug("TOPIC: %s\n", msg.Topic())
+	log.Debug("MSG: %s\n", msg.Payload())
+}
+
+// 创建全局mqtt sub消息处理 handler
+var messageSubHandler mqtts.MessageHandler = func(client mqtts.Client, msg mqtts.Message) {
+	log.Debug("收到订阅消息:")
+	log.Debug("Sub Client Topic : %s \n", msg.Topic())
+	log.Debug("Sub Client msg : %s \n", msg.Payload())
+}
+
+// 连接的回掉函数
+func (mqtt *MqttClient) connectHandler(client mqtts.Client) {
+	log.Debug("新的连接!" + " Connected")
+	for topic, st := range mqtt.topics {
+		mqtt.Subscribe(topic, st.qos, st.fun)
+	}
+}
+
+// 丢失连接的回掉函数
+var connectLostHandler mqtts.ConnectionLostHandler = func(client mqtts.Client, err error) {
+	log.Debug("Connect loss: %v\n", err)
+}
+
+func (mqtt *MqttClient) Connect() *MqttClient {
+	opts := mqtts.NewClientOptions().AddBroker("tcp://" + mqtt.Host + ":" + strconv.Itoa(mqtt.Port))
+	opts.SetKeepAlive(60 * time.Second)
+
+	id := uuid.NewV4()
+	// Message callback handler,在没有任何订阅时,发布端调用此函数
+	opts.SetDefaultPublishHandler(messagePubHandler)
+	opts.Username = mqtt.Username
+	opts.Password = mqtt.Password
+	opts.SetPingTimeout(60 * time.Second)
+	opts.OnConnect = mqtt.connectHandler
+	opts.OnConnectionLost = connectLostHandler
+	if len(mqtt.Id) == 0 {
+		opts.ClientID = id.String()
+	} else {
+		opts.ClientID = mqtt.Id
+	}
+	mqtt.client = mqtts.NewClient(opts)
+	if token := mqtt.client.Connect(); token.Wait() && token.Error() != nil {
+		panic(token.Error())
+	}
+
+	return mqtt
+}
+
+func (mqtt *MqttClient) Disconnect() {
+	mqtt.client.Disconnect(250)
+}
+
+func (mqtt *MqttClient) Publish(topic string, qos byte, payload interface{}) *MqttClient {
+	token := mqtt.client.Publish(topic, qos, false, payload)
+	token.Wait()
+	log.Debug("Push Data : "+topic, "Data Size is ", payload)
+
+	return mqtt
+}
+
+func (mqtt *MqttClient) Subscribe(topic string, qos byte, handleFun func(topic string, payload []byte)) bool {
+	// 订阅消息
+	if token := mqtt.client.Subscribe(topic, qos, func(client mqtts.Client, msg mqtts.Message) {
+		log.Debug("Receive Subscribe Message :")
+		log.Debug("Sub Client Topic : %s, Data size is  %d \n", msg.Topic(), len(msg.Payload()))
+
+		if len(msg.Payload()) > 0 {
+			handleFun(msg.Topic(), msg.Payload())
+		}
+	}); token.Wait() && token.Error() != nil {
+		log.Debug(token.Error())
+		return false
+	}
+
+	mqtt.topics[topic] = MqttTopicStore{qos, handleFun}
+	return true
+}
+
+func (mqtt *MqttClient) SubscribeMultiple(filters map[string]byte, handleFun func(topic string, payload []byte)) bool {
+
+	// 订阅消息
+	if token := mqtt.client.SubscribeMultiple(filters, func(client mqtts.Client, msg mqtts.Message) {
+		log.Debug("Receive Subscribe Message :")
+		log.Debug("Sub Client Topic : %s, Data size is  %d \n", msg.Topic(), len(msg.Payload()))
+
+		if len(msg.Payload()) > 0 {
+			handleFun(msg.Topic(), msg.Payload())
+		}
+	}); token.Wait() && token.Error() != nil {
+		log.Debug(token.Error())
+		return false
+	}
+
+	for k, v := range filters {
+		mqtt.topics[k] = MqttTopicStore{v, handleFun}
+	}
+	return true
+}
+
+func (mqtt *MqttClient) UnSubscripte(topic string) bool {
+	if token := mqtt.client.Unsubscribe(topic); token.Wait() && token.Error() != nil {
+		log.Debug(token.Error())
+		return false
+	}
+	return true
+}