develoven 1 жил өмнө
parent
commit
470958fb72
17 өөрчлөгдсөн 792 нэмэгдсэн , 73 устгасан
  1. 8 0
      .idea/.gitignore
  2. 210 0
      api/gateway.go
  3. 68 0
      api/sse.go
  4. 5 5
      api/user.go
  5. 57 2
      common/time.go
  6. 38 1
      common/utils.go
  7. 9 1
      config/application.yaml
  8. 11 0
      config/config.go
  9. 16 3
      constant/constant.go
  10. 3 2
      err/errMsg.go
  11. 34 13
      go.mod
  12. 121 0
      go.sum
  13. 111 0
      http/http.go
  14. 12 5
      initialize/router.go
  15. 40 40
      main.go
  16. 35 0
      models/device.go
  17. 14 1
      models/user.go

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml

+ 210 - 0
api/gateway.go

@@ -0,0 +1,210 @@
+package api
+
+import (
+	"confrontation-training/common"
+	"confrontation-training/constant"
+	errmsg "confrontation-training/err"
+	"confrontation-training/global"
+	"confrontation-training/http"
+	"confrontation-training/models"
+	"confrontation-training/response"
+	"encoding/hex"
+	"encoding/json"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"io/ioutil"
+	"strings"
+)
+
+// ScanDevice
+// PingExample confrontation-training
+// @Summary 扫描设备
+// @Schemes
+// @Description 扫描设备
+// @Tags 设备管理
+// @Param device body string true "chip:芯片编号,1或1;filterName:0 脑电 1 心电;filterRssi:信号强度,小于0的整数,字符串格式传输;filterMac:过滤Mac地址,以","分割,如 61-Dg-89-22-39-3b,80-kD-0E-40-57-8A"
+// @Accept json
+// @Produce json
+// @Success 200 {string} string "ok"
+// @Router /v1/device/scan [get]
+func ScanDevice(c *gin.Context) {
+	var param models.DeviceScanParam
+	err := c.ShouldBindJSON(&param)
+	if err != nil {
+		fmt.Printf("参数格式化异常:%s", err.Error())
+		response.Failed(errmsg.ParamInvalid, c)
+		return
+	}
+	paramMap := make(map[string]string)
+	if param.Chip != "" {
+		paramMap["chip"] = param.Chip
+	}
+	if param.FilterName != "" {
+		if param.FilterName == "0" {
+			paramMap["filter_name"] = constant.FilterNameEEG
+		} else if param.FilterName == "1" {
+			paramMap["filter_name"] = constant.FilterNameECG
+		} else {
+			response.Failed(errmsg.ParamInvalid+":过滤类型-"+param.FilterName+"无效", c)
+			return
+		}
+	} else {
+		paramMap["filter_name"] = constant.FilterNameALL
+	}
+	if param.FilterRssi != "" {
+		paramMap["filter_rssi"] = param.FilterRssi
+	}
+	if param.FilterMac != "" {
+		paramMap["filter_mac"] = param.FilterMac
+	}
+	paramMap["active"] = "1"
+	paramMap["event"] = "1"
+	result := SseScanDevice(paramMap)
+	response.Success("扫描完成", result, c)
+	return
+}
+
+// ConnectDevice
+// PingExample confrontation-training
+// @Summary 连接设备
+// @Schemes
+// @Description 连接设备
+// @Tags 设备管理
+// @Param device body string true "chip:芯片编号,0或1;mac:Mac地址;addrType:地址类型 public/random "
+// @Accept json
+// @Produce json
+// @Success 200 {string} string "ok"
+// @Router /v1/device/connection [get]
+func ConnectDevice(c *gin.Context) {
+	var param models.DeviceConnParam
+	err := c.ShouldBindJSON(&param)
+	if err != nil {
+		fmt.Printf("参数格式化异常:%s", err.Error())
+		response.Failed(errmsg.ParamInvalid, c)
+		return
+	}
+	jsonParam, err := json.Marshal(param)
+	if err != nil {
+		fmt.Printf("参数转换异常:%s", err.Error())
+		response.Failed("参数转换异常:%s"+err.Error(), c)
+		return
+	}
+	url := global.Config.Gateway.BaseUrl + global.Config.Gateway.ConnUrl
+	url = strings.Replace(url, "MAC", param.Mac, -1)
+	url = strings.Replace(url, "chip", "chip="+param.Chip, -1)
+	httpResponse := http.PostReqJson(url, jsonParam)
+	status := httpResponse.StatusCode
+	fmt.Println("status", status)
+	fmt.Println("response:", httpResponse.Header)
+	body, _ := ioutil.ReadAll(httpResponse.Body)
+	fmt.Println("response Body:", string(body))
+
+	if status == 200 {
+		//成功
+		response.Success(errmsg.DeviceConnectSuccess, nil, c)
+	} else {
+		//失败
+		response.Failed(errmsg.DeviceConnectError+string(body), c)
+	}
+
+}
+
+// WriteData
+// PingExample confrontation-training
+// @Summary 写入数据——发送指令
+// @Schemes
+// @Description 写入数据——发送指令 ,ECG设备开启测试功能
+// @Tags 设备管理
+// @Param mac body string true "mac:设备MAC地址 userName:用户姓名 gender:性别 age:年龄 height:身高 weight:体重"
+// @Accept json
+// @Produce json
+// @Success 200 {string} string "ok"
+// @Router /v1/device/write/data/ [post]
+func WriteData(c *gin.Context) {
+	var param models.WriteData
+	err := c.ShouldBindJSON(&param)
+	if err != nil {
+		fmt.Printf("参数格式化异常:%s", err.Error())
+		response.Failed(errmsg.ParamInvalid, c)
+		return
+	}
+	userNameHex := hex.EncodeToString([]byte(param.UserName))
+
+	//1 绑定用户指令
+	//指令头(E841) + user信息前缀(AA)+姓名(姓名字节长度+姓名+姓名不足12字节占位符)+性别+年龄+身高+体重
+	var stringBuild strings.Builder
+	stringBuild.WriteString(constant.BindUserInfoCmdPrefix)
+	length := len(userNameHex) / 2
+
+	bytes := common.Int2Bytes(length)
+	result := common.Bytes2HexStr(bytes)
+	result = common.Int2Byte(int64(length))
+	if result == "" {
+		response.Failed("用户名处理异常", c)
+		return
+	}
+	result = result[len(result)-2:]
+	stringBuild.WriteString(result)
+	stringBuild.WriteString(userNameHex)
+	placeHolder := common.GenerateHexStringCmdPlaceHolder(constant.MaxNameByteLength - length)
+	stringBuild.WriteString(placeHolder)
+	hexGender := common.Int2Byte(param.Gender)
+	stringBuild.WriteString(hexGender[len(hexGender)-2:])
+	if param.Age == 0 {
+		param.Age = constant.EcgDefaultAge
+	}
+	hexAge := common.Int2Byte(param.Age)
+	stringBuild.WriteString(hexAge[len(hexAge)-2:])
+	if param.Height == 0 {
+		param.Height = constant.EcgDefaultHeight
+	}
+	hexHeight := common.Int2Byte(param.Height)
+	stringBuild.WriteString(hexHeight[len(hexHeight)-2:])
+
+	if param.Weight == 0 {
+		param.Weight = constant.EcgDefaultWeight
+	}
+	hexWeight := common.Int2Byte(param.Weight)
+	stringBuild.WriteString(hexWeight[len(hexWeight)-2:])
+	bindUserCmdByte := []byte(stringBuild.String())
+	bindUserCmd := string(bindUserCmdByte)
+
+	fmt.Println(bindUserCmd)
+
+	//2.授时指令
+	//timeCmd := common.GetTimeCmd()
+	timeCmd := common.GetHexTimeStr()
+	//timeCmd = fmt.Sprintf("%s%s", "0x", timeCmd)
+	setTimeCmd := fmt.Sprintf("%s%s", constant.SetTimeCmdPrefix, timeCmd)
+	fmt.Println(setTimeCmd)
+	//3.开始收集指令
+	startCollectCmd := fmt.Sprintf("%s%s", constant.StartCollectCmdPrefix, timeCmd)
+	fmt.Println(startCollectCmd)
+	//发送指令
+	//绑定用户
+	bindUserUrl := fmt.Sprintf("%s%s", global.Config.Gateway.BaseUrl, global.Config.Gateway.WriteDataUrl)
+	bindUserUrl = strings.Replace(bindUserUrl, "MAC", param.Mac, -1)
+	bindUserUrl = strings.Replace(bindUserUrl, "DATA", bindUserCmd, -1)
+	fmt.Println("bindUserUrl====" + bindUserUrl)
+	http.GetReq(bindUserUrl)
+	//授时
+	setTimeUrl := fmt.Sprintf("%s%s", global.Config.Gateway.BaseUrl, global.Config.Gateway.WriteDataUrl)
+	setTimeUrl = strings.Replace(setTimeUrl, "MAC", param.Mac, -1)
+	setTimeUrl = strings.Replace(setTimeUrl, "DATA", setTimeCmd, -1)
+	http.GetReq(setTimeUrl)
+	fmt.Println("setTimeUrl=====" + setTimeUrl)
+	//开始收集
+	startCollectUrl := fmt.Sprintf("%s%s", global.Config.Gateway.BaseUrl, global.Config.Gateway.WriteDataUrl)
+	startCollectUrl = strings.Replace(startCollectUrl, "MAC", param.Mac, -1)
+	startCollectUrl = strings.Replace(startCollectUrl, "DATA", startCollectCmd, -1)
+	fmt.Println("startCollectUrl=====" + startCollectUrl)
+	http.GetReq(startCollectUrl)
+
+	//开始收集指令
+	startTransUrl := fmt.Sprintf("%s%s", global.Config.Gateway.BaseUrl, global.Config.Gateway.WriteDataUrl)
+	startTransUrl = strings.Replace(startTransUrl, "MAC", param.Mac, -1)
+	startTransUrl = strings.Replace(startTransUrl, "DATA", constant.StartTransCmd, -1)
+	fmt.Println("startTransUrl====" + startTransUrl)
+	http.GetReq(startTransUrl)
+	response.Success(errmsg.WriteDataSuccess, nil, c)
+}

