Browse Source

feature(钉钉回调): 钉钉回调添加任务和实例的两种类型;审批流对外开放接口

likai 3 years ago
parent
commit
85aba262b5

+ 9 - 9
opms_libary/plugin/dingtalk/message/message.go

@@ -8,12 +8,12 @@ type EventType string
 const (
 	//EventCheckUrl 验证URL
 	EventCheckUrl EventType = "check_url"
-	//EventSubscribe 订阅
-	EventSubscribe = "subscribe"
-	//EventUnsubscribe 取消订阅
-	EventUnsubscribe = "unsubscribe"
 	//EventCalendarChange 日程变更
 	EventCalendarChange = "calendar_event_change"
+	//BpmsInstanceChange 审批实例变更
+	BpmsInstanceChange = "bpms_instance_change"
+	//BpmsInstanceChange 审批任务变更
+	BpmsTaskChange = "bpms_task_change"
 )
 
 // SubsMessage 订阅消息
@@ -25,8 +25,7 @@ type SubsMessage struct {
 //MixMessage 存放所有钉钉发送过来的消息和事件
 type MixMessage struct {
 	EventType EventType `json:"EventType"`
-	// 日程相关
-	// 审批通知
+	// 审批相关
 	ProcessInstanceId string `json:"processInstanceId"`
 	CorpId            string `json:"corpId"`
 	CreateTime        string `json:"createTime"`
@@ -37,10 +36,11 @@ type MixMessage struct {
 	Url               string `json:"url"`
 	Result            string `json:"result"`
 	ProcessCode       string `json:"processCode"`
+	Remark            string `json:"remark"`
 	// 日程变更
-	ChangeType        string `json:"changeType"`
-	CalendarEventId   string `json:"CalendarEventId"`
-	UnionIdList      []string `json:"processCode"`
+	ChangeType        string   `json:"changeType"`
+	CalendarEventId   string   `json:"CalendarEventId"`
+	UnionIdList       []string `json:"processCode"`
 }
 
 //Reply 消息回复

+ 491 - 0
opms_libary/utils/tea.go

@@ -0,0 +1,491 @@
+package utils
+
+func String(a string) *string {
+	return &a
+}
+
+func StringValue(a *string) string {
+	if a == nil {
+		return ""
+	}
+	return *a
+}
+
+func Int(a int) *int {
+	return &a
+}
+
+func IntValue(a *int) int {
+	if a == nil {
+		return 0
+	}
+	return *a
+}
+
+func Int8(a int8) *int8 {
+	return &a
+}
+
+func Int8Value(a *int8) int8 {
+	if a == nil {
+		return 0
+	}
+	return *a
+}
+
+func Int16(a int16) *int16 {
+	return &a
+}
+
+func Int16Value(a *int16) int16 {
+	if a == nil {
+		return 0
+	}
+	return *a
+}
+
+func Int32(a int32) *int32 {
+	return &a
+}
+
+func Int32Value(a *int32) int32 {
+	if a == nil {
+		return 0
+	}
+	return *a
+}
+
+func Int64(a int64) *int64 {
+	return &a
+}
+
+func Int64Value(a *int64) int64 {
+	if a == nil {
+		return 0
+	}
+	return *a
+}
+
+func Bool(a bool) *bool {
+	return &a
+}
+
+func BoolValue(a *bool) bool {
+	if a == nil {
+		return false
+	}
+	return *a
+}
+
+func Uint(a uint) *uint {
+	return &a
+}
+
+func UintValue(a *uint) uint {
+	if a == nil {
+		return 0
+	}
+	return *a
+}
+
+func Uint8(a uint8) *uint8 {
+	return &a
+}
+
+func Uint8Value(a *uint8) uint8 {
+	if a == nil {
+		return 0
+	}
+	return *a
+}
+
+func Uint16(a uint16) *uint16 {
+	return &a
+}
+
+func Uint16Value(a *uint16) uint16 {
+	if a == nil {
+		return 0
+	}
+	return *a
+}
+
+func Uint32(a uint32) *uint32 {
+	return &a
+}
+
+func Uint32Value(a *uint32) uint32 {
+	if a == nil {
+		return 0
+	}
+	return *a
+}
+
+func Uint64(a uint64) *uint64 {
+	return &a
+}
+
+func Uint64Value(a *uint64) uint64 {
+	if a == nil {
+		return 0
+	}
+	return *a
+}
+
+func Float32(a float32) *float32 {
+	return &a
+}
+
+func Float32Value(a *float32) float32 {
+	if a == nil {
+		return 0
+	}
+	return *a
+}
+
+func Float64(a float64) *float64 {
+	return &a
+}
+
+func Float64Value(a *float64) float64 {
+	if a == nil {
+		return 0
+	}
+	return *a
+}
+
+func IntSlice(a []int) []*int {
+	if a == nil {
+		return nil
+	}
+	res := make([]*int, len(a))
+	for i := 0; i < len(a); i++ {
+		res[i] = &a[i]
+	}
+	return res
+}
+
+func IntValueSlice(a []*int) []int {
+	if a == nil {
+		return nil
+	}
+	res := make([]int, len(a))
+	for i := 0; i < len(a); i++ {
+		if a[i] != nil {
+			res[i] = *a[i]
+		}
+	}
+	return res
+}
+
+func Int8Slice(a []int8) []*int8 {
+	if a == nil {
+		return nil
+	}
+	res := make([]*int8, len(a))
+	for i := 0; i < len(a); i++ {
+		res[i] = &a[i]
+	}
+	return res
+}
+
+func Int8ValueSlice(a []*int8) []int8 {
+	if a == nil {
+		return nil
+	}
+	res := make([]int8, len(a))
+	for i := 0; i < len(a); i++ {
+		if a[i] != nil {
+			res[i] = *a[i]
+		}
+	}
+	return res
+}
+
+func Int16Slice(a []int16) []*int16 {
+	if a == nil {
+		return nil
+	}
+	res := make([]*int16, len(a))
+	for i := 0; i < len(a); i++ {
+		res[i] = &a[i]
+	}
+	return res
+}
+
+func Int16ValueSlice(a []*int16) []int16 {
+	if a == nil {
+		return nil
+	}
+	res := make([]int16, len(a))
+	for i := 0; i < len(a); i++ {
+		if a[i] != nil {
+			res[i] = *a[i]
+		}
+	}
+	return res
+}
+
+func Int32Slice(a []int32) []*int32 {
+	if a == nil {
+		return nil
+	}
+	res := make([]*int32, len(a))
+	for i := 0; i < len(a); i++ {
+		res[i] = &a[i]
+	}
+	return res
+}
+
+func Int32ValueSlice(a []*int32) []int32 {
+	if a == nil {
+		return nil
+	}
+	res := make([]int32, len(a))
+	for i := 0; i < len(a); i++ {
+		if a[i] != nil {
+			res[i] = *a[i]
+		}
+	}
+	return res
+}
+
+func Int64Slice(a []int64) []*int64 {
+	if a == nil {
+		return nil
+	}
+	res := make([]*int64, len(a))
+	for i := 0; i < len(a); i++ {
+		res[i] = &a[i]
+	}
+	return res
+}
+
+func Int64ValueSlice(a []*int64) []int64 {
+	if a == nil {
+		return nil
+	}
+	res := make([]int64, len(a))
+	for i := 0; i < len(a); i++ {
+		if a[i] != nil {
+			res[i] = *a[i]
+		}
+	}
+	return res
+}
+
+func UintSlice(a []uint) []*uint {
+	if a == nil {
+		return nil
+	}
+	res := make([]*uint, len(a))
+	for i := 0; i < len(a); i++ {
+		res[i] = &a[i]
+	}
+	return res
+}
+
+func UintValueSlice(a []*uint) []uint {
+	if a == nil {
+		return nil
+	}
+	res := make([]uint, len(a))
+	for i := 0; i < len(a); i++ {
+		if a[i] != nil {
+			res[i] = *a[i]
+		}
+	}
+	return res
+}
+
+func Uint8Slice(a []uint8) []*uint8 {
+	if a == nil {
+		return nil
+	}
+	res := make([]*uint8, len(a))
+	for i := 0; i < len(a); i++ {
+		res[i] = &a[i]
+	}
+	return res
+}
+
+func Uint8ValueSlice(a []*uint8) []uint8 {
+	if a == nil {
+		return nil
+	}
+	res := make([]uint8, len(a))
+	for i := 0; i < len(a); i++ {
+		if a[i] != nil {
+			res[i] = *a[i]
+		}
+	}
+	return res
+}
+
+func Uint16Slice(a []uint16) []*uint16 {
+	if a == nil {
+		return nil
+	}
+	res := make([]*uint16, len(a))
+	for i := 0; i < len(a); i++ {
+		res[i] = &a[i]
+	}
+	return res
+}
+
+func Uint16ValueSlice(a []*uint16) []uint16 {
+	if a == nil {
+		return nil
+	}
+	res := make([]uint16, len(a))
+	for i := 0; i < len(a); i++ {
+		if a[i] != nil {
+			res[i] = *a[i]
+		}
+	}
+	return res
+}
+
+func Uint32Slice(a []uint32) []*uint32 {
+	if a == nil {
+		return nil
+	}
+	res := make([]*uint32, len(a))
+	for i := 0; i < len(a); i++ {
+		res[i] = &a[i]
+	}
+	return res
+}
+
+func Uint32ValueSlice(a []*uint32) []uint32 {
+	if a == nil {
+		return nil
+	}
+	res := make([]uint32, len(a))
+	for i := 0; i < len(a); i++ {
+		if a[i] != nil {
+			res[i] = *a[i]
+		}
+	}
+	return res
+}
+
+func Uint64Slice(a []uint64) []*uint64 {
+	if a == nil {
+		return nil
+	}
+	res := make([]*uint64, len(a))
+	for i := 0; i < len(a); i++ {
+		res[i] = &a[i]
+	}
+	return res
+}
+
+func Uint64ValueSlice(a []*uint64) []uint64 {
+	if a == nil {
+		return nil
+	}
+	res := make([]uint64, len(a))
+	for i := 0; i < len(a); i++ {
+		if a[i] != nil {
+			res[i] = *a[i]
+		}
+	}
+	return res
+}
+
+func Float32Slice(a []float32) []*float32 {
+	if a == nil {
+		return nil
+	}
+	res := make([]*float32, len(a))
+	for i := 0; i < len(a); i++ {
+		res[i] = &a[i]
+	}
+	return res
+}
+
+func Float32ValueSlice(a []*float32) []float32 {
+	if a == nil {
+		return nil
+	}
+	res := make([]float32, len(a))
+	for i := 0; i < len(a); i++ {
+		if a[i] != nil {
+			res[i] = *a[i]
+		}
+	}
+	return res
+}
+
+func Float64Slice(a []float64) []*float64 {
+	if a == nil {
+		return nil
+	}
+	res := make([]*float64, len(a))
+	for i := 0; i < len(a); i++ {
+		res[i] = &a[i]
+	}
+	return res
+}
+
+func Float64ValueSlice(a []*float64) []float64 {
+	if a == nil {
+		return nil
+	}
+	res := make([]float64, len(a))
+	for i := 0; i < len(a); i++ {
+		if a[i] != nil {
+			res[i] = *a[i]
+		}
+	}
+	return res
+}
+
+func StringSlice(a []string) []*string {
+	if a == nil {
+		return nil
+	}
+	res := make([]*string, len(a))
+	for i := 0; i < len(a); i++ {
+		res[i] = &a[i]
+	}
+	return res
+}
+
+func StringSliceValue(a []*string) []string {
+	if a == nil {
+		return nil
+	}
+	res := make([]string, len(a))
+	for i := 0; i < len(a); i++ {
+		if a[i] != nil {
+			res[i] = *a[i]
+		}
+	}
+	return res
+}
+
+func BoolSlice(a []bool) []*bool {
+	if a == nil {
+		return nil
+	}
+	res := make([]*bool, len(a))
+	for i := 0; i < len(a); i++ {
+		res[i] = &a[i]
+	}
+	return res
+}
+
+func BoolSliceValue(a []*bool) []bool {
+	if a == nil {
+		return nil
+	}
+	res := make([]bool, len(a))
+	for i := 0; i < len(a); i++ {
+		if a[i] != nil {
+			res[i] = *a[i]
+		}
+	}
+	return res
+}

+ 440 - 0
opms_parent/app/dao/workflow/internal/plat_workflow.go

@@ -0,0 +1,440 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. DO NOT EDIT THIS FILE MANUALLY.
+// ==========================================================================
+
+package internal
+
+import (
+	"context"
+	"dashoo.cn/micro/app/model/workflow"
+	"database/sql"
+	"github.com/gogf/gf/database/gdb"
+	"github.com/gogf/gf/frame/g"
+	"github.com/gogf/gf/frame/gmvc"
+	"time"
+)
+
+// PlatWorkflowDao is the manager for logic model data accessing
+// and custom defined data operations functions management.
+type PlatWorkflowDao struct {
+	gmvc.M
+	DB      gdb.DB
+	Table   string
+	Columns platWorkflowColumns
+}
+
+// PlatWorkflowColumns defines and stores column names for table plat_workflow.
+type platWorkflowColumns struct {
+	Id              string // 主键
+	BizCode         string // 业务单号
+	BizType         string // 业务类型(10领用20项目创建30合同创建)
+	CurrentNode     string // 当前节点
+	CurrentNodeTime string // 当前节点时间
+	ApprovalResult  string // 审批结果
+	ProcessCode     string // 审批流编码
+	ProcessInstId   string // 审批实例ID
+	Remark          string // 备注
+	CreatedBy       string // 创建者
+	CreatedName     string // 创建人
+	CreatedTime     string // 创建时间
+	UpdatedBy       string // 更新者
+	UpdatedName     string // 更新人
+	UpdatedTime     string // 更新时间
+	DeletedTime     string // 删除时间
+}
+
+var (
+	// PlatWorkflow is globally public accessible object for table plat_workflow operations.
+	PlatWorkflow = PlatWorkflowDao{
+		M:     g.DB("default").Model("plat_workflow").Safe(),
+		DB:    g.DB("default"),
+		Table: "plat_workflow",
+		Columns: platWorkflowColumns{
+			Id:              "id",
+			BizCode:         "biz_code",
+			BizType:         "biz_type",
+			CurrentNode:     "current_node",
+			CurrentNodeTime: "current_node_time",
+			ApprovalResult:  "approval_result",
+			ProcessCode:     "process_code",
+			ProcessInstId:   "process_inst_id",
+			Remark:          "remark",
+			CreatedBy:       "created_by",
+			CreatedName:     "created_name",
+			CreatedTime:     "created_time",
+			UpdatedBy:       "updated_by",
+			UpdatedName:     "updated_name",
+			UpdatedTime:     "updated_time",
+			DeletedTime:     "deleted_time",
+		},
+	}
+)
+
+func NewPlatWorkflowDao(tenant string) PlatWorkflowDao {
+	var dao PlatWorkflowDao
+	dao = PlatWorkflowDao{
+		M:     g.DB(tenant).Model("plat_workflow").Safe(),
+		DB:    g.DB(tenant),
+		Table: "plat_workflow",
+		Columns: platWorkflowColumns{
+			Id:              "id",
+			BizCode:         "biz_code",
+			BizType:         "biz_type",
+			CurrentNode:     "current_node",
+			CurrentNodeTime: "current_node_time",
+			ApprovalResult:  "approval_result",
+			ProcessCode:     "process_code",
+			ProcessInstId:   "process_inst_id",
+			Remark:          "remark",
+			CreatedBy:       "created_by",
+			CreatedName:     "created_name",
+			CreatedTime:     "created_time",
+			UpdatedBy:       "updated_by",
+			UpdatedName:     "updated_name",
+			UpdatedTime:     "updated_time",
+			DeletedTime:     "deleted_time",
+		},
+	}
+	return dao
+}
+
+// Ctx is a chaining function, which creates and returns a new DB that is a shallow copy
+// of current DB object and with given context in it.
+// Note that this returned DB object can be used only once, so do not assign it to
+// a global or package variable for long using.
+func (d *PlatWorkflowDao) Ctx(ctx context.Context) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Ctx(ctx)}
+}
+
+// As sets an alias name for current table.
+func (d *PlatWorkflowDao) As(as string) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.As(as)}
+}
+
+// TX sets the transaction for current operation.
+func (d *PlatWorkflowDao) TX(tx *gdb.TX) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.TX(tx)}
+}
+
+// Master marks the following operation on master node.
+func (d *PlatWorkflowDao) Master() *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Master()}
+}
+
+// Slave marks the following operation on slave node.
+// Note that it makes sense only if there's any slave node configured.
+func (d *PlatWorkflowDao) Slave() *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Slave()}
+}
+
+// Args sets custom arguments for model operation.
+func (d *PlatWorkflowDao) Args(args ...interface{}) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Args(args...)}
+}
+
+// LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").LeftJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").LeftJoin("user_detail", "ud", "ud.uid=u.uid")
+func (d *PlatWorkflowDao) LeftJoin(table ...string) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.LeftJoin(table...)}
+}
+
+// RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").RightJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").RightJoin("user_detail", "ud", "ud.uid=u.uid")
+func (d *PlatWorkflowDao) RightJoin(table ...string) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.RightJoin(table...)}
+}
+
+// InnerJoin does "INNER JOIN ... ON ..." statement on the model.
+// The parameter <table> can be joined table and its joined condition,
+// and also with its alias name, like:
+// Table("user").InnerJoin("user_detail", "user_detail.uid=user.uid")
+// Table("user", "u").InnerJoin("user_detail", "ud", "ud.uid=u.uid")
+func (d *PlatWorkflowDao) InnerJoin(table ...string) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.InnerJoin(table...)}
+}
+
+// Fields sets the operation fields of the model, multiple fields joined using char ','.
+// The parameter <fieldNamesOrMapStruct> can be type of string/map/*map/struct/*struct.
+func (d *PlatWorkflowDao) Fields(fieldNamesOrMapStruct ...interface{}) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Fields(fieldNamesOrMapStruct...)}
+}
+
+// FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','.
+// The parameter <fieldNamesOrMapStruct> can be type of string/map/*map/struct/*struct.
+func (d *PlatWorkflowDao) FieldsEx(fieldNamesOrMapStruct ...interface{}) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.FieldsEx(fieldNamesOrMapStruct...)}
+}
+
+// Option sets the extra operation option for the model.
+func (d *PlatWorkflowDao) Option(option int) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Option(option)}
+}
+
+// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
+// the data and where attributes for empty values.
+func (d *PlatWorkflowDao) OmitEmpty() *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.OmitEmpty()}
+}
+
+// Filter marks filtering the fields which does not exist in the fields of the operated table.
+func (d *PlatWorkflowDao) Filter() *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Filter()}
+}
+
+// Where sets the condition statement for the model. The parameter <where> can be type of
+// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,
+// multiple conditions will be joined into where statement using "AND".
+// Eg:
+// Where("uid=10000")
+// Where("uid", 10000)
+// Where("money>? AND name like ?", 99999, "vip_%")
+// Where("uid", 1).Where("name", "john")
+// Where("status IN (?)", g.Slice{1,2,3})
+// Where("age IN(?,?)", 18, 50)
+// Where(User{ Id : 1, UserName : "john"})
+func (d *PlatWorkflowDao) Where(where interface{}, args ...interface{}) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Where(where, args...)}
+}
+
+// WherePri does the same logic as M.Where except that if the parameter <where>
+// is a single condition like int/string/float/slice, it treats the condition as the primary
+// key value. That is, if primary key is "id" and given <where> parameter as "123", the
+// WherePri function treats the condition as "id=123", but M.Where treats the condition
+// as string "123".
+func (d *PlatWorkflowDao) WherePri(where interface{}, args ...interface{}) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.WherePri(where, args...)}
+}
+
+// And adds "AND" condition to the where statement.
+func (d *PlatWorkflowDao) And(where interface{}, args ...interface{}) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.And(where, args...)}
+}
+
+// Or adds "OR" condition to the where statement.
+func (d *PlatWorkflowDao) Or(where interface{}, args ...interface{}) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Or(where, args...)}
+}
+
+// Group sets the "GROUP BY" statement for the model.
+func (d *PlatWorkflowDao) Group(groupBy string) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Group(groupBy)}
+}
+
+// Order sets the "ORDER BY" statement for the model.
+func (d *PlatWorkflowDao) Order(orderBy ...string) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Order(orderBy...)}
+}
+
+// Limit sets the "LIMIT" statement for the model.
+// The parameter <limit> can be either one or two number, if passed two number is passed,
+// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
+// statement.
+func (d *PlatWorkflowDao) Limit(limit ...int) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Limit(limit...)}
+}
+
+// Offset sets the "OFFSET" statement for the model.
+// It only makes sense for some databases like SQLServer, PostgreSQL, etc.
+func (d *PlatWorkflowDao) Offset(offset int) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Offset(offset)}
+}
+
+// Page sets the paging number for the model.
+// The parameter <page> is started from 1 for paging.
+// Note that, it differs that the Limit function start from 0 for "LIMIT" statement.
+func (d *PlatWorkflowDao) Page(page, limit int) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Page(page, limit)}
+}
+
+// Batch sets the batch operation number for the model.
+func (d *PlatWorkflowDao) Batch(batch int) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Batch(batch)}
+}
+
+// Cache sets the cache feature for the model. It caches the result of the sql, which means
+// if there's another same sql request, it just reads and returns the result from cache, it
+// but not committed and executed into the database.
+//
+// If the parameter <duration> < 0, which means it clear the cache with given <name>.
+// If the parameter <duration> = 0, which means it never expires.
+// If the parameter <duration> > 0, which means it expires after <duration>.
+//
+// The optional parameter <name> is used to bind a name to the cache, which means you can later
+// control the cache like changing the <duration> or clearing the cache with specified <name>.
+//
+// Note that, the cache feature is disabled if the model is operating on a transaction.
+func (d *PlatWorkflowDao) Cache(duration time.Duration, name ...string) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Cache(duration, name...)}
+}
+
+// Data sets the operation data for the model.
+// The parameter <data> can be type of string/map/gmap/slice/struct/*struct, etc.
+// Eg:
+// Data("uid=10000")
+// Data("uid", 10000)
+// Data(g.Map{"uid": 10000, "name":"john"})
+// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
+func (d *PlatWorkflowDao) Data(data ...interface{}) *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Data(data...)}
+}
+
+// All does "SELECT FROM ..." statement for the model.
+// It retrieves the records from table and returns the result as []*model.PlatWorkflow.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of M.Where function,
+// see M.Where.
+func (d *PlatWorkflowDao) All(where ...interface{}) ([]*workflow.PlatWorkflow, error) {
+	all, err := d.M.All(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*workflow.PlatWorkflow
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// One retrieves one record from table and returns the result as *model.PlatWorkflow.
+// It returns nil if there's no record retrieved with the given conditions from table.
+//
+// The optional parameter <where> is the same as the parameter of M.Where function,
+// see M.Where.
+func (d *PlatWorkflowDao) One(where ...interface{}) (*workflow.PlatWorkflow, error) {
+	one, err := d.M.One(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *workflow.PlatWorkflow
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindOne retrieves and returns a single Record by M.WherePri and M.One.
+// Also see M.WherePri and M.One.
+func (d *PlatWorkflowDao) FindOne(where ...interface{}) (*workflow.PlatWorkflow, error) {
+	one, err := d.M.FindOne(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entity *workflow.PlatWorkflow
+	if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entity, nil
+}
+
+// FindAll retrieves and returns Result by by M.WherePri and M.All.
+// Also see M.WherePri and M.All.
+func (d *PlatWorkflowDao) FindAll(where ...interface{}) ([]*workflow.PlatWorkflow, error) {
+	all, err := d.M.FindAll(where...)
+	if err != nil {
+		return nil, err
+	}
+	var entities []*workflow.PlatWorkflow
+	if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
+		return nil, err
+	}
+	return entities, nil
+}
+
+// Struct retrieves one record from table and converts it into given struct.
+// The parameter <pointer> should be type of *struct/**struct. If type **struct is given,
+// it can create the struct internally during converting.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+//
+// Note that it returns sql.ErrNoRows if there's no record retrieved with the given conditions
+// from table and <pointer> is not nil.
+//
+// Eg:
+// user := new(User)
+// err  := dao.User.Where("id", 1).Struct(user)
+//
+// user := (*User)(nil)
+// err  := dao.User.Where("id", 1).Struct(&user)
+func (d *PlatWorkflowDao) Struct(pointer interface{}, where ...interface{}) error {
+	return d.M.Struct(pointer, where...)
+}
+
+// Structs retrieves records from table and converts them into given struct slice.
+// The parameter <pointer> should be type of *[]struct/*[]*struct. It can create and fill the struct
+// slice internally during converting.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+//
+// Note that it returns sql.ErrNoRows if there's no record retrieved with the given conditions
+// from table and <pointer> is not empty.
+//
+// Eg:
+// users := ([]User)(nil)
+// err   := dao.User.Structs(&users)
+//
+// users := ([]*User)(nil)
+// err   := dao.User.Structs(&users)
+func (d *PlatWorkflowDao) Structs(pointer interface{}, where ...interface{}) error {
+	return d.M.Structs(pointer, where...)
+}
+
+// Scan automatically calls Struct or Structs function according to the type of parameter <pointer>.
+// It calls function Struct if <pointer> is type of *struct/**struct.
+// It calls function Structs if <pointer> is type of *[]struct/*[]*struct.
+//
+// The optional parameter <where> is the same as the parameter of Model.Where function,
+// see Model.Where.
+//
+// Note that it returns sql.ErrNoRows if there's no record retrieved and given pointer is not empty or nil.
+//
+// Eg:
+// user  := new(User)
+// err   := dao.User.Where("id", 1).Scan(user)
+//
+// user  := (*User)(nil)
+// err   := dao.User.Where("id", 1).Scan(&user)
+//
+// users := ([]User)(nil)
+// err   := dao.User.Scan(&users)
+//
+// users := ([]*User)(nil)
+// err   := dao.User.Scan(&users)
+func (d *PlatWorkflowDao) Scan(pointer interface{}, where ...interface{}) error {
+	return d.M.Scan(pointer, where...)
+}
+
+// Chunk iterates the table with given size and callback function.
+func (d *PlatWorkflowDao) Chunk(limit int, callback func(entities []*workflow.PlatWorkflow, err error) bool) {
+	d.M.Chunk(limit, func(result gdb.Result, err error) bool {
+		var entities []*workflow.PlatWorkflow
+		err = result.Structs(&entities)
+		if err == sql.ErrNoRows {
+			return false
+		}
+		return callback(entities, err)
+	})
+}
+
+// LockUpdate sets the lock for update for current operation.
+func (d *PlatWorkflowDao) LockUpdate() *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.LockUpdate()}
+}
+
+// LockShared sets the lock in share mode for current operation.
+func (d *PlatWorkflowDao) LockShared() *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.LockShared()}
+}
+
+// Unscoped enables/disables the soft deleting feature.
+func (d *PlatWorkflowDao) Unscoped() *PlatWorkflowDao {
+	return &PlatWorkflowDao{M: d.M.Unscoped()}
+}

