Chuxin преди 6 месеца
родител
ревизия
3583c560a4
променени са 15 файла, в които са добавени 3289 реда и са изтрити 0 реда
  1. 45 0
      db.go
  2. 68 0
      handle_array.go
  3. 54 0
      handle_code.go
  4. 340 0
      handle_file.go
  5. 14 0
      handle_hash.go
  6. 312 0
      handle_linux.go
  7. 965 0
      handle_net.go
  8. 181 0
      handle_text.go
  9. 244 0
      handle_time.go
  10. 189 0
      handle_tools.go
  11. 124 0
      handle_typechange.go
  12. 209 0
      quote/uuid/codec.go
  13. 265 0
      quote/uuid/generator.go
  14. 162 0
      quote/uuid/uuid.go
  15. 117 0
      setting.go

+ 45 - 0
db.go

@@ -0,0 +1,45 @@
+package mokuai
+
+import (
+	"fmt"
+	"github.com/gohouse/converter"
+)
+
+//转换数据库schema到go struct
+//dsn 数据库格式:"user:password@/dbname 如 user:mima@tcp(127.0.0.1:3306)/dbname"
+//path 生成的结构体保存路径
+//pacName 生成struct的包名(默认为空的话, 则取名为: package model)
+func GormT(dsn string, path string, pacName string) bool {
+	// 初始化
+	t2t := converter.NewTable2Struct()
+	// 个性化配置
+	t2t.Config(&converter.T2tConfig{
+		// 如果字段首字母本来就是大写, 就不添加tag, 默认false添加, true不添加
+		RmTagIfUcFirsted: false,
+		// tag的字段名字是否转换为小写, 如果本身有大写字母的话, 默认false不转
+		TagToLower: false,
+		// 字段首字母大写的同时, 是否要把其他字母转换为小写,默认false不转换
+		UcFirstOnly: false,
+		//// 每个struct放入单独的文件,默认false,放入同一个文件(暂未提供)
+	})
+	// 开始迁移转换
+	err := t2t.
+		// 是否添加json tag
+		EnableJsonTag(true).
+		// 生成struct的包名(默认为空的话, 则取名为: package model)
+		PackageName(pacName).
+		// tag字段的key值,默认是orm
+		TagKey("gorm").
+		// 生成的结构体保存路径
+		SavePath(path).
+		// 数据库dsn,这里可以使用 t2t.DB() 代替,参数为 *sql.DB 对象
+		Dsn(dsn).
+		// 执行
+		Run()
+
+	if err != nil {
+		fmt.Println(err)
+		return false
+	}
+	return true
+}

+ 68 - 0
handle_array.go

@@ -0,0 +1,68 @@
+package mokuai
+
+import "fmt"
+
+// 删除数组/切片中的指定位置的元素
+func Array_DelIndex(array []string, i int) []string {
+	a := append(array[:i], array[i+1])
+	return a
+}
+
+// 判断元素是否在数组中存在
+func Array_InArray(one interface{}, arr interface{}) bool {
+	switch arr.(type) {
+	case []string:
+		tmp := map[string]string{}
+		a := one.(string)
+		b := arr.([]string)
+		blen := len(b)
+		for i := 0; i < blen; i++ {
+			tmp[b[i]] = "ok"
+		}
+		if tmp[a] == "ok" {
+			return true
+		}
+		break
+	case []int:
+		tmp := map[int]string{}
+		a := one.(int)
+		b := arr.([]int)
+		blen := len(b)
+		for i := 0; i < blen; i++ {
+			tmp[b[i]] = "ok"
+		}
+		if tmp[a] == "ok" {
+			return true
+		}
+		break
+	case []float32:
+		tmp := map[float32]string{}
+		a := one.(float32)
+		b := arr.([]float32)
+		blen := len(b)
+		for i := 0; i < blen; i++ {
+			tmp[b[i]] = "ok"
+		}
+		if tmp[a] == "ok" {
+			return true
+		}
+		break
+	case []float64:
+		tmp := map[float64]string{}
+		a := one.(float64)
+		b := arr.([]float64)
+		blen := len(b)
+		for i := 0; i < blen; i++ {
+			tmp[b[i]] = "ok"
+		}
+		if tmp[a] == "ok" {
+			return true
+		}
+		break
+	default:
+		fmt.Println("暂时不支持的类型")
+		return false
+	}
+
+	return false
+}

+ 54 - 0
handle_code.go

@@ -0,0 +1,54 @@
+package mokuai
+
+import (
+	"bytes"
+	"crypto/md5"
+	"encoding/hex"
+	"golang.org/x/text/encoding/simplifiedchinese"
+	"golang.org/x/text/transform"
+	"io/ioutil"
+)
+
+func Code_GetMd5(str string) string {
+	h := md5.New()
+	h.Write([]byte(str))
+	return hex.EncodeToString(h.Sum(nil))
+}
+
+func Code_GbkToUtf8(s string) (rs string) {
+	reader := transform.NewReader(bytes.NewReader([]byte(s)), simplifiedchinese.GBK.NewDecoder())
+	d, e := ioutil.ReadAll(reader)
+	if e != nil {
+		return ""
+	}
+	return string(d)
+}
+
+func Code_GbkToUtf8_byte(s []byte) ([]byte, error) {
+	reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewDecoder())
+	d, e := ioutil.ReadAll(reader)
+	if e != nil {
+		return nil, e
+	}
+	return d, nil
+}
+
+// Utf8 转 GBK (文本)
+func Code_Utf8ToGbk(s string) string {
+	reader := transform.NewReader(bytes.NewReader([]byte(s)), simplifiedchinese.GBK.NewEncoder())
+	d, e := ioutil.ReadAll(reader)
+	if e != nil {
+		return ""
+	}
+	return string(d)
+}
+
+// Utf8 转 GBK (byte)
+func Code_Utf8ToGbk_byte(s []byte) ([]byte, error) {
+	reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewEncoder())
+	d, e := ioutil.ReadAll(reader)
+	if e != nil {
+		return nil, e
+	}
+	return d, nil
+}

+ 340 - 0
handle_file.go