+ 68 - 0
api/sse.go

@@ -0,0 +1,68 @@
+package api
+
+import (
+	"confrontation-training/global"
+	"confrontation-training/models"
+	"encoding/json"
+	"fmt"
+	"github.com/r3labs/sse/v2"
+	"time"
+)
+
+// SseScanDevice 扫描设备
+func SseScanDevice(paramMap map[string]string) map[string]models.DeviceScanned {
+	var scanUrl = global.Config.Gateway.BaseUrl + global.Config.Gateway.ScanUrl
+	deviceMap := make(map[string]models.DeviceScanned)
+	if len(paramMap) > 0 {
+		for key, value := range paramMap {
+			scanUrl += "&" + key + "=" + value
+		}
+	}
+	client := sse.NewClient(scanUrl)
+	go func() {
+		fmt.Println("开始SSE")
+		err := client.SubscribeRaw(func(msg *sse.Event) {
+			//fmt.Println(string(msg.Data))
+			var data models.DeviceScannedFromGateway
+			err := json.Unmarshal(msg.Data, &data)
+			if err != nil {
+				fmt.Printf("SSE数据转换异常:%s", err.Error())
+				return
+			}
+			deviceScanned := models.DeviceScanned{}
+			deviceScanned.Name = data.Name
+			deviceScanned.Rssi = data.Rssi
+			deviceScanned.MAC = data.Bdaddrs[0].Bdaddr
+			deviceScanned.BdadrType = data.Bdaddrs[0].BdaddrType
+			deviceScanned.Chip = data.ChipId
+			deviceMap[deviceScanned.MAC] = deviceScanned
+			fmt.Println(deviceScanned)
+		})
+
+		if err != nil {
+			fmt.Println(err.Error())
+			return
+		}
+	}()
+	timer := time.NewTimer(time.Duration(global.Config.Gateway.ScanSecond) * time.Second)
+	events := make(chan *sse.Event)
+	select {
+	case <-timer.C:
+		fmt.Println("关闭SSE:" + (time.Now()).String())
+		client.Unsubscribe(events)
+		timer.Stop()
+	}
+	return deviceMap
+}
+
+// SseOpenNotify 开启通知
+func SseOpenNotify() {
+	var notifyUrl = global.Config.Gateway.BaseUrl + global.Config.Gateway.NotifyUrl
+	client := sse.NewClient(notifyUrl)
+	err := client.SubscribeRaw(func(msg *sse.Event) {
+
+	})
+	if err != nil {
+		return
+	}
+}

