feat usn sid 改成string
This commit is contained in:
@@ -30,13 +30,13 @@ var (
|
|||||||
// ServiceProvider 服务提供者
|
// ServiceProvider 服务提供者
|
||||||
type ServiceProvider struct {
|
type ServiceProvider struct {
|
||||||
Target string
|
Target string
|
||||||
SID int64
|
SID string
|
||||||
Addr string
|
Addr string
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstanceProvider 副本提供者
|
// InstanceProvider 副本提供者
|
||||||
type InstanceProvider struct {
|
type InstanceProvider struct {
|
||||||
InstanceID int // 副本ID
|
InstanceID int // 副本ID
|
||||||
UniqueNo int64 // 副本唯一编号
|
UniqueNo string // 副本唯一编号
|
||||||
SID string
|
SID string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,14 @@ import (
|
|||||||
"git.hlsq.asia/mmorpg/service-common/discover/common"
|
"git.hlsq.asia/mmorpg/service-common/discover/common"
|
||||||
"git.hlsq.asia/mmorpg/service-common/log"
|
"git.hlsq.asia/mmorpg/service-common/log"
|
||||||
clientv3 "go.etcd.io/etcd/client/v3"
|
clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
"strconv"
|
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 大量读少量写的情况下,读写锁比同步Map更高效
|
// 大量读少量写的情况下,读写锁比同步Map更高效
|
||||||
var (
|
var (
|
||||||
instanceMU = sync.RWMutex{}
|
instanceMU = sync.RWMutex{}
|
||||||
instanceM = make(map[int64]string) // [uniqueNo]sid
|
instanceM = make(map[string]string) // [uniqueNo]sid
|
||||||
instanceLeaseM = make(map[int64]clientv3.LeaseID) // [uniqueNo]
|
instanceLeaseM = make(map[string]clientv3.LeaseID) // [uniqueNo]
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -23,7 +22,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FindInstanceByUniqueNo 根据唯一标识查询副本
|
// FindInstanceByUniqueNo 根据唯一标识查询副本
|
||||||
func FindInstanceByUniqueNo(uniqueNO int64) (sid string) {
|
func FindInstanceByUniqueNo(uniqueNO string) (sid string) {
|
||||||
instanceMU.RLock()
|
instanceMU.RLock()
|
||||||
defer instanceMU.RUnlock()
|
defer instanceMU.RUnlock()
|
||||||
if c, ok := instanceM[uniqueNO]; ok {
|
if c, ok := instanceM[uniqueNO]; ok {
|
||||||
@@ -33,7 +32,7 @@ func FindInstanceByUniqueNo(uniqueNO int64) (sid string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RegisterInstance 注册副本
|
// RegisterInstance 注册副本
|
||||||
func RegisterInstance(sid int64, instanceID int32, uniqueNo, ttl int64) error {
|
func RegisterInstance(sid string, instanceID int32, uniqueNo string, ttl int64) error {
|
||||||
serverMU.Lock()
|
serverMU.Lock()
|
||||||
defer serverMU.Unlock()
|
defer serverMU.Unlock()
|
||||||
leaseID, err := common.NewLeaseAndKeepAlive(ttl)
|
leaseID, err := common.NewLeaseAndKeepAlive(ttl)
|
||||||
@@ -41,7 +40,7 @@ func RegisterInstance(sid int64, instanceID int32, uniqueNo, ttl int64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
key := fmt.Sprintf("%v/%v/%v", common.KeyDiscoverInstance, instanceID, uniqueNo)
|
key := fmt.Sprintf("%v/%v/%v", common.KeyDiscoverInstance, instanceID, uniqueNo)
|
||||||
_, err = etcd.GetClient().Put(key, strconv.Itoa(int(sid)), clientv3.WithLease(leaseID))
|
_, err = etcd.GetClient().Put(key, sid, clientv3.WithLease(leaseID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -50,7 +49,7 @@ func RegisterInstance(sid int64, instanceID int32, uniqueNo, ttl int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UnRegisterInstance 解注册副本
|
// UnRegisterInstance 解注册副本
|
||||||
func UnRegisterInstance(uniqueNo int64) {
|
func UnRegisterInstance(uniqueNo string) {
|
||||||
serverMU.Lock()
|
serverMU.Lock()
|
||||||
defer serverMU.Unlock()
|
defer serverMU.Unlock()
|
||||||
if leaseID, ok := instanceLeaseM[uniqueNo]; ok {
|
if leaseID, ok := instanceLeaseM[uniqueNo]; ok {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"git.hlsq.asia/mmorpg/service-common/db/etcd"
|
"git.hlsq.asia/mmorpg/service-common/db/etcd"
|
||||||
"git.hlsq.asia/mmorpg/service-common/discover/common"
|
"git.hlsq.asia/mmorpg/service-common/discover/common"
|
||||||
"git.hlsq.asia/mmorpg/service-common/log"
|
"git.hlsq.asia/mmorpg/service-common/log"
|
||||||
"git.hlsq.asia/mmorpg/service-common/utils"
|
|
||||||
"go.etcd.io/etcd/api/v3/mvccpb"
|
"go.etcd.io/etcd/api/v3/mvccpb"
|
||||||
clientv3 "go.etcd.io/etcd/client/v3"
|
clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -88,13 +87,13 @@ func onServerChange(t mvccpb.Event_EventType, key, value string) {
|
|||||||
case clientv3.EventTypePut:
|
case clientv3.EventTypePut:
|
||||||
onCBByType(common.ListenerTypeNewServer, &common.ServiceProvider{
|
onCBByType(common.ListenerTypeNewServer, &common.ServiceProvider{
|
||||||
Target: common.KeyDiscoverService + "/" + split[2],
|
Target: common.KeyDiscoverService + "/" + split[2],
|
||||||
SID: utils.StringToInt64(split[3]),
|
SID: split[3],
|
||||||
Addr: value,
|
Addr: value,
|
||||||
})
|
})
|
||||||
case clientv3.EventTypeDelete:
|
case clientv3.EventTypeDelete:
|
||||||
onCBByType(common.ListenerTypeCloseServer, &common.ServiceProvider{
|
onCBByType(common.ListenerTypeCloseServer, &common.ServiceProvider{
|
||||||
Target: common.KeyDiscoverService + "/" + split[2],
|
Target: common.KeyDiscoverService + "/" + split[2],
|
||||||
SID: utils.StringToInt64(split[3]),
|
SID: split[3],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,13 +109,13 @@ func onInstanceChange(t mvccpb.Event_EventType, key, value string, preKv *mvccpb
|
|||||||
case clientv3.EventTypePut:
|
case clientv3.EventTypePut:
|
||||||
onCBByType(common.ListenerTypeNewInstance, &common.InstanceProvider{
|
onCBByType(common.ListenerTypeNewInstance, &common.InstanceProvider{
|
||||||
InstanceID: instanceID,
|
InstanceID: instanceID,
|
||||||
UniqueNo: utils.StringToInt64(split[3]),
|
UniqueNo: split[3],
|
||||||
SID: value,
|
SID: value,
|
||||||
})
|
})
|
||||||
case clientv3.EventTypeDelete:
|
case clientv3.EventTypeDelete:
|
||||||
onCBByType(common.ListenerTypeCloseInstance, &common.InstanceProvider{
|
onCBByType(common.ListenerTypeCloseInstance, &common.InstanceProvider{
|
||||||
InstanceID: instanceID,
|
InstanceID: instanceID,
|
||||||
UniqueNo: utils.StringToInt64(split[3]),
|
UniqueNo: split[3],
|
||||||
SID: string(preKv.Value),
|
SID: string(preKv.Value),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
serverMU = sync.RWMutex{}
|
serverMU = sync.RWMutex{}
|
||||||
conn = make(map[string]*grpc_conn.GrpcConnectionMgr)
|
conn = make(map[string]*grpc_conn.GrpcConnectionMgr)
|
||||||
serverLeaseM = make(map[int64]clientv3.LeaseID)
|
serverLeaseM = make(map[string]clientv3.LeaseID)
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -24,7 +24,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FindServer 根据SID或随机查找服务
|
// FindServer 根据SID或随机查找服务
|
||||||
func FindServer(target string, sid ...int64) (*grpc.ClientConn, error) {
|
func FindServer(target string, sid ...string) (*grpc.ClientConn, error) {
|
||||||
serverMU.RLock()
|
serverMU.RLock()
|
||||||
defer serverMU.RUnlock()
|
defer serverMU.RUnlock()
|
||||||
if v, ok := conn[target]; ok {
|
if v, ok := conn[target]; ok {
|
||||||
@@ -33,17 +33,17 @@ func FindServer(target string, sid ...int64) (*grpc.ClientConn, error) {
|
|||||||
return nil, fmt.Errorf("cannot find server")
|
return nil, fmt.Errorf("cannot find server")
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindServerAll(target string) map[int64]*grpc.ClientConn {
|
func FindServerAll(target string) map[string]*grpc.ClientConn {
|
||||||
serverMU.RLock()
|
serverMU.RLock()
|
||||||
defer serverMU.RUnlock()
|
defer serverMU.RUnlock()
|
||||||
if v, ok := conn[target]; ok {
|
if v, ok := conn[target]; ok {
|
||||||
return v.LoadAll()
|
return v.LoadAll()
|
||||||
}
|
}
|
||||||
return make(map[int64]*grpc.ClientConn)
|
return make(map[string]*grpc.ClientConn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterGrpcServer 注册服务提供者
|
// RegisterGrpcServer 注册服务提供者
|
||||||
func RegisterGrpcServer(target string, sid int64, addr string, ttl int64) error {
|
func RegisterGrpcServer(target string, sid string, addr string, ttl int64) error {
|
||||||
serverMU.Lock()
|
serverMU.Lock()
|
||||||
defer serverMU.Unlock()
|
defer serverMU.Unlock()
|
||||||
leaseID, err := common.NewLeaseAndKeepAlive(ttl)
|
leaseID, err := common.NewLeaseAndKeepAlive(ttl)
|
||||||
@@ -59,7 +59,7 @@ func RegisterGrpcServer(target string, sid int64, addr string, ttl int64) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UnRegisterGrpcServer 解注册服务提供者
|
// UnRegisterGrpcServer 解注册服务提供者
|
||||||
func UnRegisterGrpcServer(sid int64) {
|
func UnRegisterGrpcServer(sid string) {
|
||||||
serverMU.Lock()
|
serverMU.Lock()
|
||||||
defer serverMU.Unlock()
|
defer serverMU.Unlock()
|
||||||
if leaseID, ok := serverLeaseM[sid]; ok {
|
if leaseID, ok := serverLeaseM[sid]; ok {
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type GrpcConnection struct {
|
type GrpcConnection struct {
|
||||||
sid int64
|
sid string
|
||||||
conn *grpc.ClientConn
|
conn *grpc.ClientConn
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGrpcConnection(sid int64, address string) (*GrpcConnection, error) {
|
func NewGrpcConnection(sid string, address string) (*GrpcConnection, error) {
|
||||||
p := &GrpcConnection{
|
p := &GrpcConnection{
|
||||||
sid: sid,
|
sid: sid,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,18 +8,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type GrpcConnectionMgr struct {
|
type GrpcConnectionMgr struct {
|
||||||
poolM map[int64]*GrpcConnection
|
poolM map[string]*GrpcConnection
|
||||||
poolS []*GrpcConnection
|
poolS []*GrpcConnection
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGrpcConnectionMgr() *GrpcConnectionMgr {
|
func NewGrpcConnectionMgr() *GrpcConnectionMgr {
|
||||||
return &GrpcConnectionMgr{
|
return &GrpcConnectionMgr{
|
||||||
poolM: make(map[int64]*GrpcConnection),
|
poolM: make(map[string]*GrpcConnection),
|
||||||
poolS: make([]*GrpcConnection, 0),
|
poolS: make([]*GrpcConnection, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *GrpcConnectionMgr) Store(sid int64, addr string) {
|
func (p *GrpcConnectionMgr) Store(sid string, addr string) {
|
||||||
pool, err := NewGrpcConnection(sid, addr)
|
pool, err := NewGrpcConnection(sid, addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("create grpc err: %v, sid: %v, addr: %v", err, sid, addr)
|
log.Errorf("create grpc err: %v, sid: %v, addr: %v", err, sid, addr)
|
||||||
@@ -29,7 +29,7 @@ func (p *GrpcConnectionMgr) Store(sid int64, addr string) {
|
|||||||
p.poolS = append(p.poolS, pool)
|
p.poolS = append(p.poolS, pool)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *GrpcConnectionMgr) Delete(sid int64) int {
|
func (p *GrpcConnectionMgr) Delete(sid string) int {
|
||||||
delete(p.poolM, sid)
|
delete(p.poolM, sid)
|
||||||
for i, pool := range p.poolS {
|
for i, pool := range p.poolS {
|
||||||
if pool.sid == sid {
|
if pool.sid == sid {
|
||||||
@@ -40,9 +40,9 @@ func (p *GrpcConnectionMgr) Delete(sid int64) int {
|
|||||||
return len(p.poolS)
|
return len(p.poolS)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *GrpcConnectionMgr) Load(sid ...int64) (*grpc.ClientConn, error) {
|
func (p *GrpcConnectionMgr) Load(sid ...string) (*grpc.ClientConn, error) {
|
||||||
var pool *GrpcConnection
|
var pool *GrpcConnection
|
||||||
if len(sid) > 0 && sid[0] > 0 {
|
if len(sid) > 0 && sid[0] != "" {
|
||||||
pool = p.poolM[sid[0]]
|
pool = p.poolM[sid[0]]
|
||||||
} else {
|
} else {
|
||||||
pool = p.poolS[rand.Intn(len(p.poolS))]
|
pool = p.poolS[rand.Intn(len(p.poolS))]
|
||||||
@@ -53,8 +53,8 @@ func (p *GrpcConnectionMgr) Load(sid ...int64) (*grpc.ClientConn, error) {
|
|||||||
return pool.GetConnection(), nil
|
return pool.GetConnection(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *GrpcConnectionMgr) LoadAll() map[int64]*grpc.ClientConn {
|
func (p *GrpcConnectionMgr) LoadAll() map[string]*grpc.ClientConn {
|
||||||
sidM := make(map[int64]*grpc.ClientConn)
|
sidM := make(map[string]*grpc.ClientConn)
|
||||||
for sid, pool := range p.poolM {
|
for sid, pool := range p.poolM {
|
||||||
sidM[sid] = pool.GetConnection()
|
sidM[sid] = pool.GetConnection()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"git.hlsq.asia/mmorpg/service-common/proto/ss/grpc_pb"
|
"git.hlsq.asia/mmorpg/service-common/proto/ss/grpc_pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GatewayNewClient(sid ...int64) (grpc_pb.GatewayClient, error) {
|
func GatewayNewClient(sid ...string) (grpc_pb.GatewayClient, error) {
|
||||||
c, err := discover.FindServer(common.KeyDiscoverGateway, sid...)
|
c, err := discover.FindServer(common.KeyDiscoverGateway, sid...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -14,8 +14,8 @@ func GatewayNewClient(sid ...int64) (grpc_pb.GatewayClient, error) {
|
|||||||
return grpc_pb.NewGatewayClient(c), nil
|
return grpc_pb.NewGatewayClient(c), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GatewayNewBroadcastClient() map[int64]grpc_pb.GatewayClient {
|
func GatewayNewBroadcastClient() map[string]grpc_pb.GatewayClient {
|
||||||
clientM := make(map[int64]grpc_pb.GatewayClient)
|
clientM := make(map[string]grpc_pb.GatewayClient)
|
||||||
connM := discover.FindServerAll(common.KeyDiscoverGateway)
|
connM := discover.FindServerAll(common.KeyDiscoverGateway)
|
||||||
for sid, conn := range connM {
|
for sid, conn := range connM {
|
||||||
clientM[sid] = grpc_pb.NewGatewayClient(conn)
|
clientM[sid] = grpc_pb.NewGatewayClient(conn)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"git.hlsq.asia/mmorpg/service-common/proto/ss/grpc_pb"
|
"git.hlsq.asia/mmorpg/service-common/proto/ss/grpc_pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SceneNewClient(sid ...int64) (grpc_pb.SceneClient, error) {
|
func SceneNewClient(sid ...string) (grpc_pb.SceneClient, error) {
|
||||||
c, err := discover.FindServer(common.KeyDiscoverScene, sid...)
|
c, err := discover.FindServer(common.KeyDiscoverScene, sid...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -23,8 +23,8 @@ func SceneNewClientLB() (grpc_pb.SceneClient, error) {
|
|||||||
return grpc_pb.NewSceneClient(c), nil
|
return grpc_pb.NewSceneClient(c), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SceneNewBroadcastClient() map[int64]grpc_pb.SceneClient {
|
func SceneNewBroadcastClient() map[string]grpc_pb.SceneClient {
|
||||||
clientM := make(map[int64]grpc_pb.SceneClient)
|
clientM := make(map[string]grpc_pb.SceneClient)
|
||||||
connM := discover.FindServerAll(common.KeyDiscoverScene)
|
connM := discover.FindServerAll(common.KeyDiscoverScene)
|
||||||
for sid, conn := range connM {
|
for sid, conn := range connM {
|
||||||
clientM[sid] = grpc_pb.NewSceneClient(conn)
|
clientM[sid] = grpc_pb.NewSceneClient(conn)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"git.hlsq.asia/mmorpg/service-common/proto/ss/grpc_pb"
|
"git.hlsq.asia/mmorpg/service-common/proto/ss/grpc_pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
func UserNewClient(sid ...int64) (grpc_pb.UserClient, error) {
|
func UserNewClient(sid ...string) (grpc_pb.UserClient, error) {
|
||||||
c, err := discover.FindServer(common.KeyDiscoverUser, sid...)
|
c, err := discover.FindServer(common.KeyDiscoverUser, sid...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ type IService interface {
|
|||||||
|
|
||||||
type Base struct {
|
type Base struct {
|
||||||
Target string
|
Target string
|
||||||
SID int64
|
SID string
|
||||||
Serve *grpc.Server
|
Serve *grpc.Server
|
||||||
EtcdTTL int64
|
EtcdTTL int64
|
||||||
OnInit func(serve *grpc.Server)
|
OnInit func(serve *grpc.Server)
|
||||||
@@ -34,7 +34,7 @@ type Base struct {
|
|||||||
func (s *Base) Init(addr string, port int32) {
|
func (s *Base) Init(addr string, port int32) {
|
||||||
s.wg = &sync.WaitGroup{}
|
s.wg = &sync.WaitGroup{}
|
||||||
s.wg.Add(1)
|
s.wg.Add(1)
|
||||||
s.SID = utils.SnowflakeInstance().Generate().Int64()
|
s.SID = utils.SnowflakeInstance().Generate().String()
|
||||||
go func() {
|
go func() {
|
||||||
defer s.wg.Done()
|
defer s.wg.Done()
|
||||||
defer s.OnClose()
|
defer s.OnClose()
|
||||||
|
|||||||
14
utils/jwt.go
14
utils/jwt.go
@@ -5,16 +5,15 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Claims struct {
|
type Claims struct {
|
||||||
USN int64 `json:"usn"`
|
USN string `json:"usn"`
|
||||||
jwt.RegisteredClaims
|
jwt.RegisteredClaims
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenToken(usn int64, secret string, expires time.Duration) (string, error) {
|
func GenToken(usn string, secret string, expires time.Duration) (string, error) {
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, Claims{
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, Claims{
|
||||||
USN: usn,
|
USN: usn,
|
||||||
RegisteredClaims: jwt.RegisteredClaims{
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
@@ -41,16 +40,13 @@ func ParseToken(tokenString string, secret string) (*Claims, error) {
|
|||||||
return claims, nil
|
return claims, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ShouldBindUsn(ctx context.Context, usn *int64) bool {
|
func ShouldBindUsn(ctx context.Context, usn *string) bool {
|
||||||
if md, ok := metadata.FromIncomingContext(ctx); ok {
|
if md, ok := metadata.FromIncomingContext(ctx); ok {
|
||||||
usnArr := md.Get("X-Usn")
|
usnArr := md.Get("X-Usn")
|
||||||
if len(usnArr) == 0 || usnArr[0] == "" {
|
if len(usnArr) == 0 || usnArr[0] == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
s, _ := strconv.Atoi(usnArr[0])
|
*usn = usnArr[0]
|
||||||
if s > 0 {
|
|
||||||
*usn = int64(s)
|
|
||||||
}
|
}
|
||||||
}
|
return *usn != ""
|
||||||
return *usn > 0
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user