@@ -0,0 +1,340 @@
+package mokuai
+
+import (
+	"archive/zip"
+	"crypto/md5"
+	"encoding/hex"
+	"fmt"
+	"io"
+	"io/fs"
+	"io/ioutil"
+	"os"
+	"path"
+	"path/filepath"
+	"strings"
+)
+
+// 文件_文本写出
+func File_WriteStr(filepath string, textstr string) bool {
+	err := ioutil.WriteFile(filepath, []byte(textstr), 0644)
+	if err != nil {
+		return false
+	} else {
+		return true
+	}
+}
+
+// 文件_字节集写出
+func File_WriteByte(filepath string, dataByte []byte) bool {
+	err := ioutil.WriteFile(filepath, dataByte, 0644)
+	if err != nil {
+		return false
+	} else {
+		return true
+	}
+}
+
+// 文件_追加写入内容
+func File_WriteEndStr(filepath string, textstr string) bool {
+	f, err := os.OpenFile(filepath, os.O_CREATE|os.O_RDWR|os.O_APPEND, os.ModeAppend|os.ModePerm)
+	if err != nil {
+		return false
+	}
+	_, err = f.WriteString(textstr)
+	if err != nil {
+		return false
+	}
+	_ = f.Close()
+	return true
+}
+
+// 文件_文本读入,失败返回空
+func File_ReadStr(filepath string) (textstr string) {
+	fileobj, ok := ioutil.ReadFile(filepath)
+	if ok != nil {
+		textstr = ""
+	} else {
+		textstr = string(fileobj)
+	}
+	return
+}
+
+// 文件_字节集读入,失败返回 nil
+func File_ReadByte(filepath string) (dataByte []byte) {
+	fileobj, ok := ioutil.ReadFile(filepath)
+	if ok != nil {
+		dataByte = nil
+	} else {
+		dataByte = fileobj
+	}
+	return
+}
+
+// 文件_删除自身
+func File_Delself() bool {
+	epath, err := os.Executable()
+	if err != nil {
+		panic(err)
+	}
+	err = os.Remove(epath)
+	if err != nil {
+		return false
+	} else {
+		return true
+	}
+}
+
+// 取文件的MD5 。失败返回空
+func File_HashFileMd5(filePath string) (md5Str string) {
+	file, err := os.Open(filePath)
+	if err != nil {
+		md5Str = ""
+		return
+	}
+	defer file.Close()
+
+	hash := md5.New()
+	if _, err = io.Copy(hash, file); err != nil {
+		return
+	}
+	hashInBytes := hash.Sum(nil)[:16]
+	md5Str = hex.EncodeToString(hashInBytes)
+	return
+}
+
+// 判断所给路径是否为文件存在  true:存在 ; false:不存在
+func File_IsFile(path string) bool {
+	f, flag := File_IsExists(path)
+	return flag && !f.IsDir()
+}
+
+// 判断路径是否存在  true:存在 ; false:不存在
+func File_IsExists(path string) (os.FileInfo, bool) {
+	f, err := os.Stat(path)
+	return f, err == nil || os.IsExist(err)
+}
+
+// 判断所给路径是否为文件夹  true:存在 ; false:不存在
+func File_IsDir(path string) bool {
+	f, flag := File_IsExists(path)
+	return flag && f.IsDir()
+}
+
+// 判断文件或文件夹是否存在
+func Dir_IsExists(path string) (bool, error) {
+	_, err := os.Stat(path)
+	if err == nil {
+		return true, nil
+	}
+	if os.IsNotExist(err) {
+		return false, nil
+	}
+	return false, err
+}
+
+// 获取当前程序运行目录
+func File_Get_Current_Directory() string {
+	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
+	if err != nil {
+		fmt.Println(err)
+	}
+	return strings.Replace(dir, "\\", "/", -1)
+}
+
+// 获取当前程序运行绝对路径(包括文件名)
+func File_Get_Current_Path() string {
+	path, err := filepath.Abs(os.Args[0])
+	if err != nil {
+		fmt.Println(err)
+	}
+	return strings.Replace(path, "\\", "/", -1)
+}
+
+// 获取当前程序运行名称
+func File_Get_Current_Name() string {
+	name := filepath.Base(os.Args[0])
+	return name
+}
+
+// 创建文件夹 (可以递归创建目录)
+func Dir_Create(dirName string) bool {
+	err := os.MkdirAll(dirName, 0755)
+	if err != nil {
+		return false
+	} else {
+		return true
+	}
+}
+
+/*
+	复制文件
+
+srcFileName: 源文件路径  ;  dstFileName:目标文件路径
+*/
+func File_CopyFile(srcFileName string, dstFileName string) (ReErr string) {
+	//打开源文件
+	srcFile, err := os.Open(srcFileName)
+	if err != nil {
+		ReErr = "源文件读取失败,原因是:" + err.Error()
+		return
+	}
+	defer func() {
+		err = srcFile.Close()
+		if err != nil {
+			ReErr = "源文件关闭失败,原因是:" + err.Error()
+			return
+		}
+	}()
+
+	//创建目标文件,稍后会向这个目标文件写入拷贝内容
+	distFile, err := os.Create(dstFileName)
+	if err != nil {
+		ReErr = "目标文件创建失败,原因是:" + err.Error()
+		return
+	}
+	defer func() {
+		err = distFile.Close()
+		if err != nil {
+			ReErr = "目标文件关闭失败,原因是:" + err.Error()
+			return
+		}
+	}()
+	//定义指定长度的字节切片,每次最多读取指定长度
+	var tmp = make([]byte, 1024*4)
+	//循环读取并写入
+	for {
+		n, err := srcFile.Read(tmp)
+		n, _ = distFile.Write(tmp[:n])
+		if err != nil {
+			if err == io.EOF { //读到了文件末尾,并且写入完毕,任务完成返回(关闭文件的操作由defer来完成)
+				return
+			} else {
+				ReErr = "拷贝过程中发生错误,错误原因为:" + err.Error()
+				return
+			}
+		}
+	}
+}
+
+// 解压ZIP文件
+// Note that the destination directory don't need to specify the trailing path separator.
+func File_Unzip(zipPath, dstDir string) error {
+	// open zip file
+	reader, err := zip.OpenReader(zipPath)
+	if err != nil {
+		return err
+	}
+	defer reader.Close()
+	for _, file := range reader.File {
+		if err := unzipFile(file, dstDir); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func unzipFile(file *zip.File, dstDir string) error {
+	// create the directory of file
+	filePath := path.Join(dstDir, file.Name)
+	if file.FileInfo().IsDir() {
+		if err := os.MkdirAll(filePath, os.ModePerm); err != nil {
+			return err
+		}
+		return nil
+	}
+	if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
+		return err
+	}
+
+	// open the file
+	rc, err := file.Open()
+	if err != nil {
+		return err
+	}
+	defer rc.Close()
+
+	// create the file
+	w, err := os.Create(filePath)
+	if err != nil {
+		return err
+	}
+	defer w.Close()
+
+	// save the decompressed file content
+	_, err = io.Copy(w, rc)
+	return err
+}
+
+// Zip 压缩ZIP文件.
+// If a path is a dir don't need to specify the trailing path separator.
+// For example calling Zip("archive.zip", "dir", "csv/baz.csv") will get archive.zip and the content of which is
+// dir
+// |-- foo.txt
+// |-- bar.txt
+// baz.csv
+func File_Zip(zipPath string, paths ...string) error {
+	// create zip file
+	if err := os.MkdirAll(filepath.Dir(zipPath), os.ModePerm); err != nil {
+		return err
+	}
+	archive, err := os.Create(zipPath)
+	if err != nil {
+		return err
+	}
+	defer archive.Close()
+
+	// new zip writer
+	zipWriter := zip.NewWriter(archive)
+	defer zipWriter.Close()
+
+	// traverse the file or directory
+	for _, srcPath := range paths {
+		// remove the trailing path separator if path is a directory
+		srcPath = strings.TrimSuffix(srcPath, string(os.PathSeparator))
+
+		// visit all the files or directories in the tree
+		err = filepath.Walk(srcPath, func(path string, info fs.FileInfo, err error) error {
+			if err != nil {
+				return err
+			}
+
+			// create a local file header
+			header, err := zip.FileInfoHeader(info)
+			if err != nil {
+				return err
+			}
+
+			// set compression
+			header.Method = zip.Deflate
+
+			// set relative path of a file as the header name
+			header.Name, err = filepath.Rel(filepath.Dir(srcPath), path)
+			if err != nil {
+				return err
+			}
+			if info.IsDir() {
+				header.Name += string(os.PathSeparator)
+			}
+
+			// create writer for the file header and save content of the file
+			headerWriter, err := zipWriter.CreateHeader(header)
+			if err != nil {
+				return err
+			}
+			if info.IsDir() {
+				return nil
+			}
+			f, err := os.Open(path)
+			if err != nil {
+				return err
+			}
+			defer f.Close()
+			_, err = io.Copy(headerWriter, f)
+			return err
+		})
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}

+ 14 - 0
handle_hash.go

@@ -0,0 +1,14 @@
+package mokuai
+
+import (
+	"crypto/hmac"
+	"crypto/sha256"
+	"encoding/base64"
+)
+
+// Sha256 加密
+func Hash_hmacSha256_en(stringToSign string, secret string) string {
+	h := hmac.New(sha256.New, []byte(secret))
+	h.Write([]byte(stringToSign))
+	return base64.StdEncoding.EncodeToString(h.Sum(nil))
+}

+ 312 - 0
handle_linux.go

@@ -0,0 +1,312 @@
+package mokuai
+
+import (
+	"fmt"
+	"net"
+	"os/exec"
+	"regexp"
+	"runtime"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// 网速使用
+type Net_dev struct {
+	Ifc_bytes_r   float64 //1  Receive接收(下行)字节数 ,单位 Byte  。 1Byte(B)=8bit(b)
+	Ifc_packets_r float64 //2   接收的正确包量
+	Ifc_bytes_t   float64 //9  Transmit发出(上行)字节数 ,单位 Byte 。 1Byte(B)=8bit(b)
+	Ifc_packets_t float64 //10  发出的正确包量
+	Ifc_bytes_r_a int64   //  Receive接收(下行)总字节数(总流量) ,单位 Byte  。 1Byte(B)=8bit(b)
+	Ifc_bytes_t_a int64   //  Transmit发出(下行)总字节数(总流量) ,单位 Byte  。 1Byte(B)=8bit(b)
+}
+
+// 获取机器唯一UUID ID
+func OS_Linux_GetUuid() string {
+	return File_ReadStr("/sys/class/dmi/id/product_uuid")
+}
+
+// 获取linux版本
+func OS_Linux_GetLinuxVersion() string {
+	return File_ReadStr("/proc/version")
+}
+
+// linux下运行shell指令 仅支持一行
+func OS_Linux_RunSh(args ...string) string {
+	cmdStr := strings.Join(args, " ")
+	//	fmt.Println("cmdStr  >",cmdStr)
+	cmd := exec.Command("/bin/bash", "-c", cmdStr)
+	opBytes, err := cmd.Output()
+	//	fmt.Print("cmdStr  ",opBytes,string(opBytes))
+	if err != nil {
+		if err.Error() == "exit status 1" {
+			return Text_DelOuterSpace(string(opBytes))
+		} else {
+			return "Error:" + string(err.Error())
+		}
+
+	}
+	return Text_DelOuterSpace(string(opBytes))
+}
+
+// linux下运行shell指令 仅支持一行 带错误输出
+func OS_Linux_RunShWithErr(args ...string) (text, errText string) {
+	cmdStr := strings.Join(args, " ")
+	//	fmt.Println("cmdStr  >",cmdStr)
+	cmd := exec.Command("/bin/bash", "-c", cmdStr)
+	var out bytes.Buffer
+	var stderr bytes.Buffer
+	cmd.Stdout = &out
+	cmd.Stderr = &stderr
+	err := cmd.Run()
+	if err != nil {
+		return Text_DelOuterSpace(out.String()), err.Error() + "\n" + stderr.String()
+	} else {
+		return Text_DelOuterSpace(out.String()), ""
+	}
+}
+
+// 获取linux默认出口网卡名
+func OS_Linux_GetDefNet() string {
+	lin := OS_Linux_RunSh("ip route |grep 'default'")
+	lin = Text_GetBetween(lin, "dev ", " ")
+	return lin
+}
+
+// 获取Linux 唯一不变机器sn  默认网卡、系统UUID相关联
+func OS_Linux_GetSn() string {
+	a, _ := net.InterfaceByName(OS_Linux_GetDefNet())
+	HardwareAddr := a.HardwareAddr.String()
+	SwSecret := "yw"
+	//	fmt.Println("-->HardwareAddr:", HardwareAddr+"-->GetUuid:"+GetUuid()+"-->SwSecret:"+SwSecret)
+	return Code_GetMd5(OS_Linux_GetUuid() + SwSecret + HardwareAddr)
+}
+
+// 获取linux当前内存使用率
+// memTotal : 内存总量,单位 Byte(B) ;   used : 当前使用率,单位% ;   used_true : 当前实际使用率,单位%
+func OS_Linux_MemGetRate() (memTotal, used, used_true string) {
+	a := File_ReadStr("/proc/meminfo")
+	r, _ := regexp.Compile("(MemTotal|MemFree|Buffers|Cached):.*")
+	b := r.FindAllString(a, 4)
+	r, _ = regexp.Compile("[0-9]+")
+	memTotal = r.FindString(b[0])
+	MemTotal, _ := strconv.ParseFloat(r.FindString(b[0]), 64)
+	MemFree, _ := strconv.ParseFloat(r.FindString(b[1]), 64)
+	Buffers, _ := strconv.ParseFloat(r.FindString(b[2]), 64)
+	Cached, _ := strconv.ParseFloat(r.FindString(b[3]), 64)
+
+	//有5%的误差
+	MemAvailable := (MemFree + Buffers + Cached) * 0.95
+
+	Used := fmt.Sprintf("%.2f", (1-MemFree/MemTotal)*100)
+
+	TrueUsed := fmt.Sprintf("%.2f", (1-MemAvailable/MemTotal)*100)
+
+	return memTotal, Used, TrueUsed
+}
+
+// 获取linux当前CPU使用率 。 s 秒 间隔的时间长度
+func OS_Linux_CpuGetRate(s int) string {
+	if s < 1 {
+		s = 1
+	}
+	c1 := File_ReadStr("/proc/stat")
+	r, _ := regexp.Compile("cpu .*")
+	c1 = r.FindString(c1)
+
+	time.Sleep(time.Duration(s) * time.Second)
+
+	c2 := File_ReadStr("/proc/stat")
+	c2 = r.FindString(c2)
+
+	tmp1 := []string{}
+	tmp2 := []string{}
+	tmp1 = strings.Fields(c1)
+	tmp2 = strings.Fields(c2)
+	var c1_total, c2_total, c1_free, c2_free float64
+	c1_total, c2_total, c1_free, c2_free = 0, 0, 0, 0
+	var c_tmp, c_tmp2 float64
+
+	for i := 0; i < len(tmp1); i++ {
+		c_tmp, _ = strconv.ParseFloat(tmp1[i], 64)
+		c_tmp2, _ = strconv.ParseFloat(tmp2[i], 64)
+		c1_total += c_tmp
+		c2_total += c_tmp2
+	}
+	c1_free, _ = strconv.ParseFloat(tmp1[4], 64)
+	c2_free, _ = strconv.ParseFloat(tmp2[4], 64)
+
+	idle := (c2_free - c1_free) / (c2_total - c1_total)
+	used := (1 - idle) * 100
+	return fmt.Sprintf("%.3f", used)
+}
+
+// 获取linux当前CPU核数
+func OS_Linux_CpuGetNum() string {
+	a := runtime.NumCPU()
+	return strconv.Itoa(a)
+}
+
+/*
+	获取linux CPU信息
+
+返回值: CpuModel:CPU型号  ; CpuPHY:物理cpu个数 ; CpuCores: CPU核数 ; CpuThread: CPU(逻辑)线程数
+*/
+func OS_Linux_Cpu_info() (CpuModel string, CpuPHY, CpuCores, CpuThread int) {
+	a1 := File_ReadStr("/proc/cpuinfo")
+	cpuPHY_zu := []string{}
+	cpuCores_zu := []string{}
+	cpuThread_zu := []string{}
+	linzu := Text_GetSplitText(a1, "\n")
+
+	for _, v := range linzu {
+		if v == "" {
+			continue
+		}
+		// CPU 型号
+		if Text_FindKeyword(Text_GetLeftText(v, ":"), "model name") != -1 {
+			CpuModel = strings.TrimSpace(Text_GetRightText(v, ":"))
+			continue
+		}
+		if Text_FindKeyword(Text_GetLeftText(v, ":"), "physical id") != -1 {
+			s := 0
+			for _, v1 := range cpuPHY_zu {
+				if v1 == strings.TrimSpace(Text_GetRightText(v, ":")) {
+					s = 1
+					break
+				}
+			}
+			if s == 0 {
+				cpuPHY_zu = append(cpuPHY_zu, strings.TrimSpace(Text_GetRightText(v, ":")))
+			}
+			continue
+		}
+		if Text_FindKeyword(Text_GetLeftText(v, ":"), "cpu cores") != -1 {
+			s := 0
+			for _, v1 := range cpuCores_zu {
+				if v1 == strings.TrimSpace(Text_GetRightText(v, ":")) {
+					s = 1
+					break
+				}
+			}
+			if s == 0 {
+				cpuCores_zu = append(cpuCores_zu, strings.TrimSpace(Text_GetRightText(v, ":")))
+			}
+			continue
+		}
+
+		if Text_FindKeyword(Text_GetLeftText(v, ":"), "siblings") != -1 {
+			s := 0
+			for _, v1 := range cpuThread_zu {
+				if v1 == strings.TrimSpace(Text_GetRightText(v, ":")) {
+					s = 1
+					break
+				}
+			}
+			if s == 0 {
+				cpuThread_zu = append(cpuThread_zu, strings.TrimSpace(Text_GetRightText(v, ":")))
+			}
+			continue
+		}
+
+	}
+
+	// 整理
+
+	CpuPHY = len(cpuPHY_zu)
+
+	all := 0
+	for _, v := range cpuCores_zu {
+		i, _ := strconv.Atoi(v)
+		all += i
+	}
+
+	CpuCores = all
+
+	all = 0
+	for _, v := range cpuThread_zu {
+		i, _ := strconv.Atoi(v)
+		all += i
+	}
+
+	CpuThread = all
+
+	return
+}
+
+// 获取linux当前系统负载系数。 返回格式: 1、5、15分钟内的平均进程数,正在运行的进程数/进程总数,最近运行的进程ID号  (0.00 0.02 0.01 1/201 24781)
+func OS_Linux_GetSystemAvg() string {
+	return File_ReadStr("/proc/loadavg")
+}
+
+// 获取linux当前tcp连接数
+func OS_Linux_GetTcp() string {
+	str := File_ReadStr("/proc/net/tcp")
+	i := strings.Count(str, "\n")
+	return strconv.Itoa(i)
+}
+
+// 获取linux当前udp连接数
+func OS_Linux_GetUdp() string {
+	str := File_ReadStr("/proc/net/udp")
+	i := strings.Count(str, "\n")
+	return strconv.Itoa(i)
+}
+
+// 获取linux实时网速 。 s 秒 间隔的时间长度 ,返回网卡及对应的上下行实时流量 .返回单位见 Net_dev
+func Os_Linux_NetRealSpeed(s int) (inter map[string]Net_dev) {
+	if s < 1 {
+		s = 1
+	}
+	a1 := File_ReadStr("/proc/net/dev")
+	rt := make(map[string]Net_dev)
+	rt2 := make(map[string]Net_dev)
+	var nt Net_dev
+
+	tmp := strings.Split(a1, "\n")
+	tmp2 := []string{}
+	for i := 2; i < len(tmp); i++ {
+		tmp2 = strings.Fields(tmp[i])
+		//	fmt.Println("tmp2",tmp2)
+		if len(tmp2) > 0 {
+			nt.Ifc_bytes_r, _ = strconv.ParseFloat(tmp2[1], 64)
+			nt.Ifc_packets_r, _ = strconv.ParseFloat(tmp2[2], 64)
+			nt.Ifc_bytes_t, _ = strconv.ParseFloat(tmp2[9], 64)
+			nt.Ifc_packets_t, _ = strconv.ParseFloat(tmp2[10], 64)
+			tmp2[0] = strings.Replace(tmp2[0], ":", "", 1)
+			rt[tmp2[0]] = nt
+		}
+	}
+
+	time.Sleep(time.Duration(s) * time.Second)
+	s1 := float64(s)
+	a2 := File_ReadStr("/proc/net/dev")
+	tmp = strings.Split(a2, "\n")
+	tmp2 = []string{}
+	for i := 2; i < len(tmp); i++ {
+		tmp2 = strings.Fields(tmp[i])
+		if len(tmp2) > 0 {
+
+			nt.Ifc_bytes_r, _ = strconv.ParseFloat(tmp2[1], 64)
+			nt.Ifc_packets_r, _ = strconv.ParseFloat(tmp2[2], 64)
+			nt.Ifc_bytes_t, _ = strconv.ParseFloat(tmp2[9], 64)
+			nt.Ifc_packets_t, _ = strconv.ParseFloat(tmp2[10], 64)
+			i64, _ := strconv.ParseInt(tmp2[1], 10, 64)
+			nt.Ifc_bytes_r_a = i64
+			i64, _ = strconv.ParseInt(tmp2[9], 10, 64)
+			nt.Ifc_bytes_t_a = i64
+			tmp2[0] = strings.Replace(tmp2[0], ":", "", 1)
+			rt2[tmp2[0]] = nt
+		}
+	}
+	inter = make(map[string]Net_dev)
+	for k := range rt {
+		Ifc_bytes_r := (rt2[k].Ifc_bytes_r - rt[k].Ifc_bytes_r) / s1 / 1024
+		Ifc_packets_r := (rt2[k].Ifc_packets_r - rt[k].Ifc_packets_r) / s1
+		Ifc_bytes_t := (rt2[k].Ifc_bytes_t - rt[k].Ifc_bytes_t) / s1 / 1024
+		Ifc_packets_t := (rt2[k].Ifc_packets_t - rt[k].Ifc_packets_t) / s1
+		inter[k] = Net_dev{Ifc_bytes_r: Ifc_bytes_r, Ifc_packets_r: Ifc_packets_r, Ifc_bytes_t: Ifc_bytes_t, Ifc_packets_t: Ifc_packets_t, Ifc_bytes_r_a: rt2[k].Ifc_bytes_r_a, Ifc_bytes_t_a: rt2[k].Ifc_bytes_t_a}
+	}
+
+	return inter
+}

+ 965 - 0
handle_net.go

@@ -0,0 +1,965 @@
+package mokuai
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"github.com/tidwall/gjson"
+	"golang.org/x/net/proxy"
+	"io"
+	"io/ioutil"
+	"math/big"
+	"net"
+	"net/http"
+	"net/url"
+	"os"
+	"strings"
+	"time"
+)
+
+// Get ,失败返回空
+func Net_UrlGet(url string) string {
+
+	// 超时时间:20秒
+	client := &http.Client{Timeout: 20 * time.Second}
+	resp, err := client.Get(url)
+	if err != nil {
+		panic(err)
+		return ""
+	}
+	defer func() {
+		if e := recover(); e != nil {
+			fmt.Printf("Panicing %s\r\n", e)
+		}
+		resp.Body.Close()
+	}()
+	var buffer [512]byte
+	result := bytes.NewBuffer(nil)
+	for {
+		n, err := resp.Body.Read(buffer[0:])
+		result.Write(buffer[0:n])
+		if err != nil && err == io.EOF {
+			break
+		} else if err != nil {
+			panic(err)
+		}
+	}
+
+	return result.String()
+}
+
+// Get ,返回字节集 ,失败返回空. outtime 超时时间(s)
+func Net_UrlGetByte(url string, outtime int) []byte {
+
+	// 默认超时时间:5秒
+	if outtime < 1 {
+		outtime = 5
+	}
+	client := &http.Client{Timeout: time.Duration(outtime) * time.Second}
+	resp, err := client.Get(url)
+	if err != nil {
+		panic(err)
+		return []byte("")
+	}
+	defer func() {
+		if e := recover(); e != nil {
+			fmt.Printf("Panicing %s\r\n", e)
+		}
+		resp.Body.Close()
+	}()
+	var buffer [512]byte
+	result := bytes.NewBuffer(nil)
+	for {
+		n, err := resp.Body.Read(buffer[0:])
+		result.Write(buffer[0:n])
+		if err != nil && err == io.EOF {
+			break
+		} else if err != nil {
+			panic(err)
+		}
+	}
+
+	return result.Bytes()
+}
+
+// Post ,返回文本型 。请求data为json格式
+func Net_UrlPostJson_Str(url string, data interface{}, contentType string) string {
+
+	// 超时时间:10秒
+	client := &http.Client{Timeout: 10 * time.Second}
+	jsonStr, _ := json.Marshal(data)
+	resp, err := client.Post(url, contentType, bytes.NewBuffer(jsonStr))
+	if err != nil {
+		panic(err)
+	}
+	defer func() {
+		if e := recover(); e != nil {
+			fmt.Printf("Panicing %s\r\n", e)
+		}
+		resp.Body.Close()
+	}()
+	//	_ = resp.Body.Close()
+
+	result, _ := ioutil.ReadAll(resp.Body)
+	return string(result)
+}
+
+// Post ,返回文本型 。请求data为普通data
+func Net_UrlPostStr_Str(url string, data string, contentType string) string {
+
+	// 超时时间:10秒
+	client := &http.Client{Timeout: 10 * time.Second}
+	resp, err := client.Post(url, contentType, bytes.NewBuffer([]byte(data)))
+	if err != nil {
+		panic(err)
+	}
+	defer func() {
+		if e := recover(); e != nil {
+			fmt.Printf("Panicing %s\r\n", e)
+		}
+		resp.Body.Close()
+	}()
+	//	_ = resp.Body.Close()
+
+	result, _ := ioutil.ReadAll(resp.Body)
+	return string(result)
+}
+
+// Post ,返回字节集 。 失败返回空字节集
+func Net_UrlPostJson_Byte(url string, data interface{}, contentType string) []byte {
+
+	// 超时时间:20秒
+	client := &http.Client{Timeout: 20 * time.Second}
+	jsonStr, _ := json.Marshal(data)
+	resp, err := client.Post(url, contentType, bytes.NewBuffer(jsonStr))
+	if err != nil {
+		panic(err)
+		return []byte("")
+	}
+	defer func() {
+		if e := recover(); e != nil {
+			fmt.Printf("Panicing %s\r\n", e)
+		}
+		resp.Body.Close()
+	}()
+	result, _ := ioutil.ReadAll(resp.Body)
+	return result
+}
+
+// Post ,返回字节集 。请求data为普通data
+func Net_UrlPostStr_Byte(url string, data string, contentType string) []byte {
+
+	// 超时时间:20秒
+	client := &http.Client{Timeout: 20 * time.Second}
+	resp, err := client.Post(url, contentType, bytes.NewBuffer([]byte(data)))
+	if err != nil {
+		panic(err)
+	}
+	defer func() {
+		if e := recover(); e != nil {
+			fmt.Printf("Panicing %s\r\n", e)
+		}
+		resp.Body.Close()
+	}()
+	result, _ := ioutil.ReadAll(resp.Body)
+	return result
+}
+
+// 获取指定网卡名的网卡ip , 只输出ipv4 ,没有返回空。 返回格式 xx.xx.xx.xx/xx
+func Net_GetIPmaskByName(intername string) string {
+	byName, _ := net.InterfaceByName(intername)
+	addresses, _ := byName.Addrs()
+	for _, vv := range addresses {
+		if strings.IndexAny(vv.String(), ".") != -1 {
+			return vv.String()
+		}
+
+	}
+	return ""
+}
+
+// 获取指定网卡名的网卡ip , 只输出ipv4 ,没有返回空。 返回格式 xx.xx.xx.xx
+func Net_GetIPByName(intername string) string {
+	byName, _ := net.InterfaceByName(intername)
+	addresses, _ := byName.Addrs()
+	for _, vv := range addresses {
+		if strings.IndexAny(vv.String(), ".") != -1 {
+			comma := strings.Index(vv.String(), "/")
+			return vv.String()[:comma]
+		}
+
+	}
+	return ""
+}
+
+// 把Post请求过来的 data 输出显示
+func Net_DebugPostData(c *gin.Context) {
+	data, _ := c.GetRawData()
+	fmt.Printf("Post Data: %v\n", string(data))
+	c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data))
+}
+
+// 获取本服务器IP
+func Net_Getmyfwqip() (ipwai, ipnei string) {
+	addrs, err := net.InterfaceAddrs()
+
+	if err != nil {
+		fmt.Println("Net_Getmyfwqip Err:", err)
+		os.Exit(1)
+	}
+
+	for _, address := range addrs {
+
+		// 检查ip地址判断是否回环地址
+		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+			if ipnet.IP.To4() != nil {
+				//		fmt.Println("ip:", ipnet.IP.String())
+				if Net_IsPublicIP(ipnet.IP) == true {
+					//				fmt.Println("公网IP:"+ipnet.IP.String())
+					ipwai = ipnet.IP.String()
+				} else if Net_Isothernet(ipnet.IP) == false {
+					//				fmt.Println("内网IP:"+ipnet.IP.String())
+					ipnei = ipnet.IP.String()
+				} else {
+					//				fmt.Println("Open IP:"+ipnet.IP.String())
+				}
+
+			}
+
+		}
+	}
+
+	return
+}
+
+// 判断是否为公网ip
+func Net_IsPublicIP(IP net.IP) bool {
+	if IP.IsLoopback() || IP.IsLinkLocalMulticast() || IP.IsLinkLocalUnicast() {
+		return false
+	}
+	if ip4 := IP.To4(); ip4 != nil {
+		switch true {
+		case ip4[0] == 10:
+			return false
+		case ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31:
+			return false
+		case ip4[0] == 192 && ip4[1] == 168:
+			return false
+		default:
+			return true
+		}
+	}
+	return false
+}
+
+// 判断是否是open/169网段
+func Net_Isothernet(IP net.IP) bool {
+	if ip4 := IP.To4(); ip4 != nil {
+		switch true {
+		case ip4[0] == 150:
+			if ip4[1] == 33 {
+				return true
+			} else {
+				return false
+			}
+		case ip4[0] == 169:
+			if ip4[1] == 254 {
+				return true
+			} else {
+				return false
+			}
+		default:
+			return false
+		}
+	}
+	return true
+}
+
+// 获取本服务器IP_接口方式 主海外
+func Net_Getmyip_api() (ip, area string) {
+	s := Net_UrlGet("http://myip.zzznb.cc")
+	ip = gjson.Get(s, "ip").Str
+	if ip == "" {
+		res, _ := http.Get("http://tom.myip.top")
+		s, _ := ioutil.ReadAll(res.Body)
+		ip = gjson.Get(string(s), "ip").Str
+	}
+	if ip == "" {
+		res, _ := http.Get("http://ky.myip.top")
+		s, _ := ioutil.ReadAll(res.Body)
+		ip = gjson.Get(string(s), "ip").Str
+	}
+	area = gjson.Get(s, "country").Str + " " + gjson.Get(s, "province").Str + " " + gjson.Get(s, "city").Str + " " + gjson.Get(s, "isp").Str
+
+	return
+}
+
+/*
+使用HTTP代理GET访问(可以设置超时时间)
+urlstr 要访问的URL
+prxyurl 代理服务器地址
+outtime 超时时长,单位 秒
+
+返回
+body:接收的数据
+err:错误信息
+*/
+func Net_UrlProxyGet(urlstr, proxy string, outtime int) (body []byte, err error) {
+	urli := url.URL{}
+	var proxylin string
+	if strings.Index(proxy, "http://") == -1 {
+		proxylin = "http://" + proxy
+	} else {
+		proxylin = proxy
+	}
+
+	urlproxy, _ := urli.Parse(proxylin)
+	client := &http.Client{
+		Timeout: time.Second * time.Duration(outtime),
+		Transport: &http.Transport{
+			Proxy: http.ProxyURL(urlproxy),
+		},
+	}
+	var rqt *http.Request
+	rqt, err = http.NewRequest("GET", urlstr, nil)
+	if err != nil {
+		return
+	}
+
+	//	rqt.Header.Add("User-Agent", "xxx")
+	//处理返回结果
+	var response *http.Response
+	response, err = client.Do(rqt)
+	if response != nil {
+		defer response.Body.Close()
+	}
+
+	if err != nil {
+		return []byte(""), err
+	}
+
+	body, err = ioutil.ReadAll(response.Body)
+	defer func() {
+		if e := recover(); e != nil {
+			fmt.Printf("Panicing %s\r\n", e)
+		}
+	}()
+	return
+}
+
+/*
+使用Socks5代理GET访问
+urlstr 要访问的URL
+outtime 超时时长,单位 秒
+prxyurl 代理服务器地址
+
+返回
+body:接收的数据
+err:错误信息
+*/
+func Net_UrlProxyS5Get(urlstr string, outtime int, prxyurl, user, passwd string) (body []byte, err error) {
+	//urltmp, _ := url.Parse(prxyurl)
+	var authtmp proxy.Auth
+	authtmp.User = user
+	authtmp.Password = passwd
+	dialer, err := proxy.SOCKS5("tcp", prxyurl, &authtmp, proxy.Direct) //开启socks5连接
+	if err != nil {
+		//fmt.Println("socks5连接出错%v", err)
+		return
+	}
+
+	client := &http.Client{
+		Timeout: time.Second * time.Duration(outtime),
+		Transport: &http.Transport{
+			Dial: dialer.Dial,
+		},
+	}
+	var rqt *http.Request
+	rqt, err = http.NewRequest("GET", urlstr, nil)
+	if err != nil {
+		return
+	}
+
+	//	rqt.Header.Add("User-Agent", "xxx")
+	//处理返回结果
+	var response *http.Response
+	response, err = client.Do(rqt)
+	if response != nil {
+		defer response.Body.Close()
+	}
+
+	defer func() {
+		if e := recover(); e != nil {
+			fmt.Printf("Panicing %s\r\n", e)
+		}
+	}()
+
+	if err != nil {
+		return
+	}
+
+	body, err = ioutil.ReadAll(response.Body)
+	return
+}
+
+/*
+使用HTTP代理POST访问(可以设置超时时间)
+urlstr 要访问的URL
+data POST数据
+prxyurl 代理服务器地址
+outtime 超时时长,单位 秒
+headers 协议头 如	headers := make(map[string]string)
+
+	headers["Content-Type"] = "application/json;charset=utf-8"
+	headers["token"] = token
+	headers["Connection"] = "keep-alive"
+	headers["Accept"] = "*\/*"   去掉\
+	headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36"
+	headers["X-Requested-With"] = "XMLHttpRequest"
+	headers["Referer"] = "http://www.xxxx.com/"
+
+返回
+body:接收的数据
+err:错误信息
+Recookies 返回的Cookies
+*/
+func Net_UrlProxyPost(urlstr, data, proxy string, outtime int, headers map[string]string) (body []byte, err error, Recookies []*http.Cookie) {
+	urli := url.URL{}
+	var proxylin string
+	if strings.Index(proxy, "http://") == -1 {
+		proxylin = "http://" + proxy
+	} else {
+		proxylin = proxy
+	}
+
+	urlproxy, _ := urli.Parse(proxylin)
+	client := &http.Client{
+		Timeout: time.Second * time.Duration(outtime),
+		Transport: &http.Transport{
+			Proxy: http.ProxyURL(urlproxy),
+		},
+	}
+	var rqt *http.Request
+	rqt, err = http.NewRequest("POST", urlstr, bytes.NewReader([]byte(data)))
+	if err != nil {
+		return
+	}
+
+	for key, header := range headers {
+		rqt.Header.Set(key, header)
+	}
+
+	//	rqt.Header.Add("User-Agent", "xxx")
+	//处理返回结果
+	var response *http.Response
+	response, err = client.Do(rqt)
+	if response != nil {
+		defer response.Body.Close()
+	}
+
+	defer func() {
+		if e := recover(); e != nil {
+			fmt.Printf("Panicing %s\r\n", e)
+		}
+	}()
+
+	if err != nil {
+		return []byte(""), err, nil
+	}
+	Recookies = response.Cookies()
+	body, err = ioutil.ReadAll(response.Body)
+	return
+}
+
+/*
+使用HTTP代理GET访问 功能扩展版(可以设置超时时间、cookies、协议头)
+urlstr 要访问的URL
+prxyurl 代理服务器地址
+outtime 超时时长,单位 秒
+cookies 请求使用的Cookies,
+headers 协议头 如	headers := make(map[string]string)
+
+	headers["Content-Type"] = "application/json;charset=utf-8"
+	headers["token"] = token
+
+返回
+body:接收的数据
+err:错误信息
+*/
+func Net_UrlProxyGet_EX(urlstr, proxy string, cookies []*http.Cookie, outtime int, headers map[string]string) (body []byte, err error, Recookies []*http.Cookie) {
+	urli := url.URL{}
+	var proxylin string
+	if strings.Index(proxy, "http://") == -1 {
+		proxylin = "http://" + proxy
+	} else {
+		proxylin = proxy
+	}
+
+	urlproxy, _ := urli.Parse(proxylin)
+	client := &http.Client{
+		Timeout: time.Second * time.Duration(outtime),
+
+		Transport: &http.Transport{
+			Proxy:                 http.ProxyURL(urlproxy),
+			ResponseHeaderTimeout: time.Second * time.Duration(outtime),
+		},
+	}
+	var rqt *http.Request
+	rqt, err = http.NewRequest("GET", urlstr, nil)
+	if err != nil {
+		fmt.Println("Get -2 >", err.Error())
+		return []byte(""), err, nil
+	}
+
+	if cookies != nil {
+		for i := 0; i < len(cookies); i++ {
+			rqt.AddCookie(cookies[i])
+		}
+	}
+
+	if headers != nil {
+		for key, header := range headers {
+			rqt.Header.Set(key, header)
+		}
+	}
+
+	//	rqt.Header.Add("User-Agent", "xxx")
+	//处理返回结果
+	var response *http.Response
+	response, err = client.Do(rqt)
+	if response != nil {
+		defer response.Body.Close()
+	}
+
+	if err != nil {
+		fmt.Println("Get -3 >", err.Error())
+		return
+	} else {
+		Recookies = response.Cookies()
+		//	defer response.Body.Close()
+		body, err = ioutil.ReadAll(response.Body)
+	}
+
+	defer func() {
+		if e := recover(); e != nil {
+			fmt.Printf("Panicing %s\r\n", e)
+		}
+
+	}()
+	return
+}
+
+/*// Cookies转换, string 转 []*cookie
+func Net_CookieStrToCook(str string) (CookieZu []*http.Cookie) {
+	s1 := strings.Split(str, ";")
+	for i,v := range s1 {
+		comma := strings.Index(str, ";")
+		name := str[:comma]
+		value := str[comma+len(";"):]
+		c := &http.Cookie{
+			Name:  name,
+			Value: value,
+			Raw:   line,
+		}
+		if name != "" {
+			CookieZu
+		}
+	}
+}*/
+
+// Cookies转换, []*cookie 转 string
+func Net_CookieCookToStr(CookieZu []*http.Cookie) string {
+	lin := ""
+	for _, v := range CookieZu {
+		if v.Raw != "" {
+			lin = lin + v.Raw + ";"
+		}
+	}
+	return lin
+}
+
+/*
+	Net_Url_EX
+
+使用HTTP访问(可以设置代理/超时时间/Cookie/请求类型/协议头等) . V 1.0.2    2022.4.8
+methed [选]
+urlstr [必]要访问的URL
+data [选]POST数据
+proxy [选]代理服务器地址 . 为空则不使用代理 。 账密代理格式  {proxyUrl:proxyPort}@{proxyUser}:{proxyPass}  例如 127.0.0.1:8888@user:password; 仅代理格式 {proxyUrl:proxyPort}  例如 127.0.0.1:8888
+cookies [选]传入访问使用的Cookies . 为空则不使用
+outtime [选]超时时长,单位 秒 ,默认6秒
+headers [选]协议头 如	headers := make(map[string]string)
+
+	headers["Content-Type"] = "application/json;charset=utf-8"
+	headers["token"] = token
+	headers["Connection"] = "keep-alive"
+	headers["Accept"] = "*\/*"   去掉\
+	headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36"
+	headers["X-Requested-With"] = "XMLHttpRequest"
+	headers["Referer"] = "http://www.xxxx.com/"
+
+autoredirect [选]是否自动重定向,  1:自动处理 ; 2.不处理 ; 默认为0:自动处理
+返回
+body:接收的数据 , (字符串方式 string(body))
+err:错误信息
+Recookies 返回的Cookies 。 可以配合 Net_CookieCookToStr 使用
+*/
+func Net_Url_EX(methed, urlstr, data, proxy, cookies string, outtime int, headers map[string]string, autoredirect int) (body []byte, err error, ReCookies string, ReHeader http.Header) {
+	if methed == "" || len(methed) < 2 {
+		methed = "GET"
+	}
+	if outtime < 1 {
+		outtime = 6
+	}
+
+	var client *http.Client
+	if proxy == "" {
+		client = &http.Client{
+			Timeout: time.Second * time.Duration(outtime),
+		}
+	} else {
+
+		urli := url.URL{}
+		var proxyUrl, proxyUser, proxyPass string
+		if !strings.Contains(proxy, "http") {
+			proxy = fmt.Sprintf("http://%s", proxy)
+		}
+		if strings.Index(proxy, "@") == -1 { // 仅代理URL方式
+			proxyUrl = proxy
+		} else {
+			comma := strings.Index(proxy, "@")
+			proxyUrl = proxy[:comma]
+			lin := proxy[comma+len("@"):]
+			if len(lin) > 0 {
+				if strings.Index(lin, ":") == -1 {
+					proxyUser = lin
+					proxyPass = ""
+				} else {
+					comma = strings.Index(lin, ":")
+					proxyUser = lin[:comma]
+					proxyPass = lin[comma+len(":"):]
+				}
+			}
+		}
+		urlProxy, _ := urli.Parse(proxyUrl)
+		if proxyUser != "" && proxyPass != "" {
+			urlProxy.User = url.UserPassword(proxyUser, proxyPass)
+		}
+		client = &http.Client{
+			Timeout: time.Second * time.Duration(outtime),
+			Transport: &http.Transport{
+				Proxy: http.ProxyURL(urlProxy),
+			},
+		}
+	}
+
+	var rqt *http.Request
+	rqt, err = http.NewRequest(methed, urlstr, bytes.NewReader([]byte(data)))
+	if err != nil {
+		return
+	}
+
+	if len(headers) == 0 { // 判断是否需要自动补充基本协议头
+		rqt.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36")
+	} else {
+		for key, header := range headers {
+			rqt.Header.Set(key, header)
+		}
+	}
+
+	if len(cookies) > 1 {
+		rqt.Header.Add("Cookie", cookies)
+	}
+
+	if autoredirect == 2 { // 处理重定向使用
+		client.CheckRedirect = func(rqt *http.Request, via []*http.Request) error {
+			return http.ErrUseLastResponse
+		}
+	}
+
+	//	rqt.Header.Add("User-Agent", "xxx")
+	//处理返回结果
+	var response *http.Response
+	response, err = client.Do(rqt)
+	if response != nil {
+		defer func(Body io.ReadCloser) {
+			err := Body.Close()
+			if err != nil {
+				fmt.Println("client.Do Err > " + err.Error())
+			}
+		}(response.Body)
+	}
+
+	defer func() {
+		if e := recover(); e != nil {
+			fmt.Printf("Panicing %s\r\n", e)
+		}
+	}()
+
+	if err != nil {
+		return []byte(""), err, "", nil
+	}
+	cooklin := response.Cookies()
+	for _, v := range cooklin {
+		ReCookies = ReCookies + v.Raw + ";"
+	}
+
+	ReHeader = response.Header.Clone()
+	body, err = ioutil.ReadAll(response.Body)
+	return
+}
+
+// cookies 合并更新,返回合并后的Cookies
+func Net_CookieAndUp(oldCookies, newCookies string) string {
+
+	linzu := strings.Split(oldCookies, ";")
+	linzu1 := strings.Split(newCookies, ";")
+	lin := ""
+	for _, v := range linzu {
+		n := -1
+		comma := strings.Index(v, "=")
+		for i1, v1 := range linzu1 {
+			if strings.Index(v, "=") != -1 && strings.Index(v1, "=") != -1 {
+				comma1 := strings.Index(v1, "=")
+				if v[:comma] == v1[:comma1] {
+					lin = lin + v1 + ";"
+					linzu1[i1] = ""
+					n = 1
+					break
+				}
+			}
+		}
+
+		if n == -1 {
+			lin = lin + v
+		}
+	}
+
+	for _, v := range linzu1 {
+		if v != "" {
+			lin = lin + v + ";"
+		}
+	}
+
+	return lin
+}
+
+// 获取URL中的域名 (非根域名)
+func Net_GetDomain(url string) (domain string) {
+	var lin string
+	if strings.Index(url, "http://") != -1 {
+		comma := strings.Index(url, "http://")
+		lin = url[comma+len("http://"):]
+	} else if strings.Index(url, "https://") != -1 {
+		comma := strings.Index(url, "https://")
+		lin = url[comma+len("https://"):]
+	} else {
+		lin = url
+	}
+
+	if strings.Index(lin, "/") != -1 {
+		comma := strings.Index(lin, "/")
+		lin = lin[:comma]
+	}
+
+	// 过滤掉端口
+	if strings.Index(lin, ":") != -1 {
+		comma := strings.Index(lin, ":")
+		lin = lin[:comma]
+	}
+
+	return lin
+}
+
+// IP长整数型转字符串IP
+func Net_IPNtoA(ip int64) string {
+	return fmt.Sprintf("%d.%d.%d.%d",
+		byte(ip>>24), byte(ip>>16), byte(ip>>8), byte(ip))
+}
+
+// IP字符串型转长整数IP
+func Net_IPAtoN(ip string) int64 {
+	ret := big.NewInt(0)
+	ret.SetBytes(net.ParseIP(ip).To4())
+	return ret.Int64()
+}
+
+// Net_downloadFile 会将url下载到本地文件,它会在下载时写入,而不是将整个文件加载到内存中。
+// url  文件下载的网址
+// filepath 文件保存的路径,包含文件名
+func Net_downloadFile(url string, filepath string) (bool, error) {
+
+	// Get the data
+	resp, err := http.Get(url)
+	if err != nil {
+		return false, err
+	}
+	defer resp.Body.Close()
+
+	// Create output file
+	out, err := os.Create(filepath)
+	if err != nil {
+		return false, err
+	}
+	defer out.Close()
+
+	// copy stream
+	_, err = io.Copy(out, resp.Body)
+	if err != nil {
+		return false, err
+	}
+
+	return true, nil
+}
+
+// 取下载连接地址的文件名,通过URL获取
+func Net_GetUrlFileName(url string) (fileName string) {
+	lin := url
+	for true {
+		if strings.Index(lin, "/") != -1 {
+			comma := strings.Index(lin, "/")
+			lin = lin[comma+len("/"):]
+		} else {
+			break
+		}
+	}
+
+	if strings.Index(lin, "?") != -1 {
+		comma := strings.Index(lin, "?")
+		lin = lin[:comma]
+	}
+	fileName = lin
+	return
+}
+
+/*
+	Net_Url_S5_EX
+
+使用Socks5访问(可以设置代理/超时时间/Cookie/请求类型/协议头等) . V 1.0.0    2022.7.14
+methed [选]
+urlstr [必]要访问的URL
+data [选]POST数据
+proxy [选]代理服务器地址 . 为空则不使用代理 。 账密代理格式  {proxyUrl:proxyPort}@{proxyUser}:{proxyPass}  例如 127.0.0.1:8888@user:password; 仅代理格式 {proxyUrl:proxyPort}  例如 127.0.0.1:8888
+cookies [选]传入访问使用的Cookies . 为空则不使用
+outtime [选]超时时长,单位 秒 ,默认6秒
+headers [选]协议头 如	headers := make(map[string]string)
+
+	headers["Content-Type"] = "application/json;charset=utf-8"
+	headers["token"] = token
+	headers["Connection"] = "keep-alive"
+	headers["Accept"] = "*\/*"   去掉\
+	headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36"
+	headers["X-Requested-With"] = "XMLHttpRequest"
+	headers["Referer"] = "http://www.xxxx.com/"
+
+autoredirect [选]是否自动重定向,  1:自动处理 ; 2.不处理 ; 默认为0:自动处理
+返回
+body:接收的数据 , (字符串方式 string(body))
+err:错误信息
+Recookies 返回的Cookies 。 可以配合 Net_CookieCookToStr 使用
+*/
+func Net_Url_S5_EX(methed, urlstr, data, proxy, cookies string, outtime int, headers map[string]string, autoredirect int) (body []byte, err error, ReCookies string, ReHeader http.Header) {
+	if methed == "" || len(methed) < 2 {
+		methed = "GET"
+	}
+	if outtime < 1 {
+		outtime = 6
+	}
+
+	var client *http.Client
+	if proxy == "" {
+		client = &http.Client{
+			Timeout: time.Second * time.Duration(outtime),
+		}
+	} else {
+
+		urli := url.URL{}
+		var proxyUrl, proxyUser, proxyPass string
+		if !strings.Contains(proxy, "socks5") {
+			proxy = fmt.Sprintf("socks5://%s", proxy)
+		}
+		if strings.Index(proxy, "@") == -1 { // 仅代理URL方式
+			proxyUrl = proxy
+		} else {
+			comma := strings.Index(proxy, "@")
+			proxyUrl = proxy[:comma]
+			lin := proxy[comma+len("@"):]
+			if len(lin) > 0 {
+				if strings.Index(lin, ":") == -1 {
+					proxyUser = lin
+					proxyPass = ""
+				} else {
+					comma = strings.Index(lin, ":")
+					proxyUser = lin[:comma]
+					proxyPass = lin[comma+len(":"):]
+				}
+			}
+		}
+		urlProxy, _ := urli.Parse(proxyUrl)
+		if proxyUser != "" && proxyPass != "" {
+			urlProxy.User = url.UserPassword(proxyUser, proxyPass)
+		}
+		client = &http.Client{
+			Timeout: time.Second * time.Duration(outtime),
+			Transport: &http.Transport{
+				Proxy: http.ProxyURL(urlProxy),
+			},
+		}
+	}
+
+	var rqt *http.Request
+	rqt, err = http.NewRequest(methed, urlstr, bytes.NewReader([]byte(data)))
+	if err != nil {
+		return
+	}
+
+	if len(headers) == 0 { // 判断是否需要自动补充基本协议头
+		rqt.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4664.110 Safari/537.36")
+	} else {
+		for key, header := range headers {
+			rqt.Header.Set(key, header)
+		}
+	}
+
+	if len(cookies) > 1 {
+		rqt.Header.Add("Cookie", cookies)
+	}
+
+	if autoredirect == 2 { // 处理重定向使用
+		client.CheckRedirect = func(rqt *http.Request, via []*http.Request) error {
+			return http.ErrUseLastResponse
+		}
+	}
+
+	//	rqt.Header.Add("User-Agent", "xxx")
+	//处理返回结果
+	var response *http.Response
+	response, err = client.Do(rqt)
+	if response != nil {
+		defer func(Body io.ReadCloser) {
+			err := Body.Close()
+			if err != nil {
+				fmt.Println("client.Do Err > " + err.Error())
+			}
+		}(response.Body)
+	}
+
+	defer func() {
+		if e := recover(); e != nil {
+			fmt.Printf("Panicing %s\r\n", e)
+		}
+	}()
+
+	if err != nil {
+		return []byte(""), err, "", nil
+	}
+	cooklin := response.Cookies()
+	for _, v := range cooklin {
+		ReCookies = ReCookies + v.Raw + ";"
+	}
+
+	ReHeader = response.Header.Clone()
+	body, err = ioutil.ReadAll(response.Body)
+	return
+}