+ 5 - 5
api/user.go

@@ -20,7 +20,7 @@ func GetUser() *UserService {
 }
 
 // UseRegister
-// PingExample kjb-doc
+// PingExample confrontation-training
 // @Summary 用户注册
 // @Schemes
 // @Description 用户注册
@@ -53,7 +53,7 @@ func (u *UserService) UseRegister(c *gin.Context) {
 }
 
 // UserLogin
-// PingExample kjb-doc
+// PingExample confrontation-training
 // @Summary 用户登录
 // @Schemes
 // @Description 用户登录
@@ -86,7 +86,7 @@ func (u *UserService) UserLogin(c *gin.Context) {
 }
 
 // ResetPassword
-// PingExample kjb-doc
+// PingExample confrontation-training
 // @Summary 管理员重置普通用户密码
 // @Schemes
 // @Description 管理员重置普通用户密码
@@ -130,7 +130,7 @@ func (u *UserService) ResetPassword(c *gin.Context) {
 }
 
 // UserList
-// PingExample kjb-doc
+// PingExample confrontation-training
 // @Summary 用户列表查询
 // @Schemes
 // @Description 用户列表查询
@@ -153,7 +153,7 @@ func (u *UserService) UserList(c *gin.Context) {
 }
 
 // ModePass
-// PingExample kjb-doc
+// PingExample confrontation-training
 // @Summary 用户修改密码
 // @Schemes
 // @Description 用户修改密码

+ 57 - 2
common/time.go

@@ -1,8 +1,63 @@
 package common
 
