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