+ 181 - 0
handle_text.go

@@ -0,0 +1,181 @@
+package mokuai
+
+import (
+	"fmt"
+	"math"
+	"math/rand"
+	"strconv"
+	"strings"
+	"time"
+	"unicode"
+	"unicode/utf8"
+)
+
+//文本_取中间
+func Text_GetBetween(str, start, end string) string {
+	n := strings.Index(str, start)
+	if n == -1 {
+		n = 0
+	} else {
+		n = n + len(start) // 增加了else,不加的会把start带上
+	}
+	str = string([]byte(str)[n:])
+	m := strings.Index(str, end)
+	if m == -1 {
+		m = len(str)
+	}
+	str = string([]byte(str)[:m])
+	return str
+}
+
+//文本_寻找文本是否存在,不存在返回-1
+func Text_FindKeyword(str, keyword string) int {
+	return strings.Index(str, keyword)
+}
+
+//取随机数  参数说明: [num 返回随机数的位数]
+func Text_GetRandNum(num int) string {
+	//将时间戳设置成种子数
+	rand.Seed(time.Now().UnixNano())
+	//生成10个0-99之间的随机数
+	str := ""
+	for i := 0; i < num; i++ {
+		str = str + Type_IntToString(rand.Intn(9))
+	}
+	return str
+}
+
+//取范围内随机数  参数说明: [min 最小值;max 最大值; 返回随机数的位数]
+func Text_GetRandNumInRange(min, max int64) int64 {
+	rand.Seed(time.Now().UnixNano())
+	if min >= max || min == 0 || max == 0 {
+		return max
+	}
+	return rand.Int63n(max-min) + min
+}
+
+// 取字符串中汉字出现的数量
+func Text_GetCNWordsNum(str string) int {
+	hzc := 0
+	for _, v := range str {
+		if unicode.Is(unicode.Han, v) {
+			hzc++
+		}
+	}
+	return hzc
+}
+
+// 取字符串个数
+func Text_GetStrNum(str string) int {
+	return utf8.RuneCountInString(str)
+}
+
+// 以关键词分割文本
+func Text_GetSplitText(str, keywords string) []string {
+	s1 := strings.Split(str, keywords)
+	return s1
+
+}
+
+// 去除字符串首位空格
+func Text_DelOuterSpace(str string) string {
+	return strings.TrimSpace(str)
+}
+
+// 文本替换  (文本,旧的准备替换掉的文本,新的要替换成的文本,替换多少次 n<0为全部替换 )
+func Text_Replace(str, old, new string, n int) string {
+	return strings.Replace(str, old, new, n)
+}
+
+// 文本取左边 (取关键词左边的文本)
+func Text_GetLeftText(str, keywords string) string {
+	comma := strings.Index(str, keywords)
+	return str[:comma]
+}
+
+// 文本取右边 (取关键词右边的文本)
+func Text_GetRightText(str, keywords string) string {
+	comma := strings.Index(str, keywords)
+	return str[comma+len(keywords):]
+}
+
+// 删除关键词文本所在行 (待删除的文本,删除次数(-1为不限制,删除的包含关键词种类的次数)  。返回删除后的内容)
+func Text_DelKeywordline(str, keyword string, n int) string {
+	linzu := strings.Split(str, "\n")
+	lin := str
+	n1 := 0
+	for _, v := range linzu {
+		if strings.Index(v, keyword) != -1 {
+			lin = strings.ReplaceAll(lin, v+"\n", "")
+			if n1 >= n {
+				break
+			}
+			n1++
+		}
+
+	}
+	return lin
+}
+
+// 数 四舍五入 (value 要整理的值,bit 保留几位小数)
+func Num_round45(value float64, bit int) float64 {
+	n10 := math.Pow10(bit)
+	v := math.Trunc((value+0.5/n10)*n10) / n10
+	return v
+}
+
+/* 文本替换指定序数文本 。 如 一段文本内有3处 exit 0 , 那么可以指定仅替换 第二处的exit 0 ,其余不变。
+str : 原文本  ;  old : 欲被替换的子文本1  ; new : 用作替换的子文本1  ;  n : 指定替换的序数*/
+func Text_ReplaceNth(str, old, new string, n int) string {
+	i := 0
+	for m := 1; m <= n; m++ {
+		x := strings.Index(str[i:], old)
+		if x < 0 {
+			break
+		}
+		i += x
+		if m == n {
+			return str[:i] + new + str[i+len(old):]
+		}
+		i += len(old)
+	}
+	return str
+}
+
+// 随机获取国内IP
+func Text_GetRandCNIp() string { // 国内部分IP
+	rand.Seed(time.Now().UnixNano())
+	ipzu := make(map[int]string)
+	ipzu[1] = "607649792,608174079"     //36.56.0.0-36.63.255.255
+	ipzu[2] = "1038614528,1039007743"   //106.80.0.0-106.95.255.255
+	ipzu[3] = "1783627776,1784676351"   //121.76.0.0-121.77.255.255
+	ipzu[4] = "2078801920,2079064063"   //123.232.0.0-123.235.255.255
+	ipzu[5] = "-1950089216,-1948778497" //139.196.0.0-139.215.255.255
+	ipzu[6] = "-1425539072,-1425014785" //171.8.0.0-171.15.255.255
+	ipzu[7] = "-1236271104,-1235419137" //182.80.0.0-182.92.255.255
+	ipzu[8] = "-770113536,-768606209"   //210.25.0.0-210.47.255.255
+	ipzu[9] = "-569376768,-564133889"   //222.16.0.0-222.95.255.255
+
+	rand_key := int(rand.Int63n(9-1) + 1)
+	rand_ip := ipzu[rand_key]
+	fmt.Println("rand_ip", rand_ip)
+	comma := strings.Index(rand_ip, ",")
+	min, _ := strconv.ParseInt(rand_ip[:comma], 10, 64)
+	max, _ := strconv.ParseInt(rand_ip[comma+len(","):], 10, 64)
+	fmt.Println("min", min, "max", max)
+	if min >= max || min == 0 || max == 0 {
+		return Net_IPNtoA(max)
+	}
+	rand.Seed(time.Now().UnixNano() + rand.Int63n(3))
+	ip := Net_IPNtoA(rand.Int63n(max-min) + min)
+	return ip
+
+	//return long2ip(mt_rand($ip_long[$rand_key][0], $ip_long[$rand_key][1]));
+}
+
+// 随机获取IP  ,可能包含内网IP
+func Text_GetRandIp() string {
+	rand.Seed(time.Now().Unix())
+	ip := fmt.Sprintf("%d.%d.%d.%d", rand.Intn(255), rand.Intn(255), rand.Intn(255), rand.Intn(255))
+	return ip
+}