-import "time"
+import (
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+)
 
 // NowTime 时间格式化
 func NowTime() string {
-	return time.Now().Format("2006-01-02 15:04:05")
+	return time.Now().Format(`2006-01-02 15:04:05`)
+}
+
+// GetHexTimeStr 时间16进制字符串
+func GetHexTimeStr() string {
+	nowtime := time.Now().Format(`2006-01-02 15:04:05`)
+	nowtime = "2023-07-31 14:28:00"
+	nowtime = nowtime[2:]
+	split := strings.Split(nowtime, " ")
+	yearArr := strings.Split(split[0], "-")
+	timeArr := strings.Split(split[1], ":")
+	var result strings.Builder
+	for _, value := range yearArr {
+		valueInt, err := strconv.ParseInt(value, 10, 64)
+		if err != nil {
+			fmt.Errorf("%s", "data format error")
+			return ""
+		}
+		formatInt := strconv.FormatInt(valueInt, 16)
+		if len(formatInt) == 1 {
+			formatInt = fmt.Sprintf("%s%s", "0", formatInt)
+
+		}
+		result.WriteString(formatInt)
+	}
+	for _, value := range timeArr {
+		valueInt, err := strconv.ParseInt(value, 10, 64)
+		if err != nil {
+			fmt.Errorf("%s", "data format error")
+			return ""
+		}
+		formatInt := strconv.FormatInt(valueInt, 16)
+		if len(formatInt) == 1 {
+			formatInt = fmt.Sprintf("%s%s", "0", formatInt)
+
+		}
+		result.WriteString(formatInt)
+	}
+	//for _, value := range timeArr {
+	//	valueInt, err := strconv.ParseInt(value, 10, 64)
+	//	if err != nil {
+	//		fmt.Errorf("%s", "data format error")
+	//		return ""
+	//	}
+	//	if valueInt < 10 {
+	//		result.WriteString("0")
+	//	}
+	//	result.WriteString(strconv.FormatInt(valueInt, 16))
+	//}
+	return result.String()
+
 }

+ 38 - 1
common/utils.go

