package protocol import ( "encoding/json" "fmt" "git.noahlan.cn/noahlan/nnet/core" "git.noahlan.cn/noahlan/nnet/entity" "git.noahlan.cn/noahlan/ntools-go/core/nlog" "time" ) type ( handshakeData struct { Version string `json:"version"` // 客户端版本号,服务器以此判断是否合适与客户端通信 Type string `json:"type"` // 客户端类型,与客户端版本号一起来确定客户端是否合适 // 透传信息 Payload interface{} `json:"payload,optional,omitempty"` } handshakeAckData struct { Heartbeat int64 `json:"heartbeat"` // 心跳间隔,单位秒 0表示不需要心跳 // 路由 Routes map[string]uint16 `json:"routes"` // route map to code Codes map[uint16]string `json:"codes"` // code map to route // 服务端支持的body部分消息传输协议 //Protocol string `json:"protocol,options=[plain,json,protobuf]"` // plain/json/protobuf // 透传信息 Payload interface{} `json:"payload,optional,omitempty"` } ) func WithNNetPipeline(heartbeatInterval time.Duration, handshakeValidator func([]byte) error) core.RunOption { handshakeAck := &handshakeAckData{} data, err := json.Marshal(handshakeAck) nlog.Must(err) packer := NewNNetPacker() hrd, _ := packer.Pack(Handshake, data) return func(server *core.Server) { server.Pipeline().Inbound().PushFront(func(entity entity.NetworkEntity, v interface{}) error { pkg, ok := v.(*NNetPacket) if !ok { return ErrWrongPacketType } conn, _ := entity.Conn() switch pkg.PacketType { case Handshake: if err := handshakeValidator(pkg.Data); err != nil { return err } if err := entity.SendBytes(hrd); err != nil { return err } entity.SetStatus(core.StatusPrepare) nlog.Debugf("connection handshake Id=%d, Remote=%s", entity.Session().ID(), conn.RemoteAddr()) case HandshakeAck: entity.SetStatus(core.StatusPending) nlog.Debugf("receive handshake ACK Id=%d, Remote=%s", entity.Session().ID(), conn.RemoteAddr()) case Heartbeat: // Expected case Data: if entity.Status() < core.StatusPending { return errors.New(fmt.Sprintf("receive data on socket which not yet ACK, session will be closed immediately, remote=%s", conn.RemoteAddr())) } entity.SetStatus(core.StatusWorking) var lastMid uint64 switch pkg.MsgType { case Request: lastMid = pkg.ID case Notify: lastMid = 0 default: return fmt.Errorf("Invalid message type: %s ", pkg.MsgType.String()) } entity.SetLastMID(lastMid) } return nil }) } }