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