@@ -1,6 +1,10 @@
 package common
 
 import (
+	"bytes"
+	"confrontation-training/constant"
+	"encoding/binary"
+	"encoding/hex"
 	"fmt"
 	"github.com/google/uuid"
 	"log"
@@ -49,6 +53,39 @@ func Int2Bytes(i int) [4]byte {
 	result[3] = byte(i & 0xFF)
 	return result
 }
-func Bytes2HexStr(bytes [4]byte) {
+func Bytes2HexStr(bytes [4]byte) string {
+	var result string
+	for _, value := range bytes {
+		if &value == nil {
+			result = ""
+			break
+		}
+		result = fmt.Sprint(result, value&0xFF)
+	}
+	return result
+}
 
+// GenerateHexStringCmdPlaceHolder 生成名称占位符
+func GenerateHexStringCmdPlaceHolder(length int) string {
+	if length <= 0 {
+		return ""
+	}
+	if length%2 != 0 {
+		fmt.Println("占位符个数为奇数")
+	}
+	var sb strings.Builder
+	for i := 0; i < length; i++ {
+		sb.WriteString(constant.DefaultPlaceHolder)
+	}
+	return sb.String()
+}
+
+func Int2Byte(i int64) string {
+	bytesBuffer := bytes.NewBuffer([]byte{})
+	err := binary.Write(bytesBuffer, binary.BigEndian, i)
+	if err != nil {
+		fmt.Println("数据转换异常:" + err.Error())
+		return ""
+	}
+	return hex.EncodeToString(bytesBuffer.Bytes())
 }

+ 9 - 1
config/application.yaml

@@ -24,4 +24,12 @@ cron:
 
 #蓝牙网关地址
 gateway:
-  ip: 192.168.1.100
+  baseUrl: http://192.168.2.254
+  scanUrl: /gap/nodes?active=1&event=1
+  connUrl: /gap/nodes/MAC/connection?chip
+  notifyUrl: /gatt/nodes?event=1
+  writeDataUrl: /gatt/nodes/MAC/handle/39/value/DATA
+  scanSecond: 30 #蓝牙扫描时长
+
+
+

+ 11 - 0
config/config.go

@@ -1,11 +1,22 @@
 package config
 
+type Gateway struct {
+	BaseUrl         string `mpstructure:"baseUrl"`
+	ScanUrl         string `mapstructure:"scanUrl"`
+	ScanSecond      int64  `mapstructure:"scanSecond"`
+	ConnUrl         string `mapstructure:"connUrl"`
+	NotifyUrl       string `mapstructure:"notifyUrl"`
+	WriteDataUrl    string `mapstructure:"writeDataUrl"`
+	StartCollectUrl string `mapstructure:"startCollectUrl"`
+}
+
 type Config struct {
 	Server    Server    `mapstructure:"server"`
 	SQLite    SQLite    `mapstructure:"sqlite"`
 	Jwt       Jwt       `mapstructure:"jwt"`
 	Upload    Upload    `mapstructure:"upload"`
 	Websocket Websocket `mapstructure:"websocket"`
+	Gateway   Gateway   `mapstructure:"gateway"`
 }
 
 // Server 服务启动端口配置

+ 16 - 3
constant/constant.go

@@ -1,7 +1,20 @@
 package constant
 
 const (
-	RoleAdmin       = 1
-	RoleNormal      = 0
-	DefaultPassword = "e10adc3949ba59abbe56e057f20f883e" //系统默认密码123456
+	RoleAdmin             = 1
+	RoleNormal            = 0
+	DefaultPassword       = "e10adc3949ba59abbe56e057f20f883e" //系统默认密码123456
+	FilterNameECG         = "BW-ECG*"
+	FilterNameEEG         = "MIND*"
+	FilterNameALL         = "BE-ECG*,MIND*"
+	BindUserInfoCmdPrefix = "e841aa" //绑定用户信息指令头
+	SetTimeCmdPrefix      = "e840"
+	StartCollectCmdPrefix = "e823"
+	StartTransCmd         = "e82001363380"
+	//ECG默认用户信息
+	EcgDefaultAge      = 20 //年龄默认值20
+	EcgDefaultHeight   = 170
+	EcgDefaultWeight   = 65
+	MaxNameByteLength  = 12
+	DefaultPlaceHolder = "00"
 )

+ 3 - 2
err/errMsg.go

@@ -20,8 +20,9 @@ const (
 	SendMessageError          = "消息发送失败"
 	SocketCloseError          = "Socket关闭异常:"
 	RecordSaveError           = "记录保存失败"
-	RecordSaveSuccess         = "记录保存成功"
-	RecordNotFoundError       = "未找到记录"
+	DeviceConnectSuccess      = "设备连接成功"
+	WriteDataSuccess          = "写入数据成功"
+	DeviceConnectError        = "设备连接失败"
 	TestResultFailed          = "测试失败,失败原因:"
 	TestResultSuccess         = "测试完成,测试结果:"
 )

+ 34 - 13
go.mod

@@ -6,49 +6,70 @@ require (
 	github.com/gin-gonic/gin v1.9.1
 	github.com/golang-jwt/jwt v3.2.2+incompatible
 	github.com/google/uuid v1.1.2
+	github.com/r3labs/sse/v2 v2.10.0
 	github.com/spf13/viper v1.16.0
+	github.com/swaggo/files v1.0.1
+	github.com/swaggo/gin-swagger v1.6.0
 	gorm.io/driver/sqlite v1.5.2
 	gorm.io/gorm v1.25.2
 )
 
 require (
-	github.com/bytedance/sonic v1.9.1 // indirect
-	github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
+	github.com/KyleBanks/depth v1.2.1 // indirect
+	github.com/PuerkitoBio/purell v1.2.0 // indirect
+	github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
+	github.com/bytedance/sonic v1.10.0-rc3 // indirect
+	github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
+	github.com/chenzhuoyu/iasm v0.9.0 // indirect
+	github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
 	github.com/fsnotify/fsnotify v1.6.0 // indirect
 	github.com/gabriel-vasile/mimetype v1.4.2 // indirect
 	github.com/gin-contrib/sse v0.1.0 // indirect
+	github.com/go-openapi/jsonpointer v0.20.0 // indirect
+	github.com/go-openapi/jsonreference v0.20.2 // indirect
+	github.com/go-openapi/spec v0.20.9 // indirect
+	github.com/go-openapi/swag v0.22.4 // indirect
 	github.com/go-playground/locales v0.14.1 // indirect
 	github.com/go-playground/universal-translator v0.18.1 // indirect
-	github.com/go-playground/validator/v10 v10.14.0 // indirect
+	github.com/go-playground/validator/v10 v10.14.1 // indirect
 	github.com/goccy/go-json v0.10.2 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
 	github.com/jinzhu/inflection v1.0.0 // indirect
 	github.com/jinzhu/now v1.1.5 // indirect
+	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
-	github.com/klauspost/cpuid/v2 v2.2.4 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.5 // indirect
 	github.com/leodido/go-urn v1.2.4 // indirect
 	github.com/magiconair/properties v1.8.7 // indirect
+	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/mattn/go-isatty v0.0.19 // indirect
 	github.com/mattn/go-sqlite3 v1.14.17 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
-	github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
-	github.com/pelletier/go-toml/v2 v2.0.8 // indirect
+	github.com/pelletier/go-toml/v2 v2.0.9 // indirect
+	github.com/russross/blackfriday/v2 v2.1.0 // indirect
+	github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
 	github.com/spf13/afero v1.9.5 // indirect
 	github.com/spf13/cast v1.5.1 // indirect
 	github.com/spf13/jwalterweatherman v1.1.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/subosito/gotenv v1.4.2 // indirect
+	github.com/swaggo/swag v1.16.1 // indirect
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
 	github.com/ugorji/go/codec v1.2.11 // indirect
-	golang.org/x/arch v0.3.0 // indirect
-	golang.org/x/crypto v0.9.0 // indirect
-	golang.org/x/net v0.10.0 // indirect
-	golang.org/x/sys v0.8.0 // indirect
-	golang.org/x/text v0.9.0 // indirect
-	google.golang.org/protobuf v1.30.0 // indirect
-	gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
+	github.com/urfave/cli/v2 v2.25.7 // indirect
+	github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
+	golang.org/x/arch v0.4.0 // indirect
+	golang.org/x/crypto v0.11.0 // indirect
+	golang.org/x/net v0.12.0 // indirect
+	golang.org/x/sys v0.10.0 // indirect
+	golang.org/x/text v0.11.0 // indirect
+	golang.org/x/tools v0.11.0 // indirect
+	google.golang.org/protobuf v1.31.0 // indirect
+	gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect
+	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
+	sigs.k8s.io/yaml v1.3.0 // indirect
 )

+ 121 - 0
go.sum

@@ -38,13 +38,28 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
+github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
+github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/purell v1.2.0 h1:/Jdm5QfyM8zdlqT6WVZU4cfP23sot6CEHA4CS49Ezig=
+github.com/PuerkitoBio/purell v1.2.0/go.mod h1:OhLRTaaIzhvIyofkJfB24gokC7tM42Px5UhoT32THBk=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
 github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
 github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
 github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
+github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
+github.com/bytedance/sonic v1.10.0-rc3 h1:uNSnscRapXTwUgTyOF0GVljYD08p9X/Lbr9MweSV3V0=
+github.com/bytedance/sonic v1.10.0-rc3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
 github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
 github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
+github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
+github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
+github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo=
+github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -52,6 +67,9 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
 github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
+github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -66,6 +84,7 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4
 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
 github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
 github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
+github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
 github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
 github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
 github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
@@ -73,6 +92,27 @@ github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SU
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
+github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
+github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
+github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
+github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
+github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
+github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
+github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
+github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
+github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
+github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
+github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8=
+github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
+github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
+github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
+github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
 github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
 github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
 github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
@@ -80,6 +120,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
 github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
 github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
 github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
+github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
+github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
 github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
 github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
@@ -153,6 +195,8 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
 github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
 github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
@@ -161,16 +205,27 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
 github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
+github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
+github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
 github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
 github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
 github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
 github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
+github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
+github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
 github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
 github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
@@ -186,13 +241,21 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
 github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
+github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
+github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0=
+github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
+github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
 github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
 github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
@@ -210,6 +273,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 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=
@@ -217,16 +281,31 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
 github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
 github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
 github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
+github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
+github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
+github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
+github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
+github.com/swaggo/swag v1.8.12 h1:pctzkNPu0AlQP2royqX3apjKCQonAnf7KGoxeO4y64w=
+github.com/swaggo/swag v1.8.12/go.mod h1:lNfm6Gg+oAq3zRJQNEMBE66LIJKM44mxFqhEEgy2its=
+github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg=
+github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto=
 github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
 github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
 github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
 github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
+github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
+github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
+github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -236,15 +315,20 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
 golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
 golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
 golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc=
+golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
 golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
+golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
+golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -278,6 +362,9 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
+golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -290,6 +377,7 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -309,9 +397,14 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
 golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
 golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
+golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -331,6 +424,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -363,15 +457,23 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
+golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -380,8 +482,11 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
+golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -432,6 +537,11 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
 golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
+golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
+golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8=
+golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -527,15 +637,23 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
 google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=
+gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 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.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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=
 gorm.io/driver/sqlite v1.5.2 h1:TpQ+/dqCY4uCigCFyrfnrJnrW9zjpelWVoEVNy5qJkc=
@@ -549,7 +667,10 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
 honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
+sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=

+ 111 - 0
http/http.go

@@ -0,0 +1,111 @@
+package http
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"strings"
+	"unsafe"
+)
+
+func GetReq(url string) map[string]string {
+	client := &http.Client{}
+
+	req, err := http.NewRequest("GET", url, nil)
+	if err != nil {
+		panic(err)
+	}
+
+	resp, err := client.Do(req)
+
+	defer resp.Body.Close()
+
+	body, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		panic(err)
+	}
+	var resData map[string]string
+	err = json.Unmarshal(body, &resData)
+	if err != nil {
+		fmt.Println("body===" + string(body))
+		return nil
+	} else {
+		return resData
+	}
+
+}
+
+func postReq(name string, age int) {
+	client := &http.Client{}
+
+	req, err := http.NewRequest("POST", "http://localhost:5000/post",
+		strings.NewReader(fmt.Sprintf("name=%s&age=%d", name, age)))
+	if err != nil {
+		panic(err)
+	}
+
+	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+
+	resp, err := client.Do(req)
+
+	defer resp.Body.Close()
+
+}
+
+// PostReqJson 通过json提交post
+func PostReqJson(url string, json []byte) *http.Response {
+	req, err := http.NewRequest("POST", url, bytes.NewBuffer(json))
+	req.Header.Set("Content-Type", "application/json")
+	client := &http.Client{}
+	resp, err := client.Do(req)
+	if err != nil {
+		panic(err)
+	}
+	defer func(Body io.ReadCloser) {
+		err := Body.Close()
+		if err != nil {
+			fmt.Print("Body close err" + err.Error())
+		}
+	}(resp.Body)
+	return resp
+}
+
+type JsonPost struct {
+}
+
+func (jp *JsonPost) postReqJson2() {
+	post := make(map[string]interface{})
+	post["name"] = "王柳"
+	post["age"] = 21
+	bytesData, err := json.Marshal(post)
+	if err != nil {
+		fmt.Println(err.Error())
+		return
+	}
+	reader := bytes.NewReader(bytesData)
+	url := "http://localhost:5000/post"
+	request, err := http.NewRequest("POST", url, reader)
+	if err != nil {
+		fmt.Println(err.Error())
+		return
+	}
+	request.Header.Set("Content-Type", "application/json;charset=UTF-8")
+	client := http.Client{}
+	resp, err := client.Do(request)
+	if err != nil {
+		fmt.Println(err.Error())
+		return
+	}
+	respBytes, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		fmt.Println(err.Error())
+		return
+	}
+	//byte数组直接转成string,优化内存
+	str := (*string)(unsafe.Pointer(&respBytes))
+	fmt.Println(*str)
+
+}

