重构远程接口,替换为Baiyin SDK & 添加实名认证处理逻辑
This commit is contained in:
199
web/handlers/iden.go
Normal file
199
web/handlers/iden.go
Normal file
@@ -0,0 +1,199 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"platform/pkg/env"
|
||||
"platform/pkg/rds"
|
||||
"platform/pkg/u"
|
||||
"platform/web/auth"
|
||||
m "platform/web/models"
|
||||
q "platform/web/queries"
|
||||
"platform/web/services"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
jdc "github.com/jdcloud-api/jdcloud-sdk-go/core"
|
||||
"github.com/jdcloud-api/jdcloud-sdk-go/services/cloudauth/apis"
|
||||
jdclient "github.com/jdcloud-api/jdcloud-sdk-go/services/cloudauth/client"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
// region Identify
|
||||
|
||||
type IdentifyReq struct {
|
||||
Type int32 `json:"type" validate:"required,oneof=1 2"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
IdenNo string `json:"iden_no" validate:"required"`
|
||||
}
|
||||
|
||||
type IdentifyRes struct {
|
||||
Identified bool `json:"identified"`
|
||||
Target string `json:"target"`
|
||||
}
|
||||
|
||||
func Identify(c *fiber.Ctx) error {
|
||||
|
||||
// 检查权限
|
||||
authCtx, err := auth.Protect(c, []services.PayloadType{services.PayloadUser}, []string{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user, err := q.User.
|
||||
Where(q.User.ID.Eq(authCtx.Payload.Id)).
|
||||
Select(q.User.ID, q.User.IDToken).
|
||||
Take()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if user.IDToken != "" {
|
||||
// 用户已实名认证
|
||||
return c.JSON(IdentifyRes{
|
||||
Identified: true,
|
||||
})
|
||||
}
|
||||
|
||||
// 解析请求参数
|
||||
req := new(IdentifyReq)
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 请求活体认证
|
||||
var id = services.ID.GenReadable("iden")
|
||||
|
||||
var credential = jdc.NewCredentials(env.IdenAccessKey, env.IdenSecretKey)
|
||||
var client = jdclient.NewCloudauthClient(credential)
|
||||
resp, err := client.GetAliveUrl(apis.NewGetAliveUrlRequestWithAllParams(
|
||||
u.P(req.Name),
|
||||
u.P(req.IdenNo),
|
||||
env.IdenCallbackUrl+"?id="+id,
|
||||
))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 保存认证中间状态
|
||||
info := idenInfo{
|
||||
Uid: authCtx.Payload.Id,
|
||||
Type: req.Type,
|
||||
Name: req.Name,
|
||||
IdNo: req.IdenNo,
|
||||
Token: resp.Result.Token,
|
||||
}
|
||||
infoStr, err := json.Marshal(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = rds.Client.Set(c.Context(), idenKey(id), infoStr, 30*time.Minute).Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.JSON(IdentifyRes{
|
||||
Identified: false,
|
||||
Target: resp.Result.Url,
|
||||
})
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region IdentifyCallback
|
||||
|
||||
type IdentifyCallbackReq struct {
|
||||
Id string `json:"id" validate:"required"`
|
||||
}
|
||||
|
||||
type IdentifyCallbackRes struct {
|
||||
Success bool `json:"success"`
|
||||
Message string `json:"desc"`
|
||||
}
|
||||
|
||||
func IdentifyCallback(c *fiber.Ctx) error {
|
||||
|
||||
// 解析请求参数
|
||||
req := new(IdentifyCallbackReq)
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 获取 token
|
||||
infoStr, err := rds.Client.GetDel(c.Context(), idenKey(req.Id)).Result()
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return c.JSON(IdentifyCallbackRes{
|
||||
Success: false,
|
||||
Message: "认证已过期",
|
||||
})
|
||||
}
|
||||
return err
|
||||
}
|
||||
info := idenInfo{}
|
||||
err = json.Unmarshal([]byte(infoStr), &info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 获取认证结果
|
||||
var credential = jdc.NewCredentials(env.IdenAccessKey, env.IdenSecretKey)
|
||||
var client = jdclient.NewCloudauthClient(credential)
|
||||
resp, err := client.GetAliveResult(apis.NewGetAliveResultRequestWithAllParams(
|
||||
info.Token,
|
||||
))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Error.Code != 0 {
|
||||
return c.JSON(IdentifyCallbackRes{
|
||||
Success: false,
|
||||
Message: resp.Error.Message,
|
||||
})
|
||||
}
|
||||
|
||||
if resp.Result.H5Result != "ok" || resp.Result.SmResult != "ok" || resp.Result.RxResult != "ok" {
|
||||
return c.JSON(IdentifyCallbackRes{
|
||||
Success: false,
|
||||
Message: resp.Result.Desc,
|
||||
})
|
||||
}
|
||||
|
||||
// 更新用户实名认证状态
|
||||
_, err = q.User.Debug().
|
||||
Where(q.User.ID.Eq(info.Uid)).
|
||||
Select(
|
||||
q.User.IDType,
|
||||
q.User.IDNo,
|
||||
q.User.IDToken,
|
||||
q.User.Name,
|
||||
).
|
||||
Updates(m.User{
|
||||
IDType: info.Type,
|
||||
IDNo: info.IdNo,
|
||||
IDToken: info.Token,
|
||||
Name: info.Name,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.JSON(IdentifyCallbackRes{
|
||||
Success: true,
|
||||
Message: resp.Result.Desc,
|
||||
})
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
func idenKey(id string) string {
|
||||
return fmt.Sprintf("iden:%s", id)
|
||||
}
|
||||
|
||||
type idenInfo struct {
|
||||
Uid int32 `json:"uid"`
|
||||
Type int32 `json:"type"`
|
||||
Name string `json:"name"`
|
||||
IdNo string `json:"id_no"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
@@ -66,8 +66,8 @@ func loginByPhone(c *fiber.Ctx, req *LoginReq) error {
|
||||
// 如果用户不存在,初始化用户 todo 保存默认权限信息
|
||||
if user == nil {
|
||||
user = &models.User{
|
||||
Phone: req.Username,
|
||||
Name: req.Username,
|
||||
Phone: req.Username,
|
||||
Username: req.Username,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ func ApplyRouters(app *fiber.App) {
|
||||
// 用户
|
||||
user := api.Group("/user")
|
||||
user.Post("/get/token", handlers.GetUserByToken)
|
||||
user.Post("/identify", handlers.Identify)
|
||||
user.Post("/identify/callback", handlers.IdentifyCallback)
|
||||
|
||||
// 支付
|
||||
trade := api.Group("/trade")
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"platform/pkg/env"
|
||||
"platform/pkg/orm"
|
||||
"platform/pkg/rds"
|
||||
"platform/pkg/remote"
|
||||
"platform/pkg/sdks/baiyin"
|
||||
"platform/pkg/u"
|
||||
"platform/web/common"
|
||||
"platform/web/models"
|
||||
@@ -132,18 +132,18 @@ func (s *channelService) RemoveChannels(ctx context.Context, auth *AuthContext,
|
||||
step = time.Now()
|
||||
|
||||
// 组织数据
|
||||
var configMap = make(map[int32][]remote.PortConfigsReq, len(proxies))
|
||||
var configMap = make(map[int32][]baiyin.PortConfigsReq, len(proxies))
|
||||
var proxyMap = make(map[int32]*models.Proxy, len(proxies))
|
||||
for _, proxy := range proxies {
|
||||
configMap[proxy.ID] = make([]remote.PortConfigsReq, 0)
|
||||
configMap[proxy.ID] = make([]baiyin.PortConfigsReq, 0)
|
||||
proxyMap[proxy.ID] = proxy
|
||||
}
|
||||
var portMap = make(map[uint64]struct{})
|
||||
for _, channel := range channels {
|
||||
var config = remote.PortConfigsReq{
|
||||
var config = baiyin.PortConfigsReq{
|
||||
Port: int(channel.ProxyPort),
|
||||
Edge: &[]string{},
|
||||
AutoEdgeConfig: &remote.AutoEdgeConfig{
|
||||
AutoEdgeConfig: &baiyin.AutoEdgeConfig{
|
||||
Count: u.P(0),
|
||||
},
|
||||
Status: false,
|
||||
@@ -167,7 +167,7 @@ func (s *channelService) RemoveChannels(ctx context.Context, auth *AuthContext,
|
||||
}
|
||||
|
||||
var secret = strings.Split(proxy.Secret, ":")
|
||||
gateway := remote.NewGateway(
|
||||
gateway := baiyin.NewGateway(
|
||||
proxy.Host,
|
||||
secret[0],
|
||||
secret[1],
|
||||
@@ -208,7 +208,7 @@ func (s *channelService) RemoveChannels(ctx context.Context, auth *AuthContext,
|
||||
}
|
||||
}
|
||||
if len(edges) > 0 {
|
||||
_, err := remote.Cloud.CloudDisconnect(remote.CloudDisconnectReq{
|
||||
_, err := baiyin.Cloud.CloudDisconnect(baiyin.CloudDisconnectReq{
|
||||
Uuid: proxy.Name,
|
||||
Edge: edges,
|
||||
})
|
||||
@@ -406,7 +406,7 @@ func assignEdge(q *q.Query, count int, filter NodeFilterConfig) (*AssignEdgeResu
|
||||
// 查询已配置的节点
|
||||
step = time.Now()
|
||||
|
||||
rProxyConfigs, err := remote.Cloud.CloudAutoQuery()
|
||||
rProxyConfigs, err := baiyin.Cloud.CloudAutoQuery()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -480,13 +480,13 @@ func assignEdge(q *q.Query, count int, filter NodeFilterConfig) (*AssignEdgeResu
|
||||
|
||||
rConfigs := rProxyConfigs[info.proxy.Name]
|
||||
|
||||
var newConfig = remote.AutoConfig{
|
||||
var newConfig = baiyin.AutoConfig{
|
||||
Province: filter.Prov,
|
||||
City: filter.City,
|
||||
Isp: filter.Isp,
|
||||
Count: int(math.Ceil(float64(info.used) * 2)),
|
||||
}
|
||||
var newConfigs []remote.AutoConfig
|
||||
var newConfigs []baiyin.AutoConfig
|
||||
var update = false
|
||||
for _, rConfig := range rConfigs {
|
||||
if rConfig.Isp == filter.Isp && rConfig.City == filter.City && rConfig.Province == filter.Prov {
|
||||
@@ -500,7 +500,7 @@ func assignEdge(q *q.Query, count int, filter NodeFilterConfig) (*AssignEdgeResu
|
||||
newConfigs = append(newConfigs, newConfig)
|
||||
}
|
||||
|
||||
err := remote.Cloud.CloudConnect(remote.CloudConnectReq{
|
||||
err := baiyin.Cloud.CloudConnect(baiyin.CloudConnectReq{
|
||||
Uuid: info.proxy.Name,
|
||||
Edge: nil,
|
||||
AutoConfig: newConfigs,
|
||||
@@ -587,7 +587,7 @@ func assignPort(
|
||||
var count = config.count
|
||||
|
||||
// 筛选可用端口
|
||||
var configs = make([]remote.PortConfigsReq, 0, count)
|
||||
var configs = make([]baiyin.PortConfigsReq, 0, count)
|
||||
for port := 10000; port < 20000 && len(configs) < count; port++ {
|
||||
// 跳过存在的端口
|
||||
key := uint64(proxy.ID)<<32 | uint64(port)
|
||||
@@ -598,11 +598,11 @@ func assignPort(
|
||||
|
||||
// 配置新端口
|
||||
var i = len(configs)
|
||||
configs = append(configs, remote.PortConfigsReq{
|
||||
configs = append(configs, baiyin.PortConfigsReq{
|
||||
Port: port,
|
||||
Edge: nil,
|
||||
Status: true,
|
||||
AutoEdgeConfig: &remote.AutoEdgeConfig{
|
||||
AutoEdgeConfig: &baiyin.AutoEdgeConfig{
|
||||
Province: filter.Prov,
|
||||
City: filter.City,
|
||||
Isp: filter.Isp,
|
||||
@@ -682,7 +682,7 @@ func assignPort(
|
||||
step = time.Now()
|
||||
|
||||
var secret = strings.Split(proxy.Secret, ":")
|
||||
gateway := remote.NewGateway(
|
||||
gateway := baiyin.NewGateway(
|
||||
proxy.Host,
|
||||
secret[0],
|
||||
secret[1],
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"platform/pkg/remote"
|
||||
"platform/pkg/sdks/baiyin"
|
||||
"platform/pkg/testutil"
|
||||
"platform/web/common"
|
||||
"platform/web/models"
|
||||
@@ -288,9 +288,9 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
ctx := context.WithValue(context.Background(), requestid.ConfigDefault.ContextKey, "test-request-id")
|
||||
var adminAuth = &AuthContext{Payload: Payload{Id: 100, Type: PayloadAdmin}}
|
||||
var userAuth = &AuthContext{Payload: Payload{Id: 101, Type: PayloadUser}}
|
||||
mc.AutoQueryMock = func() (remote.CloudConnectResp, error) {
|
||||
return remote.CloudConnectResp{
|
||||
"test-proxy": []remote.AutoConfig{
|
||||
mc.AutoQueryMock = func() (baiyin.CloudConnectResp, error) {
|
||||
return baiyin.CloudConnectResp{
|
||||
"test-proxy": []baiyin.AutoConfig{
|
||||
{Province: "河南省", Count: 10},
|
||||
},
|
||||
}, nil
|
||||
@@ -373,14 +373,14 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
mr.FlushAll()
|
||||
resetDb()
|
||||
|
||||
mc.ConnectMock = func(param remote.CloudConnectReq) error {
|
||||
mc.ConnectMock = func(param baiyin.CloudConnectReq) error {
|
||||
if param.Uuid != proxy.Name {
|
||||
return fmt.Errorf("代理名称不符合预期: %s", param.Uuid)
|
||||
}
|
||||
if len(param.Edge) != 0 {
|
||||
return fmt.Errorf("边缘节点不符合预期: %v", param.Edge)
|
||||
}
|
||||
if !reflect.DeepEqual(param.AutoConfig, []remote.AutoConfig{
|
||||
if !reflect.DeepEqual(param.AutoConfig, []baiyin.AutoConfig{
|
||||
{Province: "河南省", Count: 10},
|
||||
{Province: "北京市", Count: 6},
|
||||
}) {
|
||||
@@ -389,7 +389,7 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
return nil
|
||||
}
|
||||
|
||||
mg.PortConfigsMock = func(c *testutil.MockGatewayClient, params []remote.PortConfigsReq) error {
|
||||
mg.PortConfigsMock = func(c *testutil.MockGatewayClient, params []baiyin.PortConfigsReq) error {
|
||||
if c.Host != proxy.Host {
|
||||
return fmt.Errorf("代理主机不符合预期: %s", c.Host)
|
||||
}
|
||||
@@ -523,14 +523,14 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
mr.FlushAll()
|
||||
resetDb()
|
||||
|
||||
mc.ConnectMock = func(param remote.CloudConnectReq) error {
|
||||
mc.ConnectMock = func(param baiyin.CloudConnectReq) error {
|
||||
if param.Uuid != proxy.Name {
|
||||
return fmt.Errorf("代理名称不符合预期: %s", param.Uuid)
|
||||
}
|
||||
if len(param.Edge) != 0 {
|
||||
return fmt.Errorf("边缘节点不符合预期: %v", param.Edge)
|
||||
}
|
||||
if !reflect.DeepEqual(param.AutoConfig, []remote.AutoConfig{
|
||||
if !reflect.DeepEqual(param.AutoConfig, []baiyin.AutoConfig{
|
||||
{Province: "河南省", Count: 10},
|
||||
{Province: "北京市", Count: 6},
|
||||
}) {
|
||||
@@ -539,7 +539,7 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
return nil
|
||||
}
|
||||
|
||||
mg.PortConfigsMock = func(c *testutil.MockGatewayClient, params []remote.PortConfigsReq) error {
|
||||
mg.PortConfigsMock = func(c *testutil.MockGatewayClient, params []baiyin.PortConfigsReq) error {
|
||||
if c.Host != proxy.Host {
|
||||
return fmt.Errorf("代理主机不符合预期: %s", c.Host)
|
||||
}
|
||||
@@ -667,14 +667,14 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
mr.FlushAll()
|
||||
resetDb()
|
||||
|
||||
mc.ConnectMock = func(param remote.CloudConnectReq) error {
|
||||
mc.ConnectMock = func(param baiyin.CloudConnectReq) error {
|
||||
if param.Uuid != proxy.Name {
|
||||
return fmt.Errorf("代理名称不符合预期: %s", param.Uuid)
|
||||
}
|
||||
if len(param.Edge) != 0 {
|
||||
return fmt.Errorf("边缘节点不符合预期: %v", param.Edge)
|
||||
}
|
||||
if !reflect.DeepEqual(param.AutoConfig, []remote.AutoConfig{
|
||||
if !reflect.DeepEqual(param.AutoConfig, []baiyin.AutoConfig{
|
||||
{Province: "河南省", Count: 10},
|
||||
{Province: "北京市", Count: 6},
|
||||
}) {
|
||||
@@ -683,7 +683,7 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
return nil
|
||||
}
|
||||
|
||||
mg.PortConfigsMock = func(c *testutil.MockGatewayClient, params []remote.PortConfigsReq) error {
|
||||
mg.PortConfigsMock = func(c *testutil.MockGatewayClient, params []baiyin.PortConfigsReq) error {
|
||||
if c.Host != proxy.Host {
|
||||
return fmt.Errorf("代理主机不符合预期: %s", c.Host)
|
||||
}
|
||||
@@ -899,9 +899,9 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
setup: func() {
|
||||
mr.FlushAll()
|
||||
resetDb()
|
||||
mc.AutoQueryMock = func() (remote.CloudConnectResp, error) {
|
||||
return remote.CloudConnectResp{
|
||||
"test-proxy": []remote.AutoConfig{
|
||||
mc.AutoQueryMock = func() (baiyin.CloudConnectResp, error) {
|
||||
return baiyin.CloudConnectResp{
|
||||
"test-proxy": []baiyin.AutoConfig{
|
||||
{Count: 20000},
|
||||
},
|
||||
}, nil
|
||||
@@ -1054,21 +1054,21 @@ func Test_channelService_RemoveChannels(t *testing.T) {
|
||||
}
|
||||
|
||||
// 模拟网关客户端的响应
|
||||
mg.PortActiveMock = func(m *testutil.MockGatewayClient, param ...remote.PortActiveReq) (map[string]remote.PortData, error) {
|
||||
mg.PortActiveMock = func(m *testutil.MockGatewayClient, param ...baiyin.PortActiveReq) (map[string]baiyin.PortData, error) {
|
||||
switch {
|
||||
case m.Host == proxy.Host:
|
||||
return map[string]remote.PortData{
|
||||
return map[string]baiyin.PortData{
|
||||
"10001": {Edge: []string{"edge1", "edge4"}},
|
||||
"10002": {Edge: []string{"edge2"}},
|
||||
}, nil
|
||||
case m.Host == proxy2.Host:
|
||||
return map[string]remote.PortData{
|
||||
return map[string]baiyin.PortData{
|
||||
"10001": {Edge: []string{"edge3"}},
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("代理主机不符合预期: %s", m.Host)
|
||||
}
|
||||
mg.PortConfigsMock = func(m *testutil.MockGatewayClient, params []remote.PortConfigsReq) error {
|
||||
mg.PortConfigsMock = func(m *testutil.MockGatewayClient, params []baiyin.PortConfigsReq) error {
|
||||
switch {
|
||||
case m.Host == proxy.Host:
|
||||
for _, param := range params {
|
||||
@@ -1099,7 +1099,7 @@ func Test_channelService_RemoveChannels(t *testing.T) {
|
||||
}
|
||||
return fmt.Errorf("代理主机不符合预期: %s", m.Host)
|
||||
}
|
||||
mc.DisconnectMock = func(param remote.CloudDisconnectReq) (int, error) {
|
||||
mc.DisconnectMock = func(param baiyin.CloudDisconnectReq) (int, error) {
|
||||
switch {
|
||||
case param.Uuid == proxy.Name:
|
||||
var edges = []string{"edge1", "edge2", "edge4"}
|
||||
@@ -1168,21 +1168,21 @@ func Test_channelService_RemoveChannels(t *testing.T) {
|
||||
}
|
||||
|
||||
// 模拟网关客户端的响应
|
||||
mg.PortActiveMock = func(m *testutil.MockGatewayClient, param ...remote.PortActiveReq) (map[string]remote.PortData, error) {
|
||||
mg.PortActiveMock = func(m *testutil.MockGatewayClient, param ...baiyin.PortActiveReq) (map[string]baiyin.PortData, error) {
|
||||
switch {
|
||||
case m.Host == proxy.Host:
|
||||
return map[string]remote.PortData{
|
||||
return map[string]baiyin.PortData{
|
||||
"10001": {Edge: []string{"edge1", "edge4"}},
|
||||
"10002": {Edge: []string{"edge2"}},
|
||||
}, nil
|
||||
case m.Host == proxy2.Host:
|
||||
return map[string]remote.PortData{
|
||||
return map[string]baiyin.PortData{
|
||||
"10001": {Edge: []string{"edge3"}},
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("代理主机不符合预期: %s", m.Host)
|
||||
}
|
||||
mg.PortConfigsMock = func(m *testutil.MockGatewayClient, params []remote.PortConfigsReq) error {
|
||||
mg.PortConfigsMock = func(m *testutil.MockGatewayClient, params []baiyin.PortConfigsReq) error {
|
||||
switch {
|
||||
case m.Host == proxy.Host:
|
||||
for _, param := range params {
|
||||
@@ -1213,7 +1213,7 @@ func Test_channelService_RemoveChannels(t *testing.T) {
|
||||
}
|
||||
return fmt.Errorf("代理主机不符合预期: %s", m.Host)
|
||||
}
|
||||
mc.DisconnectMock = func(param remote.CloudDisconnectReq) (int, error) {
|
||||
mc.DisconnectMock = func(param baiyin.CloudDisconnectReq) (int, error) {
|
||||
switch {
|
||||
case param.Uuid == proxy.Name:
|
||||
var edges = []string{"edge1", "edge2", "edge4"}
|
||||
|
||||
Reference in New Issue
Block a user