func (p *protocol) Exec(client *client, params [][]byte) ([]byte, error) { switch { case bytes.Equal(params[0], []byte("H")): return p.HEARTBEAT(client, params) case bytes.Equal(params[0], []byte("FIN")): return p.FIN(client, params) // case bytes.Equal(params[0], []byte("RDY")): // return p.RDY(client, params) // case bytes.Equal(params[0], []byte("REQ")): // return p.REQ(client, params) case bytes.Equal(params[0], []byte("PUB")): return p.PUB(client, params) // case bytes.Equal(params[0], []byte("MPUB")): // return p.MPUB(client, params) case bytes.Equal(params[0], []byte("NOP")): return p.NOP(client, params) // case bytes.Equal(params[0], []byte("TOUCH")): // return p.TOUCH(client, params) case bytes.Equal(params[0], []byte("IDENTIFY")): return p.IDENTIFY(client, params) case bytes.Equal(params[0], []byte("SUB")): return p.SUB(client, params) case bytes.Equal(params[0], []byte("CLS")): return p.CLS(client, params) } return nil, util.NewFatalClientErr(nil, "E_INVALID", fmt.Sprintf("invalid command %s", params[0])) }
func (p *protocol) FIN(client *client, params [][]byte) ([]byte, error) { state := atomic.LoadInt32(&client.State) if state != StateSubscribed && state != StateClosing { return nil, util.NewFatalClientErr(nil, "E_INVALID", "cannot FIN in current state") } if len(params) < 2 { return nil, util.NewFatalClientErr(nil, "E_INVALID", "FIN insufficient number of params") } // id := *(*MessageID)(unsafe.Pointer(¶ms[1][0])) // err := client.Channel.FinishMessage(client.ID, id) // if err != nil { // return nil, util.NewClientErr(err, "E_FIN_FAILED", // fmt.Sprintf("FIN %s failed %s", id, err.Error())) // } // client.FinishedMessage() return nil, nil }
func (p *protocol) PUB(client *client, params [][]byte) ([]byte, error) { // var err error var buf bytes.Buffer if client.Role != "$_@push_sign_$_kz_worker" { return nil, util.NewFatalClientErr(nil, "E_INVALID_REQUEST", "client can't pub message") } if len(params) < 3 { return nil, util.NewFatalClientErr(nil, "E_INVALID", "PUB insufficient number of parameters") } log.Printf("receive params on sub %s", params) bodyLen, err := readLen(client.Reader, client.lenSlice) if err != nil { return nil, util.NewFatalClientErr(err, "E_BAD_BODY", "IDENTIFY failed to read body size") } if int64(bodyLen) > p.context.broker.options.MaxBodySize { return nil, util.NewFatalClientErr(nil, "E_BAD_BODY", fmt.Sprintf("IDENTIFY body too big %d > %d", bodyLen, p.context.broker.options.MaxBodySize)) } body := make([]byte, bodyLen) _, err = io.ReadFull(client.Reader, body) if err != nil { return nil, util.NewFatalClientErr(err, "E_BAD_BODY", "IDENTIFY failed to read body") } client_id := string(params[1]) channel_id := string(params[2]) message_id := string(params[3]) msgId, _ := strconv.ParseInt(message_id, 10, 64) log.Printf("msgId == %d", msgId) // TODO 另外启动一个channel 与 goroutine 用来处理这个消息 dstClient, err := p.context.broker.GetClient(client_id, channel_id) if err != nil || dstClient == nil { p.ackPublish(client, util.ACK_OFF, client_id, msgId) // model.SaveOfflineMessage(dstClient.ClientID, msgId) log.Printf("client %s is null", client_id) return nil, nil //return nil, util.NewFatalClientErr(nil, "E_INVALID", "PUB insufficient number of parameters") // return FrameTypeACKError message_id } log.Printf("get client %s by channel %s = %s ", client_id, channel_id, dstClient) msg := &Message{ Id: util.Guid(msgId).Hex(), Body: body, Timestamp: time.Now().UnixNano(), } log.Printf("msg is %#v", msg) // dstClient.SendingMessage() err = p.SendMessage(dstClient, msg, &buf) if err != nil { log.Printf("send message to client %s error %s", dstClient, err) } dstClient.Lock() err = dstClient.Flush() dstClient.Unlock() if err != nil { p.ackPublish(client, util.ACT_ERR, client_id, msgId) } else { p.ackPublish(client, util.ACK_SUCCESS, client_id, msgId) } return nil, nil }
func (p *protocol) SUB(client *client, params [][]byte) ([]byte, error) { if atomic.LoadInt32(&client.State) != StateInit { return nil, util.NewFatalClientErr(nil, "E_INVALID", "cannot SUB in current state") } if client.HeartbeatInterval <= 0 { return nil, util.NewFatalClientErr(nil, "E_INVALID", "cannot SUB with heartbeats disabled") } log.Printf("receive params on sub %s", params) if len(params) < 1 { return nil, util.NewFatalClientErr(nil, "E_INVALID", "SUB insufficient number of parameters") } //TODO FIXME str_channel_id := string(params[1]) channel_id, err := strconv.ParseInt(str_channel_id, 10, 64) //TODO need validate channel_id if err != nil { return nil, util.NewFatalClientErr(nil, "E_INVALID", "invalid channel id ") } client_id, err := strconv.ParseInt(client.ClientID, 10, 64) if err != nil { log.Printf("invalid client id [%s] err: %s", client.ClientID, err) return nil, util.NewFatalClientErr(nil, "E_INVALID", "invalid client id ") } channel, err := model.FindChannelByID(channel_id) if err != nil || channel == nil { return nil, util.NewFatalClientErr(nil, "E_INVALID", "invalid channel id ") } device, err := model.FindDeviceByID(client_id) if err != nil || device == nil { log.Printf("invalid client id [%d] err: %s", client_id, err) return nil, util.NewFatalClientErr(nil, "E_INVALID", "invalid client id ") } //TODO send subscribe event sub := &model.Subscribe{ ChannelID: channel_id, DeviceID: client_id, DeviceType: device.DeviceType, CreatedAt: time.Now().UnixNano(), UpdatedAt: time.Now().UnixNano(), } err = model.SaveOrUpdateSubscribe(sub) if err != nil { return nil, util.NewFatalClientErr(nil, "internal error", "save subscribe error") } p.context.broker.AddClient(client.ClientID, str_channel_id, client) log.Printf("INFO: clientId %d sub channel %s success ", client.ClientID, channel_id) // touch devie online model.TouchDeviceOnline(client_id) // should send client connected eventsf log.Printf("INFO: SetClientConn clientID=%s, broker_addr=%s", client.ClientID, client.LocalAddr().String()) err = model.SetClientConn(client.ClientID, client.LocalAddr().String()) if err != nil { return nil, util.NewFatalClientErr(nil, "internal error", "save subscribe error") } // increase channel sub count // add client to channel sub list // topic := p.context.broker.GetTopic(topicName) // channel := topic.GetChannel(channelName) // channel.AddClient(client.ID, client) atomic.StoreInt32(&client.State, StateSubscribed) client.SubChannel = str_channel_id go p.checkOfflineMessage(client) // client.Channel = channel // update message pump // client.SubEventChan <- channel return okBytes, nil }
func (p *protocol) IDENTIFY(client *client, params [][]byte) ([]byte, error) { var err error if atomic.LoadInt32(&client.State) != StateInit { return nil, util.NewFatalClientErr(nil, "E_INVALID", "cannot IDENTIFY in current state") } bodyLen, err := readLen(client.Reader, client.lenSlice) if err != nil { return nil, util.NewFatalClientErr(err, "E_BAD_BODY", "IDENTIFY failed to read body size") } if int64(bodyLen) > p.context.broker.options.MaxBodySize { return nil, util.NewFatalClientErr(nil, "E_BAD_BODY", fmt.Sprintf("IDENTIFY body too big %d > %d", bodyLen, p.context.broker.options.MaxBodySize)) } body := make([]byte, bodyLen) _, err = io.ReadFull(client.Reader, body) if err != nil { return nil, util.NewFatalClientErr(err, "E_BAD_BODY", "IDENTIFY failed to read body") } // body is a json structure with producer information var identifyData identifyDataV2 err = json.Unmarshal(body, &identifyData) if err != nil { return nil, util.NewFatalClientErr(err, "E_BAD_BODY", "IDENTIFY failed to decode JSON body") } if p.context.broker.options.Verbose { log.Printf("PROTOCOL(V2): [%s] %+v", client, identifyData) } err = client.Identify(identifyData) if err != nil { return nil, util.NewFatalClientErr(err, "E_BAD_BODY", "IDENTIFY "+err.Error()) } // bail out early if we're not negotiating features if !identifyData.FeatureNegotiation { return okBytes, nil } tlsv1 := p.context.broker.tlsConfig != nil && identifyData.TLSv1 deflate := p.context.broker.options.DeflateEnabled && identifyData.Deflate deflateLevel := 0 if deflate { if identifyData.DeflateLevel <= 0 { deflateLevel = 6 } deflateLevel = int(math.Min(float64(deflateLevel), float64(p.context.broker.options.MaxDeflateLevel))) } snappy := p.context.broker.options.SnappyEnabled && identifyData.Snappy if deflate && snappy { return nil, util.NewFatalClientErr(nil, "E_IDENTIFY_FAILED", "cannot enable both deflate and snappy compression") } resp, err := json.Marshal(struct { // MaxRdyCount int64 `json:"max_rdy_count"` Version string `json:"version"` MaxMsgTimeout int64 `json:"max_msg_timeout"` MsgTimeout int64 `json:"msg_timeout"` TLSv1 bool `json:"tls_v1"` Deflate bool `json:"deflate"` DeflateLevel int `json:"deflate_level"` MaxDeflateLevel int `json:"max_deflate_level"` Snappy bool `json:"snappy"` SampleRate int32 `json:"sample_rate"` }{ // MaxRdyCount: p.context.broker.options.MaxRdyCount, Version: util.BINARY_VERSION, MaxMsgTimeout: int64(p.context.broker.options.MaxMsgTimeout / time.Millisecond), MsgTimeout: int64(p.context.broker.options.MsgTimeout / time.Millisecond), TLSv1: tlsv1, Deflate: deflate, DeflateLevel: deflateLevel, MaxDeflateLevel: p.context.broker.options.MaxDeflateLevel, Snappy: snappy, SampleRate: client.SampleRate, }) if err != nil { return nil, util.NewFatalClientErr(err, "E_IDENTIFY_FAILED", "IDENTIFY failed "+err.Error()) } err = p.Send(client, util.FrameTypeResponse, resp) if err != nil { return nil, util.NewFatalClientErr(err, "E_IDENTIFY_FAILED", "IDENTIFY failed "+err.Error()) } if tlsv1 { log.Printf("PROTOCOL(V2): [%s] upgrading connection to TLS", client) err = client.UpgradeTLS() if err != nil { return nil, util.NewFatalClientErr(err, "E_IDENTIFY_FAILED", "IDENTIFY failed "+err.Error()) } err = p.Send(client, util.FrameTypeResponse, okBytes) if err != nil { return nil, util.NewFatalClientErr(err, "E_IDENTIFY_FAILED", "IDENTIFY failed "+err.Error()) } } if snappy { log.Printf("PROTOCOL(V2): [%s] upgrading connection to snappy", client) err = client.UpgradeSnappy() if err != nil { return nil, util.NewFatalClientErr(err, "E_IDENTIFY_FAILED", "IDENTIFY failed "+err.Error()) } err = p.Send(client, util.FrameTypeResponse, okBytes) if err != nil { return nil, util.NewFatalClientErr(err, "E_IDENTIFY_FAILED", "IDENTIFY failed "+err.Error()) } } if deflate { log.Printf("PROTOCOL(V2): [%s] upgrading connection to deflate", client) err = client.UpgradeDeflate(deflateLevel) if err != nil { return nil, util.NewFatalClientErr(err, "E_IDENTIFY_FAILED", "IDENTIFY failed "+err.Error()) } err = p.Send(client, util.FrameTypeResponse, okBytes) if err != nil { return nil, util.NewFatalClientErr(err, "E_IDENTIFY_FAILED", "IDENTIFY failed "+err.Error()) } } return nil, nil }