+ 12 - 5
initialize/router.go

@@ -3,9 +3,12 @@ package initialize
 import (
 	"confrontation-training/api"
 	"confrontation-training/global"
+	_ "confrontation-training/global"
 	"confrontation-training/middleware"
 	"fmt"
 	"github.com/gin-gonic/gin"
+	swaggerFiles "github.com/swaggo/files"
+	ginSwagger "github.com/swaggo/gin-swagger"
 	"net/http"
 )
 
@@ -20,21 +23,25 @@ func Router() {
 		context.String(http.StatusNotFound, "404 not found")
 	})
 
-	////swag
-	//engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
-	//engine.Static("/file", "./files")
+	//swag
+	engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
+	engine.Static("/file", "./files")
 	//engine.GET("/ws", WsHandler)
-	//
+
 	//group
 	v1 := engine.Group("/v1")
 	user := v1.Group("/user")
 	user.POST("/login", api.GetUser().UserLogin)
 
-	user.Use(middleware.JwtAuth())
+	//user.Use(middleware.JwtAuth())
 	user.POST("/register", api.GetUser().UseRegister)
 	user.POST("/reset", api.GetUser().ResetPassword)
 	user.POST("/find", api.GetUser().UserList)
 	user.POST("/change/password", api.GetUser().ModePass)