+ 244 - 0
handle_time.go

@@ -0,0 +1,244 @@
+package mokuai
+
+import (
+	"strconv"
+	"time"
+)
+
+// 时间戳 转 字符串 。 OutForm 输出格式 整数型      可空。 0=N年N月N日 N时N分N秒 1=年-月-日 时:分:秒 2=年/月/日 时/分/秒 3=年月日时分秒
+// OutType 取出类型 整数型      可空。-1=全部 + PM(12小时制) ,0=全部,1=只取年月日,2=取月日,3=只取时分秒,4=时分,5=分秒,6=只取年,7=只取月,8=只取日,9=只取时,10=只取分,11=只取秒
+func Time_TimestampToTimeStr(timestamp string, OutForm, OutType int) string {
+	i64, _ := strconv.ParseInt(timestamp, 10, 64)
+	tm := time.Unix(i64, 0)
+	if OutForm == 0 {
+		if OutType == 0 {
+			return tm.Format("2006年01月02日 15时04分05秒")
+		} else if OutType == 1 {
+			return tm.Format("2006年01月02日")
+		} else if OutType == 2 {
+			return tm.Format("01月02日")
+		} else if OutType == 3 {
+			return tm.Format("15时04分05秒")
+		} else if OutType == 4 {
+			return tm.Format("15时04分")
+		} else if OutType == 5 {
+			return tm.Format("04分05秒")
+		} else if OutType == 6 {
+			return tm.Format("2006年")
+		} else if OutType == 7 {
+			return tm.Format("01月")
+		} else if OutType == 8 {
+			return tm.Format("02日")
+		} else if OutType == 9 {
+			return tm.Format("15时")
+		} else if OutType == 10 {
+			return tm.Format("04分")
+		} else if OutType == 11 {
+			return tm.Format("05秒")
+		}
+	} else if OutForm == 1 {
+		if OutType == 0 {
+			return tm.Format("2006-01-02 15:04:05")
+		} else if OutType == 1 {
+			return tm.Format("2006-01-02")
+		} else if OutType == 2 {
+			return tm.Format("01-02")
+		} else if OutType == 3 {
+			return tm.Format("15:04:05")
+		} else if OutType == 4 {
+			return tm.Format("15:04")
+		} else if OutType == 5 {
+			return tm.Format("04:05")
+		} else if OutType == 6 {
+			return tm.Format("2006")
+		} else if OutType == 7 {
+			return tm.Format("01")
+		} else if OutType == 8 {
+			return tm.Format("02")
+		} else if OutType == 9 {
+			return tm.Format("15")
+		} else if OutType == 10 {
+			return tm.Format("04")
+		} else if OutType == 11 {
+			return tm.Format("05")
+		}
+	} else if OutForm == 2 {
+		if OutType == 0 {
+			return tm.Format("2006/01/02 15/04/05")
+		} else if OutType == 1 {
+			return tm.Format("2006/01/02")
+		} else if OutType == 2 {
+			return tm.Format("01/02")
+		} else if OutType == 3 {
+			return tm.Format("15/04/05")
+		} else if OutType == 4 {
+			return tm.Format("15/04")
+		} else if OutType == 5 {
+			return tm.Format("04/05")
+		} else if OutType == 6 {
+			return tm.Format("2006")
+		} else if OutType == 7 {
+			return tm.Format("01")
+		} else if OutType == 8 {
+			return tm.Format("02")
+		} else if OutType == 9 {
+			return tm.Format("15")
+		} else if OutType == 10 {
+			return tm.Format("04")
+		} else if OutType == 11 {
+			return tm.Format("05")
+		}
+	} else if OutForm == 3 {
+		if OutType == 0 {
+			return tm.Format("20060102 150405")
+		} else if OutType == 1 {
+			return tm.Format("20060102")
+		} else if OutType == 2 {
+			return tm.Format("0102")
+		} else if OutType == 3 {
+			return tm.Format("150405")
+		} else if OutType == 4 {
+			return tm.Format("1504")
+		} else if OutType == 5 {
+			return tm.Format("0405")
+		} else if OutType == 6 {
+			return tm.Format("2006")
+		} else if OutType == 7 {
+			return tm.Format("01")
+		} else if OutType == 8 {
+			return tm.Format("02")
+		} else if OutType == 9 {
+			return tm.Format("15")
+		} else if OutType == 10 {
+			return tm.Format("04")
+		} else if OutType == 11 {
+			return tm.Format("05")
+		}
+	} else {
+		return tm.Format("2006-01-02 15:04:05 PM")
+	}
+
+	return tm.Format("2006-01-02 03:04:05 PM")
+}
+
+// 取当前时间戳 ,10位
+func Time_GetNowTimestamp() int {
+	return int(time.Now().Unix())
+}
+
+// 取当前时间 文本型
+// OutForm 输出格式 整数型      可空。 0=N年N月N日 N时N分N秒 1=年-月-日 时:分:秒 2=年/月/日 时/分/秒 3=年月日时分秒
+// OutType 取出类型 整数型      可空。 -1=全部 + PM(12小时制) ,0=全部,1=只取年月日,2=取月日,3=只取时分秒,4=时分,5=分秒,6=只取年,7=只取月,8=只取日,9=只取时,10=只取分,11=只取秒
+func Time_GetNowTimeStr(OutForm, OutType int) string {
+	tm := time.Now()
+	if OutForm == 0 {
+		if OutType == 0 {
+			return tm.Format("2006年01月02日 15时04分05秒")
+		} else if OutType == 1 {
+			return tm.Format("2006年01月02日")
+		} else if OutType == 2 {
+			return tm.Format("01月02日")
+		} else if OutType == 3 {
+			return tm.Format("15时04分05秒")
+		} else if OutType == 4 {
+			return tm.Format("15时04分")
+		} else if OutType == 5 {
+			return tm.Format("04分05秒")
+		} else if OutType == 6 {
+			return tm.Format("2006年")
+		} else if OutType == 7 {
+			return tm.Format("01月")
+		} else if OutType == 8 {
+			return tm.Format("02日")
+		} else if OutType == 9 {
+			return tm.Format("15时")
+		} else if OutType == 10 {
+			return tm.Format("04分")
+		} else if OutType == 11 {
+			return tm.Format("05秒")
+		}
+	} else if OutForm == 1 {
+		if OutType == 0 {
+			return tm.Format("2006-01-02 15:04:05")
+		} else if OutType == 1 {
+			return tm.Format("2006-01-02")
+		} else if OutType == 2 {
+			return tm.Format("01-02")
+		} else if OutType == 3 {
+			return tm.Format("15:04:05")
+		} else if OutType == 4 {
+			return tm.Format("15:04")
+		} else if OutType == 5 {
+			return tm.Format("04:05")
+		} else if OutType == 6 {
+			return tm.Format("2006")
+		} else if OutType == 7 {
+			return tm.Format("01")
+		} else if OutType == 8 {
+			return tm.Format("02")
+		} else if OutType == 9 {
+			return tm.Format("15")
+		} else if OutType == 10 {
+			return tm.Format("04")
+		} else if OutType == 11 {
+			return tm.Format("05")
+		}
+	} else if OutForm == 2 {
+		if OutType == 0 {
+			return tm.Format("2006/01/02 15/04/05")
+		} else if OutType == 1 {
+			return tm.Format("2006/01/02")
+		} else if OutType == 2 {
+			return tm.Format("01/02")
+		} else if OutType == 3 {
+			return tm.Format("15/04/05")
+		} else if OutType == 4 {
+			return tm.Format("15/04")
+		} else if OutType == 5 {
+			return tm.Format("04/05")
+		} else if OutType == 6 {
+			return tm.Format("2006")
+		} else if OutType == 7 {
+			return tm.Format("01")
+		} else if OutType == 8 {
+			return tm.Format("02")
+		} else if OutType == 9 {
+			return tm.Format("15")
+		} else if OutType == 10 {
+			return tm.Format("04")
+		} else if OutType == 11 {
+			return tm.Format("05")
+		}
+	} else if OutForm == 3 {
+		if OutType == 0 {
+			return tm.Format("20060102 150405")
+		} else if OutType == 1 {
+			return tm.Format("20060102")
+		} else if OutType == 2 {
+			return tm.Format("0102")
+		} else if OutType == 3 {
+			return tm.Format("150405")
+		} else if OutType == 4 {
+			return tm.Format("1504")
+		} else if OutType == 5 {
+			return tm.Format("0405")
+		} else if OutType == 6 {
+			return tm.Format("2006")
+		} else if OutType == 7 {
+			return tm.Format("01")
+		} else if OutType == 8 {
+			return tm.Format("02")
+		} else if OutType == 9 {
+			return tm.Format("15")
+		} else if OutType == 10 {
+			return tm.Format("04")
+		} else if OutType == 11 {
+			return tm.Format("05")
+		}
+	} else {
+		return tm.Format("2006-01-02 15:04:05 PM")
+	}
+
+	return tm.Format("2006-01-02 03:04:05 PM")
+
+}

