コード例 #1
0
ファイル: protocol.go プロジェクト: sharewind/push-server
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]))
}
コード例 #2
0
ファイル: protocol.go プロジェクト: sharewind/push-server
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(&params[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
}
コード例 #3
0
ファイル: protocol.go プロジェクト: sharewind/push-server
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
}
コード例 #4
0
ファイル: protocol.go プロジェクト: sharewind/push-server
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
}
コード例 #5
0
ファイル: protocol.go プロジェクト: sharewind/push-server
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
}