+	device := v1.Group("/device")
+	device.GET("/scan", api.ScanDevice)
+	device.GET("/connection", api.ConnectDevice)
+	device.POST("/write/data/", api.WriteData)
 	//
 	//record := v1.Group("/record")
 	//record.POST("/create", api.GetRecord().SaveRecord)

+ 40 - 40
main.go

@@ -2,46 +2,46 @@ package main
 
 import "confrontation-training/initialize"
 
-//func main() {
-//	fmt.Println("===>hello world!")
-//	db, err := gorm.Open(sqlite.Open("confrontation-training.db"), &gorm.Config{})
-//	if err != nil {
-//		fmt.Printf("初始化数据库异常:%s", err)
-//		panic("failed to open database")
-//	}
-//	error := db.AutoMigrate(&Product{})
-//	if error != nil {
-//		fmt.Printf("AutoMigrate Product 数据库异常:%s", error)
-//		panic("failed to open database")
-//	}
-//	create := db.Create(&Product{Title: "手机", Code: "001", Price: 10000})
-//	if create.RowsAffected < 0 {
-//		fmt.Println("插入有误--23 line")
-//	}
-//	db.Create(&Product{Title: "平板", Code: "002", Price: 110000})
-//	// 读取内容
-//	var product Product
-//	db.First(&product, 1) // find product with integer primary key
-//	fmt.Println(product)
-//	db.First(&product, "code = ?", "001") // find product with code D42
-//	fmt.Println(product)
-//	// 更新操作:更新单个字段
-//	db.Model(&product).Update("Price", 2000)
-//	fmt.Println(product)
-//	// 更新操作:更新多个字段
-//	db.Model(&product).Updates(Product{Price: 2000, Code: "001"}) // non-zero fields
-//	fmt.Println(product)
-//	db.Model(&product).Updates(map[string]interface{}{"Price": 2000, "Code": "001"})
-//	fmt.Println(product)
-//}
-//
-//type Product struct {
-//	gorm.Model
-//	Title string
-//	Code  string
-//	Price uint
-//}
-
+//@title 对抗训练
+//@version 1.0
+//@description 对抗训练
+//@contact.name Develoven
+//contact.email develoven@163.com
+//contact.url https://www.cnblogs.com/wormworm
 func main() {
 	initialize.Run()
+	//aa()
+}
+
+func aa() {
+	//parse, err := time.Parse(`2006-01-02 15:04:05`, "2023-07-31 14:28:00")
+	//if err != nil {
+	//	return ""
+	//}
+	//fmt.Println(parse)
+	//year := parse.Year()
+	//monthStr := parse.Format("01")
+	//month, err := strconv.ParseInt(monthStr, 10, 64)
+	//if err != nil {
+	//	return ""
+	//}
+	//day := parse.Day()
+	//hour := parse.Hour()
+	//minute := parse.Minute()
+	//second := parse.Second()
+	//return strconv.FormatInt(23, 16) +
+	//	strconv.FormatInt(07, 16) +
+	//	strconv.FormatInt(int64(31), 16) +
+	//	strconv.FormatInt(int64(14), 16) +
+	//	strconv.FormatInt(int64(28), 16) +
+	//	strconv.FormatInt(int64(00), 16)
+	//i := int64(23)
+	//var str strings.Builder
+	//if i < 10 {
+	//	str.WriteString("0")
+	//	str.WriteString(strconv.FormatInt(i, 16))
+	//} else {
+	//	str.WriteString(strconv.FormatInt(23, 16))
+	//}
+	//fmt.Println(str.String())
 }