+ 189 - 0
handle_tools.go

@@ -0,0 +1,189 @@
+package mokuai
+
+import (
+	"bytes"
+	"crypto/tls"
+	"encoding/json"
+	"errors"
+	"fmt"
+	gomail "gopkg.in/gomail.v2"
+	"io/ioutil"
+	"math/rand"
+	"net/http"
+	"regexp"
+	"strings"
+	"time"
+)
+
+type monitormail struct {
+	Smtpurl    string `gorm:"smtpurl" json:"smtpurl"`       // smtp服务器
+	Smtpport   int    `gorm:"smtpport" json:"smtpport"`     // smtp 端口
+	Smtpuser   string `gorm:"smtpuser" json:"smtpuser"`     // 邮箱账号
+	Smtpname   string `gorm:"smtpname" json:"smtpname"`     // 发件人别名
+	Smtppasswd string `gorm:"smtppasswd" json:"smtppasswd"` // 邮箱密码/授权码
+	Smtpssl    int    `gorm:"smtpssl" json:"smtpssl"`       // 是否启用SSL .  (1. 启用 )
+	Sendmail   string `gorm:"sendmail" json:"sendmail"`     // 发送到的邮箱
+}
+
+// 钉钉通知 文本内容  Sign方式
+// webhook_url 文本型 机器人webhook URL ;
+// text 文本型 通知的消息内容 ;
+// secret 文本型 机器人安全设置内的加签 ;
+// atMobiles 文本型 被@人的手机号,多个用|隔开 ; (与 ”是否@所有人“ 互斥)
+// isAtAll 布尔型 ,是否@所有人。  (与 ”被@人的手机号“ 互斥 ,两者都有此为优先)
+func Tools_DingToInfo(webhook_url, text, secret, atMobiles string, isAtAll bool) bool {
+	timestamp := time.Now().UnixNano() / 1e6
+	stringToSign := fmt.Sprintf("%d\n%s", timestamp, secret)
+	sign := Hash_hmacSha256_en(stringToSign, secret)
+	url := fmt.Sprintf("%s&timestamp=%d&sign=%s", webhook_url, timestamp, sign)
+	var mobilezu []string
+	if Text_FindKeyword(atMobiles, "|") != -1 {
+		mobilezu = Text_GetSplitText(atMobiles, "|")
+	} else {
+		mobilezu = append(mobilezu, atMobiles)
+	}
+	content, data, at := make(map[string]string), make(map[string]interface{}), make(map[string]interface{})
+	content["content"] = text
+	at["atMobiles"] = mobilezu
+	at["isAtAll"] = isAtAll
+	data["msgtype"] = "text"
+	data["text"] = content
+	data["at"] = at
+
+	b, _ := json.Marshal(data)
+	resp, err := http.Post(url,
+		"application/json",
+		bytes.NewBuffer(b))
+	if err != nil {
+		fmt.Println("DingToInfo ERROR :", err)
+		return false
+	}
+	defer resp.Body.Close()
+	//	body, _ := ioutil.ReadAll(resp.Body)
+	//	fmt.Println(string(body))
+	return true
+}
+
+// 获取本机公网出口IP . 失败返回空
+// n 为 访问哪个接口获取。 0为随机 ; 1. h.myip.top ; 2. myip.top ; 3. myip.zzznb.cc ; 4. HTTP ip检测接口 ;
+func Tools_GetPublicIP_Api(n int) string {
+	if n == 0 {
+		n = int(Text_GetRandNumInRange(1, 4))
+	}
+	var resp *http.Response
+	var err error
+	if n == 1 {
+		resp, err = http.Get("http://h.myip.top/")
+		if err != nil {
+			return ""
+		}
+	} else if n == 2 {
+		resp, err = http.Get("http://myip.top/")
+		if err != nil {
+			return ""
+		}
+	} else if n == 3 {
+		resp, err = http.Get("http://myip.zzznb.cc/")
+		if err != nil {
+			return ""
+		}
+	} else if n == 4 {
+		resp, err = http.Get("http://106.15.239.72/myip")
+		if err != nil {
+			return ""
+		}
+	}
+	defer resp.Body.Close()
+	lin, _ := ioutil.ReadAll(resp.Body)
+	ip := ""
+	linzu := Text_GetSplitText(string(lin), ",")
+	for _, v := range linzu {
+		if Text_FindKeyword(v, "ip") != -1 {
+			ip = Text_GetBetween(Text_GetRightText(v, ":"), "\"", "\"")
+		}
+	}
+
+	return ip
+}
+
+// 检测IP正确性
+func Tools_ChkIp(ip string) bool {
+	r, _ := regexp.Compile("^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$")
+	if !r.MatchString(ip) {
+		return false
+	}
+	return true
+}
+
+// 随机生成mac
+func Tools_RandMac() string {
+	var m [6]byte
+	rand.Seed(time.Now().UnixNano())
+	for i := 0; i < 6; i++ {
+		mac_byte := rand.Intn(256)
+		m[i] = byte(mac_byte)
+
+		rand.Seed(int64(mac_byte))
+	}
+
+	return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", m[0], m[1], m[2], m[3], m[4], m[5])
+}
+
+// 发送邮件
+func Tool_sendmail(euser monitormail, mailSubject, mailBody string) (isOk bool, err error) {
+
+	if mailSubject == "" {
+		return false, errors.New("mailSubject is Null")
+	}
+	if mailBody == "" {
+		return false, errors.New("mailBody is Null")
+	}
+	if euser.Smtpurl == "" {
+		return false, errors.New("Smtpurl is Null")
+	}
+	if euser.Smtpport <= 0 {
+		return false, errors.New("Smtpport is Null")
+	}
+	if euser.Sendmail == "" {
+		return false, errors.New("Sendmail is Null")
+	}
+	if euser.Smtpuser == "" {
+		return false, errors.New("Smtpuser is Null")
+	}
+
+	m := gomail.NewMessage()
+	if euser.Smtpname != "" {
+		m.SetHeader("From", euser.Smtpname+"<"+euser.Smtpuser+">")
+	} else {
+		m.SetHeader("From", euser.Smtpuser)
+	}
+
+	u := strings.Split(euser.Sendmail, ",")
+	m.SetHeader("To", u...)
+	m.SetHeader("Subject", mailSubject)
+	m.SetBody("text/html", mailBody)
+
+	/*	if files != "" {   // 添加附件
+		f := strings.Split(files, ",")
+		for _, i := range f {
+			m.Attach(i)
+		}
+	}*/
+
+	//
+	d := gomail.NewDialer(euser.Smtpurl, euser.Smtpport, euser.Smtpuser, euser.Smtppasswd)
+
+	if euser.Smtpssl == 1 {
+		// 开启SSL协议认证
+		d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
+	}
+
+	// Send the email to Bob, Cora and Dan.
+	err = d.DialAndSend(m)
+	if err == nil {
+		isOk = true
+	} else {
+		isOk = false
+	}
+	return
+}