+ 36 - 0
opms_parent/app/dao/workflow/plat_workflow.go

@@ -0,0 +1,36 @@
+// ============================================================================
+// This is auto-generated by gf cli tool only once. Fill this file as you wish.
+// ============================================================================
+
+package workflow
+
+import (
+	"dashoo.cn/micro/app/dao/workflow/internal"
+)
+
+// platWorkflowDao is the manager for logic model data accessing
+// and custom defined data operations functions management. You can define
+// methods on it to extend its functionality as you wish.
+type platWorkflowDao struct {
+	internal.PlatWorkflowDao
+}
+
+var (
+	// PlatWorkflow is globally public accessible object for table plat_workflow operations.
+	PlatWorkflow = platWorkflowDao{
+		internal.PlatWorkflow,
+	}
+)
+
+type PlatWorkflowDao struct {
+	internal.PlatWorkflowDao
+}
+
+func NewPlatWorkflowDao(tenant string) *PlatWorkflowDao {
+	dao := internal.NewPlatWorkflowDao(tenant)
+	return &PlatWorkflowDao{
+		dao,
+	}
+}
+
+// Fill with you ideas below.

+ 3 - 0
opms_parent/app/handler/dingtalk/ding_event.go

@@ -12,6 +12,9 @@ import (
 
 type DingHandler struct{}
 
+// CallBack 钉钉事件回调
+// 日程相关详情参照文档:https://open.dingtalk.com/document/orgapp/schedule-event
+// 审批相关详情参照文档:https://open.dingtalk.com/document/orgapp/approval-events
 func (h *DingHandler) CallBack(ctx context.Context, req *message.SubsMessage, rsp *message.Reply) error {
 	req.Ctx = ctx
 	handler := dingtalk.Client.GetDingTalkHandler(req)

+ 29 - 0
opms_parent/app/model/workflow/internal/plat_workflow.go

@@ -0,0 +1,29 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. DO NOT EDIT THIS FILE MANUALLY.
+// ==========================================================================
+
+package internal
+
+import (
+	"github.com/gogf/gf/os/gtime"
+)
+
+// PlatWorkflow is the golang structure for table plat_workflow.
+type PlatWorkflow struct {
+	Id              int         `orm:"id,primary"        json:"id"`              // 主键
+	BizCode         string      `orm:"biz_code"          json:"bizCode"`         // 业务单号
+	BizType         string      `orm:"biz_type"          json:"bizType"`         // 业务类型(10领用20项目创建30合同创建)
+	CurrentNode     string      `orm:"current_node"      json:"currentNode"`     // 当前节点
+	CurrentNodeTime string      `orm:"current_node_time" json:"currentNodeTime"` // 当前节点时间
+	ApprovalResult  string      `orm:"approval_result"   json:"approvalResult"`  // 审批结果
+	ProcessCode     string      `orm:"process_code"      json:"processCode"`     // 审批流编码
+	ProcessInstId   string      `orm:"process_inst_id"   json:"processInstId"`   // 审批实例ID
+	Remark          string      `orm:"remark"            json:"remark"`          // 备注
+	CreatedBy       int         `orm:"created_by"        json:"createdBy"`       // 创建者
+	CreatedName     string      `orm:"created_name"      json:"createdName"`     // 创建人
+	CreatedTime     *gtime.Time `orm:"created_time"      json:"createdTime"`     // 创建时间
+	UpdatedBy       int         `orm:"updated_by"        json:"updatedBy"`       // 更新者
+	UpdatedName     string      `orm:"updated_name"      json:"updatedName"`     // 更新人
+	UpdatedTime     *gtime.Time `orm:"updated_time"      json:"updatedTime"`     // 更新时间
+	DeletedTime     *gtime.Time `orm:"deleted_time"      json:"deletedTime"`     // 删除时间
+}

+ 14 - 0
opms_parent/app/model/workflow/plat_workflow.go

@@ -0,0 +1,14 @@
+// ==========================================================================
+// This is auto-generated by gf cli tool. Fill this file as you wish.
+// ==========================================================================
+
+package workflow
+
+import (
+	"dashoo.cn/micro/app/model/workflow/internal"
+)
+
+// PlatWorkflow is the golang structure for table plat_workflow.
+type PlatWorkflow internal.PlatWorkflow
+
+// Fill with you ideas below.

+ 81 - 0
opms_parent/app/service/workflow/work_flow.go

@@ -0,0 +1,81 @@
+package workflow
+
+import (
+	"context"
+	"dashoo.cn/micro/app/dao/plat"
+	"dashoo.cn/micro/app/service"
+	"dashoo.cn/opms_libary/plugin/dingtalk"
+	"dashoo.cn/opms_libary/plugin/dingtalk/workflow"
+	"dashoo.cn/opms_libary/utils"
+	"github.com/gogf/gf/frame/g"
+)
+
+type workflowService struct {
+	*service.ContextService
+
+	Dao *plat.PlatTaskDao
+}
+
+func NewTaskService(ctx context.Context) (svc *workflowService, err error) {
+	svc = new(workflowService)
+	if svc.ContextService, err = svc.Init(ctx); err != nil {
+		return nil, err
+	}
+	svc.Dao = plat.NewPlatTaskDao(svc.Tenant)
+	return svc, nil
+}
+
+// GetProcessInstanceDetail 获取审批实例详情
+func (s *workflowService) GetProcessInstanceDetail(instId string) (*workflow.QueryProcessInstanceResponse, error) {
+	g.Log().Info("搜索值", instId)
+	// 调用钉钉接口
+	client := dingtalk.NewClient()
+	w := client.GetWorkflow()
+	resp, err := w.QueryProcessInstanceDetail(instId)
+	if err != nil {
+		return nil, err
+	}
+	return &resp, nil
+}
+
+// StartProcessInstance 发起一个新的审批流
+// OriginatorUserId = utils.String("当前用户的钉钉中的Id")
+// ProcessCode = utils.String("每种审批对应固定的code")
+// bizType:业务类型(10领用20项目创建30合同创建
+// 详情参照文档:https://open.dingtalk.com/document/orgapp/create-an-approval-instance
+func (s *workflowService) StartProcessInstance(bizCode, bizType string, flow *workflow.StartProcessInstanceRequest) (insertId int64, err error) {
+	g.Log().Info("搜索值", flow)
+	// 参数调整
+	if flow.OriginatorUserId == nil {
+		// TODO s.GetCxtDingId()
+		flow.OriginatorUserId = utils.String("s.GetCxtDingId()")
+	}
+	// 调用钉钉接口
+	client := dingtalk.NewClient()
+	w := client.GetWorkflow()
+	resp, err := w.StartProcessInstance(flow)
+	if err != nil {
+		return 0, err
+	}
+
+	return s.saveWorkflowInstance(bizCode, bizType, resp.InstanceId, flow)
+}
+
+// RevokeProcessInstance 撤销审批实例
+func (s *workflowService) RevokeProcessInstance(instId, remark string) (string, error) {
+	g.Log().Info("搜索值instId, remark:", instId, remark)
+	// 调用钉钉接口
+	client := dingtalk.NewClient()
+	w := client.GetWorkflow()
+	// TODO 获取当前用户的钉钉中的Id  s.GetCxtDingId()
+	resp, err := w.RevokeProcessInstance(instId, remark, "s.GetCxtDingId()")
+	if err != nil {
+		return "", err
+	}
+	return resp.InstanceId, nil
+}
+
+// 将审批实例同步到数据库中
+func (s *workflowService) saveWorkflowInstance(bizCode, bizType, instanceId string, flow *workflow.StartProcessInstanceRequest) (insertId int64, err error) {
+	return 0, nil
+}

+ 0 - 47
opms_parent/go.sum

@@ -47,7 +47,6 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
 github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
 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=
@@ -60,7 +59,6 @@ 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/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 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=
 github.com/dgryski/go-jump v0.0.0-20170409065014-e1f439676b57/go.mod h1:4hKCXuwrJoYvHZxJ86+bRVTOMyJ0Ej+RqfSm8mHi6KA=
 github.com/dgryski/go-jump v0.0.0-20211018200510-ba001c3ffce0 h1:0wH6nO9QEa02Qx8sIQGw6ieKdz+BXjpccSOo9vXNl4U=
@@ -107,7 +105,6 @@ github.com/go-redis/redis_rate/v9 v9.1.2/go.mod h1:oam2de2apSgRG8aJzwJddXbNu91Iy
 github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
 github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
 github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
 github.com/gogf/gf v1.16.4/go.mod h1:EjnxZXddTwfFoLPofDE3NokFWx+immofINtSyFCj280=
 github.com/gogf/gf v1.16.9 h1:Q803UmmRo59+Ws08sMVFOcd8oNpkSWL9vS33hlo/Cyk=
@@ -124,7 +121,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
 github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
-github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
 github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -137,14 +133,12 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
 github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
 github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
 github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
 github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -152,7 +146,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
 github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
 github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
 github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
@@ -180,7 +173,6 @@ github.com/hashicorp/consul/api v1.8.1/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+Xbo
 github.com/hashicorp/consul/api v1.13.0 h1:2hnLQ0GjQvw7f3O61jMO8gbasZviZTrt9R8WzgiirHc=
 github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ=
 github.com/hashicorp/consul/sdk v0.7.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM=
-github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU=
 github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
 github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
@@ -197,7 +189,6 @@ github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh
 github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
 github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
 github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4=
 github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
 github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
 github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
@@ -206,11 +197,9 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9
 github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
 github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
 github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
-github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs=
 github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
 github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
 github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
 github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
@@ -219,7 +208,6 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
 github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
 github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
 github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
-github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA=
 github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
 github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
 github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
@@ -238,13 +226,10 @@ github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSg
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
 github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
-github.com/kavu/go_reuseport v1.5.0 h1:UNuiY2OblcqAtVDE8Gsg1kZz8zbBWg907sP1ceBV+bk=
 github.com/kavu/go_reuseport v1.5.0/go.mod h1:CG8Ee7ceMFSMnx/xr25Vm0qXaj2Z4i5PWoUx+JZ5/CU=
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/cpuid/v2 v2.0.14 h1:QRqdp6bb9M9S5yyKeYteXKuoKE4p0tGlra81fKOpWH8=
 github.com/klauspost/cpuid/v2 v2.0.14/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
-github.com/klauspost/reedsolomon v1.10.0 h1:MonMtg979rxSHjwtsla5dZLhreS0Lu42AyQ20bhjIGg=
 github.com/klauspost/reedsolomon v1.10.0/go.mod h1:qHMIzMkuZUWqIh8mS/GruPdo3u0qwX2jk/LH440ON7Y=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@@ -252,21 +237,15 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
 github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/lucas-clemente/quic-go v0.28.0 h1:9eXVRgIkMQQyiyorz/dAaOYIx3TFzXsIFkNFz4cxuJM=
 github.com/lucas-clemente/quic-go v0.28.0/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0=
 github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
 github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
 github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
-github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
 github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
-github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ=
 github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
-github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM=
 github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
-github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1 h1:7m/WlWcSROrcK5NxuXaxYD32BZqe/LEEnBrWcH/cOqQ=
 github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -294,9 +273,7 @@ github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJys
 github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
 github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
 github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
-github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
 github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
@@ -317,10 +294,8 @@ github.com/mozillazg/go-pinyin v0.19.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
 github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
-github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
 github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
 github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
 github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
@@ -330,7 +305,6 @@ github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k
 github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg=
 github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
 github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
-github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
 github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
 github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
@@ -339,21 +313,16 @@ github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7
 github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
 github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
 github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
-github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
 github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
 github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
 github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/peterbourgon/g2s v0.0.0-20140925154142-ec76db4c1ac1 h1:5Dl+ADmsGerAqHwWzyLqkNaUBQ+48DQwfDCaW1gHAQM=
 github.com/peterbourgon/g2s v0.0.0-20140925154142-ec76db4c1ac1/go.mod h1:1VcHEd3ro4QMoHfiNl/j7Jkln9+KQuorp0PItHMJYNg=
 github.com/philhofer/fwd v1.1.1 h1:GdGcTjf5RNAxwS4QLsiMzJYj5KEvPJD3Abr261yRQXQ=
 github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
@@ -387,7 +356,6 @@ github.com/rubyist/circuitbreaker v2.2.1+incompatible/go.mod h1:Ycs3JgJADPuzJDwf
 github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/samuel/go-zookeeper v0.0.0-20201211165307-7117e9ea2414/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
-github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
 github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
@@ -416,7 +384,6 @@ github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYED
 github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/smallnest/quick v0.0.0-20220703133648-f13409fa6c67 h1:eIa+/FyZCItCSwE1tjTEzYYHEk+5vtAw3jCW8DlnP3g=
 github.com/smallnest/quick v0.0.0-20220703133648-f13409fa6c67/go.mod h1:0UHAX9lwPR4gsKF94tv4fQIDIF+POCyixbrBp/zK6To=
 github.com/smallnest/rpcx v1.7.5/go.mod h1:xAsj679fx0xUWWy2RfiC6YSZLgWwBRZIu3WEbnsK/hA=
 github.com/smallnest/rpcx v1.8.0 h1:pZVSdEFXK8I+HNUg9GDLeJJVGXaMjFEFuDEUwbSYC8Y=
@@ -428,7 +395,6 @@ github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
-github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@@ -439,16 +405,12 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 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.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
-github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
 github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
-github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI=
 github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
 github.com/tinylib/msgp v1.1.6 h1:i+SbKraHhnrf9M5MYmvQhFnbLhAXSDWF8WWsuyRdocw=
 github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw=
-github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
 github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
@@ -460,9 +422,7 @@ github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9
 github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
 github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
 github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
-github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZWQ1bABv5xAg=
 github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
-github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E=
 github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -494,7 +454,6 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
 golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
@@ -508,7 +467,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
 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.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 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=
@@ -644,13 +602,11 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
 golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
-golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 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=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0=
 golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
 google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
 google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
@@ -686,11 +642,9 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
 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-20190902080502-41f04d3bba15/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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -698,7 +652,6 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.3.0/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-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=