+ 35 - 0
models/device.go

@@ -0,0 +1,35 @@
+package models
+
+type DeviceScanParam struct {
+	Chip       string `json:"chip"`       //芯片 0和1
+	FilterName string `json:"filterName"` // 0 脑电 1 心电
+	FilterRssi string `json:"filterRssi"` //信号强度
+	FilterMac  string `json:"filterMac"`  //过滤Mac地址,以","分割,如 61-Dg-89-22-39-3b,80-kD-0E-40-57-8A
+}
+
+type DeviceConnParam struct {
+	Chip     string `json:"chip" binding:"required" `    //芯片 0/1
+	AddrType string `json:"addrType" binding:"required"` //地址类型 public/random
+	Mac      string `json:"mac" binding:"required"`      //设备Mac地址
+}
+
+type DeviceScannedFromGateway struct {
+	Bdaddrs []Bdaddrs
+	ChipId  int64
+	EvtType int64
+	Name    string
+	Rssi    int64
+	adData  string
+}
+type Bdaddrs struct {
+	Bdaddr     string `json:"bdaddr"`
+	BdaddrType string `json:"bdaddrType"`
+}
+
+type DeviceScanned struct {
+	MAC       string
+	Name      string
+	Rssi      int64
+	BdadrType string //地址类型
+	Chip      int64
+}

+ 14 - 1
models/user.go

@@ -5,10 +5,14 @@ import "gorm.io/gorm"
 //User 用户数据映射模型
 type User struct {
 	gorm.Model
-	Password string `gorm:"password"`
+	Password string `gorm:"password type:varchar(50) not null comment '密码'" `
 	UserName string `gorm:"user_name"`
 	Phone    string `gorm:"phone"`
 	Role     *uint8 `gorm:"role" `
+	Gender   string `gorm:"gender type:varchar(2) comment '性别:1男 0女'"`
+	Age      string `gorm:"age type:varchar(10) comment '年龄'"`
+	Height   string `gorm:"height type:varchar(10) comment '身高:cm'"`
+	Weight   string `gorm:"weight type:varchar(10) comment '体重'"`
 }
 
 type UserRegister struct {
@@ -41,3 +45,12 @@ type ChangePassword struct {
 	Password    string `json:"password" binding:"required"`
 	NewPassword string `json:"newPassword" binding:"required"`
 }
+
+type WriteData struct {
+	UserName string `json:"userName" binding:"required"`
+	Gender   int64  `json:"gender"`
+	Height   int64  `json:"height"`
+	Weight   int64  `json:"weight"`
+	Age      int64  `json:"age"`
+	Mac      string `json:"mac" binding:"required"`
+}