+ 124 - 0
handle_typechange.go

@@ -0,0 +1,124 @@
+package mokuai
+
+import (
+	"encoding/binary"
+	"io/ioutil"
+	"math"
+	"net/http"
+	"strconv"
+)
+
+// 整数型转文本型(int)
+func Type_IntToString(i int) string {
+	return strconv.Itoa(i)
+}
+
+// 文本型转整数型(int)
+func Type_StringToInt(str string) int {
+	i, _ := strconv.Atoi(str)
+	return i
+}
+
+// string到int64
+func Type_StringToInt64(str string) int64 {
+	i64, _ := strconv.ParseInt(str, 10, 64)
+	return i64
+}
+
+// int64到string
+func Type_Int64ToString(i64 int64) string {
+	str := strconv.FormatInt(i64, 10)
+	return str
+}
+
+// int到int64
+func Type_IntToInt64(i int) int64 {
+	return int64(i)
+}
+
+// int64到int
+func Type_Int64ToInt(i64 int64) int {
+	return int(i64)
+}
+
+/*  // float(32)到string
+func Type_FloatToString(f float32) string {
+	return strconv.FormatFloat(f,'E',-1,32)
+}*/
+
+// float(64)到string
+func Type_Float64ToString(f64 float64) string {
+	return strconv.FormatFloat(f64, 'E', -1, 64)
+}
+
+/*  //string到float(32)
+func Type_StringToFloat(str string) float32 {
+	f , _ := strconv.ParseFloat(str,32)
+	return f
+}*/
+
+// string到float(64)
+func Type_StringToFloat64(str string) float64 {
+	f64, _ := strconv.ParseFloat(str, 64)
+	return f64
+}
+
+// float(32)到Byte
+func Type_FloatToByte(float float32) []byte {
+	bits := math.Float32bits(float)
+	bytes := make([]byte, 4)
+	binary.LittleEndian.PutUint32(bytes, bits)
+	return bytes
+}
+
+// Byte到float(32)
+func Type_ByteToFloat(bytes []byte) float32 {
+	bits := binary.LittleEndian.Uint32(bytes)
+	return math.Float32frombits(bits)
+}
+
+// float(64)到Byte
+func Type_Float64ToByte(float float64) []byte {
+	bits := math.Float64bits(float)
+	bytes := make([]byte, 8)
+	binary.LittleEndian.PutUint64(bytes, bits)
+	return bytes
+}
+
+// Byte到float(64)
+func Type_ByteToFloat64(bytes []byte) float64 {
+	bits := binary.LittleEndian.Uint64(bytes)
+	return math.Float64frombits(bits)
+}
+
+// string 转 []byte
+func Type_StringToByte(str string) []byte {
+	return []byte(str)
+}
+
+// []byte 转 string
+func Type_ByteToString(byteval []byte) string {
+	return string(byteval)
+}
+
+// string 转 rune
+func Type_StringToRune(str string) []rune {
+	return []rune(str)
+}
+
+// rune 转 string
+func Type_RuneToString(runeval []rune) string {
+	return string(runeval)
+}
+
+// Response 转 string
+func Type_ResponseToString(resp http.Response) string {
+	bodyRes, _ := ioutil.ReadAll(resp.Body)
+	return string(bodyRes)
+}
+
+// Response 转 []byte
+func Type_ResponseToByte(resp http.Response) []byte {
+	bodyRes, _ := ioutil.ReadAll(resp.Body)
+	return bodyRes
+}

