init
This commit is contained in:
parent
f32d0c1d69
commit
d869020487
|
@ -0,0 +1,299 @@
|
||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.27.1
|
||||||
|
// protoc v3.21.4
|
||||||
|
// source: base.proto
|
||||||
|
|
||||||
|
package hpds_net_framework
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
// 协议消息
|
||||||
|
type Protocol struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||||
|
Content []byte `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Protocol) Reset() {
|
||||||
|
*x = Protocol{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_base_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Protocol) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Protocol) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Protocol) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_base_proto_msgTypes[0]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Protocol.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Protocol) Descriptor() ([]byte, []int) {
|
||||||
|
return file_base_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Protocol) GetId() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Id
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Protocol) GetContent() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.Content
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打包消息
|
||||||
|
type ScProtocolPack struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||||
|
Pack []*Protocol `protobuf:"bytes,2,rep,name=pack,proto3" json:"pack,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ScProtocolPack) Reset() {
|
||||||
|
*x = ScProtocolPack{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_base_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ScProtocolPack) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ScProtocolPack) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ScProtocolPack) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_base_proto_msgTypes[1]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ScProtocolPack.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ScProtocolPack) Descriptor() ([]byte, []int) {
|
||||||
|
return file_base_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ScProtocolPack) GetId() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Id
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ScProtocolPack) GetPack() []*Protocol {
|
||||||
|
if x != nil {
|
||||||
|
return x.Pack
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 帧消息
|
||||||
|
type ScFrame struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Frame uint32 `protobuf:"varint,1,opt,name=frame,proto3" json:"frame,omitempty"`
|
||||||
|
Protocols [][]byte `protobuf:"bytes,2,rep,name=protocols,proto3" json:"protocols,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ScFrame) Reset() {
|
||||||
|
*x = ScFrame{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_base_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ScFrame) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ScFrame) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ScFrame) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_base_proto_msgTypes[2]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ScFrame.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ScFrame) Descriptor() ([]byte, []int) {
|
||||||
|
return file_base_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ScFrame) GetFrame() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Frame
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ScFrame) GetProtocols() [][]byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.Protocols
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_base_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_base_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x0a, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x34, 0x0a, 0x08,
|
||||||
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
|
||||||
|
0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74,
|
||||||
|
0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65,
|
||||||
|
0x6e, 0x74, 0x22, 0x41, 0x0a, 0x10, 0x73, 0x63, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
|
||||||
|
0x6c, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||||
|
0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x04, 0x70, 0x61, 0x63, 0x6b, 0x18, 0x02,
|
||||||
|
0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52,
|
||||||
|
0x04, 0x70, 0x61, 0x63, 0x6b, 0x22, 0x3e, 0x0a, 0x08, 0x73, 0x63, 0x5f, 0x66, 0x72, 0x61, 0x6d,
|
||||||
|
0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
|
||||||
|
0x52, 0x05, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
|
0x63, 0x6f, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x42, 0x16, 0x5a, 0x14, 0x2e, 0x3b, 0x68, 0x70, 0x64, 0x73, 0x5f,
|
||||||
|
0x6e, 0x65, 0x74, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x62, 0x06, 0x70,
|
||||||
|
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_base_proto_rawDescOnce sync.Once
|
||||||
|
file_base_proto_rawDescData = file_base_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_base_proto_rawDescGZIP() []byte {
|
||||||
|
file_base_proto_rawDescOnce.Do(func() {
|
||||||
|
file_base_proto_rawDescData = protoimpl.X.CompressGZIP(file_base_proto_rawDescData)
|
||||||
|
})
|
||||||
|
return file_base_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_base_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||||
|
var file_base_proto_goTypes = []interface{}{
|
||||||
|
(*Protocol)(nil), // 0: protocol
|
||||||
|
(*ScProtocolPack)(nil), // 1: sc_protocol_pack
|
||||||
|
(*ScFrame)(nil), // 2: sc_frame
|
||||||
|
}
|
||||||
|
var file_base_proto_depIdxs = []int32{
|
||||||
|
0, // 0: sc_protocol_pack.pack:type_name -> protocol
|
||||||
|
1, // [1:1] is the sub-list for method output_type
|
||||||
|
1, // [1:1] is the sub-list for method input_type
|
||||||
|
1, // [1:1] is the sub-list for extension type_name
|
||||||
|
1, // [1:1] is the sub-list for extension extendee
|
||||||
|
0, // [0:1] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_base_proto_init() }
|
||||||
|
func file_base_proto_init() {
|
||||||
|
if File_base_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_base_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Protocol); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_base_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*ScProtocolPack); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_base_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*ScFrame); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_base_proto_rawDesc,
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 3,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_base_proto_goTypes,
|
||||||
|
DependencyIndexes: file_base_proto_depIdxs,
|
||||||
|
MessageInfos: file_base_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_base_proto = out.File
|
||||||
|
file_base_proto_rawDesc = nil
|
||||||
|
file_base_proto_goTypes = nil
|
||||||
|
file_base_proto_depIdxs = nil
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
option go_package = ".;hpds_net_framework";
|
||||||
|
// 协议消息
|
||||||
|
message protocol {
|
||||||
|
uint32 id = 1;
|
||||||
|
bytes content = 2;
|
||||||
|
}
|
||||||
|
// 打包消息
|
||||||
|
message sc_protocol_pack {
|
||||||
|
uint32 id = 1;
|
||||||
|
repeated protocol pack = 2;
|
||||||
|
}
|
||||||
|
// 帧消息
|
||||||
|
message sc_frame {
|
||||||
|
uint32 frame = 1;
|
||||||
|
repeated bytes protocols = 2;
|
||||||
|
}
|
|
@ -0,0 +1,164 @@
|
||||||
|
package hpds_net_framework
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"git.hpds.cc/Component/logging"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"runtime/debug"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BroadcastNode 广播转发节点
|
||||||
|
type BroadcastNode struct {
|
||||||
|
// 节点ID
|
||||||
|
NodeId string
|
||||||
|
// 网络连接
|
||||||
|
Connections map[interface{}]IConnection
|
||||||
|
// 当前连接数量
|
||||||
|
clientSize int64
|
||||||
|
// message channel
|
||||||
|
onMessage chan interface{}
|
||||||
|
recentMessages []interface{}
|
||||||
|
// AddConn
|
||||||
|
addConnChan chan IConnection
|
||||||
|
delConnChan chan string
|
||||||
|
closeFlag int64
|
||||||
|
logger *logging.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// errFoo node closed error
|
||||||
|
var errFoo = errors.New("node closed")
|
||||||
|
|
||||||
|
// NewBroadcastNode return a new BroadcastNode
|
||||||
|
func NewBroadcastNode(logger *logging.Logger) *BroadcastNode {
|
||||||
|
return &BroadcastNode{
|
||||||
|
Connections: make(map[interface{}]IConnection),
|
||||||
|
NodeId: uuid.New().String(),
|
||||||
|
onMessage: make(chan interface{}),
|
||||||
|
addConnChan: make(chan IConnection),
|
||||||
|
delConnChan: make(chan string),
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serve the node
|
||||||
|
func (bNode *BroadcastNode) Serve() {
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
for _, conn := range bNode.Connections {
|
||||||
|
conn.SetNode(nil)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
for {
|
||||||
|
// 优先管理连接
|
||||||
|
select {
|
||||||
|
// add conn
|
||||||
|
case ic := <-bNode.addConnChan:
|
||||||
|
bNode.Connections[ic.GetUuid()] = ic
|
||||||
|
bNode.clientSize++
|
||||||
|
// conn leave
|
||||||
|
case key := <-bNode.delConnChan:
|
||||||
|
delete(bNode.Connections, key)
|
||||||
|
bNode.clientSize--
|
||||||
|
default:
|
||||||
|
select {
|
||||||
|
case pkg := <-bNode.onMessage:
|
||||||
|
if pkg == nil {
|
||||||
|
bNode.logger.Info("BroadcastNode stop serve", zap.String("nodeId", bNode.NodeId))
|
||||||
|
// stop Serve
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bNode.recentMessages = append(bNode.recentMessages, pkg)
|
||||||
|
// cache recent 100
|
||||||
|
recentSize := len(bNode.recentMessages)
|
||||||
|
if recentSize > 100 {
|
||||||
|
bNode.recentMessages = bNode.recentMessages[recentSize-100:]
|
||||||
|
}
|
||||||
|
bNode.broadcast(pkg)
|
||||||
|
default:
|
||||||
|
time.Sleep(time.Millisecond * 50)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bNode *BroadcastNode) broadcast(msg interface{}) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
bNode.logger.Error("write frame error",
|
||||||
|
zap.Any("frame data", r),
|
||||||
|
zap.ByteString("stack", debug.Stack()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if bNode.clientSize == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bNode.logger.Debug("broadcast",
|
||||||
|
zap.Int64("amount", bNode.clientSize),
|
||||||
|
zap.Any("msg", msg),
|
||||||
|
)
|
||||||
|
for _, conn := range bNode.Connections {
|
||||||
|
conn.WriteMsg(msg)
|
||||||
|
}
|
||||||
|
bNode.logger.Debug("broadcast ok")
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnRawMessage bytes
|
||||||
|
func (bNode *BroadcastNode) OnRawMessage([]byte) error { return nil }
|
||||||
|
|
||||||
|
// OnProtocolMessage interface
|
||||||
|
func (bNode *BroadcastNode) OnProtocolMessage(msg interface{}) error {
|
||||||
|
if bNode.available() {
|
||||||
|
bNode.onMessage <- msg
|
||||||
|
}
|
||||||
|
return errFoo
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllMessage return chan []interface{}
|
||||||
|
func (bNode *BroadcastNode) GetAllMessage() chan []interface{} {
|
||||||
|
data := make(chan []interface{}, 1)
|
||||||
|
data <- bNode.recentMessages
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddConn by conn
|
||||||
|
func (bNode *BroadcastNode) AddConn(conn IConnection) error {
|
||||||
|
if bNode.available() {
|
||||||
|
bNode.addConnChan <- conn
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errFoo
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelConn by key
|
||||||
|
func (bNode *BroadcastNode) DelConn(key string) error {
|
||||||
|
if bNode.available() {
|
||||||
|
bNode.delConnChan <- key
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errFoo
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete sync
|
||||||
|
func (bNode *BroadcastNode) Complete() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the node
|
||||||
|
func (bNode *BroadcastNode) Destroy() error {
|
||||||
|
if bNode.available() {
|
||||||
|
atomic.AddInt64(&bNode.closeFlag, 1)
|
||||||
|
go func() {
|
||||||
|
bNode.onMessage <- nil
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
return errFoo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bNode *BroadcastNode) available() bool {
|
||||||
|
return atomic.LoadInt64(&bNode.closeFlag) == 0
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package hpds_net_framework
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Cfg is the config instance
|
||||||
|
Cfg *Data
|
||||||
|
once sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
// Data is the config struct
|
||||||
|
type Data struct {
|
||||||
|
// 单个连接未处理消息包缓存队列大小
|
||||||
|
// 注意:[超过这个大小,包将丢弃,视为当前系统无法处理,默认100]
|
||||||
|
ConnUndoQueueSize int
|
||||||
|
// 单个连接未写入消息包队列大小 [超过这个大小,包将丢弃,视为当前系统无法处理,默认为1]
|
||||||
|
ConnWriteQueueSize int
|
||||||
|
// 第一个包等待超市时间 (s) [默认5秒,连接上来未读到正确包,断开连接]
|
||||||
|
FirstPackageTimeout int
|
||||||
|
// 连接读取超时(s) [默认35秒, 超时等待时间内,请发送任何数据包,如心跳包]
|
||||||
|
ConnReadTimeout int
|
||||||
|
// 连接写超时(s) [默认5秒, 超时等待时间内,请发送任何数据包,如心跳包]
|
||||||
|
ConnWriteTimeout int
|
||||||
|
// 数据包最大限制,[默认2048]
|
||||||
|
MaxDataPackageSize int
|
||||||
|
// ws 最大header,[默认1024]
|
||||||
|
MaxHeaderLen int
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Cfg = &Data{
|
||||||
|
ConnUndoQueueSize: 100,
|
||||||
|
ConnWriteQueueSize: 10,
|
||||||
|
FirstPackageTimeout: 5,
|
||||||
|
ConnReadTimeout: 35,
|
||||||
|
ConnWriteTimeout: 5,
|
||||||
|
MaxDataPackageSize: 4096,
|
||||||
|
MaxHeaderLen: 1024,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConf this before startup server
|
||||||
|
func SetConf(cfg *Data) {
|
||||||
|
once.Do(func() {
|
||||||
|
Cfg = cfg
|
||||||
|
if C.ConnUndoQueueSize == 0 {
|
||||||
|
C.ConnUndoQueueSize = 1
|
||||||
|
}
|
||||||
|
if C.ConnWriteQueueSize == 0 {
|
||||||
|
C.ConnWriteQueueSize = 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package code
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Hello msg code
|
||||||
|
Hello = 2001
|
||||||
|
|
||||||
|
// FrameData msg code
|
||||||
|
FrameData = 1000000
|
||||||
|
// FrameStart msg code
|
||||||
|
FrameStart = 1000001
|
||||||
|
// FrameEnd msg code
|
||||||
|
FrameEnd = 1000002
|
||||||
|
// MoveOp msg code
|
||||||
|
MoveOp = 3001
|
||||||
|
)
|
|
@ -0,0 +1,364 @@
|
||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.25.0-devel
|
||||||
|
// protoc v3.14.0
|
||||||
|
// source: test.proto
|
||||||
|
|
||||||
|
package protobuf
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
// protoc --go_out=. *.proto
|
||||||
|
type Hello struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Hello string `protobuf:"bytes,1,opt,name=hello,proto3" json:"hello,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Hello) Reset() {
|
||||||
|
*x = Hello{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_test_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Hello) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Hello) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Hello) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_test_proto_msgTypes[0]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Hello.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Hello) Descriptor() ([]byte, []int) {
|
||||||
|
return file_test_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Hello) GetHello() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Hello
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type CsStartFrame struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CsStartFrame) Reset() {
|
||||||
|
*x = CsStartFrame{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_test_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CsStartFrame) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*CsStartFrame) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *CsStartFrame) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_test_proto_msgTypes[1]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use CsStartFrame.ProtoReflect.Descriptor instead.
|
||||||
|
func (*CsStartFrame) Descriptor() ([]byte, []int) {
|
||||||
|
return file_test_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
type CsEndFrame struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CsEndFrame) Reset() {
|
||||||
|
*x = CsEndFrame{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_test_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CsEndFrame) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*CsEndFrame) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *CsEndFrame) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_test_proto_msgTypes[2]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use CsEndFrame.ProtoReflect.Descriptor instead.
|
||||||
|
func (*CsEndFrame) Descriptor() ([]byte, []int) {
|
||||||
|
return file_test_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移动
|
||||||
|
type CsMove struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
FromX float32 `protobuf:"fixed32,1,opt,name=fromX,proto3" json:"fromX,omitempty"`
|
||||||
|
FromY float32 `protobuf:"fixed32,2,opt,name=fromY,proto3" json:"fromY,omitempty"`
|
||||||
|
FromZ float32 `protobuf:"fixed32,3,opt,name=fromZ,proto3" json:"fromZ,omitempty"`
|
||||||
|
ToX float32 `protobuf:"fixed32,4,opt,name=toX,proto3" json:"toX,omitempty"`
|
||||||
|
ToY float32 `protobuf:"fixed32,5,opt,name=toY,proto3" json:"toY,omitempty"`
|
||||||
|
ToZ float32 `protobuf:"fixed32,6,opt,name=toZ,proto3" json:"toZ,omitempty"`
|
||||||
|
Speed float32 `protobuf:"fixed32,7,opt,name=speed,proto3" json:"speed,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CsMove) Reset() {
|
||||||
|
*x = CsMove{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_test_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CsMove) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*CsMove) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *CsMove) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_test_proto_msgTypes[3]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use CsMove.ProtoReflect.Descriptor instead.
|
||||||
|
func (*CsMove) Descriptor() ([]byte, []int) {
|
||||||
|
return file_test_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CsMove) GetFromX() float32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.FromX
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CsMove) GetFromY() float32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.FromY
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CsMove) GetFromZ() float32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.FromZ
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CsMove) GetToX() float32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.ToX
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CsMove) GetToY() float32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.ToY
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CsMove) GetToZ() float32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.ToZ
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CsMove) GetSpeed() float32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Speed
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_test_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_test_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x0a, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1d, 0x0a, 0x05,
|
||||||
|
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x18, 0x01,
|
||||||
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x10, 0x0a, 0x0e, 0x63,
|
||||||
|
0x73, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x22, 0x0e, 0x0a,
|
||||||
|
0x0c, 0x63, 0x73, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x22, 0x97, 0x01,
|
||||||
|
0x0a, 0x07, 0x63, 0x73, 0x5f, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x72, 0x6f,
|
||||||
|
0x6d, 0x58, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x66, 0x72, 0x6f, 0x6d, 0x58, 0x12,
|
||||||
|
0x14, 0x0a, 0x05, 0x66, 0x72, 0x6f, 0x6d, 0x59, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05,
|
||||||
|
0x66, 0x72, 0x6f, 0x6d, 0x59, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x72, 0x6f, 0x6d, 0x5a, 0x18, 0x03,
|
||||||
|
0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x66, 0x72, 0x6f, 0x6d, 0x5a, 0x12, 0x10, 0x0a, 0x03, 0x74,
|
||||||
|
0x6f, 0x58, 0x18, 0x04, 0x20, 0x01, 0x28, 0x02, 0x52, 0x03, 0x74, 0x6f, 0x58, 0x12, 0x10, 0x0a,
|
||||||
|
0x03, 0x74, 0x6f, 0x59, 0x18, 0x05, 0x20, 0x01, 0x28, 0x02, 0x52, 0x03, 0x74, 0x6f, 0x59, 0x12,
|
||||||
|
0x10, 0x0a, 0x03, 0x74, 0x6f, 0x5a, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, 0x03, 0x74, 0x6f,
|
||||||
|
0x5a, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x02,
|
||||||
|
0x52, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x42, 0x0c, 0x5a, 0x0a, 0x2e, 0x3b, 0x70, 0x72, 0x6f,
|
||||||
|
0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_test_proto_rawDescOnce sync.Once
|
||||||
|
file_test_proto_rawDescData = file_test_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_test_proto_rawDescGZIP() []byte {
|
||||||
|
file_test_proto_rawDescOnce.Do(func() {
|
||||||
|
file_test_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_proto_rawDescData)
|
||||||
|
})
|
||||||
|
return file_test_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_test_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||||
|
var file_test_proto_goTypes = []interface{}{
|
||||||
|
(*Hello)(nil), // 0: hello
|
||||||
|
(*CsStartFrame)(nil), // 1: cs_start_frame
|
||||||
|
(*CsEndFrame)(nil), // 2: cs_end_frame
|
||||||
|
(*CsMove)(nil), // 3: cs_move
|
||||||
|
}
|
||||||
|
var file_test_proto_depIdxs = []int32{
|
||||||
|
0, // [0:0] is the sub-list for method output_type
|
||||||
|
0, // [0:0] is the sub-list for method input_type
|
||||||
|
0, // [0:0] is the sub-list for extension type_name
|
||||||
|
0, // [0:0] is the sub-list for extension extendee
|
||||||
|
0, // [0:0] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_test_proto_init() }
|
||||||
|
func file_test_proto_init() {
|
||||||
|
if File_test_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_test_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Hello); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_test_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*CsStartFrame); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_test_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*CsEndFrame); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_test_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*CsMove); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_test_proto_rawDesc,
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 4,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_test_proto_goTypes,
|
||||||
|
DependencyIndexes: file_test_proto_depIdxs,
|
||||||
|
MessageInfos: file_test_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_test_proto = out.File
|
||||||
|
file_test_proto_rawDesc = nil
|
||||||
|
file_test_proto_goTypes = nil
|
||||||
|
file_test_proto_depIdxs = nil
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
option go_package = ".;protobuf";
|
||||||
|
|
||||||
|
// protoc --go_out=. *.proto
|
||||||
|
message hello {
|
||||||
|
string hello = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message cs_start_frame {
|
||||||
|
}
|
||||||
|
|
||||||
|
message cs_end_frame {
|
||||||
|
}
|
||||||
|
// 移动
|
||||||
|
message cs_move {
|
||||||
|
float fromX = 1;
|
||||||
|
float fromY = 2;
|
||||||
|
float fromZ = 3;
|
||||||
|
float toX = 4;
|
||||||
|
float toY = 5;
|
||||||
|
float toZ = 6;
|
||||||
|
float speed = 7;
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.hpds.cc/Component/hpds_net_framework"
|
||||||
|
"git.hpds.cc/Component/hpds_net_framework/examples/comm/msg/code"
|
||||||
|
"git.hpds.cc/Component/hpds_net_framework/examples/comm/protobuf"
|
||||||
|
"git.hpds.cc/Component/hpds_net_framework/security"
|
||||||
|
"git.hpds.cc/Component/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
logger *logging.Logger
|
||||||
|
processor *hpds_net_framework.PbProcessor
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
logger = LoadLoggerConfig()
|
||||||
|
passwd := security.RandLittlePassword()
|
||||||
|
cipher := security.NewAESCipher(passwd)
|
||||||
|
processor = hpds_net_framework.NewPbProcessor(logger)
|
||||||
|
// add encrypt cipher for processor
|
||||||
|
processor.SetEncryptor(cipher)
|
||||||
|
// 注册消息,以及回调处理
|
||||||
|
processor.RegisterHandler(code.Hello, &protobuf.Hello{}, func(args ...interface{}) {
|
||||||
|
msg := args[hpds_net_framework.Msg].(*protobuf.Hello)
|
||||||
|
logger.Info("Message => from client", zap.String("content", msg.Hello))
|
||||||
|
conn := args[hpds_net_framework.Conn].(hpds_net_framework.IConnection)
|
||||||
|
conn.WriteMsg(msg)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// run server
|
||||||
|
if s, err := hpds_net_framework.NewTcpServer("localhost:2021", processor, logger); err != nil {
|
||||||
|
panic(err)
|
||||||
|
} else {
|
||||||
|
e := s.Run()
|
||||||
|
if e != nil {
|
||||||
|
logger.Fatal("Fatal", zap.Error(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadLoggerConfig 加载日志配置
|
||||||
|
func LoadLoggerConfig() *logging.Logger {
|
||||||
|
return logging.NewLogger(
|
||||||
|
logging.SetPath("./log/"),
|
||||||
|
logging.SetPrefix(""),
|
||||||
|
logging.SetDevelopment(true),
|
||||||
|
logging.SetDebugFileSuffix(""),
|
||||||
|
logging.SetWarnFileSuffix(""),
|
||||||
|
logging.SetErrorFileSuffix(""),
|
||||||
|
logging.SetInfoFileSuffix(""),
|
||||||
|
logging.SetMaxAge(30),
|
||||||
|
logging.SetMaxBackups(100),
|
||||||
|
logging.SetMaxSize(100),
|
||||||
|
logging.SetLevel(logging.LogLevel["debug"]),
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,187 @@
|
||||||
|
package hpds_net_framework
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"git.hpds.cc/Component/logging"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FrameNode 帧同步节点
|
||||||
|
type FrameNode struct {
|
||||||
|
// 节点ID
|
||||||
|
NodeId string
|
||||||
|
// 网络连接
|
||||||
|
Connections map[interface{}]IConnection
|
||||||
|
// 当前连接数量
|
||||||
|
clientSize int64
|
||||||
|
// 完成同步数量
|
||||||
|
overSize int64
|
||||||
|
// 同步周期
|
||||||
|
FrameTicker *time.Ticker
|
||||||
|
// current frame messages
|
||||||
|
frameData [][]byte
|
||||||
|
frameId uint32
|
||||||
|
allFrame []interface{}
|
||||||
|
// rand seed
|
||||||
|
RandSeed int64
|
||||||
|
// message channel
|
||||||
|
onMessage chan []byte
|
||||||
|
// AddConn
|
||||||
|
addConnChan chan IConnection
|
||||||
|
delConnChan chan string
|
||||||
|
completeChan chan interface{}
|
||||||
|
closeFlag int64
|
||||||
|
logger *logging.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFrameNode return a new FrameNode
|
||||||
|
func NewFrameNode(logger *logging.Logger) *FrameNode {
|
||||||
|
return &FrameNode{
|
||||||
|
Connections: make(map[interface{}]IConnection),
|
||||||
|
NodeId: uuid.New().String(),
|
||||||
|
FrameTicker: time.NewTicker(time.Millisecond * 66),
|
||||||
|
RandSeed: time.Now().UnixNano(),
|
||||||
|
onMessage: make(chan []byte),
|
||||||
|
addConnChan: make(chan IConnection),
|
||||||
|
delConnChan: make(chan string),
|
||||||
|
completeChan: make(chan interface{}),
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serve the node
|
||||||
|
func (gr *FrameNode) Serve() {
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
for _, conn := range gr.Connections {
|
||||||
|
conn.SetNode(nil)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
for {
|
||||||
|
// 优先管理连接状态
|
||||||
|
select {
|
||||||
|
// add conn
|
||||||
|
case ic := <-gr.addConnChan:
|
||||||
|
gr.Connections[ic.GetUuid()] = ic
|
||||||
|
gr.clientSize++
|
||||||
|
// conn leave
|
||||||
|
case key := <-gr.delConnChan:
|
||||||
|
delete(gr.Connections, key)
|
||||||
|
gr.clientSize--
|
||||||
|
// sync complete
|
||||||
|
case <-gr.completeChan:
|
||||||
|
gr.overSize++
|
||||||
|
if gr.overSize >= gr.clientSize/2 {
|
||||||
|
_ = gr.Destroy()
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
select {
|
||||||
|
case <-gr.FrameTicker.C:
|
||||||
|
gr.sendFrame()
|
||||||
|
case pkg := <-gr.onMessage:
|
||||||
|
if pkg == nil {
|
||||||
|
gr.logger.Info("FrameNode stop serve", zap.String("NodeId", gr.NodeId))
|
||||||
|
// stop Serve
|
||||||
|
gr.FrameTicker.Stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gr.frameData = append(gr.frameData, pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gr *FrameNode) sendFrame() {
|
||||||
|
// 没有消息
|
||||||
|
if len(gr.frameData) == 0 || gr.clientSize == 0 {
|
||||||
|
//log.Debug("Server empty frame without data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 打包消息
|
||||||
|
frame := ScFrame{
|
||||||
|
Frame: gr.frameId,
|
||||||
|
Protocols: gr.frameData,
|
||||||
|
}
|
||||||
|
gr.logger.Debug("send frame to connections",
|
||||||
|
zap.Int("connection count", len(gr.Connections)),
|
||||||
|
zap.Int("contains package count", len(gr.frameData)),
|
||||||
|
)
|
||||||
|
for _, conn := range gr.Connections {
|
||||||
|
conn.WriteMsg(&frame)
|
||||||
|
}
|
||||||
|
// reset data
|
||||||
|
gr.frameId++
|
||||||
|
gr.frameData = gr.frameData[:0]
|
||||||
|
gr.allFrame = append(gr.allFrame, gr.frameData)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnRawMessage msg
|
||||||
|
func (gr *FrameNode) OnRawMessage(msg []byte) error {
|
||||||
|
if msg == nil {
|
||||||
|
err := errors.New("can't frame nil message")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if gr.available() {
|
||||||
|
gr.onMessage <- msg
|
||||||
|
}
|
||||||
|
return errFoo
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnProtocolMessage interface
|
||||||
|
func (gr *FrameNode) OnProtocolMessage(interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllMessage return chan []interface
|
||||||
|
func (gr *FrameNode) GetAllMessage() chan []interface{} {
|
||||||
|
data := make(chan []interface{}, 1)
|
||||||
|
data <- gr.allFrame
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddConn conn
|
||||||
|
func (gr *FrameNode) AddConn(conn IConnection) error {
|
||||||
|
if gr.available() {
|
||||||
|
gr.addConnChan <- conn
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errFoo
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelConn by key
|
||||||
|
func (gr *FrameNode) DelConn(key string) error {
|
||||||
|
if gr.available() {
|
||||||
|
gr.delConnChan <- key
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errFoo
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete sync
|
||||||
|
func (gr *FrameNode) Complete() error {
|
||||||
|
if gr.available() {
|
||||||
|
gr.completeChan <- struct{}{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errFoo
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the node
|
||||||
|
func (gr *FrameNode) Destroy() error {
|
||||||
|
if gr.available() {
|
||||||
|
atomic.AddInt64(&gr.closeFlag, 1)
|
||||||
|
go func() {
|
||||||
|
gr.onMessage <- nil
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errFoo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gr *FrameNode) available() bool {
|
||||||
|
return atomic.LoadInt64(&gr.closeFlag) == 0
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
module git.hpds.cc/Component/hpds_net_framework
|
||||||
|
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
git.hpds.cc/Component/logging v0.0.0-20220802072911-f95dfe16666a
|
||||||
|
github.com/google/uuid v1.3.0
|
||||||
|
go.uber.org/zap v1.21.0
|
||||||
|
google.golang.org/protobuf v1.28.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||||
|
)
|
|
@ -0,0 +1,18 @@
|
||||||
|
package hpds_net_framework
|
||||||
|
|
||||||
|
// Encryptor interface
|
||||||
|
type Encryptor interface {
|
||||||
|
Encode(bs []byte) []byte
|
||||||
|
Decode(bs []byte) []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Processor interface
|
||||||
|
type Processor interface {
|
||||||
|
SetBigEndian()
|
||||||
|
GetBigEndian() bool
|
||||||
|
SetEncryptor(enc Encryptor)
|
||||||
|
OnReceivedPackage(interface{}, []byte) error
|
||||||
|
WrapMsg(interface{}) ([]byte, error)
|
||||||
|
WrapIdMsg(id uint32, data interface{}) ([]byte, error)
|
||||||
|
RegisterHandler(id int, entity interface{}, handle func(args ...interface{}))
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package hpds_net_framework
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.hpds.cc/Component/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"reflect"
|
||||||
|
"runtime/debug"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 回调传参常量
|
||||||
|
const (
|
||||||
|
Msg = iota
|
||||||
|
Conn
|
||||||
|
Raw
|
||||||
|
)
|
||||||
|
|
||||||
|
// 消息信息
|
||||||
|
type msgInfo struct {
|
||||||
|
msgId int
|
||||||
|
msgType reflect.Type
|
||||||
|
msgCallback func(args ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行消息回调
|
||||||
|
func execute(mInfo msgInfo, msg interface{}, writer interface{}, body []byte, id uint32) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
logging.L().Error("panic at msg",
|
||||||
|
zap.Uint32("id", id),
|
||||||
|
zap.Any("recover", r),
|
||||||
|
zap.ByteString("stack", debug.Stack()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
begin := time.Now().UnixNano() / int64(time.Millisecond)
|
||||||
|
mInfo.msgCallback(msg, writer, body)
|
||||||
|
costs := time.Now().UnixNano()/int64(time.Millisecond) - begin
|
||||||
|
logging.L().Debug("execute logic",
|
||||||
|
zap.Int("msgId", mInfo.msgId),
|
||||||
|
zap.Int64("costs", costs),
|
||||||
|
zap.Any("msgType", mInfo.msgType),
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package hpds_net_framework
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Server interface
|
||||||
|
type Server interface {
|
||||||
|
Run() error
|
||||||
|
Handle(conn net.Conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// INode 网络同步节点,如消息节点,聊天室节点
|
||||||
|
type INode interface {
|
||||||
|
AddConn(IConnection) error
|
||||||
|
DelConn(string) error
|
||||||
|
Serve()
|
||||||
|
OnRawMessage([]byte) error
|
||||||
|
OnProtocolMessage(interface{}) error
|
||||||
|
GetAllMessage() chan []interface{}
|
||||||
|
Destroy() error
|
||||||
|
Complete() error
|
||||||
|
}
|
||||||
|
|
||||||
|
// IConnection 网络连接
|
||||||
|
type IConnection interface {
|
||||||
|
GetUuid() string
|
||||||
|
ReadMsg()
|
||||||
|
WriteMsg(message interface{})
|
||||||
|
Close() error
|
||||||
|
AfterClose(func())
|
||||||
|
//SetData 设置自定义数据
|
||||||
|
SetData(interface{})
|
||||||
|
GetData() interface{}
|
||||||
|
//SetNode 设置节点
|
||||||
|
SetNode(INode)
|
||||||
|
GetNode() INode
|
||||||
|
//IsClosed 是否关闭
|
||||||
|
IsClosed() bool
|
||||||
|
}
|
|
@ -0,0 +1,177 @@
|
||||||
|
package hpds_net_framework
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"git.hpds.cc/Component/logging"
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PbProcessor one of Processor implement protoc --go_out=. *.proto
|
||||||
|
type PbProcessor struct {
|
||||||
|
bigEndian bool
|
||||||
|
enc Encryptor
|
||||||
|
msgTypes map[reflect.Type]int
|
||||||
|
handlers map[int]msgInfo
|
||||||
|
logger *logging.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPbProcessor return PB processor
|
||||||
|
func NewPbProcessor(logger *logging.Logger) *PbProcessor {
|
||||||
|
pb := PbProcessor{
|
||||||
|
msgTypes: make(map[reflect.Type]int),
|
||||||
|
handlers: make(map[int]msgInfo),
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
return &pb
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnReceivedPackage 收到完整数据包, 返回解包错误
|
||||||
|
func (pbf *PbProcessor) OnReceivedPackage(writer interface{}, body []byte) error {
|
||||||
|
// 解密
|
||||||
|
if pbf.enc != nil {
|
||||||
|
//log.Debug("before decode:: %v", body)
|
||||||
|
body = pbf.enc.Decode(body)
|
||||||
|
//log.Debug("after decode:: %v", body)
|
||||||
|
}
|
||||||
|
// 解码
|
||||||
|
var pack Protocol
|
||||||
|
if err := proto.UnmarshalMerge(body, &pack); err != nil {
|
||||||
|
pbf.logger.Error("Can't unmarshal pack body to protocolMsg",
|
||||||
|
zap.ByteString("body", body),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
info, ok := pbf.handlers[int(pack.Id)]
|
||||||
|
if !ok {
|
||||||
|
pbf.logger.Error("Not register msg id",
|
||||||
|
zap.Uint32("pack Id", pack.Id),
|
||||||
|
)
|
||||||
|
// handler not found, not a dead err
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
msg := reflect.New(info.msgType.Elem()).Interface()
|
||||||
|
err := proto.UnmarshalMerge(pack.Content, msg.(proto.Message))
|
||||||
|
if err != nil {
|
||||||
|
pbf.logger.Error("Unmarshal Merge pack contents error",
|
||||||
|
zap.Uint32("pack id", pack.Id),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// 执行逻辑
|
||||||
|
execute(info, msg, writer, body, pack.Id)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrapMsg format the interface message to []byte
|
||||||
|
func (pbf *PbProcessor) WrapMsg(message interface{}) ([]byte, error) {
|
||||||
|
pbf.logger.Debug("Protobuf processor wrap for write",
|
||||||
|
zap.Any("reflect.TypeOf", reflect.TypeOf(message)),
|
||||||
|
)
|
||||||
|
data, err := proto.Marshal(message.(proto.Message))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tp := reflect.TypeOf(message)
|
||||||
|
id, ok := pbf.msgTypes[tp]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("not register %v", tp)
|
||||||
|
}
|
||||||
|
protocol := Protocol{
|
||||||
|
Id: uint32(id),
|
||||||
|
Content: data,
|
||||||
|
}
|
||||||
|
data, err = proto.Marshal(&protocol)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if pbf.enc != nil {
|
||||||
|
//log.Debug("before encode:: %v", data)
|
||||||
|
data = pbf.enc.Encode(data)
|
||||||
|
//log.Debug("after encode:: %v", data)
|
||||||
|
}
|
||||||
|
// head
|
||||||
|
head := make([]byte, 2)
|
||||||
|
if pbf.bigEndian {
|
||||||
|
binary.BigEndian.PutUint16(head, uint16(len(data)))
|
||||||
|
} else {
|
||||||
|
binary.LittleEndian.PutUint16(head, uint16(len(data)))
|
||||||
|
}
|
||||||
|
pkg := append(head, data...)
|
||||||
|
return pkg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrapIdMsg format the interface message to []byte with id
|
||||||
|
func (pbf *PbProcessor) WrapIdMsg(id uint32, message interface{}) ([]byte, error) {
|
||||||
|
pbf.logger.Debug("Protobuf processor wrap for write",
|
||||||
|
zap.Any("reflect.TypeOf", reflect.TypeOf(message)),
|
||||||
|
)
|
||||||
|
data, err := proto.Marshal(message.(proto.Message))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
protocol := Protocol{
|
||||||
|
Id: id,
|
||||||
|
Content: data,
|
||||||
|
}
|
||||||
|
data, err = proto.Marshal(&protocol)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if pbf.enc != nil {
|
||||||
|
//log.Debug("before encode:: %v", data)
|
||||||
|
data = pbf.enc.Encode(data)
|
||||||
|
//log.Debug("after encode:: %v", data)
|
||||||
|
}
|
||||||
|
// head
|
||||||
|
head := make([]byte, 2)
|
||||||
|
if pbf.bigEndian {
|
||||||
|
binary.BigEndian.PutUint16(head, uint16(len(data)))
|
||||||
|
} else {
|
||||||
|
binary.LittleEndian.PutUint16(head, uint16(len(data)))
|
||||||
|
}
|
||||||
|
pkg := append(head, data...)
|
||||||
|
return pkg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrapMsgNoHeader without header length
|
||||||
|
func (pbf *PbProcessor) WrapMsgNoHeader(message interface{}) ([]byte, error) {
|
||||||
|
data, err := pbf.WrapMsg(message)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return data[2:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterHandler for logic
|
||||||
|
func (pbf *PbProcessor) RegisterHandler(id int, entity interface{}, handle func(args ...interface{})) {
|
||||||
|
if _, ok := pbf.handlers[id]; ok {
|
||||||
|
pbf.logger.Error("Already register handler", zap.Int("ID", id))
|
||||||
|
} else {
|
||||||
|
pbf.handlers[id] = msgInfo{
|
||||||
|
msgId: id,
|
||||||
|
msgType: reflect.TypeOf(entity),
|
||||||
|
msgCallback: handle,
|
||||||
|
}
|
||||||
|
pbf.msgTypes[reflect.TypeOf(entity)] = id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBigEndian for order
|
||||||
|
func (pbf *PbProcessor) SetBigEndian() {
|
||||||
|
pbf.bigEndian = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBigEndian of the order
|
||||||
|
func (pbf *PbProcessor) GetBigEndian() bool {
|
||||||
|
return pbf.bigEndian
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEncryptor for processor
|
||||||
|
func (pbf *PbProcessor) SetEncryptor(enc Encryptor) {
|
||||||
|
pbf.enc = enc
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
package security
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AESCipher one of Encryptor implement
|
||||||
|
type AESCipher struct {
|
||||||
|
key []byte
|
||||||
|
iv []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAESCipher return a AESCipher
|
||||||
|
func NewAESCipher(key string) *AESCipher {
|
||||||
|
size := len(key) / 8
|
||||||
|
if size < 2 {
|
||||||
|
//log.Error("incorrect key, need 16(aes-128), 24(aes-192), 32(aes-256) length string")
|
||||||
|
return nil
|
||||||
|
} else if size > 4 {
|
||||||
|
size = 4
|
||||||
|
}
|
||||||
|
key = key[:size*8]
|
||||||
|
return &AESCipher{key: []byte(key), iv: []byte(key[:16])}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode src
|
||||||
|
func (cipher *AESCipher) Decode(src []byte) []byte {
|
||||||
|
encrypt, err := aesDeCrypt(src, cipher.key, cipher.iv)
|
||||||
|
if err != nil {
|
||||||
|
return src
|
||||||
|
}
|
||||||
|
return encrypt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode src
|
||||||
|
func (cipher *AESCipher) Encode(src []byte) []byte {
|
||||||
|
encrypt, err := aesEcrypt(src, cipher.key, cipher.iv)
|
||||||
|
if err != nil {
|
||||||
|
//log.Error("Aes Encode error %s", err)
|
||||||
|
return src
|
||||||
|
}
|
||||||
|
return encrypt
|
||||||
|
}
|
||||||
|
|
||||||
|
//PKCS7 填充模式
|
||||||
|
func pKCS7Padding(ciphertext []byte, blockSize int) []byte {
|
||||||
|
padding := blockSize - len(ciphertext)%blockSize
|
||||||
|
//Repeat()函数的功能是把切片[]byte{byte(padding)}复制padding个,然后合并成新的字节切片返回
|
||||||
|
padText := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||||
|
return append(ciphertext, padText...)
|
||||||
|
}
|
||||||
|
|
||||||
|
//填充的反向操作,删除填充字符串
|
||||||
|
func pKCS7UnPadding(origData []byte) ([]byte, error) {
|
||||||
|
//获取数据长度
|
||||||
|
length := len(origData)
|
||||||
|
if length == 0 {
|
||||||
|
return nil, errors.New("pKCS7UnPadding error")
|
||||||
|
}
|
||||||
|
//获取填充字符串长度
|
||||||
|
unpadding := int(origData[length-1])
|
||||||
|
//截取切片,删除填充字节,并且返回明文
|
||||||
|
return origData[:(length - unpadding)], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//实现加密
|
||||||
|
func aesEcrypt(origData []byte, key, iv []byte) ([]byte, error) {
|
||||||
|
//创建加密算法实例
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
//获取块的大小
|
||||||
|
blockSize := block.BlockSize()
|
||||||
|
//对数据进行填充,让数据长度满足需求
|
||||||
|
origData = pKCS7Padding(origData, blockSize)
|
||||||
|
//采用AES加密方法中CBC加密模式
|
||||||
|
blocMode := cipher.NewCBCEncrypter(block, iv)
|
||||||
|
crypted := make([]byte, len(origData))
|
||||||
|
//执行加密
|
||||||
|
blocMode.CryptBlocks(crypted, origData)
|
||||||
|
return crypted, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//实现解密
|
||||||
|
func aesDeCrypt(cypted []byte, key, iv []byte) ([]byte, error) {
|
||||||
|
//创建加密算法实例
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
//创建加密客户端实例
|
||||||
|
blockMode := cipher.NewCBCDecrypter(block, iv)
|
||||||
|
origData := make([]byte, len(cypted))
|
||||||
|
//这个函数也可以用来解密
|
||||||
|
blockMode.CryptBlocks(origData, cypted)
|
||||||
|
//去除填充字符串
|
||||||
|
origData, err = pKCS7UnPadding(origData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return origData, err
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package security
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"math/rand"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const passwordLength = 256
|
||||||
|
|
||||||
|
type password [passwordLength]byte
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// 更新随机种子,防止生成一样的随机密码
|
||||||
|
rand.Seed(time.Now().Unix())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 采用base64编码把密码转换为字符串
|
||||||
|
func (password *password) String() string {
|
||||||
|
return base64.StdEncoding.EncodeToString(password[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseLittlePassword 解析采用base64编码的字符串获取密码
|
||||||
|
func ParseLittlePassword(passwordString string) (*password, error) {
|
||||||
|
bs, err := base64.StdEncoding.DecodeString(strings.TrimSpace(passwordString))
|
||||||
|
if err != nil || len(bs) != passwordLength {
|
||||||
|
return nil, errors.New("不合法的密码")
|
||||||
|
}
|
||||||
|
password := password{}
|
||||||
|
copy(password[:], bs)
|
||||||
|
//bs = nil
|
||||||
|
return &password, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandLittlePassword 产生 256个byte随机组合的 密码,最后会使用base64编码为字符串存储在配置文件中
|
||||||
|
// 不能出现任何一个重复的byte位,必须又 0-255 组成,并且都需要包含
|
||||||
|
func RandLittlePassword() string {
|
||||||
|
// 随机生成一个由 0~255 组成的 byte 数组
|
||||||
|
intArr := rand.Perm(passwordLength)
|
||||||
|
password := &password{}
|
||||||
|
for i, v := range intArr {
|
||||||
|
password[i] = byte(v)
|
||||||
|
if i == v {
|
||||||
|
// 确保不会出现如何一个byte位出现重复
|
||||||
|
return RandLittlePassword()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return password.String()
|
||||||
|
}
|
|
@ -0,0 +1,257 @@
|
||||||
|
package hpds_net_framework
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"git.hpds.cc/Component/logging"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"runtime/debug"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TCPConn is warped tcp conn for luck
|
||||||
|
type TCPConn struct {
|
||||||
|
sync.RWMutex
|
||||||
|
uuid string
|
||||||
|
net.Conn
|
||||||
|
// 缓写队列
|
||||||
|
writeQueue chan []byte
|
||||||
|
// 逻辑消息队列
|
||||||
|
logicQueue chan []byte
|
||||||
|
// 消息处理器
|
||||||
|
processor Processor
|
||||||
|
userData interface{}
|
||||||
|
node INode
|
||||||
|
// after close
|
||||||
|
closeCb func()
|
||||||
|
closeFlag int64
|
||||||
|
logger *logging.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// KCPConn 可靠的UDP,like TCP
|
||||||
|
type KCPConn struct {
|
||||||
|
*TCPConn
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewKcpConn get new kcp conn
|
||||||
|
func NewKcpConn(conn net.Conn, processor Processor, logger *logging.Logger) *KCPConn {
|
||||||
|
tcpConn := NewTcpConn(conn, processor, logger)
|
||||||
|
if tcpConn != nil {
|
||||||
|
return &KCPConn{tcpConn}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTcpConn return new tcp conn
|
||||||
|
func NewTcpConn(conn net.Conn, processor Processor, logger *logging.Logger) *TCPConn {
|
||||||
|
if processor == nil || conn == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
tc := &TCPConn{
|
||||||
|
uuid: uuid.New().String(),
|
||||||
|
Conn: conn,
|
||||||
|
writeQueue: make(chan []byte, Cfg.ConnWriteQueueSize),
|
||||||
|
processor: processor,
|
||||||
|
// 单个缓存100个为处理的包
|
||||||
|
logicQueue: make(chan []byte, Cfg.ConnUndoQueueSize),
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
// write q
|
||||||
|
go func() {
|
||||||
|
for pkg := range tc.writeQueue {
|
||||||
|
if pkg == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if Cfg.ConnWriteTimeout > 0 {
|
||||||
|
_ = tc.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(Cfg.ConnWriteTimeout)))
|
||||||
|
}
|
||||||
|
_, err := tc.Write(pkg)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("tcp write", zap.Error(err))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
_ = tc.SetWriteDeadline(time.Time{})
|
||||||
|
}
|
||||||
|
// write over or error
|
||||||
|
_ = tc.Close()
|
||||||
|
logger.Info("Conn Close",
|
||||||
|
zap.String("local address", tc.Conn.LocalAddr().String()),
|
||||||
|
zap.String("remote address", tc.Conn.RemoteAddr().String()),
|
||||||
|
)
|
||||||
|
}()
|
||||||
|
// logic q
|
||||||
|
go func() {
|
||||||
|
for pkg := range tc.logicQueue {
|
||||||
|
// logic over
|
||||||
|
if pkg == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// processor handle the package
|
||||||
|
func() {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
logger.Error("processor panic",
|
||||||
|
zap.Any("panic", r),
|
||||||
|
zap.ByteString("stack", debug.Stack()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
_ = tc.processor.OnReceivedPackage(tc, pkg)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return tc
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUuid get uuid of conn
|
||||||
|
func (tc *TCPConn) GetUuid() string {
|
||||||
|
return tc.uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadMsg read | write end -> write | read end -> conn end
|
||||||
|
func (tc *TCPConn) ReadMsg() {
|
||||||
|
defer func() {
|
||||||
|
tc.logicQueue <- nil
|
||||||
|
tc.writeQueue <- nil
|
||||||
|
// force close conn
|
||||||
|
if !tc.IsClosed() {
|
||||||
|
_ = tc.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
bf := make([]byte, Cfg.MaxDataPackageSize)
|
||||||
|
// 第一个包默认5秒
|
||||||
|
timeout := time.Second * time.Duration(Cfg.FirstPackageTimeout)
|
||||||
|
for {
|
||||||
|
_ = tc.SetReadDeadline(time.Now().Add(timeout))
|
||||||
|
// read length
|
||||||
|
_, err := io.ReadAtLeast(tc, bf[:2], 2)
|
||||||
|
if err != nil {
|
||||||
|
tc.logger.Error("TCPConn read message head",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var ln uint16
|
||||||
|
if tc.processor.GetBigEndian() {
|
||||||
|
ln = binary.BigEndian.Uint16(bf[:2])
|
||||||
|
} else {
|
||||||
|
ln = binary.LittleEndian.Uint16(bf[:2])
|
||||||
|
}
|
||||||
|
if ln < 1 || int(ln) > Cfg.MaxDataPackageSize {
|
||||||
|
tc.logger.Error("TCPConn message length invalid",
|
||||||
|
zap.Uint16("length", ln),
|
||||||
|
zap.Error(fmt.Errorf("TCPConn message length invalid")),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// read data
|
||||||
|
_, err = io.ReadFull(tc, bf[:ln])
|
||||||
|
if err != nil {
|
||||||
|
tc.logger.Error("TCPConn read data",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// clean
|
||||||
|
_ = tc.SetDeadline(time.Time{})
|
||||||
|
// write to cache queue
|
||||||
|
select {
|
||||||
|
case tc.logicQueue <- append(make([]byte, 0), bf[:ln]...):
|
||||||
|
default:
|
||||||
|
// ignore overflow package not close conn
|
||||||
|
tc.logger.Error("TCPConn logic queue overflow",
|
||||||
|
zap.String("local address", tc.LocalAddr().String()),
|
||||||
|
zap.String("remote address", tc.RemoteAddr().String()),
|
||||||
|
zap.Int("queue length", len(tc.logicQueue)),
|
||||||
|
zap.Error(fmt.Errorf("TCPConn logic queue overflow")),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// after first pack | check heartbeat
|
||||||
|
timeout = time.Second * time.Duration(Cfg.ConnReadTimeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteMsg warp msg base on connection's processor
|
||||||
|
func (tc *TCPConn) WriteMsg(message interface{}) {
|
||||||
|
pkg, err := tc.processor.WrapMsg(message)
|
||||||
|
if err != nil {
|
||||||
|
tc.logger.Error("OnWrapMsg package",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
push:
|
||||||
|
select {
|
||||||
|
case tc.writeQueue <- pkg:
|
||||||
|
default:
|
||||||
|
if tc.IsClosed() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 50)
|
||||||
|
// re push
|
||||||
|
goto push
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the connection
|
||||||
|
func (tc *TCPConn) Close() error {
|
||||||
|
tc.Lock()
|
||||||
|
defer func() {
|
||||||
|
tc.Unlock()
|
||||||
|
// add close flag
|
||||||
|
atomic.AddInt64(&tc.closeFlag, 1)
|
||||||
|
if tc.closeCb != nil {
|
||||||
|
tc.closeCb()
|
||||||
|
}
|
||||||
|
// clean write q if not empty
|
||||||
|
for len(tc.writeQueue) > 0 {
|
||||||
|
<-tc.writeQueue
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return tc.Conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsClosed return the status of conn
|
||||||
|
func (tc *TCPConn) IsClosed() bool {
|
||||||
|
return atomic.LoadInt64(&tc.closeFlag) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterClose conn call back
|
||||||
|
func (tc *TCPConn) AfterClose(cb func()) {
|
||||||
|
tc.Lock()
|
||||||
|
defer tc.Unlock()
|
||||||
|
tc.closeCb = cb
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetData for conn
|
||||||
|
func (tc *TCPConn) SetData(data interface{}) {
|
||||||
|
tc.Lock()
|
||||||
|
defer tc.Unlock()
|
||||||
|
tc.userData = data
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetData from conn
|
||||||
|
func (tc *TCPConn) GetData() interface{} {
|
||||||
|
tc.RLock()
|
||||||
|
defer tc.RUnlock()
|
||||||
|
return tc.userData
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNode for conn
|
||||||
|
func (tc *TCPConn) SetNode(node INode) {
|
||||||
|
tc.Lock()
|
||||||
|
defer tc.Unlock()
|
||||||
|
tc.node = node
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNode from conn
|
||||||
|
func (tc *TCPConn) GetNode() INode {
|
||||||
|
tc.RLock()
|
||||||
|
defer tc.RUnlock()
|
||||||
|
return tc.node
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package hpds_net_framework
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"net"
|
||||||
|
"runtime/debug"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"git.hpds.cc/Component/logging"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tcpServer struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
addr string
|
||||||
|
ln net.Listener
|
||||||
|
processor Processor
|
||||||
|
logger *logging.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTcpServer return new tcpServer
|
||||||
|
func NewTcpServer(addr string, processor Processor, logger *logging.Logger) (s *tcpServer, err error) {
|
||||||
|
ts := new(tcpServer)
|
||||||
|
ts.addr = addr
|
||||||
|
ts.ln, err = net.Listen("tcp", addr)
|
||||||
|
if processor == nil {
|
||||||
|
panic("processor must be set.")
|
||||||
|
}
|
||||||
|
ts.processor = processor
|
||||||
|
ts.logger = logger
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ts, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the server
|
||||||
|
func (s *tcpServer) Run() error {
|
||||||
|
s.logger.Info("Starting tcp server", zap.String("address", s.addr))
|
||||||
|
for {
|
||||||
|
conn, err := s.ln.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go s.Handle(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle goroutine handle connection
|
||||||
|
func (s *tcpServer) Handle(conn net.Conn) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
s.logger.Error("TCP handle panic", zap.Any("PANIC", r),
|
||||||
|
zap.ByteString("stack", debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
var ic IConnection
|
||||||
|
ic = NewTcpConn(conn, s.processor, s.logger)
|
||||||
|
ic.ReadMsg()
|
||||||
|
}
|
Loading…
Reference in New Issue