+ 209 - 0
quote/uuid/codec.go

@@ -0,0 +1,209 @@
+// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+package uuid
+
+import (
+	"bytes"
+	"encoding/hex"
+	"fmt"
+)
+
+// FromBytes returns UUID converted from raw byte slice input.
+// It will return error if the slice isn't 16 bytes long.
+func FromBytes(input []byte) (u UUID, err error) {
+	err = u.UnmarshalBinary(input)
+	return
+}
+
+// FromBytesOrNil returns UUID converted from raw byte slice input.
+// Same behavior as FromBytes, but returns a Nil UUID on error.
+func FromBytesOrNil(input []byte) UUID {
+	uuid, err := FromBytes(input)
+	if err != nil {
+		return Nil
+	}
+	return uuid
+}
+
+// FromString returns UUID parsed from string input.
+// Input is expected in a form accepted by UnmarshalText.
+func FromString(input string) (u UUID, err error) {
+	err = u.UnmarshalText([]byte(input))
+	return
+}
+
+// FromStringOrNil returns UUID parsed from string input.
+// Same behavior as FromString, but returns a Nil UUID on error.
+func FromStringOrNil(input string) UUID {
+	uuid, err := FromString(input)
+	if err != nil {
+		return Nil
+	}
+	return uuid
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+// The encoding is the same as returned by String.
+func (u UUID) MarshalText() (text []byte, err error) {
+	text = []byte(u.String())
+	return
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+// Following formats are supported:
+//
+//	"6ba7b810-9dad-11d1-80b4-00c04fd430c8",
+//	"{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
+//	"urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
+//	"6ba7b8109dad11d180b400c04fd430c8"
+//
+// ABNF for supported UUID text representation follows:
+//
+//	uuid := canonical | hashlike | braced | urn
+//	plain := canonical | hashlike
+//	canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct
+//	hashlike := 12hexoct
+//	braced := '{' plain '}'
+//	urn := URN ':' UUID-NID ':' plain
+//	URN := 'urn'
+//	UUID-NID := 'uuid'
+//	12hexoct := 6hexoct 6hexoct
+//	6hexoct := 4hexoct 2hexoct
+//	4hexoct := 2hexoct 2hexoct
+//	2hexoct := hexoct hexoct
+//	hexoct := hexdig hexdig
+//	hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
+//	          'a' | 'b' | 'c' | 'd' | 'e' | 'f' |
+//	          'A' | 'B' | 'C' | 'D' | 'E' | 'F'
+func (u *UUID) UnmarshalText(text []byte) (err error) {
+	switch len(text) {
+	case 32:
+		return u.decodeHashLike(text)
+	case 36:
+		return u.decodeCanonical(text)
+	case 38:
+		return u.decodeBraced(text)
+	case 41:
+		fallthrough
+	case 45:
+		return u.decodeURN(text)
+	default:
+		return fmt.Errorf("uuid: incorrect UUID length: %s", text)
+	}
+}
+
+// decodeCanonical decodes UUID string in format
+// "6ba7b810-9dad-11d1-80b4-00c04fd430c8".
+func (u *UUID) decodeCanonical(t []byte) (err error) {
+	if t[8] != '-' || t[13] != '-' || t[18] != '-' || t[23] != '-' {
+		return fmt.Errorf("uuid: incorrect UUID format %s", t)
+	}
+
+	src := t[:]
+	dst := u[:]
+
+	for i, byteGroup := range byteGroups {
+		if i > 0 {
+			src = src[1:] // skip dash
+		}
+		_, err = hex.Decode(dst[:byteGroup/2], src[:byteGroup])
+		if err != nil {
+			return
+		}
+		src = src[byteGroup:]
+		dst = dst[byteGroup/2:]
+	}
+
+	return
+}
+
+// decodeHashLike decodes UUID string in format
+// "6ba7b8109dad11d180b400c04fd430c8".
+func (u *UUID) decodeHashLike(t []byte) (err error) {
+	src := t[:]
+	dst := u[:]
+
+	if _, err = hex.Decode(dst, src); err != nil {
+		return err
+	}
+	return
+}
+
+// decodeBraced decodes UUID string in format
+// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}" or in format
+// "{6ba7b8109dad11d180b400c04fd430c8}".
+func (u *UUID) decodeBraced(t []byte) (err error) {
+	l := len(t)
+
+	if t[0] != '{' || t[l-1] != '}' {
+		return fmt.Errorf("uuid: incorrect UUID format %s", t)
+	}
+
+	return u.decodePlain(t[1 : l-1])
+}
+
+// decodeURN decodes UUID string in format
+// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in format
+// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8".
+func (u *UUID) decodeURN(t []byte) (err error) {
+	total := len(t)
+
+	urn_uuid_prefix := t[:9]
+
+	if !bytes.Equal(urn_uuid_prefix, urnPrefix) {
+		return fmt.Errorf("uuid: incorrect UUID format: %s", t)
+	}
+
+	return u.decodePlain(t[9:total])
+}
+
+// decodePlain decodes UUID string in canonical format
+// "6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in hash-like format
+// "6ba7b8109dad11d180b400c04fd430c8".
+func (u *UUID) decodePlain(t []byte) (err error) {
+	switch len(t) {
+	case 32:
+		return u.decodeHashLike(t)
+	case 36:
+		return u.decodeCanonical(t)
+	default:
+		return fmt.Errorf("uuid: incorrrect UUID length: %s", t)
+	}
+}
+
+// MarshalBinary implements the encoding.BinaryMarshaler interface.
+func (u UUID) MarshalBinary() (data []byte, err error) {
+	data = u.Bytes()
+	return
+}
+
+// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
+// It will return error if the slice isn't 16 bytes long.
+func (u *UUID) UnmarshalBinary(data []byte) (err error) {
+	if len(data) != Size {
+		err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data))
+		return
+	}
+	copy(u[:], data)
+
+	return
+}

+ 265 - 0
quote/uuid/generator.go

@@ -0,0 +1,265 @@
+// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+package uuid
+
+import (
+	"crypto/md5"
+	"crypto/rand"
+	"crypto/sha1"
+	"encoding/binary"
+	"fmt"
+	"hash"
+	"io"
+	"net"
+	"os"
+	"sync"
+	"time"
+)
+
+// Difference in 100-nanosecond intervals between
+// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
+const epochStart = 122192928000000000
+
+type epochFunc func() time.Time
+type hwAddrFunc func() (net.HardwareAddr, error)
+
+var (
+	global = newRFC4122Generator()
+
+	posixUID = uint32(os.Getuid())
+	posixGID = uint32(os.Getgid())
+)
+
+// NewV1 returns UUID based on current timestamp and MAC address.
+func NewV1() (UUID, error) {
+	return global.NewV1()
+}
+
+// NewV2 returns DCE Security UUID based on POSIX UID/GID.
+func NewV2(domain byte) (UUID, error) {
+	return global.NewV2(domain)
+}
+
+// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
+func NewV3(ns UUID, name string) UUID {
+	return global.NewV3(ns, name)
+}
+
+// NewV4 returns random generated UUID.
+func NewV4() (UUID, error) {
+	return global.NewV4()
+}
+
+// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
+func NewV5(ns UUID, name string) UUID {
+	return global.NewV5(ns, name)
+}
+
+// Generator provides interface for generating UUIDs.
+type Generator interface {
+	NewV1() (UUID, error)
+	NewV2(domain byte) (UUID, error)
+	NewV3(ns UUID, name string) UUID
+	NewV4() (UUID, error)
+	NewV5(ns UUID, name string) UUID
+}
+
+// Default generator implementation.
+type rfc4122Generator struct {
+	clockSequenceOnce sync.Once
+	hardwareAddrOnce  sync.Once
+	storageMutex      sync.Mutex
+
+	rand io.Reader
+
+	epochFunc     epochFunc
+	hwAddrFunc    hwAddrFunc
+	lastTime      uint64
+	clockSequence uint16
+	hardwareAddr  [6]byte
+}
+
+func newRFC4122Generator() Generator {
+	return &rfc4122Generator{
+		epochFunc:  time.Now,
+		hwAddrFunc: defaultHWAddrFunc,
+		rand:       rand.Reader,
+	}
+}
+
+// NewV1 returns UUID based on current timestamp and MAC address.
+func (g *rfc4122Generator) NewV1() (UUID, error) {
+	u := UUID{}
+
+	timeNow, clockSeq, err := g.getClockSequence()
+	if err != nil {
+		return Nil, err
+	}
+	binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
+	binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
+	binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
+	binary.BigEndian.PutUint16(u[8:], clockSeq)
+
+	hardwareAddr, err := g.getHardwareAddr()
+	if err != nil {
+		return Nil, err
+	}
+	copy(u[10:], hardwareAddr)
+
+	u.SetVersion(V1)
+	u.SetVariant(VariantRFC4122)
+
+	return u, nil
+}
+
+// NewV2 returns DCE Security UUID based on POSIX UID/GID.
+func (g *rfc4122Generator) NewV2(domain byte) (UUID, error) {
+	u, err := g.NewV1()
+	if err != nil {
+		return Nil, err
+	}
+
+	switch domain {
+	case DomainPerson:
+		binary.BigEndian.PutUint32(u[:], posixUID)
+	case DomainGroup:
+		binary.BigEndian.PutUint32(u[:], posixGID)
+	}
+
+	u[9] = domain
+
+	u.SetVersion(V2)
+	u.SetVariant(VariantRFC4122)
+
+	return u, nil
+}
+
+// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
+func (g *rfc4122Generator) NewV3(ns UUID, name string) UUID {
+	u := newFromHash(md5.New(), ns, name)
+	u.SetVersion(V3)
+	u.SetVariant(VariantRFC4122)
+
+	return u
+}
+
+// NewV4 returns random generated UUID.
+func (g *rfc4122Generator) NewV4() (UUID, error) {
+	u := UUID{}
+	if _, err := io.ReadFull(g.rand, u[:]); err != nil {
+		return Nil, err
+	}
+	u.SetVersion(V4)
+	u.SetVariant(VariantRFC4122)
+
+	return u, nil
+}
+
+// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
+func (g *rfc4122Generator) NewV5(ns UUID, name string) UUID {
+	u := newFromHash(sha1.New(), ns, name)
+	u.SetVersion(V5)
+	u.SetVariant(VariantRFC4122)
+
+	return u
+}
+
+// Returns epoch and clock sequence.
+func (g *rfc4122Generator) getClockSequence() (uint64, uint16, error) {
+	var err error
+	g.clockSequenceOnce.Do(func() {
+		buf := make([]byte, 2)
+		if _, err = io.ReadFull(g.rand, buf); err != nil {
+			return
+		}
+		g.clockSequence = binary.BigEndian.Uint16(buf)
+	})
+	if err != nil {
+		return 0, 0, err
+	}
+
+	g.storageMutex.Lock()
+	defer g.storageMutex.Unlock()
+
+	timeNow := g.getEpoch()
+	// Clock didn't change since last UUID generation.
+	// Should increase clock sequence.
+	if timeNow <= g.lastTime {
+		g.clockSequence++
+	}
+	g.lastTime = timeNow
+
+	return timeNow, g.clockSequence, nil
+}
+
+// Returns hardware address.
+func (g *rfc4122Generator) getHardwareAddr() ([]byte, error) {
+	var err error
+	g.hardwareAddrOnce.Do(func() {
+		if hwAddr, err := g.hwAddrFunc(); err == nil {
+			copy(g.hardwareAddr[:], hwAddr)
+			return
+		}
+
+		// Initialize hardwareAddr randomly in case
+		// of real network interfaces absence.
+		if _, err = io.ReadFull(g.rand, g.hardwareAddr[:]); err != nil {
+			return
+		}
+		// Set multicast bit as recommended by RFC 4122
+		g.hardwareAddr[0] |= 0x01
+	})
+	if err != nil {
+		return []byte{}, err
+	}
+	return g.hardwareAddr[:], nil
+}
+
+// Returns difference in 100-nanosecond intervals between
+// UUID epoch (October 15, 1582) and current time.
+func (g *rfc4122Generator) getEpoch() uint64 {
+	return epochStart + uint64(g.epochFunc().UnixNano()/100)
+}
+
+// Returns UUID based on hashing of namespace UUID and name.
+func newFromHash(h hash.Hash, ns UUID, name string) UUID {
+	u := UUID{}
+	h.Write(ns[:])
+	h.Write([]byte(name))
+	copy(u[:], h.Sum(nil))
+
+	return u
+}
+
+// Returns hardware address.
+func defaultHWAddrFunc() (net.HardwareAddr, error) {
+	ifaces, err := net.Interfaces()
+	if err != nil {
+		return []byte{}, err
+	}
+	for _, iface := range ifaces {
+		if len(iface.HardwareAddr) >= 6 {
+			return iface.HardwareAddr, nil
+		}
+	}
+	return []byte{}, fmt.Errorf("uuid: no HW address found")
+}

+ 162 - 0
quote/uuid/uuid.go

@@ -0,0 +1,162 @@
+// Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// Package uuid provides implementation of Universally Unique Identifier (UUID).
+// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and
+// version 2 (as specified in DCE 1.1).
+package uuid
+
+import (
+	"bytes"
+	"encoding/hex"
+)
+
+// Size of a UUID in bytes.
+const Size = 16
+
+// UUID representation compliant with specification
+// described in RFC 4122.
+type UUID [Size]byte
+
+// UUID versions
+const (
+	_ byte = iota
+	V1
+	V2
+	V3
+	V4
+	V5
+)
+
+// UUID layout variants.
+const (
+	VariantNCS byte = iota
+	VariantRFC4122
+	VariantMicrosoft
+	VariantFuture
+)
+
+// UUID DCE domains.
+const (
+	DomainPerson = iota
+	DomainGroup
+	DomainOrg
+)
+
+// String parse helpers.
+var (
+	urnPrefix  = []byte("urn:uuid:")
+	byteGroups = []int{8, 4, 4, 4, 12}
+)
+
+// Nil is special form of UUID that is specified to have all
+// 128 bits set to zero.
+var Nil = UUID{}
+
+// Predefined namespace UUIDs.
+var (
+	NamespaceDNS  = Must(FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
+	NamespaceURL  = Must(FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
+	NamespaceOID  = Must(FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
+	NamespaceX500 = Must(FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
+)
+
+// Equal returns true if u1 and u2 equals, otherwise returns false.
+func Equal(u1 UUID, u2 UUID) bool {
+	return bytes.Equal(u1[:], u2[:])
+}
+
+// Version returns algorithm version used to generate UUID.
+func (u UUID) Version() byte {
+	return u[6] >> 4
+}
+
+// Variant returns UUID layout variant.
+func (u UUID) Variant() byte {
+	switch {
+	case (u[8] >> 7) == 0x00:
+		return VariantNCS
+	case (u[8] >> 6) == 0x02:
+		return VariantRFC4122
+	case (u[8] >> 5) == 0x06:
+		return VariantMicrosoft
+	case (u[8] >> 5) == 0x07:
+		fallthrough
+	default:
+		return VariantFuture
+	}
+}
+
+// Bytes returns bytes slice representation of UUID.
+func (u UUID) Bytes() []byte {
+	return u[:]
+}
+
+// Returns canonical string representation of UUID:
+// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
+func (u UUID) String() string {
+	buf := make([]byte, 36)
+
+	hex.Encode(buf[0:8], u[0:4])
+	buf[8] = '-'
+	hex.Encode(buf[9:13], u[4:6])
+	buf[13] = '-'
+	hex.Encode(buf[14:18], u[6:8])
+	buf[18] = '-'
+	hex.Encode(buf[19:23], u[8:10])
+	buf[23] = '-'
+	hex.Encode(buf[24:], u[10:])
+
+	return string(buf)
+}
+
+// SetVersion sets version bits.
+func (u *UUID) SetVersion(v byte) {
+	u[6] = (u[6] & 0x0f) | (v << 4)
+}
+
+// SetVariant sets variant bits.
+func (u *UUID) SetVariant(v byte) {
+	switch v {
+	case VariantNCS:
+		u[8] = (u[8]&(0xff>>1) | (0x00 << 7))
+	case VariantRFC4122:
+		u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
+	case VariantMicrosoft:
+		u[8] = (u[8]&(0xff>>3) | (0x06 << 5))
+	case VariantFuture:
+		fallthrough
+	default:
+		u[8] = (u[8]&(0xff>>3) | (0x07 << 5))
+	}
+}
+
+// Must is a helper that wraps a call to a function returning (UUID, error)
+// and panics if the error is non-nil. It is intended for use in variable
+// initializations such as
+//
+//	var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000"));
+func Must(u UUID, err error) UUID {
+	if err != nil {
+		panic(err)
+	}
+	return u
+}

+ 117 - 0
setting.go

@@ -0,0 +1,117 @@
+package mokuai
+
+import (
+	"fmt"
+	"github.com/go-ini/ini"
+	"log"
+	"runtime"
+	"time"
+)
+
+type App struct {
+	GinLog        int
+	Proxyapi      string
+	Proxyapi_data string
+}
+
+type Server struct {
+	RunMode      string
+	HttpPort     int
+	ReadTimeout  time.Duration
+	WriteTimeout time.Duration
+}
+
+type Database struct {
+	Type     string
+	Host     string
+	User     string
+	Password string
+	DbName   string
+	RmHost   string
+}
+
+var ServerConfig = &Server{}
+var AppConfig = &App{}
+var DatabaseConfig = &Database{}
+var (
+	Cfg *ini.File
+)
+
+// 初始化配置文件
+func InitConfigFile() {
+	// 修改此处初始化的配置文件内容
+	var lin = "[UserCookies]\n#MT bbs Cookies (格式<有反单引号> : `cookies值`)\nMtCookies = \nMtProxy ="
+	dirpath := File_Get_Current_Directory()
+	if runtime.GOOS == "linux" {
+		Dir_Create(dirpath + "/conf")
+		File_WriteStr(dirpath+"/conf/app.ini", lin)
+	} else if runtime.GOOS == "windows" {
+		Dir_Create(dirpath + "\\conf")
+		File_WriteStr(dirpath+"\\conf\\app.ini", lin)
+	}
+}
+
+func IniSetup() {
+	var err error
+	dirpath := File_Get_Current_Directory()
+	filePath := ""
+	if runtime.GOOS == "linux" {
+		_, reBool := File_IsExists(dirpath + "/conf/app.ini")
+		if reBool == false {
+			filePath = ""
+		} else {
+			filePath = dirpath + "/conf/app.ini"
+		}
+	} else if runtime.GOOS == "windows" {
+		_, reBool := File_IsExists(dirpath + "\\conf\\app.ini")
+		if reBool == false {
+			filePath = ""
+		} else {
+			filePath = dirpath + "\\conf\\app.ini"
+		}
+	}
+
+	if filePath == "" {
+		if runtime.GOOS == "linux" {
+			_, reBool := File_IsExists("conf/app.ini")
+			if reBool == false {
+				filePath = ""
+			} else {
+				filePath = "conf/app.ini"
+			}
+		} else if runtime.GOOS == "windows" {
+			_, reBool := File_IsExists("conf\\app.ini")
+			if reBool == false {
+				filePath = ""
+			} else {
+				filePath = "conf\\app.ini"
+			}
+		}
+	}
+
+	if filePath == "" {
+		InitConfigFile()
+		log.Fatalf("fail to parse " + dirpath + "\\conf\\app.ini" + "   <已创建初始化配置文件,请打开 conf/app.ini 配入信息>后 运行")
+		return
+	}
+
+	Cfg, err = ini.Load(filePath)
+	fmt.Println("配置文件 >> " + filePath)
+
+	if err != nil {
+		InitConfigFile()
+		log.Fatalf("fail to parse " + dirpath + "\\conf\\app.ini" + "   <已创建初始化配置文件,请打开 conf/app.ini 配入信息>后 运行")
+		return
+	}
+
+}
+
+func SaveConfig() {
+	dirpath := File_Get_Current_Directory()
+	if runtime.GOOS == "linux" {
+		_ = Cfg.SaveTo(dirpath + "/conf/app.ini")
+	} else if runtime.GOOS == "windows" {
+		_ = Cfg.SaveTo(dirpath + "\\conf\\app.ini")
+	}
+	IniSetup()
+}