diff --git a/eventmesh-sdk-go/README.md b/eventmesh-sdk-go/README.md new file mode 100644 index 0000000000..efdb1cef74 --- /dev/null +++ b/eventmesh-sdk-go/README.md @@ -0,0 +1,6 @@ +EventMesh Go SDK +--- +support api +1. gRPC +2. HTTP +3. TCP \ No newline at end of file diff --git a/eventmesh-sdk-go/common/constants.go b/eventmesh-sdk-go/common/constants.go new file mode 100644 index 0000000000..b4f8449b61 --- /dev/null +++ b/eventmesh-sdk-go/common/constants.go @@ -0,0 +1,48 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package common + +var Constants = struct { + LANGUAGE_GO string + HTTP_PROTOCOL_PREFIX string + HTTPS_PROTOCOL_PREFIX string + PROTOCOL_TYPE string + PROTOCOL_VERSION string + PROTOCOL_DESC string + DEFAULT_HTTP_TIME_OUT int64 + EVENTMESH_MESSAGE_CONST_TTL string + + // Client heartbeat interval + HEARTBEAT int64 + + // Protocol type + CLOUD_EVENTS_PROTOCOL_NAME string + EM_MESSAGE_PROTOCOL_NAME string + OPEN_MESSAGE_PROTOCOL_NAME string +}{ + LANGUAGE_GO: "GO", + HTTP_PROTOCOL_PREFIX: "http://", + HTTPS_PROTOCOL_PREFIX: "https://", + PROTOCOL_TYPE: "protocoltype", + PROTOCOL_VERSION: "protocolversion", + PROTOCOL_DESC: "protocoldesc", + DEFAULT_HTTP_TIME_OUT: 15000, + EVENTMESH_MESSAGE_CONST_TTL: "ttl", + HEARTBEAT: 30 * 1000, + CLOUD_EVENTS_PROTOCOL_NAME: "cloudevents", + EM_MESSAGE_PROTOCOL_NAME: "eventmeshmessage", + OPEN_MESSAGE_PROTOCOL_NAME: "openmessage", +} diff --git a/eventmesh-sdk-go/common/id/api.go b/eventmesh-sdk-go/common/id/api.go new file mode 100644 index 0000000000..379b5457c5 --- /dev/null +++ b/eventmesh-sdk-go/common/id/api.go @@ -0,0 +1,22 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package id + +// Interface api to generate uniq id +type Interface interface { + // Next create uniq ID + Next() string +} diff --git a/eventmesh-sdk-go/common/id/id_snake.go b/eventmesh-sdk-go/common/id/id_snake.go new file mode 100644 index 0000000000..675669a55e --- /dev/null +++ b/eventmesh-sdk-go/common/id/id_snake.go @@ -0,0 +1,79 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package id + +import ( + "bytes" + "fmt" + "net" + "strconv" + "strings" + + "github.com/sony/sonyflake" +) + +// flake generate uid by flake +type flake struct { + sf *sonyflake.Sonyflake +} + +func NewFlake() Interface { + macAddr := getMacAddr() + st := sonyflake.Settings{ + MachineID: func() (uint16, error) { + ma := strings.Split(macAddr, ":") + mid, err := strconv.ParseInt(ma[0]+ma[1], 16, 16) + return uint16(mid), err + }, + } + return &flake{ + sf: sonyflake.NewSonyflake(st), + } +} + +// getMacAddr return the current machine mac address +func getMacAddr() (addr string) { + interfaces, err := net.Interfaces() + if err == nil { + for _, i := range interfaces { + if i.Flags&net.FlagUp != 0 && bytes.Compare(i.HardwareAddr, nil) != 0 { + // Don't use random as we have a real address + addr = i.HardwareAddr.String() + break + } + } + } + return +} + +// Nextv generates next id as an uint64 +func (f *flake) Nextv() (id uint64, err error) { + var i uint64 + if f.sf != nil { + i, err = f.sf.NextID() + if err == nil { + id = i + } + } + return +} + +// Next generates next id as a string +func (f *flake) Next() string { + var i uint64 + i, _ = f.Nextv() + return fmt.Sprintf("%d", i) +} diff --git a/eventmesh-sdk-go/common/id/id_uuid.go b/eventmesh-sdk-go/common/id/id_uuid.go new file mode 100644 index 0000000000..fb1c36a5ef --- /dev/null +++ b/eventmesh-sdk-go/common/id/id_uuid.go @@ -0,0 +1,34 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package id + +import ( + "github.com/google/uuid" + "strings" +) + +// UUID generate id by uuid +type UUID struct { +} + +// NewUUID uuid instance +func NewUUID() Interface { + return &UUID{} +} + +func (u *UUID) Next() string { + return strings.ReplaceAll(uuid.New().String(), "-", "") +} diff --git a/eventmesh-sdk-go/common/protocol/http/body/body.go b/eventmesh-sdk-go/common/protocol/http/body/body.go new file mode 100644 index 0000000000..f7053ffdf5 --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/http/body/body.go @@ -0,0 +1,24 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package body + +type Body struct { + ToMap map[string]interface{} +} + +func (b *Body) BuildBody(requestCode string, originalMap map[string]interface{}) *Body { + return nil +} diff --git a/eventmesh-sdk-go/common/protocol/http/body/client/heartbeat_request_body.go b/eventmesh-sdk-go/common/protocol/http/body/client/heartbeat_request_body.go new file mode 100644 index 0000000000..e7ebe973b7 --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/http/body/client/heartbeat_request_body.go @@ -0,0 +1,72 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package client + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/http/body" +) + +var HeartbeatRequestBodyKey = struct { + CLIENTTYPE string + CONSUMERGROUP string + HEARTBEATENTITIES string +}{ + CLIENTTYPE: "clientType", + HEARTBEATENTITIES: "heartbeatEntities", + CONSUMERGROUP: "consumerGroup", +} + +type HeartbeatEntity struct { + Topic string `json:"topic"` + Url string `json:"url"` + ServiceId string `json:"serviceId"` + InstanceId string `json:"instanceId"` +} + +type HeartbeatRequestBody struct { + body.Body + consumerGroup string + clientType string + heartbeatEntities string +} + +func (h *HeartbeatRequestBody) ConsumerGroup() string { + return h.consumerGroup +} + +func (h *HeartbeatRequestBody) SetConsumerGroup(consumerGroup string) { + h.consumerGroup = consumerGroup +} + +func (h *HeartbeatRequestBody) ClientType() string { + return h.clientType +} + +func (h *HeartbeatRequestBody) SetClientType(clientType string) { + h.clientType = clientType +} + +func (h *HeartbeatRequestBody) HeartbeatEntities() string { + return h.heartbeatEntities +} + +func (h *HeartbeatRequestBody) SetHeartbeatEntities(heartbeatEntities string) { + h.heartbeatEntities = heartbeatEntities +} + +func (h *HeartbeatRequestBody) BuildBody(bodyParam map[string]interface{}) *HeartbeatRequestBody { + return nil +} diff --git a/eventmesh-sdk-go/common/protocol/http/body/client/subscribe_request_body.go b/eventmesh-sdk-go/common/protocol/http/body/client/subscribe_request_body.go new file mode 100644 index 0000000000..78dc39cccc --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/http/body/client/subscribe_request_body.go @@ -0,0 +1,38 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package client + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/http/body" +) + +var SubscribeRequestBodyKey = struct { + TOPIC string + URL string + CONSUMERGROUP string +}{ + TOPIC: "topic", + URL: "url", + CONSUMERGROUP: "consumerGroup", +} + +type SubscribeRequestBody struct { + body.Body + topics []protocol.SubscriptionItem + url string + consumerGroup string +} diff --git a/eventmesh-sdk-go/common/protocol/http/common/client_type.go b/eventmesh-sdk-go/common/protocol/http/common/client_type.go new file mode 100644 index 0000000000..28e8d05784 --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/http/common/client_type.go @@ -0,0 +1,35 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package common + +type ClientType struct { + Type int `json:"type"` + Desc string `json:"desc"` +} + +var DefaultClientType = struct { + PUB ClientType + SUB ClientType +}{ + PUB: ClientType{ + Type: 1, + Desc: "Client for publishing", + }, + SUB: ClientType{ + Type: 2, + Desc: "Client for subscribing", + }, +} diff --git a/eventmesh-sdk-go/common/protocol/http/common/eventmesh_ret_code.go b/eventmesh-sdk-go/common/protocol/http/common/eventmesh_ret_code.go new file mode 100644 index 0000000000..55358cb7d9 --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/http/common/eventmesh_ret_code.go @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package common + +type EventMeshRetCode struct { + RetCode int `json:"retCode"` + ErrMsg string `json:"errMsg"` +} + +var DefaultEventMeshRetCode = struct { + SUCCESS EventMeshRetCode +}{ + SUCCESS: EventMeshRetCode{RetCode: 0, ErrMsg: "success"}, +} diff --git a/eventmesh-sdk-go/common/protocol/http/common/protocol_key.go b/eventmesh-sdk-go/common/protocol/http/common/protocol_key.go new file mode 100644 index 0000000000..11337ccc0d --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/http/common/protocol_key.go @@ -0,0 +1,85 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package common + +type ClientInstanceKey struct { + //Protocol layer requester description + ENV string + IDC string + SYS string + PID string + IP string + USERNAME string + PASSWORD string + BIZSEQNO string + UNIQUEID string +} + +type EventMeshInstanceKey struct { + //Protocol layer EventMesh description + EVENTMESHCLUSTER string + EVENTMESHIP string + EVENTMESHENV string + EVENTMESHIDC string +} + +var ProtocolKey = struct { + REQUEST_CODE string + LANGUAGE string + VERSION string + PROTOCOL_TYPE string + PROTOCOL_VERSION string + PROTOCOL_DESC string + + ClientInstanceKey ClientInstanceKey + + EventMeshInstanceKey EventMeshInstanceKey + + //return of CLIENT <-> EventMesh + RETCODE string + RETMSG string + RESTIME string +}{ + REQUEST_CODE: "code", + LANGUAGE: "language", + VERSION: "version", + PROTOCOL_TYPE: "protocoltype", + PROTOCOL_VERSION: "protocolversion", + PROTOCOL_DESC: "protocoldesc", + + ClientInstanceKey: ClientInstanceKey{ + ENV: "env", + IDC: "idc", + SYS: "sys", + PID: "pid", + IP: "ip", + USERNAME: "username", + PASSWORD: "passwd", + BIZSEQNO: "bizseqno", + UNIQUEID: "uniqueid", + }, + + EventMeshInstanceKey: EventMeshInstanceKey{ + EVENTMESHCLUSTER: "eventmeshcluster", + EVENTMESHIP: "eventmeship", + EVENTMESHENV: "eventmeshenv", + EVENTMESHIDC: "eventmeshidc", + }, + + RETCODE: "retCode", + RETMSG: "retMsg", + RESTIME: "resTime", +} diff --git a/eventmesh-sdk-go/common/protocol/http/common/protocol_version.go b/eventmesh-sdk-go/common/protocol/http/common/protocol_version.go new file mode 100644 index 0000000000..bdf774686a --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/http/common/protocol_version.go @@ -0,0 +1,40 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package common + +type ProtocolVersion struct { + version string +} + +func (p *ProtocolVersion) Version() string { + return p.version +} + +func (p *ProtocolVersion) SetVersion(version string) { + p.version = version +} + +var DefaultProtocolVersion = struct { + V1 ProtocolVersion + V2 ProtocolVersion +}{ + V1: ProtocolVersion{ + version: "1.0", + }, + V2: ProtocolVersion{ + version: "2.0", + }, +} diff --git a/eventmesh-sdk-go/common/protocol/http/common/request_code.go b/eventmesh-sdk-go/common/protocol/http/common/request_code.go new file mode 100644 index 0000000000..38407f19f0 --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/http/common/request_code.go @@ -0,0 +1,95 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package common + +type RequestCode struct { + RequestCode int `json:"requestCode"` + Desc string `json:"desc"` +} + +var DefaultRequestCode = struct { + MSG_BATCH_SEND RequestCode + MSG_BATCH_SEND_V2 RequestCode + MSG_SEND_SYNC RequestCode + MSG_SEND_ASYNC RequestCode + HTTP_PUSH_CLIENT_ASYNC RequestCode + HTTP_PUSH_CLIENT_SYNC RequestCode + REGISTER RequestCode + UNREGISTER RequestCode + HEARTBEAT RequestCode + SUBSCRIBE RequestCode + UNSUBSCRIBE RequestCode + REPLY_MESSAGE RequestCode + ADMIN_METRICS RequestCode + ADMIN_SHUTDOWN RequestCode +}{ + MSG_BATCH_SEND: RequestCode{ + RequestCode: 102, + Desc: "SEND BATCH MSG", + }, + MSG_BATCH_SEND_V2: RequestCode{ + RequestCode: 107, + Desc: "SEND BATCH MSG V2", + }, + MSG_SEND_SYNC: RequestCode{ + RequestCode: 101, + Desc: "SEND SINGLE MSG SYNC", + }, + MSG_SEND_ASYNC: RequestCode{ + RequestCode: 104, + Desc: "SEND SINGLE MSG ASYNC", + }, + HTTP_PUSH_CLIENT_ASYNC: RequestCode{ + RequestCode: 105, + Desc: "PUSH CLIENT BY HTTP POST", + }, + HTTP_PUSH_CLIENT_SYNC: RequestCode{ + RequestCode: 106, + Desc: "PUSH CLIENT BY HTTP POST", + }, + REGISTER: RequestCode{ + RequestCode: 201, + Desc: "REGISTER", + }, + UNREGISTER: RequestCode{ + RequestCode: 202, + Desc: "UNREGISTER", + }, + HEARTBEAT: RequestCode{ + RequestCode: 203, + Desc: "HEARTBEAT", + }, + SUBSCRIBE: RequestCode{ + RequestCode: 206, + Desc: "SUBSCRIBE", + }, + UNSUBSCRIBE: RequestCode{ + RequestCode: 207, + Desc: "UNSUBSCRIBE", + }, + REPLY_MESSAGE: RequestCode{ + RequestCode: 301, + Desc: "REPLY MESSAGE", + }, + ADMIN_METRICS: RequestCode{ + RequestCode: 603, + Desc: "ADMIN METRICS", + }, + ADMIN_SHUTDOWN: RequestCode{ + RequestCode: 601, + Desc: "ADMIN SHUTDOWN", + }, +} diff --git a/eventmesh-sdk-go/common/protocol/http/message/send_message_request_body.go b/eventmesh-sdk-go/common/protocol/http/message/send_message_request_body.go new file mode 100644 index 0000000000..a74fdbeaa2 --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/http/message/send_message_request_body.go @@ -0,0 +1,111 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package message + +type SendMessageRequestBody struct { + topic string + bizSeqNo string + uniqueId string + ttl string + content string + tag string + extFields map[string]string + producerGroup string +} + +func (s *SendMessageRequestBody) Topic() string { + return s.topic +} + +func (s *SendMessageRequestBody) SetTopic(topic string) { + s.topic = topic +} + +func (s *SendMessageRequestBody) BizSeqNo() string { + return s.bizSeqNo +} + +func (s *SendMessageRequestBody) SetBizSeqNo(bizSeqNo string) { + s.bizSeqNo = bizSeqNo +} + +func (s *SendMessageRequestBody) UniqueId() string { + return s.uniqueId +} + +func (s *SendMessageRequestBody) SetUniqueId(uniqueId string) { + s.uniqueId = uniqueId +} + +func (s *SendMessageRequestBody) Ttl() string { + return s.ttl +} + +func (s *SendMessageRequestBody) SetTtl(ttl string) { + s.ttl = ttl +} + +func (s *SendMessageRequestBody) Content() string { + return s.content +} + +func (s *SendMessageRequestBody) SetContent(content string) { + s.content = content +} + +func (s *SendMessageRequestBody) Tag() string { + return s.tag +} + +func (s *SendMessageRequestBody) SetTag(tag string) { + s.tag = tag +} + +func (s *SendMessageRequestBody) ExtFields() map[string]string { + return s.extFields +} + +func (s *SendMessageRequestBody) SetExtFields(extFields map[string]string) { + s.extFields = extFields +} + +func (s *SendMessageRequestBody) ProducerGroup() string { + return s.producerGroup +} + +func (s *SendMessageRequestBody) SetProducerGroup(producerGroup string) { + s.producerGroup = producerGroup +} + +var SendMessageRequestBodyKey = struct { + TOPIC string + BIZSEQNO string + UNIQUEID string + CONTENT string + TTL string + TAG string + EXTFIELDS string + PRODUCERGROUP string +}{ + TOPIC: "topic", + BIZSEQNO: "bizseqno", + UNIQUEID: "uniqueid", + CONTENT: "content", + TTL: "ttl", + TAG: "tag", + EXTFIELDS: "extFields", + PRODUCERGROUP: "producergroup", +} diff --git a/eventmesh-sdk-go/common/protocol/message_type.go b/eventmesh-sdk-go/common/protocol/message_type.go new file mode 100644 index 0000000000..590d189878 --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/message_type.go @@ -0,0 +1,28 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package protocol + +type MessageType string + +var DefaultMessageType = struct { + CloudEvent MessageType + OpenMessage MessageType + EventMeshMessage MessageType +}{ + CloudEvent: "CloudEvent", + OpenMessage: "OpenMessage", + EventMeshMessage: "EventMeshMessage", +} diff --git a/eventmesh-sdk-go/common/protocol/subscription_item.go b/eventmesh-sdk-go/common/protocol/subscription_item.go new file mode 100644 index 0000000000..65e828663f --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/subscription_item.go @@ -0,0 +1,22 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package protocol + +type SubscriptionItem struct { + Topic string `json:"topic"` + Mode SubscriptionMode `json:"mode"` + Type SubscriptionType `json:"type"` +} diff --git a/eventmesh-sdk-go/common/protocol/subscription_mode.go b/eventmesh-sdk-go/common/protocol/subscription_mode.go new file mode 100644 index 0000000000..89f933c8dc --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/subscription_mode.go @@ -0,0 +1,26 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package protocol + +type SubscriptionMode string + +var DefaultSubscriptionMode = struct { + BROADCASTING SubscriptionMode + CLUSTERING SubscriptionMode +}{ + BROADCASTING: "BROADCASTING", + CLUSTERING: "CLUSTERING", +} diff --git a/eventmesh-sdk-go/common/protocol/subscription_type.go b/eventmesh-sdk-go/common/protocol/subscription_type.go new file mode 100644 index 0000000000..cacf314b8b --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/subscription_type.go @@ -0,0 +1,26 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package protocol + +type SubscriptionType string + +var DefaultSubscriptionType = struct { + SYNC SubscriptionType + ASYNC SubscriptionType +}{ + SYNC: "SYNC", + ASYNC: "ASYNC", +} diff --git a/eventmesh-sdk-go/common/protocol/tcp/codec/codec.go b/eventmesh-sdk-go/common/protocol/tcp/codec/codec.go new file mode 100644 index 0000000000..a2f588715c --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/tcp/codec/codec.go @@ -0,0 +1,184 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package codec + +import ( + "bytes" + "encoding/binary" + + gcommon "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" + gutils "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/common" +) + +const ( + MAGIC = "EventMesh" + VERSION = "0000" + LENGTH_SIZE = 4 +) + +func EncodePackage(message tcp.Package) *bytes.Buffer { + + header := message.Header + headerData := header.Marshal() + + var bodyData []byte + if header.GetProperty(gcommon.Constants.PROTOCOL_TYPE) != common.EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME { + bodyData = gutils.MarshalJsonBytes(message.Body) + } else { + bodyData = (message.Body).([]byte) + } + + headerLen := len(headerData) + bodyLen := len(bodyData) + + length := LENGTH_SIZE + LENGTH_SIZE + headerLen + bodyLen + + var out bytes.Buffer + out.WriteString(MAGIC) + out.WriteString(VERSION) + + lengthBytes := make([]byte, LENGTH_SIZE) + binary.BigEndian.PutUint32(lengthBytes, uint32(length)) + + headerLenBytes := make([]byte, LENGTH_SIZE) + binary.BigEndian.PutUint32(headerLenBytes, uint32(headerLen)) + + out.Write(lengthBytes) + out.Write(headerLenBytes) + out.Write(headerData) + out.Write(bodyData) + + return &out +} + +func DecodePackage(in *bytes.Buffer) tcp.Package { + flagBytes := parseFlag(in) + versionBytes := parseVersion(in) + validateFlag(flagBytes, versionBytes) + + length := parseLength(in) + headerLen := parseLength(in) + bodyLen := length - headerLen - LENGTH_SIZE - LENGTH_SIZE + header := parseHeader(in, int(headerLen)) + body := parseBody(in, header, int(bodyLen)) + return tcp.Package{Header: header, Body: body} +} + +func parseFlag(in *bytes.Buffer) []byte { + flagLen := len([]byte(MAGIC)) + flagBytes := make([]byte, flagLen) + n, err := in.Read(flagBytes) + if err != nil { + return nil + } + log.Infof("read %d bytes (flag) ", n) + return flagBytes +} + +func parseVersion(in *bytes.Buffer) []byte { + verLen := len([]byte(VERSION)) + verBytes := make([]byte, verLen) + n, err := in.Read(verBytes) + if err != nil { + return nil + } + log.Infof("read %d bytes (version) ", n) + return verBytes +} + +func parseLength(in *bytes.Buffer) uint32 { + lenBytes := make([]byte, 4) + n, err := in.Read(lenBytes) + if err != nil { + log.Errorf("Failed to parse length") + } + log.Infof("read %d bytes (length) ", n) + return binary.BigEndian.Uint32(lenBytes) +} + +func parseHeader(in *bytes.Buffer, headerLen int) tcp.Header { + headerBytes := make([]byte, headerLen) + n, err := in.Read(headerBytes) + if err != nil { + log.Errorf("Failed to parse header") + } + log.Infof("read %d bytes (header) ", n) + + var header tcp.Header + return header.Unmarshal(headerBytes) +} + +func parseBody(in *bytes.Buffer, header tcp.Header, bodyLen int) interface{} { + if bodyLen <= 0 { + return nil + } + + bodyBytes := make([]byte, bodyLen) + n, err := in.Read(bodyBytes) + if err != nil { + log.Errorf("Failed to parse body") + } + log.Infof("read %d bytes (body) ", n) + + bodyStr := string(bodyBytes) + return deserializeBody(bodyStr, header) +} + +func deserializeBody(bodyStr string, header tcp.Header) interface{} { + command := header.Cmd + switch command { + case tcp.DefaultCommand.HELLO_REQUEST: + case tcp.DefaultCommand.RECOMMEND_REQUEST: + var useAgent tcp.UserAgent + gutils.UnMarshalJsonString(bodyStr, &useAgent) + return useAgent + case tcp.DefaultCommand.SUBSCRIBE_REQUEST: + case tcp.DefaultCommand.UNSUBSCRIBE_REQUEST: + return nil + //return OBJECT_MAPPER.readValue(bodyJsonString, Subscription.class); + case tcp.DefaultCommand.REQUEST_TO_SERVER: + case tcp.DefaultCommand.RESPONSE_TO_SERVER: + case tcp.DefaultCommand.ASYNC_MESSAGE_TO_SERVER: + case tcp.DefaultCommand.BROADCAST_MESSAGE_TO_SERVER: + case tcp.DefaultCommand.REQUEST_TO_CLIENT: + case tcp.DefaultCommand.RESPONSE_TO_CLIENT: + case tcp.DefaultCommand.ASYNC_MESSAGE_TO_CLIENT: + case tcp.DefaultCommand.BROADCAST_MESSAGE_TO_CLIENT: + case tcp.DefaultCommand.REQUEST_TO_CLIENT_ACK: + case tcp.DefaultCommand.RESPONSE_TO_CLIENT_ACK: + case tcp.DefaultCommand.ASYNC_MESSAGE_TO_CLIENT_ACK: + case tcp.DefaultCommand.BROADCAST_MESSAGE_TO_CLIENT_ACK: + // The message string will be deserialized by protocol plugin, if the event is cloudevents, the body is + // just a string. + return bodyStr + case tcp.DefaultCommand.REDIRECT_TO_CLIENT: + return nil + //return OBJECT_MAPPER.readValue(bodyJsonString, RedirectInfo.class); + default: + // FIXME improve codes + log.Errorf("Invalidate TCP command: %s", command) + return nil + } + + return nil +} + +func validateFlag(flagBytes, versionBytes []byte) { + // TODO add check +} diff --git a/eventmesh-sdk-go/common/protocol/tcp/command.go b/eventmesh-sdk-go/common/protocol/tcp/command.go new file mode 100644 index 0000000000..8b316dffbf --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/tcp/command.go @@ -0,0 +1,217 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tcp + +type Command string + +var DefaultCommand = struct { + //heartbeat + HEARTBEAT_REQUEST Command //client send heartbeat packet to server + HEARTBEAT_RESPONSE Command //server response heartbeat packet of client + + //handshake + HELLO_REQUEST Command //client send handshake request to server + HELLO_RESPONSE Command //server response handshake request of client + + //disconnection + CLIENT_GOODBYE_REQUEST Command //Notify server when client actively disconnects + CLIENT_GOODBYE_RESPONSE Command //Server replies to client's active disconnection notification + SERVER_GOODBYE_REQUEST Command //Notify client when server actively disconnects + SERVER_GOODBYE_RESPONSE Command //Client replies to server's active disconnection notification + + //subscription management + SUBSCRIBE_REQUEST Command //Subscription request sent by client to server + SUBSCRIBE_RESPONSE Command //Server replies to client's subscription request + UNSUBSCRIBE_REQUEST Command //Unsubscribe request from client to server + UNSUBSCRIBE_RESPONSE Command //Server replies to client's unsubscribe request + + //monitor + LISTEN_REQUEST Command //Request from client to server to start topic listening + LISTEN_RESPONSE Command //The server replies to the client's listening request + + //RR + REQUEST_TO_SERVER Command //The client sends the RR request to the server + REQUEST_TO_CLIENT Command //The server pushes the RR request to the client + REQUEST_TO_CLIENT_ACK Command //After receiving RR request, the client sends ACK to the server + RESPONSE_TO_SERVER Command //The client sends the RR packet back to the server + RESPONSE_TO_CLIENT Command //The server pushes the RR packet back to the client + RESPONSE_TO_CLIENT_ACK Command //After receiving the return packet, the client sends ACK to the server + + //Asynchronous events + ASYNC_MESSAGE_TO_SERVER Command //The client sends asynchronous events to the server + ASYNC_MESSAGE_TO_SERVER_ACK Command //After receiving the asynchronous event, the server sends ack to the client + ASYNC_MESSAGE_TO_CLIENT Command //The server pushes asynchronous events to the client + ASYNC_MESSAGE_TO_CLIENT_ACK Command //After the client receives the asynchronous event, the ACK is sent to the server + + //radio broadcast + BROADCAST_MESSAGE_TO_SERVER Command //The client sends the broadcast message to the server + BROADCAST_MESSAGE_TO_SERVER_ACK Command //After receiving the broadcast message, the server sends ACK to the client + BROADCAST_MESSAGE_TO_CLIENT Command //The server pushes the broadcast message to the client + BROADCAST_MESSAGE_TO_CLIENT_ACK Command //After the client receives the broadcast message, the ACK is sent to the server + + //Log reporting + SYS_LOG_TO_LOGSERVER Command //Business log reporting + + //RMB tracking log reporting + TRACE_LOG_TO_LOGSERVER Command //RMB tracking log reporting + + //Redirecting instruction + REDIRECT_TO_CLIENT Command //The server pushes the redirection instruction to the client + + //service register + REGISTER_REQUEST Command //Client sends registration request to server + REGISTER_RESPONSE Command //The server sends the registration result to the client + + //service unregister + UNREGISTER_REQUEST Command //The client sends a de registration request to the server + UNREGISTER_RESPONSE Command //The server will register the result to the client + + //The client asks which EventMesh to recommend + RECOMMEND_REQUEST Command //Client sends recommendation request to server + RECOMMEND_RESPONSE Command //The server will recommend the results to the client +}{ + //heartbeat + HEARTBEAT_REQUEST: "HEARTBEAT_REQUEST", + HEARTBEAT_RESPONSE: "HEARTBEAT_RESPONSE", + + //handshake + HELLO_REQUEST: "HELLO_REQUEST", + HELLO_RESPONSE: "HELLO_RESPONSE", + + //disconnection + CLIENT_GOODBYE_REQUEST: "CLIENT_GOODBYE_REQUEST", + CLIENT_GOODBYE_RESPONSE: "CLIENT_GOODBYE_RESPONSE", + SERVER_GOODBYE_REQUEST: "SERVER_GOODBYE_REQUEST", + SERVER_GOODBYE_RESPONSE: "SERVER_GOODBYE_RESPONSE", + + //subscription management + SUBSCRIBE_REQUEST: "SUBSCRIBE_REQUEST", + SUBSCRIBE_RESPONSE: "SUBSCRIBE_RESPONSE", + UNSUBSCRIBE_REQUEST: "UNSUBSCRIBE_REQUEST", + UNSUBSCRIBE_RESPONSE: "UNSUBSCRIBE_RESPONSE", + + //monitor + LISTEN_REQUEST: "LISTEN_REQUEST", + LISTEN_RESPONSE: "LISTEN_RESPONSE", + + //RR + REQUEST_TO_SERVER: "REQUEST_TO_SERVER", + REQUEST_TO_CLIENT: "REQUEST_TO_CLIENT", + REQUEST_TO_CLIENT_ACK: "REQUEST_TO_CLIENT_ACK", + RESPONSE_TO_SERVER: "RESPONSE_TO_SERVER", + RESPONSE_TO_CLIENT: "RESPONSE_TO_CLIENT", + RESPONSE_TO_CLIENT_ACK: "RESPONSE_TO_CLIENT_ACK", + + //Asynchronous events + ASYNC_MESSAGE_TO_SERVER: "ASYNC_MESSAGE_TO_SERVER", + ASYNC_MESSAGE_TO_SERVER_ACK: "ASYNC_MESSAGE_TO_SERVER_ACK", + ASYNC_MESSAGE_TO_CLIENT: "ASYNC_MESSAGE_TO_CLIENT", + ASYNC_MESSAGE_TO_CLIENT_ACK: "ASYNC_MESSAGE_TO_CLIENT_ACK", + + //radio broadcast + BROADCAST_MESSAGE_TO_SERVER: "BROADCAST_MESSAGE_TO_SERVER", + BROADCAST_MESSAGE_TO_SERVER_ACK: "BROADCAST_MESSAGE_TO_SERVER_ACK", + BROADCAST_MESSAGE_TO_CLIENT: "BROADCAST_MESSAGE_TO_CLIENT", + BROADCAST_MESSAGE_TO_CLIENT_ACK: "BROADCAST_MESSAGE_TO_CLIENT_ACK", + + //Log reporting + SYS_LOG_TO_LOGSERVER: "SYS_LOG_TO_LOGSERVER", + + //RMB tracking log reporting + TRACE_LOG_TO_LOGSERVER: "TRACE_LOG_TO_LOGSERVER", + + //Redirecting instruction + REDIRECT_TO_CLIENT: "REDIRECT_TO_CLIENT", + + //service register + REGISTER_REQUEST: "REGISTER_REQUEST", + REGISTER_RESPONSE: "REGISTER_RESPONSE", + + //service unregister + UNREGISTER_REQUEST: "UNREGISTER_REQUEST", + UNREGISTER_RESPONSE: "UNREGISTER_RESPONSE", + + //The client asks which EventMesh to recommend + RECOMMEND_REQUEST: "RECOMMEND_REQUEST", + RECOMMEND_RESPONSE: "RECOMMEND_RESPONSE", +} + +//{ +// //heartbeat +// HEARTBEAT_REQUEST: 0, +// HEARTBEAT_RESPONSE: 1, +// +// //handshake +// HELLO_REQUEST: 2, +// HELLO_RESPONSE: 3, +// +// //disconnection +// CLIENT_GOODBYE_REQUEST: 4, +// CLIENT_GOODBYE_RESPONSE: 5, +// SERVER_GOODBYE_REQUEST: 6, +// SERVER_GOODBYE_RESPONSE: 7, +// +// //subscription management +// SUBSCRIBE_REQUEST: 8, +// SUBSCRIBE_RESPONSE: 9, +// UNSUBSCRIBE_REQUEST: 10, +// UNSUBSCRIBE_RESPONSE: 11, +// +// //monitor +// LISTEN_REQUEST: 12, +// LISTEN_RESPONSE: 13, +// +// //RR +// REQUEST_TO_SERVER: 14, +// REQUEST_TO_CLIENT: 15, +// REQUEST_TO_CLIENT_ACK: 16, +// RESPONSE_TO_SERVER: 17, +// RESPONSE_TO_CLIENT: 18, +// RESPONSE_TO_CLIENT_ACK: 19, +// +// //Asynchronous events +// ASYNC_MESSAGE_TO_SERVER: 20, +// ASYNC_MESSAGE_TO_SERVER_ACK: 21, +// ASYNC_MESSAGE_TO_CLIENT: 22, +// ASYNC_MESSAGE_TO_CLIENT_ACK: 23, +// +// //radio broadcast +// BROADCAST_MESSAGE_TO_SERVER: 24, +// BROADCAST_MESSAGE_TO_SERVER_ACK: 25, +// BROADCAST_MESSAGE_TO_CLIENT: 26, +// BROADCAST_MESSAGE_TO_CLIENT_ACK: 27, +// +// //Log reporting +// SYS_LOG_TO_LOGSERVER: 28, +// +// //RMB tracking log reporting +// TRACE_LOG_TO_LOGSERVER: 29, +// +// //Redirecting instruction +// REDIRECT_TO_CLIENT: 30, +// +// //service register +// REGISTER_REQUEST: 31, +// REGISTER_RESPONSE: 32, +// +// //service unregister +// UNREGISTER_REQUEST: 33, +// UNREGISTER_RESPONSE: 34, +// +// //The client asks which EventMesh to recommend +// RECOMMEND_REQUEST: 35, +// RECOMMEND_RESPONSE: 36, +//} diff --git a/eventmesh-sdk-go/common/protocol/tcp/header.go b/eventmesh-sdk-go/common/protocol/tcp/header.go new file mode 100644 index 0000000000..ed8dcf81ee --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/tcp/header.go @@ -0,0 +1,95 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tcp + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/utils" +) + +type Header struct { + Cmd Command `json:"cmd"` + Code int `json:"code"` + Desc string `json:"desc"` + Seq string `json:"seq"` + Properties map[string]interface{} `json:"properties"` +} + +func (h Header) PutProperty(name string, value interface{}) { + h.Properties[name] = value +} + +func (h Header) GetProperty(name string) interface{} { + if h.Properties == nil { + return nil + } + + if val, ok := h.Properties[name]; ok { + return val + } + + return nil +} + +func (h Header) Marshal() []byte { + newHeader := make(map[string]interface{}) + newHeader["cmd"] = h.Cmd + // Compatible with Java Enum serialization + newHeader["command"] = h.Cmd + newHeader["code"] = h.Code + newHeader["desc"] = h.Desc + newHeader["seq"] = h.Seq + newHeader["properties"] = h.Properties + return utils.MarshalJsonBytes(newHeader) +} + +func (h Header) getVal(key string, headerDict map[string]interface{}) interface{} { + if val, ok := headerDict[key]; ok { + return val + } + return nil +} + +func (h Header) Unmarshal(header []byte) Header { + + var headerDict map[string]interface{} + utils.UnMarshalJsonBytes(header, &headerDict) + + if val := h.getVal("cmd", headerDict); val != nil { + h.Cmd = Command(val.(string)) + } + + if val := h.getVal("code", headerDict); val != nil { + h.Code = int(val.(float64)) + } + + if val := h.getVal("desc", headerDict); val != nil { + h.Desc = val.(string) + } + + if val := h.getVal("seq", headerDict); val != nil { + h.Seq = val.(string) + } + + if val := h.getVal("properties", headerDict); val != nil { + h.Properties = val.(map[string]interface{}) + } + + return h +} + +func NewHeader(cmd Command, code int, desc string, seq string) Header { + return Header{Cmd: cmd, Code: code, Desc: desc, Seq: seq, Properties: map[string]interface{}{}} +} diff --git a/eventmesh-sdk-go/common/protocol/tcp/package.go b/eventmesh-sdk-go/common/protocol/tcp/package.go new file mode 100644 index 0000000000..7e579047ff --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/tcp/package.go @@ -0,0 +1,25 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tcp + +type Package struct { + Header Header `json:"header"` + Body interface{} `json:"body"` +} + +func NewPackage(header Header) Package { + return Package{Header: header} +} diff --git a/eventmesh-sdk-go/common/protocol/tcp/user_agent.go b/eventmesh-sdk-go/common/protocol/tcp/user_agent.go new file mode 100644 index 0000000000..8c309e1895 --- /dev/null +++ b/eventmesh-sdk-go/common/protocol/tcp/user_agent.go @@ -0,0 +1,38 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tcp + +type UserAgent struct { + Env string `json:"env"` + Subsystem string `json:"subsystem"` + Path string `json:"path"` + Pid int `json:"pid"` + Host string `json:"host"` + Port int `json:"port"` + Version string `json:"version"` + Username string `json:"username"` + Password string `json:"password"` + Idc string `json:"idc"` + Group string `json:"group"` + Purpose string `json:"purpose"` + Unack int `json:"unack"` +} + +func NewUserAgent(env string, subsystem string, path string, pid int, host string, port int, version string, + username string, password string, idc string, producerGroup string, consumerGroup string) *UserAgent { + return &UserAgent{Env: env, Subsystem: subsystem, Path: path, Pid: pid, Host: host, Port: port, Version: version, + Username: username, Password: password, Idc: idc, Group: producerGroup} +} diff --git a/eventmesh-sdk-go/common/seq/num.go b/eventmesh-sdk-go/common/seq/num.go new file mode 100644 index 0000000000..c962ea8731 --- /dev/null +++ b/eventmesh-sdk-go/common/seq/num.go @@ -0,0 +1,42 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package seq + +import ( + "fmt" + "go.uber.org/atomic" +) + +// Interface to generate sequence number +type Interface interface { + Next() string +} + +// AtomicSeq use atomic.Int64 to create seq number +type AtomicSeq struct { + *atomic.Uint64 +} + +// NewAtomicSeq new atomic sequence instance +func NewAtomicSeq() Interface { + return &AtomicSeq{ + Uint64: atomic.NewUint64(0), + } +} + +func (a *AtomicSeq) Next() string { + return fmt.Sprintf("%v", a.Inc()) +} diff --git a/eventmesh-sdk-go/common/utils/ip.go b/eventmesh-sdk-go/common/utils/ip.go new file mode 100644 index 0000000000..588cff3d32 --- /dev/null +++ b/eventmesh-sdk-go/common/utils/ip.go @@ -0,0 +1,52 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utils + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + + "net" + "sync" +) + +var ( + // hostIP hold the client ip for current machine + hostIPv4 string + + // ipOnce once to set the hostIP + ipOnce sync.Once +) + +// HostIPV4 return the current client ip v4 +func HostIPV4() string { + ipOnce.Do(func() { + addrs, err := net.InterfaceAddrs() + if err != nil { + log.Panicf("get client ipv4, enum addrs err:%v", err) + } + for _, addr := range addrs { + if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { + if ipnet.IP.To4() != nil { + hostIPv4 = ipnet.IP.String() + } + } + } + if hostIPv4 == "" { + log.Panicf("get client ipv4 is empty") + } + }) + return hostIPv4 +} diff --git a/eventmesh-sdk-go/common/utils/json_utils.go b/eventmesh-sdk-go/common/utils/json_utils.go new file mode 100644 index 0000000000..f871609d87 --- /dev/null +++ b/eventmesh-sdk-go/common/utils/json_utils.go @@ -0,0 +1,45 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utils + +import ( + "encoding/json" + + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" +) + +func MarshalJsonBytes(obj interface{}) []byte { + ret, err := json.Marshal(obj) + if err != nil { + log.Fatalf("Failed to marshal json") + } + return ret +} + +func MarshalJsonString(obj interface{}) string { + return string(MarshalJsonBytes(obj)) +} + +func UnMarshalJsonBytes(data []byte, obj interface{}) { + err := json.Unmarshal(data, obj) + if err != nil { + log.Fatalf("Failed to unmarshal json") + } +} + +func UnMarshalJsonString(data string, obj interface{}) { + UnMarshalJsonBytes([]byte(data), obj) +} diff --git a/eventmesh-sdk-go/common/utils/pid.go b/eventmesh-sdk-go/common/utils/pid.go new file mode 100644 index 0000000000..abfdc8bd85 --- /dev/null +++ b/eventmesh-sdk-go/common/utils/pid.go @@ -0,0 +1,38 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utils + +import ( + "fmt" + "os" + "sync" +) + +var ( + // pid the current running process id + pid string + + // pidOnce make sure get pid once + pidOnce sync.Once +) + +// CurrentPID return the current running process id +func CurrentPID() string { + pidOnce.Do(func() { + pid = fmt.Sprintf("%v", os.Getpid()) + }) + return pid +} diff --git a/eventmesh-sdk-go/examples/grpc/consumer/asyncsub/main.go b/eventmesh-sdk-go/examples/grpc/consumer/asyncsub/main.go new file mode 100644 index 0000000000..28f26a7b54 --- /dev/null +++ b/eventmesh-sdk-go/examples/grpc/consumer/asyncsub/main.go @@ -0,0 +1,77 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "io/ioutil" + "net/http" + "time" +) + +func main() { + cli, err := grpc.New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 10205, + ENV: "go-grpc-test-env", + Region: "sh", + IDC: "pd", + SYS: "grpc-go", + Username: "grpc-go-username", + Password: "grpc-go-passwd", + ProtocolType: grpc.EventmeshMessage, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test-async-consumer-group-subscribe", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + if err != nil { + panic(err) + } + defer func() { + if err := cli.Close(); err != nil { + panic(err) + } + }() + err = cli.SubscribeWebhook(conf.SubscribeItem{ + SubscribeMode: conf.CLUSTERING, + SubscribeType: conf.ASYNC, + Topic: "async-sub-grpc-topic", + }, "http://localhost:8080/onmessage") + if err != nil { + fmt.Println(err.Error()) + return + } + http.HandleFunc("/onmessage", func(writer http.ResponseWriter, request *http.Request) { + buf, err := ioutil.ReadAll(request.Body) + if err != nil { + return + } + defer request.Body.Close() + fmt.Println(string(buf)) + }) + http.ListenAndServe(":8080", nil) +} diff --git a/eventmesh-sdk-go/examples/grpc/consumer/boradcast/main.go b/eventmesh-sdk-go/examples/grpc/consumer/boradcast/main.go new file mode 100644 index 0000000000..6d5c518820 --- /dev/null +++ b/eventmesh-sdk-go/examples/grpc/consumer/boradcast/main.go @@ -0,0 +1,67 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "time" +) + +func main() { + cli, err := grpc.New(&conf.GRPCConfig{ + Host: "101.43.84.47", + Port: 10205, + ENV: "go-grpc-test-env", + Region: "sh", + IDC: "pd", + SYS: "grpc-go", + Username: "grpc-go-username", + Password: "grpc-go-passwd", + ProtocolType: grpc.EventmeshMessage, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test-broadcast-consumer-group-subscribe", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + if err != nil { + panic(err) + } + defer func() { + if err := cli.Close(); err != nil { + panic(err) + } + }() + err = cli.SubscribeWebhook(conf.SubscribeItem{ + SubscribeMode: conf.BROADCASTING, + SubscribeType: conf.ASYNC, + Topic: "grpc-broadcast-topic", + }, "") + if err != nil { + fmt.Println(err.Error()) + return + } + time.Sleep(time.Hour) +} diff --git a/eventmesh-sdk-go/examples/grpc/consumer/broadcast/main.go b/eventmesh-sdk-go/examples/grpc/consumer/broadcast/main.go new file mode 100644 index 0000000000..47973c5e70 --- /dev/null +++ b/eventmesh-sdk-go/examples/grpc/consumer/broadcast/main.go @@ -0,0 +1,67 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "time" +) + +func main() { + cli, err := grpc.New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 10205, + ENV: "go-grpc-test-env", + Region: "sh", + IDC: "pd", + SYS: "grpc-go", + Username: "grpc-go-username", + Password: "grpc-go-passwd", + ProtocolType: grpc.EventmeshMessage, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test-broadcast-consumer-group-subscribe", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + if err != nil { + panic(err) + } + defer func() { + if err := cli.Close(); err != nil { + panic(err) + } + }() + err = cli.SubscribeWebhook(conf.SubscribeItem{ + SubscribeMode: conf.BROADCASTING, + SubscribeType: conf.ASYNC, + Topic: "grpc-broadcast-topic", + }, "http://localhost:18080/onmessage") + if err != nil { + fmt.Println(err.Error()) + return + } + time.Sleep(time.Hour) +} diff --git a/eventmesh-sdk-go/examples/grpc/consumer/rr/main.go b/eventmesh-sdk-go/examples/grpc/consumer/rr/main.go new file mode 100644 index 0000000000..d95b44ef81 --- /dev/null +++ b/eventmesh-sdk-go/examples/grpc/consumer/rr/main.go @@ -0,0 +1,67 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "time" +) + +func main() { + cli, err := grpc.New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 10205, + ENV: "go-grpc-test-env", + Region: "sh", + IDC: "pd", + SYS: "grpc-go", + Username: "grpc-go-username", + Password: "grpc-go-passwd", + ProtocolType: grpc.EventmeshMessage, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-sync-consumer-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test-consumer-group-subscribe", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + if err != nil { + panic(err) + } + defer func() { + if err := cli.Close(); err != nil { + panic(err) + } + }() + err = cli.SubscribeWebhook(conf.SubscribeItem{ + SubscribeMode: conf.CLUSTERING, + SubscribeType: conf.SYNC, + Topic: "grpc-topic", + }, "") + if err != nil { + fmt.Println(err.Error()) + return + } + time.Sleep(time.Hour) +} diff --git a/eventmesh-sdk-go/examples/grpc/consumer/stream/main.go b/eventmesh-sdk-go/examples/grpc/consumer/stream/main.go new file mode 100644 index 0000000000..32303feb7d --- /dev/null +++ b/eventmesh-sdk-go/examples/grpc/consumer/stream/main.go @@ -0,0 +1,71 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" + "time" +) + +func main() { + cli, err := grpc.New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 10205, + ENV: "go-grpc-test-env", + Region: "sh", + IDC: "pd", + SYS: "grpc-go", + Username: "grpc-go-username", + Password: "grpc-go-passwd", + ProtocolType: grpc.EventmeshMessage, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-sync-consumer-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test-consumer-group-subscribe", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + if err != nil { + panic(err) + } + defer func() { + if err := cli.Close(); err != nil { + panic(err) + } + }() + err = cli.SubscribeStream(conf.SubscribeItem{ + SubscribeMode: conf.CLUSTERING, + SubscribeType: conf.ASYNC, + Topic: "grpc-topic", + }, func(msg *proto.SimpleMessage) interface{} { + fmt.Println("receive msg: " + msg.String()) + return nil + }) + if err != nil { + fmt.Println(err.Error()) + return + } + time.Sleep(time.Hour) +} diff --git a/eventmesh-sdk-go/examples/grpc/producer/bp/main.go b/eventmesh-sdk-go/examples/grpc/producer/bp/main.go new file mode 100644 index 0000000000..fe3cb55607 --- /dev/null +++ b/eventmesh-sdk-go/examples/grpc/producer/bp/main.go @@ -0,0 +1,88 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "context" + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" +) + +func main() { + cfg := &conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 10205, + ENV: "go-grpc-test-env", + Region: "sh", + IDC: "pd", + SYS: "grpc-go", + Username: "grpc-go-username", + Password: "grpc-go-passwd", + ProtocolType: grpc.EventmeshMessage, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-batch-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: false, + }, + } + cli, err := grpc.New(cfg) + if err != nil { + fmt.Println("create publish client err:" + err.Error()) + return + } + defer func() { + if err := cli.Close(); err != nil { + panic(err) + } + }() + batchMsg := &proto.BatchMessage{ + Header: grpc.CreateHeader(cfg), + ProducerGroup: "grpc-producergroup", + Topic: "grpc-batch-topic", + MessageItem: []*proto.BatchMessage_MessageItem{ + { + Content: "test for batch publish go grpc -1", + Ttl: "1024", + UniqueId: "110", + SeqNum: "111", + Tag: "batch publish tag 1", + Properties: map[string]string{ + "from": "grpc", + "type": "batch publish", + }, + }, + { + Content: "test for batch publish go grpc", + Ttl: "1024", + UniqueId: "210", + SeqNum: "211", + Tag: "batch publish tag 2", + Properties: map[string]string{ + "from": "grpc", + "type": "batch publish", + }, + }, + }, + } + resp, err := cli.BatchPublish(context.TODO(), batchMsg) + if err != nil { + panic(err) + } + fmt.Println(resp.String()) +} diff --git a/eventmesh-sdk-go/examples/grpc/producer/publish/main.go b/eventmesh-sdk-go/examples/grpc/producer/publish/main.go new file mode 100644 index 0000000000..c86fcedc8e --- /dev/null +++ b/eventmesh-sdk-go/examples/grpc/producer/publish/main.go @@ -0,0 +1,74 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "context" + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/google/uuid" + "time" +) + +func main() { + cfg := &conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 10205, + ENV: "go-grpc-test-env", + Region: "sh", + IDC: "pd", + SYS: "grpc-go", + Username: "grpc-go-username", + Password: "grpc-go-passwd", + ProtocolType: grpc.EventmeshMessage, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: false, + }, + } + cli, err := grpc.New(cfg) + if err != nil { + fmt.Println("create publish client err:" + err.Error()) + return + } + defer func() { + if err := cli.Close(); err != nil { + panic(err) + } + }() + for i := 0; i < 10; i++ { + builder := grpc.NewMessageBuilder() + builder.WithHeader(grpc.CreateHeader(cfg)). + WithContent("test for publish go grpc"). + WithProperties(map[string]string{ + "from": "grpc", + "for": "test"}). + WithProducerGroup("grpc-publish-producergroup"). + WithTag("grpc publish tag"). + WithTopic("grpc-topic"). + WithTTL(time.Hour). + WithSeqNO(uuid.New().String()). + WithUniqueID(uuid.New().String()) + resp, err := cli.Publish(context.TODO(), builder.SimpleMessage) + if err != nil { + panic(err) + } + fmt.Println(resp.String()) + } +} diff --git a/eventmesh-sdk-go/examples/grpc/producer/rr/main.go b/eventmesh-sdk-go/examples/grpc/producer/rr/main.go new file mode 100644 index 0000000000..70e486bf09 --- /dev/null +++ b/eventmesh-sdk-go/examples/grpc/producer/rr/main.go @@ -0,0 +1,73 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "context" + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "time" +) + +func main() { + cfg := &conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 10205, + ENV: "go-grpc-test-env", + Region: "sh", + IDC: "pd", + SYS: "grpc-go", + Username: "grpc-go-username", + Password: "grpc-go-passwd", + ProtocolType: grpc.EventmeshMessage, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-rr-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: false, + }, + } + cli, err := grpc.New(cfg) + if err != nil { + panic(err) + } + defer func() { + if err := cli.Close(); err != nil { + panic(err) + } + }() + builder := grpc.NewMessageBuilder() + builder.WithHeader(grpc.CreateHeader(cfg)). + WithContent("test for rr go grpc"). + WithProperties(map[string]string{ + "from": "grpc", + "for": "test"}). + WithProducerGroup("grpc-rr-producergroup"). + WithTag("grpc rr tag"). + WithTopic("grpc-topic"). + WithTTL(time.Hour). + WithSeqNO("1"). + WithUniqueID("1") + + msg, err := cli.RequestReply(context.TODO(), builder.SimpleMessage) + if err != nil { + fmt.Println("send rr msg err:" + err.Error()) + return + } + fmt.Println(msg.String()) + +} diff --git a/eventmesh-sdk-go/examples/http/async_pub_cloudevents.go b/eventmesh-sdk-go/examples/http/async_pub_cloudevents.go new file mode 100644 index 0000000000..5ca6362ae5 --- /dev/null +++ b/eventmesh-sdk-go/examples/http/async_pub_cloudevents.go @@ -0,0 +1,69 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package http + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/conf" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/producer" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + + cloudevents "github.com/cloudevents/sdk-go/v2" + "github.com/google/uuid" + + "os" + "strconv" +) + +func AsyncPubCloudEvents() { + eventMeshIPPort := "127.0.0.1" + ":" + "10105" + producerGroup := "EventMeshTest-producerGroup" + topic := "TEST-TOPIC-HTTP-ASYNC" + env := "P" + idc := "FT" + subSys := "1234" + // FIXME Get ip dynamically + localIp := "127.0.0.1" + + // (Deep) Copy of default config + eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig + eventMeshClientConfig.SetLiteEventMeshAddr(eventMeshIPPort) + eventMeshClientConfig.SetProducerGroup(producerGroup) + eventMeshClientConfig.SetEnv(env) + eventMeshClientConfig.SetIdc(idc) + eventMeshClientConfig.SetSys(subSys) + eventMeshClientConfig.SetIp(localIp) + eventMeshClientConfig.SetPid(strconv.Itoa(os.Getpid())) + + // Make event to send + event := cloudevents.NewEvent() + event.SetID(uuid.New().String()) + event.SetSubject(topic) + event.SetSource("example/uri") + event.SetType(common.Constants.CLOUD_EVENTS_PROTOCOL_NAME) + event.SetExtension(common.Constants.EVENTMESH_MESSAGE_CONST_TTL, strconv.Itoa(4*1000)) + event.SetDataContentType(cloudevents.ApplicationCloudEventsJSON) + data := map[string]string{"hello": "EventMesh"} + err := event.SetData(cloudevents.ApplicationCloudEventsJSON, utils.MarshalJsonBytes(data)) + if err != nil { + log.Fatalf("Failed to set cloud event data, error: %v", err) + } + + // Publish event + httpProducer := producer.NewEventMeshHttpProducer(eventMeshClientConfig) + httpProducer.Publish(event) +} diff --git a/eventmesh-sdk-go/examples/http/sub_cloudevents.go b/eventmesh-sdk-go/examples/http/sub_cloudevents.go new file mode 100644 index 0000000000..76b9866cc8 --- /dev/null +++ b/eventmesh-sdk-go/examples/http/sub_cloudevents.go @@ -0,0 +1,115 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package http + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/conf" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/consumer" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + + cloudevents "github.com/cloudevents/sdk-go/v2" + "net/http" + "os" + "strconv" + "strings" +) + +func SubCloudEvents() { + eventMeshIPPort := "127.0.0.1" + ":" + "10105" + consumerGroup := "EventMeshTest-consumerGroup" + topic := "TEST-TOPIC-HTTP-ASYNC" + env := "P" + idc := "FT" + subSys := "1234" + // FIXME Get ip dynamically + localIp := "127.0.0.1" + localPort := 8090 + + subscribeUrl := "http://" + localIp + ":" + strconv.Itoa(localPort) + "/hello" + topicList := []protocol.SubscriptionItem{ + { + Topic: topic, + Mode: protocol.DefaultSubscriptionMode.CLUSTERING, + Type: protocol.DefaultSubscriptionType.ASYNC, + }, + } + + // Callback handle + exit := make(chan bool) + go httpServer(localIp, localPort, exit) + + // (Deep) Copy of default config + eventMeshClientConfig := conf.DefaultEventMeshHttpClientConfig + eventMeshClientConfig.SetLiteEventMeshAddr(eventMeshIPPort) + eventMeshClientConfig.SetConsumerGroup(consumerGroup) + eventMeshClientConfig.SetEnv(env) + eventMeshClientConfig.SetIdc(idc) + eventMeshClientConfig.SetSys(subSys) + eventMeshClientConfig.SetIp(localIp) + eventMeshClientConfig.SetPid(strconv.Itoa(os.Getpid())) + + // Subscribe + eventMeshHttpConsumer := consumer.NewEventMeshHttpConsumer(eventMeshClientConfig) + eventMeshHttpConsumer.Subscribe(topicList, subscribeUrl) + eventMeshHttpConsumer.HeartBeat(topicList, subscribeUrl) + + // FIXME Add unsubscribe + + // Wait for exit + <-exit +} + +func httpServer(ip string, port int, exit chan<- bool) { + http.HandleFunc("/hello", hello) + err := http.ListenAndServe(ip+":"+strconv.Itoa(port), nil) + if err != nil { + log.Fatalf("Failed to launch a callback http server, error: %v", err) + } + + exit <- true +} + +func hello(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/hello" { + http.NotFound(w, r) + return + } + + switch r.Method { + case "POST": + contentType := r.Header.Get("Content-Type") + + // FIXME Now we only support post form + if strings.Contains(contentType, "application/x-www-form-urlencoded") { + err := r.ParseForm() + if err != nil { + log.Errorf("Failed to parse post form parameter, error: %v", err) + } + content := r.FormValue("content") + event := cloudevents.NewEvent() + utils.UnMarshalJsonString(content, &event) + log.Infof("Received data from eventmesh server: %v", string(event.Data())) + return + } + + w.WriteHeader(http.StatusUnsupportedMediaType) + default: + w.WriteHeader(http.StatusNotImplemented) + w.Write([]byte(http.StatusText(http.StatusNotImplemented))) + } +} diff --git a/eventmesh-sdk-go/examples/tcp/async_pub_cloudevents.go b/eventmesh-sdk-go/examples/tcp/async_pub_cloudevents.go new file mode 100644 index 0000000000..0af60d5f53 --- /dev/null +++ b/eventmesh-sdk-go/examples/tcp/async_pub_cloudevents.go @@ -0,0 +1,60 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tcp + +import ( + "time" + + "github.com/google/uuid" + "strconv" + + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol" + gtcp "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/conf" + cloudevents "github.com/cloudevents/sdk-go/v2" +) + +func AsyncPubCloudEvents() { + eventMeshIp := "127.0.0.1" + eventMeshTcpPort := 10000 + topic := "TEST-TOPIC-TCP-ASYNC" + + // Init client + userAgent := gtcp.UserAgent{Env: "test", Subsystem: "5023", Path: "/data/app/umg_proxy", Pid: 32893, + Host: "127.0.0.1", Port: 8362, Version: "2.0.11", Username: "PU4283", Password: "PUPASS", Idc: "FT", + Group: "EventmeshTestGroup", Purpose: "pub"} + config := conf.NewEventMeshTCPClientConfig(eventMeshIp, eventMeshTcpPort, userAgent) + client := tcp.CreateEventMeshTCPClient(*config, protocol.DefaultMessageType.CloudEvent) + client.Init() + + // Make event to send + event := cloudevents.NewEvent() + event.SetID(uuid.New().String()) + event.SetSubject(topic) + event.SetSource("example/uri") + event.SetType(common.Constants.CLOUD_EVENTS_PROTOCOL_NAME) + event.SetExtension(common.Constants.EVENTMESH_MESSAGE_CONST_TTL, strconv.Itoa(4*1000)) + event.SetDataContentType(cloudevents.ApplicationCloudEventsJSON) + data := map[string]string{"hello": "EventMesh"} + event.SetData(cloudevents.ApplicationCloudEventsJSON, utils.MarshalJsonBytes(data)) + + // Publish event + client.Publish(event, 10000) + time.Sleep(10 * time.Second) +} diff --git a/eventmesh-sdk-go/go.mod b/eventmesh-sdk-go/go.mod new file mode 100644 index 0000000000..2ae6bd6c9a --- /dev/null +++ b/eventmesh-sdk-go/go.mod @@ -0,0 +1,32 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +module github.com/apache/incubator-eventmesh/eventmesh-sdk-go + +go 1.16 + +require ( + github.com/cespare/xxhash v1.1.0 + github.com/cloudevents/sdk-go/v2 v2.6.0 + github.com/google/uuid v1.3.0 + github.com/json-iterator/go v1.1.10 + github.com/panjf2000/ants v1.3.0 + github.com/sony/sonyflake v1.0.0 + github.com/stretchr/testify v1.7.0 + go.uber.org/atomic v1.4.0 + go.uber.org/zap v1.10.0 + google.golang.org/grpc v1.45.0 + google.golang.org/protobuf v1.28.0 +) diff --git a/eventmesh-sdk-go/go.sum b/eventmesh-sdk-go/go.sum new file mode 100644 index 0000000000..80f6b9c21c --- /dev/null +++ b/eventmesh-sdk-go/go.sum @@ -0,0 +1,172 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudevents/sdk-go/v2 v2.6.0 h1:yp6zLEvhXSi6P25zzfgORgFI0quG2/NXoH9QoHzvKn8= +github.com/cloudevents/sdk-go/v2 v2.6.0/go.mod h1:nlXhgFkf0uTopxmRXalyMwS2LG70cRGPrxzmjJgSG0U= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= +github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/panjf2000/ants v1.3.0 h1:8pQ+8leaLc9lys2viEEr8md0U4RN6uOSUCE9bOYjQ9M= +github.com/panjf2000/ants v1.3.0/go.mod h1:AaACblRPzq35m1g3enqYcxspbbiOJJYaxU2wMpm1cXY= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM= +github.com/sony/sonyflake v1.0.0/go.mod h1:Jv3cfhf/UFtolOTTRd3q4Nl6ENqM+KfyZ5PseKfZGF4= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/eventmesh-sdk-go/grpc/README.md b/eventmesh-sdk-go/grpc/README.md new file mode 100644 index 0000000000..e22a5a9555 --- /dev/null +++ b/eventmesh-sdk-go/grpc/README.md @@ -0,0 +1,43 @@ +grpc +=== +grpc client for evenemesh, support multiple type of loadbalancer + +how to use +--- +### send message + +### subscribe message + +setup with option +--- +### 1. setup the logger +if you want to rewrite the log to other place, such as some promethus and so on, you need to implements the ```log.Logger``` +interface, and set it with ```GRPCOption``` +for example: +```GO +type selfLogger struct{ +} + +func (s *selfLogger) Infof(template string, args ...interface{}) { + // todo +} +// ... +// other methods + +cli, err := grpc.New(&conf.GRPCConfig{}, []Option{WithLogger(&selfLogger{})}) +``` +### 2. setup the idgen +in grpc client, we provide two kinds of id generator, uuid/flake, you can refers to ```commom/id``` for details. +and if you want to implement it yourself, just implement the ```id.Interface``` api, for example: +```GO +type selfIdg struct{} +func (s* selfIdg) Next() string { + return "uniq id" +} + +cli, err := grpc.New(&conf.GRPCConfig{}, []Option{WithID(&selfIdg{})}) +``` + +TODO +--- +use etcd as service discovery \ No newline at end of file diff --git a/eventmesh-sdk-go/grpc/api.go b/eventmesh-sdk-go/grpc/api.go new file mode 100644 index 0000000000..b6568e6d6f --- /dev/null +++ b/eventmesh-sdk-go/grpc/api.go @@ -0,0 +1,51 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grpc + +import ( + "context" + + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" + "google.golang.org/grpc" +) + +// OnMessage on receive message from eventmesh, used in subscribe message +type OnMessage func(*proto.SimpleMessage) interface{} + +// Interface grpc client to producer and consumer message +type Interface interface { + // Publish send message to eventmesh, without wait the response from other client + Publish(ctx context.Context, msg *proto.SimpleMessage, opts ...grpc.CallOption) (*proto.Response, error) + + // RequestReply send message to eventmesh, and wait for the response + RequestReply(ctx context.Context, msg *proto.SimpleMessage, opts ...grpc.CallOption) (*proto.SimpleMessage, error) + + // BatchPublish send batch message to eventmesh + BatchPublish(ctx context.Context, msg *proto.BatchMessage, opts ...grpc.CallOption) (*proto.Response, error) + + // SubscribeWebhook consumer message in webhook, and OnMessage invoked when new message arrived + SubscribeWebhook(item conf.SubscribeItem, callbackURL string) error + + // SubscribeStream stream subscribe the message + SubscribeStream(item conf.SubscribeItem, handler OnMessage) error + + // UnSubscribe unsubcribe topic, and don't subscribe msg anymore + UnSubscribe() error + + // Close release all resources in the client + Close() error +} diff --git a/eventmesh-sdk-go/grpc/client.go b/eventmesh-sdk-go/grpc/client.go new file mode 100644 index 0000000000..d77373e070 --- /dev/null +++ b/eventmesh-sdk-go/grpc/client.go @@ -0,0 +1,192 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grpc + +import ( + "context" + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/id" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/seq" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "math/rand" + "time" +) + +// New create new eventmesh grpc client +func New(cfg *conf.GRPCConfig, opts ...GRPCOption) (Interface, error) { + cli, err := newEventMeshGRPCClient(cfg, opts...) + if err != nil { + return nil, err + } + + return cli, err +} + +// eventMeshGRPCClient define the grpc client for eventmesh api +type eventMeshGRPCClient struct { + grpcConn *grpc.ClientConn + // producer used to send msg to evenmesh + *eventMeshProducer + // consumer used to subscribe msg from eventmesh + *eventMeshConsumer + // cancel to close the client + cancel context.CancelFunc + // idg generate id api + idg id.Interface + // seqg generate uniq id + seqg seq.Interface +} + +// newEventMeshGRPCClient create new grpc client +func newEventMeshGRPCClient(cfg *conf.GRPCConfig, opts ...GRPCOption) (*eventMeshGRPCClient, error) { + var ( + err error + ctx, cancel = context.WithCancel(context.Background()) + grpConn *grpc.ClientConn + ) + if err = conf.ValidateDefaultConf(cfg); err != nil { + return nil, err + } + defer func() { + if err != nil && grpConn != nil { + // if err != nil and the grpc.ClientConn is connected + // we need to close it + if err := grpConn.Close(); err != nil { + log.Warnf("failed to close conn with, err:%v", err) + } + } + }() + makeGRPCConn := func(host string, port int) (*grpc.ClientConn, error) { + addr := fmt.Sprintf("%v:%v", host, port) + conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + log.Warnf("failed to make grpc conn with:%s, err:%v", addr, err) + return nil, err + } + log.Infof("success make grpc conn with:%s", addr) + return conn, nil + } + cli := &eventMeshGRPCClient{} + for _, opt := range opts { + opt(cli) + } + if cli.idg == nil { + cli.idg = id.NewUUID() + } + if cli.seqg == nil { + cli.seqg = seq.NewAtomicSeq() + } + time.Sleep(time.Nanosecond * time.Duration(rand.Int31n(50))) + conn, err := makeGRPCConn(cfg.Host, cfg.Port) + if err != nil { + return nil, err + } + grpConn = conn + producer, err := newProducer(grpConn) + if err != nil { + log.Warnf("failed to create producer, err:%v", err) + return nil, err + } + cli.grpcConn = grpConn + cli.eventMeshProducer = producer + cli.cancel = cancel + if cfg.ConsumerConfig.Enabled { + log.Infof("subscribe enabled") + consumer, err := newConsumer(ctx, cfg, grpConn, cli.idg, cli.seqg) + if err != nil { + log.Warnf("failed to create producer, err:%v", err) + return nil, err + } + if err := consumer.startConsumerStream(); err != nil { + return nil, err + } + cli.eventMeshConsumer = consumer + } + + return cli, nil +} + +// Publish send message to eventmesh, without wait the response from other client +func (e *eventMeshGRPCClient) Publish(ctx context.Context, msg *proto.SimpleMessage, opts ...grpc.CallOption) (*proto.Response, error) { + ctx = e.setupContext(ctx) + return e.eventMeshProducer.Publish(ctx, msg, opts...) +} + +// RequestReply send message to eventmesh, and wait for the response +func (e *eventMeshGRPCClient) RequestReply(ctx context.Context, msg *proto.SimpleMessage, opts ...grpc.CallOption) (*proto.SimpleMessage, error) { + ctx = e.setupContext(ctx) + return e.eventMeshProducer.RequestReply(ctx, msg, opts...) +} + +// BatchPublish send batch message to eventmesh +func (e *eventMeshGRPCClient) BatchPublish(ctx context.Context, msg *proto.BatchMessage, opts ...grpc.CallOption) (*proto.Response, error) { + ctx = e.setupContext(ctx) + return e.eventMeshProducer.BatchPublish(ctx, msg, opts...) +} + +// SubscribeWebhook consumer message, and OnMessage invoked when new message arrived +func (e *eventMeshGRPCClient) SubscribeWebhook(item conf.SubscribeItem, callbackURL string) error { + return e.Subscribe(item, callbackURL) +} + +// SubscribeStream subscribe stream for topic +func (e *eventMeshGRPCClient) SubscribeStream(item conf.SubscribeItem, handler OnMessage) error { + return e.SubscribeWithStream(item, handler) +} + +// UnSubscribe unsubcribe topic, and don't subscribe msg anymore +func (e *eventMeshGRPCClient) UnSubscribe() error { + return e.eventMeshConsumer.UnSubscribe() +} + +// setupContext set up the context, add id if not exist +func (e *eventMeshGRPCClient) setupContext(ctx context.Context) context.Context { + val := ctx.Value(GRPC_ID_KEY) + if val == nil { + ctx = context.WithValue(ctx, GRPC_ID_KEY, e.idg.Next()) + } + return ctx +} + +// Close meshclient and free all resources +func (e *eventMeshGRPCClient) Close() error { + log.Infof("close grpc client") + if e.cancel != nil { + e.cancel() + } + if e.eventMeshProducer != nil { + if err := e.eventMeshProducer.Close(); err != nil { + log.Warnf("close producer err:%v", err) + } + e.eventMeshProducer = nil + } + if e.eventMeshConsumer != nil { + if err := e.eventMeshConsumer.close(); err != nil { + log.Warnf("close consumer err:%v", err) + } + e.eventMeshConsumer = nil + } + if err := e.grpcConn.Close(); err != nil { + log.Warnf("err in close conn with err:%v", err) + } + + log.Infof("success close grpc client") + return nil +} diff --git a/eventmesh-sdk-go/grpc/client_test.go b/eventmesh-sdk-go/grpc/client_test.go new file mode 100644 index 0000000000..f3ebf3b8ec --- /dev/null +++ b/eventmesh-sdk-go/grpc/client_test.go @@ -0,0 +1,464 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grpc + +import ( + "context" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" + "github.com/stretchr/testify/assert" + "google.golang.org/grpc" + "testing" + "time" +) + +func Test_newEventMeshGRPCClient(t *testing.T) { + type args struct { + cfg *conf.GRPCConfig + } + tests := []struct { + name string + args args + want *eventMeshGRPCClient + wantErr bool + }{ + { + name: "host is empty", + args: args{cfg: &conf.GRPCConfig{ + Host: "", + }}, + wantErr: true, + want: nil, + }, + { + name: "producer wrong", + args: args{cfg: &conf.GRPCConfig{ + Host: "1.1.1.1", + ProducerConfig: conf.ProducerConfig{}, + }}, + wantErr: true, + want: nil, + }, + { + name: "client with send msg", + args: args{cfg: &conf.GRPCConfig{ + Host: "101.43.84.47", + Port: 10205, + ENV: "sendmsgenv", + Region: "sh", + IDC: "idc01", + SYS: "test-system", + ProtocolType: "grpc", + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-producer-group", + }, + Username: "user", + Password: "passwd", + }}, + want: nil, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cli, err := newEventMeshGRPCClient(tt.args.cfg) + if (err != nil) != tt.wantErr { + t.Errorf("newEventMeshGRPCClient() error = %v, wantErr %v", err, tt.wantErr) + return + } + if err == nil { + assert.NoError(t, cli.Close()) + } + }) + } +} + +func Test_multiple_set_context(t *testing.T) { + root := context.Background() + onec, cancel := context.WithTimeout(root, time.Second*5) + defer cancel() + valc := context.WithValue(onec, "test", "got") + + select { + case <-valc.Done(): + val := valc.Value("test") + t.Logf("5 s reached, value in context:%v", val) + case <-time.After(time.Second * 10): + t.Logf("ooor, 10s timeout") + } + +} + +func Test_eventMeshGRPCClient_Publish(t *testing.T) { + // run fake server + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go runFakeServer(ctx) + cli, err := New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 8086, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: false, + }, + }) + assert.NoError(t, err, "create grpc client") + type args struct { + ctx context.Context + msg *proto.SimpleMessage + opts []grpc.CallOption + } + tests := []struct { + name string + args args + want *proto.Response + wantErr assert.ErrorAssertionFunc + }{ + { + name: "publish msg", + args: args{ + ctx: context.TODO(), + msg: &proto.SimpleMessage{ + Header: &proto.RequestHeader{}, + Topic: "test-publish-topic", + }, + }, + wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + return true + }, + }, + { + name: "publish with timeout", + args: args{ + ctx: func() context.Context { + ctx, _ := context.WithTimeout(context.Background(), time.Second*10) + return ctx + }(), + msg: &proto.SimpleMessage{ + Header: &proto.RequestHeader{}, + Topic: "test-timeout-topic", + }, + }, + wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + return true + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := cli.Publish(tt.args.ctx, tt.args.msg, tt.args.opts...) + assert.NoError(t, err) + t.Logf("receive publish response:%v", got.String()) + assert.NoError(t, cli.Close()) + }) + } +} + +func Test_eventMeshGRPCClient_RequestReply(t *testing.T) { + // run fake server + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go runFakeServer(ctx) + cli, err := New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 8086, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: false, + }, + }) + assert.NoError(t, err, "create grpc client") + type args struct { + ctx context.Context + msg *proto.SimpleMessage + opts []grpc.CallOption + } + tests := []struct { + name string + args args + want *proto.SimpleMessage + wantErr assert.ErrorAssertionFunc + }{ + { + name: "test-request-reply", + args: args{ + ctx: context.TODO(), + msg: &proto.SimpleMessage{ + Header: &proto.RequestHeader{}, + Topic: "test-request-reply-topic", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := cli.RequestReply(tt.args.ctx, tt.args.msg, tt.args.opts...) + assert.NoError(t, err) + t.Logf("receive request reply response:%v", got.String()) + assert.NoError(t, cli.Close()) + }) + } +} + +func Test_eventMeshGRPCClient_BatchPublish(t *testing.T) { + // run fake server + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go runFakeServer(ctx) + cli, err := New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 8086, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: false, + }, + }) + assert.NoError(t, err, "create grpc client") + type args struct { + ctx context.Context + msg *proto.BatchMessage + opts []grpc.CallOption + } + tests := []struct { + name string + args args + want *proto.Response + wantErr assert.ErrorAssertionFunc + }{ + { + name: "test batch publish", + args: args{ + ctx: context.TODO(), + msg: &proto.BatchMessage{ + Header: &proto.RequestHeader{}, + ProducerGroup: "fake-batch-group", + Topic: "fake-batch-topic", + MessageItem: []*proto.BatchMessage_MessageItem{ + { + Content: "batch-1", + Ttl: "1", + UniqueId: "batch-id", + SeqNum: "1", + Tag: "tag", + Properties: map[string]string{ + "from": "test", + "type": "batch-msg", + }, + }, + { + Content: "batch-2", + Ttl: "2", + UniqueId: "batch-id", + SeqNum: "2", + Tag: "tag", + Properties: map[string]string{ + "from": "test", + "type": "batch-msg", + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := cli.BatchPublish(tt.args.ctx, tt.args.msg, tt.args.opts...) + assert.NoError(t, err) + t.Logf("receive request reply response:%v", got.String()) + assert.NoError(t, cli.Close()) + }) + } +} + +func Test_eventMeshGRPCClient_webhook_subscribe(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) + defer cancel() + go runWebhookServer(ctx) + go runFakeServer(ctx) + cli, err := New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 8086, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test-consumer-group-subscribe", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + assert.NoError(t, err, "create grpc client") + assert.NoError(t, cli.SubscribeWebhook(conf.SubscribeItem{ + SubscribeMode: 1, + SubscribeType: 1, + Topic: "topic-1", + }, "http://localhost:8080/onmessage")) + time.Sleep(time.Second * 5) +} + +func Test_eventMeshGRPCClient_Subscribe(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go runFakeServer(ctx) + cli, err := New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 8086, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test-consumer-group-subscribe", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + assert.NoError(t, err, "create grpc client") + type args struct { + item conf.SubscribeItem + handler OnMessage + } + tests := []struct { + name string + args args + wantErr assert.ErrorAssertionFunc + }{ + { + name: "subcribe one", + args: args{ + item: conf.SubscribeItem{ + SubscribeMode: 1, + SubscribeType: 1, + Topic: "topic-1", + }, + handler: func(message *proto.SimpleMessage) interface{} { + t.Logf("receive subscribe response:%s", message.String()) + return nil + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := cli.SubscribeStream(tt.args.item, tt.args.handler) + assert.NoError(t, err) + assert.NoError(t, cli.Close()) + }) + } +} + +func Test_eventMeshGRPCClient_UnSubscribe(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go runFakeServer(ctx) + cli, err := New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 8086, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test-consumer-group-subscribe", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + assert.NoError(t, err, "create grpc client") + err = cli.SubscribeStream(conf.SubscribeItem{ + SubscribeMode: 1, + SubscribeType: 1, + Topic: "topic-1", + }, func(message *proto.SimpleMessage) interface{} { + t.Logf("receive subscribe response:%s", message.String()) + return nil + }) + assert.NoError(t, err, "subscribe err") + tests := []struct { + name string + wantErr assert.ErrorAssertionFunc + }{ + { + name: "unsubcribe", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.NoError(t, cli.UnSubscribe()) + assert.NoError(t, cli.Close()) + }) + } +} + +type fakeidg struct { +} + +func (f *fakeidg) Next() string { + return "fake" +} + +func Test_eventMeshGRPCClient_setupContext(t *testing.T) { + type args struct { + ctx context.Context + } + + cli := &eventMeshGRPCClient{ + idg: &fakeidg{}, + } + tests := []struct { + name string + args args + want string + }{ + { + name: "setup with uid", + args: args{ + ctx: context.WithValue(context.Background(), GRPC_ID_KEY, "value"), + }, + want: "value", + }, + { + name: "setup without uid", + args: args{ + ctx: context.TODO(), + }, + want: "fake", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := cli.setupContext(tt.args.ctx) + assert.Equal(t, ctx.Value(GRPC_ID_KEY).(string), tt.want) + }) + } +} diff --git a/eventmesh-sdk-go/grpc/conf/config.go b/eventmesh-sdk-go/grpc/conf/config.go new file mode 100644 index 0000000000..522bb2a99f --- /dev/null +++ b/eventmesh-sdk-go/grpc/conf/config.go @@ -0,0 +1,155 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package conf + +import ( + "fmt" + "time" +) + +var ( + // Language define the current sdk language + Language = "GO" + // ProtocolDesc the protocol type + ProtocolDesc = "grpc" + + // ProtocolVersion version for current sdk used + ProtocolVersion = "1.0" +) + +// GRPCConfig grpc configuration +type GRPCConfig struct { + // Hosts about the target eventmesh server + Host string `validator:"required"` + // Port port for eventmesh server + Port int `validator:"required"` + // ENV environment for client + ENV string + // Region always be the location + Region string + // IDC idc district + IDC string + // SYS system name + SYS string + // Username to access the eventmesh + Username string + // Password to access the eventmesh + Password string + // ProtocolType the type for current protocol + ProtocolType string + // ConsumerConfig if the client is listen some event + // optional + ConsumerConfig + + // ProducerConfig if the client need to send message + // you should configure it + // optional + ProducerConfig + + // HeartbeatConfig heartbeat configuration + HeartbeatConfig +} + +// LoadBalancerType type for LoadBalancer +type LoadBalancerType string + +var ( + Random LoadBalancerType = "random" + RoundRobin LoadBalancerType = "roundrobin" + IPHash LoadBalancerType = "iphash" +) + +// ProducerConfig configuration producer +type ProducerConfig struct { + // LoadBalancerType load balancer type, support random/roundrobin/iphash + LoadBalancerType LoadBalancerType + // ProducerGroup uniq consumer group for current client + ProducerGroup string +} + +// HeartbeatConfig heartbeat configuration +// required +type HeartbeatConfig struct { + // Period duration to send heartbeat + // default to 5s + Period time.Duration + // Timeout ticker in send heartbeat msg + // default to 3s + Timeout time.Duration +} + +// ConsumerConfig consumer configuration, include subscribe configurations +type ConsumerConfig struct { + // Enabled enable subscribe + Enabled bool + // ConsumerGroup uniq consumergroup for current client + ConsumerGroup string + // PoolSize goroutine pool to dispatch msg for a topic + PoolSize int + // Timeout in handle received msg + // default to 5s + Timeout time.Duration +} + +type SubscriptionMode int + +const ( + CLUSTERING SubscriptionMode = 0 + BROADCASTING SubscriptionMode = 1 +) + +type SubscriptionType int + +const ( + ASYNC = 0 + SYNC = 1 +) + +// SubscribeItem content about subscribe +type SubscribeItem struct { + // Topic uniq for eventmesh + Topic string + // SubscribeType type for subscribe, support as fellow + SubscribeType SubscriptionType + // SubscribeMode mode for subscribe, support as fellow + SubscribeMode SubscriptionMode +} + +// ValidateDefaultConf set the default configuration if user not provided +// check the conf which is required, and return not nil with parameter error +func ValidateDefaultConf(cfg *GRPCConfig) error { + if len(cfg.Host) == 0 { + return fmt.Errorf("no host provided") + } + if cfg.ConsumerConfig.Enabled { + if cfg.ConsumerConfig.ConsumerGroup == "" { + return fmt.Errorf("consumer enabled, but consumer group is empty") + } + } + if cfg.HeartbeatConfig.Timeout == 0 { + cfg.HeartbeatConfig.Timeout = time.Second * 3 + } + if cfg.HeartbeatConfig.Period == 0 { + cfg.HeartbeatConfig.Period = time.Second * 5 + } + if cfg.ConsumerConfig.PoolSize == 0 { + cfg.ConsumerConfig.PoolSize = 5 + } + if cfg.ConsumerConfig.Timeout == 0 { + cfg.ConsumerConfig.Timeout = time.Second * 5 + } + return nil +} diff --git a/eventmesh-sdk-go/grpc/conf/config_test.go b/eventmesh-sdk-go/grpc/conf/config_test.go new file mode 100644 index 0000000000..6b5b32db6d --- /dev/null +++ b/eventmesh-sdk-go/grpc/conf/config_test.go @@ -0,0 +1,78 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package conf + +import "testing" + +func TestValidateDefaultConf(t *testing.T) { + type args struct { + cfg *GRPCConfig + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "test no hosts", + args: args{ + cfg: &GRPCConfig{}, + }, + wantErr: true, + }, + { + name: "test default duration", + args: args{ + cfg: &GRPCConfig{ + Host: "1", + }, + }, + wantErr: false, + }, + { + name: "test consumer enable, but no group", + args: args{ + cfg: &GRPCConfig{ + Host: "1", + ConsumerConfig: ConsumerConfig{ + Enabled: true, + }, + }, + }, + wantErr: true, + }, + { + name: "test consumer enable, but no group", + args: args{ + cfg: &GRPCConfig{ + Host: "1", + ConsumerConfig: ConsumerConfig{ + Enabled: true, + ConsumerGroup: "test", + }, + }, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := ValidateDefaultConf(tt.args.cfg); (err != nil) != tt.wantErr { + t.Errorf("ValidateDefaultConf() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/eventmesh-sdk-go/grpc/consts.go b/eventmesh-sdk-go/grpc/consts.go new file mode 100644 index 0000000000..e487dd8c1b --- /dev/null +++ b/eventmesh-sdk-go/grpc/consts.go @@ -0,0 +1,25 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grpc + +// Success grpc code success +var Success = "0" + +// GRPC_ID_KEY key to indicate the uniq id +var GRPC_ID_KEY = "GRPC_ID_KEY" + +// EVENTMESH_MESSAGE_CONST_TTL msg ttl store in the properties +var EVENTMESH_MESSAGE_CONST_TTL = "ttl" diff --git a/eventmesh-sdk-go/grpc/consumer.go b/eventmesh-sdk-go/grpc/consumer.go new file mode 100644 index 0000000000..26d271a0b6 --- /dev/null +++ b/eventmesh-sdk-go/grpc/consumer.go @@ -0,0 +1,293 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grpc + +import ( + "context" + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/id" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/seq" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + jsoniter "github.com/json-iterator/go" + "google.golang.org/grpc" + "io" + "reflect" + "sync" + "time" +) + +var ( + // ErrSubscribeResponse subscribe response code not ok + ErrSubscribeResponse = fmt.Errorf("subscribe response code err") + // ErrUnSupportResponse only support reflect.String, reflect.Struct, reflect.Ptr, reflect.Map + ErrUnSupportResponse = fmt.Errorf("un support response msg type") + + // defaultTTL default msg ttl + defaultTTL = time.Second * 4 +) + +// eventMeshConsumer consumer to implements the ConsumerService +type eventMeshConsumer struct { + // client subscribe api client + client proto.ConsumerServiceClient + // topics subscribe topics + // map[string]*proto.Subscription_SubscriptionItem + topics *sync.Map + // cfg configuration + cfg *conf.GRPCConfig + // dispatcher for topic + dispatcher *messageDispatcher + // heartbeat used to keepalive with eventmesh + heartbeat *eventMeshHeartbeat + // closeCtx close context + closeCtx context.Context + // streamSubscribeChan chan to receive the subscribe request with stream type + streamSubscribeChan chan *proto.Subscription + // idg generate uniq id + idg id.Interface + // seqg generate sequenced id + seqg seq.Interface +} + +// newConsumer create new consumer +func newConsumer(ctx context.Context, cfg *conf.GRPCConfig, grpcConn *grpc.ClientConn, idg id.Interface, seqg seq.Interface) (*eventMeshConsumer, error) { + cli := proto.NewConsumerServiceClient(grpcConn) + heartbeat, err := newHeartbeat(ctx, cfg, grpcConn) + if err != nil { + log.Warnf("failed to create producer, err:%v", err) + return nil, err + } + return &eventMeshConsumer{ + client: cli, + closeCtx: ctx, + topics: new(sync.Map), + cfg: cfg, + heartbeat: heartbeat, + dispatcher: newMessageDispatcher(cfg.ConsumerConfig.PoolSize, cfg.ConsumerConfig.Timeout), + streamSubscribeChan: make(chan *proto.Subscription, 1024), + idg: idg, + seqg: seqg, + }, nil +} + +// startConsumerStream run stream goroutine to receive the msg send by stream not webhook +func (d *eventMeshConsumer) startConsumerStream() error { + stream, err := d.client.SubscribeStream(d.closeCtx) + if err != nil { + log.Warnf("failed to get subscribe stream, err:%v", err) + return err + } + go func() { + ss := stream + for { + select { + case <-d.closeCtx.Done(): + log.Infof("close consumer subscribe goroutine") + case sub, ok := <-d.streamSubscribeChan: + if ok { + if err := ss.Send(sub); err != nil { + log.Warnf("send subscribe stream msg err:%v", err) + } + } + } + } + }() + go func() { + ss := stream + log.Infof("start receive msg stream") + for { + msg, err := ss.Recv() + if err == io.EOF { + log.Infof("receive msg got io.EOF exit stream") + break + } + if err != nil { + log.Warnf("receive msg got err:%v, need to return", err) + return + } + reply, err := d.dispatcher.onMessage(msg) + if err != nil { + log.Warnf("dispatch msg got err:%v, msgID:%s", err, msg.UniqueId) + continue + } + + if reply == nil { + continue + } + // for async message, do not need to reply it + if !d.needToReply(msg.Topic) { + continue + } + if err := d.replyMsg(msg, reply); err != nil { + log.Warnf("reply msg err:%v, msgID:%s", err, msg.UniqueId) + continue + } + } + log.Infof("close receive stream") + }() + + return nil +} + +func (d *eventMeshConsumer) replyMsg(msg *proto.SimpleMessage, reply interface{}) error { + replyContent := "" + typ := reflect.TypeOf(reply) + switch typ.Kind() { + case reflect.String: + replyContent = reply.(string) + case reflect.Ptr, reflect.Struct, reflect.Map: + jv, err := jsoniter.MarshalToString(reply) + if err != nil { + log.Warnf("failed to unmarshal the response for kind:%v, err:%v, msgID:%s", typ.Kind(), err, msg.UniqueId) + return err + } + replyContent = jv + default: + log.Warnf("un support response msg type:%v", typ.Kind()) + return ErrUnSupportResponse + } + ttl := GetTTLWithDefault(msg, defaultTTL) + d.streamSubscribeChan <- &proto.Subscription{ + Header: msg.Header, + ConsumerGroup: d.cfg.ConsumerGroup, + Reply: &proto.Subscription_Reply{ + ProducerGroup: d.cfg.ConsumerGroup, + Topic: msg.Topic, + Content: replyContent, + Ttl: fmt.Sprintf("%v", ttl.Seconds()), + UniqueId: d.idg.Next(), + SeqNum: d.seqg.Next(), + Tag: msg.Tag, + Properties: msg.Properties, + }, + } + + return nil +} + +// Subscribe topic for webhook +func (d *eventMeshConsumer) Subscribe(item conf.SubscribeItem, callbackURL string) error { + log.Infof("subscribe with webhook topic:%v, url:%s", item, callbackURL) + if callbackURL == "" { + return fmt.Errorf("webhook subscribe err, url is empty") + } + subItem := &proto.Subscription_SubscriptionItem{ + Topic: item.Topic, + Mode: proto.Subscription_SubscriptionItem_SubscriptionMode(item.SubscribeMode), + Type: proto.Subscription_SubscriptionItem_SubscriptionType(item.SubscribeType), + } + subMsg := &proto.Subscription{ + Header: CreateHeader(d.cfg), + ConsumerGroup: d.cfg.ConsumerGroup, + SubscriptionItems: []*proto.Subscription_SubscriptionItem{subItem}, + Url: callbackURL, + } + resp, err := d.client.Subscribe(context.TODO(), subMsg) + if err != nil { + log.Warnf("failed to subscribe topic:%v, err :%v", subItem, err) + return err + } + if resp.RespCode != Success { + log.Warnf("failed to subscribe resp:%v", resp.String()) + return ErrSubscribeResponse + } + d.topics.Store(item.Topic, subItem) + d.heartbeat.addHeartbeat(subItem) + log.Infof("success subscribe with topic:%s, resp:%s", item.Topic, resp.String()) + return nil +} + +// UnSubscribe unsubscribe topic with all eventmesh server +func (d *eventMeshConsumer) UnSubscribe() error { + log.Infof("unsubscribe topics") + resp, err := d.client.Unsubscribe(context.TODO(), &proto.Subscription{ + Header: CreateHeader(d.cfg), + ConsumerGroup: d.cfg.ConsumerGroup, + SubscriptionItems: func() []*proto.Subscription_SubscriptionItem { + var sitems []*proto.Subscription_SubscriptionItem + d.topics.Range(func(key, value interface{}) bool { + sitems = append(sitems, value.(*proto.Subscription_SubscriptionItem)) + return true + }) + return sitems + }(), + }) + if err != nil { + log.Warnf("failed to subscribe topic:%v, err :%v", d.topics, err) + return err + } + log.Infof("success unsubscribe with resp:%s", resp.String()) + + return nil +} + +// SubscribeWithStream subscribe stream, dispatch the message for all topic +func (d *eventMeshConsumer) SubscribeWithStream(item conf.SubscribeItem, handler OnMessage) error { + log.Infof("subscribe stream topic:%v", item) + subItem := &proto.Subscription_SubscriptionItem{ + Topic: item.Topic, + Mode: proto.Subscription_SubscriptionItem_SubscriptionMode(item.SubscribeMode), + Type: proto.Subscription_SubscriptionItem_SubscriptionType(item.SubscribeType), + } + if err := d.addSubscribeHandler(item, handler); err != nil { + return err + } + d.streamSubscribeChan <- &proto.Subscription{ + Header: CreateHeader(d.cfg), + ConsumerGroup: d.cfg.ConsumerGroup, + SubscriptionItems: []*proto.Subscription_SubscriptionItem{subItem}, + } + + log.Infof("success subscribe stream with topic:%s", item.Topic) + return nil +} + +func (d *eventMeshConsumer) addSubscribeHandler(item conf.SubscribeItem, handler OnMessage) error { + subItem := &proto.Subscription_SubscriptionItem{ + Topic: item.Topic, + Mode: proto.Subscription_SubscriptionItem_SubscriptionMode(item.SubscribeMode), + Type: proto.Subscription_SubscriptionItem_SubscriptionType(item.SubscribeType), + } + if err := d.dispatcher.addHandler(item.Topic, handler); err != nil { + log.Warnf("failed to add handler for topic:%s", item.Topic) + return err + } + d.topics.Store(item.Topic, subItem) + d.heartbeat.addHeartbeat(subItem) + return nil +} + +func (d *eventMeshConsumer) close() error { + if d.heartbeat != nil { + if err := d.heartbeat.close(); err != nil { + log.Warnf("failed to close heartbeat:%v", err) + } + d.heartbeat = nil + } + return nil +} + +// needToReply check the message need to reply, only works on RequestReply +func (d *eventMeshConsumer) needToReply(topic string) bool { + val, ok := d.topics.Load(topic) + if !ok { + return false + } + subType := val.(*proto.Subscription_SubscriptionItem) + return subType.Type == proto.Subscription_SubscriptionItem_SYNC +} diff --git a/eventmesh-sdk-go/grpc/dispatcher.go b/eventmesh-sdk-go/grpc/dispatcher.go new file mode 100644 index 0000000000..cb1017bb10 --- /dev/null +++ b/eventmesh-sdk-go/grpc/dispatcher.go @@ -0,0 +1,120 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grpc + +import ( + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "sync" + "time" + + "github.com/panjf2000/ants" +) + +var ( + // ErrTopicDispatcherExist repeated dispatcher for topic + ErrTopicDispatcherExist = fmt.Errorf("already exist dispatcher for given topic") +) + +// pooledHandler internal handler for subscribe message with goroutine pool +type pooledHandler struct { + *ants.Pool + handler OnMessage + timeout time.Duration +} + +// OnMessage redirect the msg with pool +func (p *pooledHandler) OnMessage(msg *proto.SimpleMessage) interface{} { + ch := make(chan interface{}) + if err := p.Submit(func() { + m := *msg + ch <- p.handler(&m) + }); err != nil { + log.Warnf("submit msg to pool err:%v, msgID:%v", err, msg.UniqueId) + return err + } + select { + case <-time.After(p.timeout): + log.Warnf("timeout in wait the response, msgID:%v", msg.UniqueId) + break + case val, ok := <-ch: + if !ok { + log.Warnf("wait response, msg chan closed, msgID:%v", msg.UniqueId) + } else { + if val != nil { + log.Infof("reply for msg:%v", msg.UniqueId) + return val + } + } + } + return nil +} + +// messageDispatcher dispatch the message to different handler according to +// it's topic +type messageDispatcher struct { + // topicMap key is the topic name, value is the SubscribeMessageHandler + topicMap *sync.Map + // poolSize concurrent for dispatch received msg + poolsize int + // timeout to process on message + timeout time.Duration +} + +// newMessageDispatcher create new message dispatcher +func newMessageDispatcher(ps int, tm time.Duration) *messageDispatcher { + return &messageDispatcher{ + topicMap: new(sync.Map), + poolsize: ps, + timeout: tm, + } +} + +// addHandler add msg handler +func (m *messageDispatcher) addHandler(topic string, hdl OnMessage) error { + _, ok := m.topicMap.Load(topic) + if ok { + return ErrTopicDispatcherExist + } + pool, err := ants.NewPool(m.poolsize, ants.WithPanicHandler(func(i interface{}) { + log.Warnf("process message failure, err:%v", i) + })) + if err != nil { + return err + } + m.topicMap.Store(topic, &pooledHandler{ + Pool: pool, + handler: hdl, + timeout: m.timeout, + }) + return nil +} + +// OnMessage dispatch the message by topic +func (m *messageDispatcher) onMessage(msg *proto.SimpleMessage) (interface{}, error) { + // subscribe response ignore it + if msg.Topic == "" { + return nil, nil + } + val, ok := m.topicMap.Load(msg.Topic) + if !ok { + log.Warnf("no dispatch found for topic:%s, drop msg", msg.Topic) + return nil, ErrTopicDispatcherExist + } + ph := val.(*pooledHandler) + return ph.OnMessage(msg), nil +} diff --git a/eventmesh-sdk-go/grpc/dispatcher_test.go b/eventmesh-sdk-go/grpc/dispatcher_test.go new file mode 100644 index 0000000000..49392057fb --- /dev/null +++ b/eventmesh-sdk-go/grpc/dispatcher_test.go @@ -0,0 +1,65 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grpc + +import ( + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" + "github.com/stretchr/testify/assert" + "sync" + "testing" +) + +func Test_messageDispatcher_addHandler(t *testing.T) { + type fields struct { + topicMap *sync.Map + poolsize int + } + type args struct { + topic string + hdl OnMessage + } + tests := []struct { + name string + fields fields + args args + wantErr assert.ErrorAssertionFunc + }{ + { + name: "test add handler", + fields: fields{ + topicMap: new(sync.Map), + poolsize: 5, + }, + args: args{ + topic: "handler-1", + hdl: func(message *proto.SimpleMessage) interface{} { + t.Logf("handle message") + return nil + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &messageDispatcher{ + topicMap: tt.fields.topicMap, + poolsize: tt.fields.poolsize, + } + tt.wantErr(t, m.addHandler(tt.args.topic, tt.args.hdl), fmt.Sprintf("addHandler(%v, %v)", tt.args.topic, tt.args.hdl)) + }) + } +} diff --git a/eventmesh-sdk-go/grpc/fake_grpcserver.go b/eventmesh-sdk-go/grpc/fake_grpcserver.go new file mode 100644 index 0000000000..077e214af3 --- /dev/null +++ b/eventmesh-sdk-go/grpc/fake_grpcserver.go @@ -0,0 +1,208 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grpc + +import ( + "context" + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/seq" + "io" + "io/ioutil" + "net" + "net/http" + "strings" + "sync" + "time" + + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/id" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + + "google.golang.org/grpc" +) + +// fakeServer used to do the test +type fakeServer struct { + proto.UnsafeConsumerServiceServer + proto.UnimplementedPublisherServiceServer + proto.UnimplementedHeartbeatServiceServer + idg id.Interface + seq seq.Interface + closeCtx context.Context +} + +// newFakeServer create new fake grpc server for eventmesh +func runFakeServer(ctx context.Context) error { + lis, err := net.Listen("tcp", ":8086") + if err != nil { + return err + } + f := &fakeServer{ + idg: id.NewUUID(), + seq: seq.NewAtomicSeq(), + closeCtx: ctx, + } + srv := grpc.NewServer() + proto.RegisterConsumerServiceServer(srv, f) + proto.RegisterHeartbeatServiceServer(srv, f) + proto.RegisterPublisherServiceServer(srv, f) + go func() { + select { + case <-ctx.Done(): + srv.GracefulStop() + } + }() + log.Infof("serve fake server on:%v", srv.GetServiceInfo()) + if err := srv.Serve(lis); err != nil { + log.Warnf("create fake server err:%v", err) + return err + } + log.Infof("stop fake server") + return nil +} + +// Subscribe The subscribed event will be delivered by invoking the webhook url in the Subscription +func (f *fakeServer) Subscribe(ctx context.Context, msg *proto.Subscription) (*proto.Response, error) { + log.Infof("fake-server, receive subcribe request:%v", msg.String()) + go func() { + // send a fake msg by webhook + resp, err := http.Post(msg.Url, "Content-Type:application/json", strings.NewReader("msg from webhook")) + if err != nil { + log.Errorf("err in create http webhook url:%s, err:%v", msg.Url, err) + return + } + buf, _ := ioutil.ReadAll(resp.Body) + log.Infof("send webhook msg success", string(buf)) + }() + return &proto.Response{ + RespCode: "0", + RespMsg: "OK", + RespTime: time.Now().Format("2006-01-02 15:04:05"), + }, nil +} + +// SubscribeStream The subscribed event will be delivered through stream of Message +func (f *fakeServer) SubscribeStream(srv proto.ConsumerService_SubscribeStreamServer) error { + wg := new(sync.WaitGroup) + wg.Add(2) + go func() { + defer wg.Done() + for { + sub, err := srv.Recv() + if err == io.EOF { + log.Infof("return sub as rece io.EOF") + break + } + if err != nil { + log.Warnf("return sub as rece err:%v", err) + break + } + log.Infof("rece sub:%s", sub.String()) + } + }() + go func() { + defer wg.Done() + var index int = 0 + for { + msg := &proto.SimpleMessage{ + Header: &proto.RequestHeader{}, + ProducerGroup: "substream-fake-group", + Topic: "fake-topic", + Content: fmt.Sprintf("%v msg from fake server", index), + Ttl: fmt.Sprintf("%v", time.Hour.Seconds()*24), + UniqueId: f.idg.Next(), + SeqNum: f.seq.Next(), + Tag: "substream-fake-tag", + Properties: map[string]string{ + "from": "fake", + "service": "substream", + }, + } + err := srv.Send(msg) + if err == io.EOF { + log.Infof("return send as rece io.EOF") + break + } + if err != nil { + log.Warnf("return send as rece err:%v", err) + break + } + log.Infof("send msg:%s", msg.String()) + index++ + time.Sleep(time.Second * 5) + } + }() + wg.Wait() + log.Infof("close SubscribeStream") + return nil +} + +func (f *fakeServer) Unsubscribe(ctx context.Context, msg *proto.Subscription) (*proto.Response, error) { + log.Infof("fake-server, receive unsubcribe request:%v", msg.String()) + return &proto.Response{ + RespCode: "OK", + RespMsg: "OK", + RespTime: time.Now().Format("2006-01-02 15:04:05"), + }, nil +} + +func (f *fakeServer) Heartbeat(ctx context.Context, msg *proto.Heartbeat) (*proto.Response, error) { + log.Infof("fake-server, receive heartbeat request:%v", msg.String()) + return &proto.Response{ + RespCode: "OK", + RespMsg: "OK", + RespTime: time.Now().Format("2006-01-02 15:04:05"), + }, nil +} + +// Publish Async event publish +func (f *fakeServer) Publish(ctx context.Context, msg *proto.SimpleMessage) (*proto.Response, error) { + log.Infof("fake-server, receive publish request:%v", msg.String()) + return &proto.Response{ + RespCode: "OK", + RespMsg: "OK", + RespTime: time.Now().Format("2006-01-02 15:04:05"), + }, nil +} + +// RequestReply Sync event publish +func (f *fakeServer) RequestReply(ctx context.Context, rece *proto.SimpleMessage) (*proto.SimpleMessage, error) { + log.Infof("receive request reply topic:%s, content:%s", rece.Topic, rece.Content) + return &proto.SimpleMessage{ + Header: rece.Header, + ProducerGroup: "fake-mock-group", + Topic: rece.Topic, + Content: "fake response for request reply" + rece.Content, + Ttl: fmt.Sprintf("%v", time.Hour.Seconds()*24), + UniqueId: f.idg.Next(), + SeqNum: f.seq.Next(), + Tag: "fake-tag", + Properties: map[string]string{ + "from": "fake", + "service": "RequestReply", + }, + }, nil +} + +// BatchPublish Async batch event publish +func (f *fakeServer) BatchPublish(ctx context.Context, rece *proto.BatchMessage) (*proto.Response, error) { + log.Infof("receive batch publish topic:%s, content len:%s", rece.Topic, len(rece.MessageItem)) + return &proto.Response{ + RespCode: "OK", + RespMsg: "Response for batchpublish", + RespTime: time.Now().Format("2006-01-02 15:04:05"), + }, nil +} diff --git a/eventmesh-sdk-go/grpc/fake_webhookserver.go b/eventmesh-sdk-go/grpc/fake_webhookserver.go new file mode 100644 index 0000000000..46ed6a0971 --- /dev/null +++ b/eventmesh-sdk-go/grpc/fake_webhookserver.go @@ -0,0 +1,57 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grpc + +import ( + "context" + "fmt" + "io/ioutil" + "net/http" +) + +// runWebhookServer start a webhook server for fake server on +// subscribe topic with webhook +// need to call srv.Shutdown() to close the http.Server gracefully +func runWebhookServer(ctx context.Context) { + mux := http.NewServeMux() + mux.HandleFunc("/onmessage", func(writer http.ResponseWriter, request *http.Request) { + buf, err := ioutil.ReadAll(request.Body) + if err != nil { + fmt.Printf("read webhook msg from body, err:%v", err) + writer.WriteHeader(http.StatusOK) + writer.Write([]byte("read body err")) + return + } + fmt.Printf("got webhook msg:%s\n", string(buf)) + writer.WriteHeader(http.StatusOK) + writer.Write([]byte("OK")) + }) + srv := &http.Server{ + Addr: ":8080", + Handler: mux, + } + go func() { + if err := srv.ListenAndServe(); err != nil { + return + } + fmt.Println("http server shutdown") + }() + + select { + case <-ctx.Done(): + srv.Shutdown(context.TODO()) + } +} diff --git a/eventmesh-sdk-go/grpc/heartbeat.go b/eventmesh-sdk-go/grpc/heartbeat.go new file mode 100644 index 0000000000..105b1656e6 --- /dev/null +++ b/eventmesh-sdk-go/grpc/heartbeat.go @@ -0,0 +1,136 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grpc + +import ( + "context" + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "google.golang.org/grpc" + "sync" + "time" +) + +var ( + // ErrHeartbeatResp err in sent heartbeat msg to mesh server, response not success + ErrHeartbeatResp = fmt.Errorf("heartbeat response err") +) + +// eventMeshHeartbeat heartbeat to keep the client conn +type eventMeshHeartbeat struct { + // clientsMap hold all grp client to send heartbeat msg + client proto.HeartbeatServiceClient + // cfg the configuration for grpc client + cfg *conf.GRPCConfig + // closeCtx close context + closeCtx context.Context + // subscribeItems subscribe items, heartbeat for these topic + subscribeItems []*proto.Subscription_SubscriptionItem + // subscribeItemsLock lock for subscribeItems + subscribeItemsLock *sync.RWMutex +} + +// newHeartbeat create heartbeat service, and start a goroutine +// with all eventmesh server +func newHeartbeat(ctx context.Context, cfg *conf.GRPCConfig, grpcConn *grpc.ClientConn) (*eventMeshHeartbeat, error) { + cli := proto.NewHeartbeatServiceClient(grpcConn) + heartbeat := &eventMeshHeartbeat{ + client: cli, + cfg: cfg, + closeCtx: ctx, + subscribeItemsLock: new(sync.RWMutex), + } + go heartbeat.run() + return heartbeat, nil +} + +// run the ticker to send heartbeat msg +func (e *eventMeshHeartbeat) run() { + log.Infof("start heartbeat goroutine") + tick := time.NewTicker(e.cfg.Period) + for { + select { + case <-tick.C: + go e.sendMsg(e.client) + case <-e.closeCtx.Done(): + log.Infof("exit heartbeat goroutine as closed") + return + } + } +} + +// sendMsg send heartbeat msg to eventmesh server +func (e *eventMeshHeartbeat) sendMsg(cli proto.HeartbeatServiceClient) error { + log.Debugf("send heartbeat msg to server:%s") + cancelCtx, cancel := context.WithTimeout(e.closeCtx, e.cfg.HeartbeatConfig.Timeout) + defer cancel() + e.subscribeItemsLock.RLock() + defer e.subscribeItemsLock.RUnlock() + msg := &proto.Heartbeat{ + Header: CreateHeader(e.cfg), + ClientType: proto.Heartbeat_SUB, + ConsumerGroup: e.cfg.ConsumerGroup, + HeartbeatItems: func() []*proto.Heartbeat_HeartbeatItem { + var items []*proto.Heartbeat_HeartbeatItem + for _, tp := range e.subscribeItems { + items = append(items, &proto.Heartbeat_HeartbeatItem{ + Topic: tp.Topic, + }) + } + return items + }(), + } + resp, err := cli.Heartbeat(cancelCtx, msg) + if err != nil { + log.Warnf("failed to send heartbeat msg, err:%v", err) + return err + } + if resp.RespCode != Success { + log.Warnf("heartbeat msg return err, resp:%s", resp.String()) + return ErrHeartbeatResp + } + log.Debugf("success send heartbeat to server resp:%s", resp.String()) + return nil +} + +// addHeartbeat add heartbeat for topic +func (e *eventMeshHeartbeat) addHeartbeat(item *proto.Subscription_SubscriptionItem) { + e.subscribeItemsLock.Lock() + defer e.subscribeItemsLock.Unlock() + e.subscribeItems = append(e.subscribeItems, item) +} + +// removeHeartbeat remove heartbeat for topic +func (e *eventMeshHeartbeat) removeHeartbeat(item *proto.Subscription_SubscriptionItem) { + e.subscribeItemsLock.Lock() + defer e.subscribeItemsLock.Unlock() + var newSubscribeItems []*proto.Subscription_SubscriptionItem + for _, it := range e.subscribeItems { + if it.Topic == item.Topic { + continue + } + newSubscribeItems = append(newSubscribeItems, it) + } + e.subscribeItems = newSubscribeItems +} + +// close free the heartbeat resources +func (e *eventMeshHeartbeat) close() error { + log.Infof("close heartbeat") + return nil +} diff --git a/eventmesh-sdk-go/grpc/heartbeat_test.go b/eventmesh-sdk-go/grpc/heartbeat_test.go new file mode 100644 index 0000000000..45f6ed1610 --- /dev/null +++ b/eventmesh-sdk-go/grpc/heartbeat_test.go @@ -0,0 +1,76 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grpc + +import ( + "context" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" + "github.com/stretchr/testify/assert" + "testing" + "time" +) + +func Test_eventMeshHeartbeat_sendMsg(t *testing.T) { + // run fake server + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go runFakeServer(ctx) + cli, err := New(&conf.GRPCConfig{ + Host: "127.0.0.1", + Port: 8086, + ProducerConfig: conf.ProducerConfig{ + ProducerGroup: "test-publish-group", + LoadBalancerType: conf.Random, + }, + ConsumerConfig: conf.ConsumerConfig{ + Enabled: true, + ConsumerGroup: "fake-consumer", + PoolSize: 5, + }, + HeartbeatConfig: conf.HeartbeatConfig{ + Period: time.Second * 5, + Timeout: time.Second * 3, + }, + }) + topic := "fake-topic" + assert.NoError(t, cli.SubscribeStream(conf.SubscribeItem{ + SubscribeType: 1, + SubscribeMode: 1, + Topic: topic, + }, func(message *proto.SimpleMessage) interface{} { + t.Logf("receive sub msg:%v", message.String()) + return nil + })) + rcli := cli.(*eventMeshGRPCClient) + beat := rcli.heartbeat + assert.NoError(t, err, "create grpc client") + defer assert.NoError(t, cli.Close()) + tests := []struct { + name string + want error + }{ + { + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := beat.sendMsg(beat.client) + assert.NoError(t, err) + }) + } +} diff --git a/eventmesh-sdk-go/grpc/loadbalancer/README.md b/eventmesh-sdk-go/grpc/loadbalancer/README.md new file mode 100644 index 0000000000..7f1cbca01d --- /dev/null +++ b/eventmesh-sdk-go/grpc/loadbalancer/README.md @@ -0,0 +1,10 @@ +loadbalancer +=== +provide loadbalancer algorithms for multiple eventmesh grpc server + +support: +1. random, peek one grpc server randomly +2. roundrobin, peek one grpc server with roundrobin, no weight +3. iphash, peek one grpc server with iphash, need to provide the client on choose API + +https://github.com/lafikl/liblb/blob \ No newline at end of file diff --git a/eventmesh-sdk-go/grpc/loadbalancer/loadbalancer.go b/eventmesh-sdk-go/grpc/loadbalancer/loadbalancer.go new file mode 100644 index 0000000000..890162a5e1 --- /dev/null +++ b/eventmesh-sdk-go/grpc/loadbalancer/loadbalancer.go @@ -0,0 +1,102 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package loadbalancer + +import ( + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "go.uber.org/atomic" + "sync" +) + +// LoadBalancer interface to process all grpc client +type LoadBalancer interface { + // GetAllStatusServer return all status server in the lb + GetAllStatusServer() []*StatusServer + + // GetAvailableServer available servers which is ready for service + GetAvailableServer() []*StatusServer + + // AddServer add servers to LoadBalancer + AddServer([]*StatusServer) + + // Choose peek client with rule inside + Choose(input interface{}) (interface{}, error) +} + +// BaseLoadBalancer loadbalancer instance +type BaseLoadBalancer struct { + servers []*StatusServer + lock *sync.RWMutex + rule Rule +} + +// NewLoadBalancer create new loadbalancer with lb type and servers +func NewLoadBalancer(lbType conf.LoadBalancerType, srvs []*StatusServer) (LoadBalancer, error) { + lb := &BaseLoadBalancer{ + servers: srvs, + lock: new(sync.RWMutex), + } + switch lbType { + case conf.IPHash: + lb.rule = &IPHashRule{BaseRule{ + lb: lb, + }} + case conf.Random: + lb.rule = &RandomRule{BaseRule{ + lb: lb, + }} + case conf.RoundRobin: + lb.rule = &RoundRobinRule{ + cycleCounter: atomic.NewInt64(-1), + BaseRule: BaseRule{lb: lb}, + } + default: + return nil, fmt.Errorf("invalid load balancer rule:%v", lbType) + } + + return lb, nil +} + +// AddServer add servers to the lb +func (b *BaseLoadBalancer) AddServer(srvs []*StatusServer) { + b.lock.Lock() + defer b.lock.Unlock() + b.servers = append(b.servers, srvs...) +} + +// Choose choose server in current lb +func (b *BaseLoadBalancer) Choose(input interface{}) (interface{}, error) { + return b.rule.Choose(input) +} + +func (b *BaseLoadBalancer) GetAllStatusServer() []*StatusServer { + b.lock.RLock() + defer b.lock.RUnlock() + return b.servers +} + +func (b *BaseLoadBalancer) GetAvailableServer() []*StatusServer { + b.lock.RLock() + defer b.lock.RUnlock() + var asrvs []*StatusServer + for _, r := range b.servers { + if r.ReadyForService { + asrvs = append(asrvs, r) + } + } + return asrvs +} diff --git a/eventmesh-sdk-go/grpc/loadbalancer/loadbalancer_test.go b/eventmesh-sdk-go/grpc/loadbalancer/loadbalancer_test.go new file mode 100644 index 0000000000..b3eb916230 --- /dev/null +++ b/eventmesh-sdk-go/grpc/loadbalancer/loadbalancer_test.go @@ -0,0 +1,202 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package loadbalancer + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/stretchr/testify/assert" + "sync" + "testing" +) + +func TestNewLoadBalancer(t *testing.T) { + type args struct { + lbType conf.LoadBalancerType + srvs []*StatusServer + } + tests := []struct { + name string + args args + want LoadBalancer + wantErr bool + }{ + { + name: "lb with random", + args: args{ + srvs: []*StatusServer{}, + lbType: conf.Random, + }, + want: nil, + wantErr: false, + }, + { + name: "lb with roundrobin", + args: args{ + srvs: []*StatusServer{}, + lbType: conf.RoundRobin, + }, + want: nil, + wantErr: false, + }, + { + name: "lb with iphash", + args: args{ + srvs: []*StatusServer{}, + lbType: conf.IPHash, + }, + want: nil, + wantErr: false, + }, + { + name: "lb without type", + args: args{ + srvs: []*StatusServer{}, + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := NewLoadBalancer(tt.args.lbType, tt.args.srvs) + if (err != nil) != tt.wantErr { + t.Errorf("NewLoadBalancer() error = %v, wantErr %v", err, tt.wantErr) + return + } + }) + } +} + +func TestBaseLoadBalancer_AddServer(t *testing.T) { + type fields struct { + servers []*StatusServer + lock *sync.RWMutex + rule Rule + } + type args struct { + srvs []*StatusServer + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "add srv", + fields: fields{ + servers: []*StatusServer{}, + lock: new(sync.RWMutex), + rule: &RoundRobinRule{}, + }, + args: args{ + srvs: []*StatusServer{{ + RealServer: "", + Host: "127.1.1.1", + ReadyForService: false, + }}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &BaseLoadBalancer{ + servers: tt.fields.servers, + lock: tt.fields.lock, + rule: tt.fields.rule, + } + b.AddServer(tt.args.srvs) + assert.Equal(t, len(tt.args.srvs), len(b.GetAllStatusServer())) + }) + } +} + +func TestBaseLoadBalancer_GetAllStatusServer(t *testing.T) { + type fields struct { + servers []*StatusServer + lock *sync.RWMutex + rule Rule + } + tests := []struct { + name string + fields fields + want int + }{ + { + name: "", + fields: fields{ + servers: []*StatusServer{{ + RealServer: "1", + ReadyForService: true, + Host: "127.0.0.1", + }}, + lock: new(sync.RWMutex), + rule: &RoundRobinRule{}, + }, + want: 1, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &BaseLoadBalancer{ + servers: tt.fields.servers, + lock: tt.fields.lock, + rule: tt.fields.rule, + } + assert.Equalf(t, tt.want, len(b.GetAllStatusServer()), "GetAllStatusServer()") + }) + } +} + +func TestBaseLoadBalancer_GetAvailableServer(t *testing.T) { + type fields struct { + servers []*StatusServer + lock *sync.RWMutex + rule Rule + } + tests := []struct { + name string + fields fields + want int + }{ + { + name: "1 ok", + fields: fields{ + servers: []*StatusServer{{ + RealServer: "1", + ReadyForService: true, + Host: "127.0.0.1", + }, { + RealServer: "2", + ReadyForService: false, + Host: "127.0.0.2", + }}, + lock: new(sync.RWMutex), + rule: &RoundRobinRule{}, + }, + want: 1, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := &BaseLoadBalancer{ + servers: tt.fields.servers, + lock: tt.fields.lock, + rule: tt.fields.rule, + } + assert.Equalf(t, tt.want, len(b.GetAvailableServer()), "GetAvailableServer()") + }) + } +} diff --git a/eventmesh-sdk-go/grpc/loadbalancer/rule.go b/eventmesh-sdk-go/grpc/loadbalancer/rule.go new file mode 100644 index 0000000000..3748f29983 --- /dev/null +++ b/eventmesh-sdk-go/grpc/loadbalancer/rule.go @@ -0,0 +1,40 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package loadbalancer + +import "fmt" + +var ( + ErrNoServerFound = fmt.Errorf("no server found") + ErrInvalidInput = fmt.Errorf("invalidate input") +) + +// Rule for loadbalancer algorithms +type Rule interface { + // Choose return the instance by rule + Choose(interface{}) (interface{}, error) +} + +// BaseRule base rule for all implements, holds the lb to +// fetch the latest server lists +type BaseRule struct { + lb LoadBalancer +} + +// SetLoadBalancer set the lb for current rule +func (b *BaseRule) SetLoadBalancer(balancer LoadBalancer) { + b.lb = balancer +} diff --git a/eventmesh-sdk-go/grpc/loadbalancer/rule_iphash.go b/eventmesh-sdk-go/grpc/loadbalancer/rule_iphash.go new file mode 100644 index 0000000000..dfde0e735f --- /dev/null +++ b/eventmesh-sdk-go/grpc/loadbalancer/rule_iphash.go @@ -0,0 +1,48 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package loadbalancer + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "github.com/cespare/xxhash" + "reflect" + "unsafe" +) + +// IPHashRule iphash rule +type IPHashRule struct { + BaseRule +} + +// Choose return the instance by ip hash +// the input must be ip +func (i *IPHashRule) Choose(ip interface{}) (interface{}, error) { + host, ok := ip.(string) + if !ok { + log.Warnf("provide host not a string type:%s", reflect.TypeOf(ip).String()) + return nil, ErrInvalidInput + } + srvs := i.lb.GetAvailableServer() + if len(srvs) == 0 { + log.Warnf("no available server found, load all server instead") + srvs = i.lb.GetAllStatusServer() + } + count := len(srvs) + hashN := xxhash.Sum64(*(*[]byte)(unsafe.Pointer(&host))) % uint64(count) + srv := srvs[hashN] + log.Debugf("success peek host:%s by iphash, input:%v", srv.Host, ip) + return srv, nil +} diff --git a/eventmesh-sdk-go/grpc/loadbalancer/rule_iphash_test.go b/eventmesh-sdk-go/grpc/loadbalancer/rule_iphash_test.go new file mode 100644 index 0000000000..7375c78f3e --- /dev/null +++ b/eventmesh-sdk-go/grpc/loadbalancer/rule_iphash_test.go @@ -0,0 +1,98 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package loadbalancer + +import ( + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestIPHashRule_Choose(t *testing.T) { + type fields struct { + BaseRule BaseRule + } + type args struct { + ip interface{} + } + fled := fields{ + BaseRule: func() BaseRule { + lb, _ := NewLoadBalancer(conf.IPHash, []*StatusServer{ + { + RealServer: "127.0.0.1", + ReadyForService: true, + Host: "127.0.0.1", + }, + { + RealServer: "127.0.0.2", + ReadyForService: true, + Host: "127.0.0.2", + }, + { + RealServer: "127.0.0.3", + ReadyForService: true, + Host: "127.0.0.3", + }, + }) + return BaseRule{ + lb: lb, + } + }(), + } + tests := []struct { + name string + fields fields + args args + want interface{} + wantErr assert.ErrorAssertionFunc + }{ + { + name: "iphash with 1", + fields: fled, + args: args{ + ip: "127.1.1.1", + }, + wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + return false + }, + want: "127.0.0.1", + }, + { + name: "iphash with 2", + fields: fled, + args: args{ + ip: "168.1.1.2", + }, + wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + return true + }, + want: "127.0.0.2", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + i := &IPHashRule{ + BaseRule: tt.fields.BaseRule, + } + got, err := i.Choose(tt.args.ip) + if !tt.wantErr(t, err, fmt.Sprintf("Choose(%v)", tt.args.ip)) { + return + } + assert.Equalf(t, tt.want, got.(*StatusServer).Host, "Choose(%v)", tt.args.ip) + }) + } +} diff --git a/eventmesh-sdk-go/grpc/loadbalancer/rule_random.go b/eventmesh-sdk-go/grpc/loadbalancer/rule_random.go new file mode 100644 index 0000000000..03b8011986 --- /dev/null +++ b/eventmesh-sdk-go/grpc/loadbalancer/rule_random.go @@ -0,0 +1,53 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package loadbalancer + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "math/rand" +) + +// RandomRule random rule by math.Random +type RandomRule struct { + BaseRule +} + +// Choose return the instance by random +// the input must be ip +func (r *RandomRule) Choose(interface{}) (interface{}, error) { + count := 0 + for { + if count == 64 { + log.Warnf("failed to peek server by roundrobin after try 64 times") + return nil, ErrNoServerFound + } + srvs := r.lb.GetAvailableServer() + if len(srvs) == 0 { + log.Warnf("no available server found, load all server instead") + srvs = r.lb.GetAllStatusServer() + } + serverCount := len(srvs) + rdi := rand.Int63n(int64(serverCount)) + srv := srvs[rdi] + if !srv.ReadyForService { + count++ + continue + } + + log.Debugf("success peek server:%s by random", srv.Host) + return srv, nil + } +} diff --git a/eventmesh-sdk-go/grpc/loadbalancer/rule_random_test.go b/eventmesh-sdk-go/grpc/loadbalancer/rule_random_test.go new file mode 100644 index 0000000000..9eaec0b6dd --- /dev/null +++ b/eventmesh-sdk-go/grpc/loadbalancer/rule_random_test.go @@ -0,0 +1,87 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package loadbalancer + +import ( + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestRandomRule_Choose(t *testing.T) { + type fields struct { + BaseRule BaseRule + } + type args struct { + in0 interface{} + } + fled := fields{ + BaseRule: func() BaseRule { + lb, _ := NewLoadBalancer(conf.Random, []*StatusServer{ + { + RealServer: "127.0.0.1", + ReadyForService: true, + Host: "127.0.0.1", + }, + { + RealServer: "127.0.0.2", + ReadyForService: true, + Host: "127.0.0.2", + }, + { + RealServer: "127.0.0.3", + ReadyForService: true, + Host: "127.0.0.3", + }, + }) + return BaseRule{ + lb: lb, + } + }(), + } + tests := []struct { + name string + fields fields + args args + want interface{} + wantErr assert.ErrorAssertionFunc + }{ + { + name: "random one", + fields: fled, + args: args{ + in0: "", + }, + want: "", + wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + return true + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &RandomRule{ + BaseRule: tt.fields.BaseRule, + } + got, err := r.Choose(tt.args.in0) + if !tt.wantErr(t, err, fmt.Sprintf("Choose(%v)", tt.args.in0)) { + return + } + assert.NotEmpty(t, got, "Choose(%v)", tt.args.in0) + }) + } +} diff --git a/eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin.go b/eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin.go new file mode 100644 index 0000000000..bf12d1847c --- /dev/null +++ b/eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin.go @@ -0,0 +1,64 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package loadbalancer + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "go.uber.org/atomic" +) + +// RoundRobinRule rule with roundrobin algorithm +type RoundRobinRule struct { + BaseRule + cycleCounter *atomic.Int64 +} + +// Choose return the instance by roundrobin +// the input must be ip +func (r *RoundRobinRule) Choose(interface{}) (interface{}, error) { + count := 0 + for { + if count == 64 { + log.Warnf("failed to peek server by roundrobin after try 64 times") + return nil, ErrNoServerFound + } + srvs := r.lb.GetAvailableServer() + if len(srvs) == 0 { + log.Warnf("no available server found, load all server instead") + srvs = r.lb.GetAllStatusServer() + } + serverCount := len(srvs) + nextIndex := r.incrementAndGetModulo(int64(serverCount)) + srv := srvs[nextIndex] + if !srv.ReadyForService { + continue + count++ + } + log.Debugf("success peek server:%s by roundrobin", srv.Host) + return srv, nil + } +} + +// incrementAndGetModulo calculate to get the next modulo +func (r *RoundRobinRule) incrementAndGetModulo(modulo int64) int64 { + for { + current := r.cycleCounter.Load() + next := (current + 1) % modulo + if r.cycleCounter.CAS(current, next) { + return next + } + } +} diff --git a/eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin_test.go b/eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin_test.go new file mode 100644 index 0000000000..986f163268 --- /dev/null +++ b/eventmesh-sdk-go/grpc/loadbalancer/rule_roundrobin_test.go @@ -0,0 +1,93 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package loadbalancer + +import ( + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/stretchr/testify/assert" + "go.uber.org/atomic" + "testing" +) + +func TestRoundRobinRule_Choose(t *testing.T) { + type fields struct { + BaseRule BaseRule + cycleCounter *atomic.Int64 + } + type args struct { + in0 interface{} + } + fid := fields{ + BaseRule: func() BaseRule { + lb, _ := NewLoadBalancer(conf.RoundRobin, []*StatusServer{ + { + RealServer: "127.0.0.1", + ReadyForService: true, + Host: "127.0.0.1", + }, + { + RealServer: "127.0.0.2", + ReadyForService: true, + Host: "127.0.0.2", + }, + { + RealServer: "127.0.0.3", + ReadyForService: true, + Host: "127.0.0.3", + }, + }) + return BaseRule{ + lb: lb, + } + }(), + cycleCounter: atomic.NewInt64(-1), + } + tests := []struct { + name string + fields fields + args args + want interface{} + wantErr assert.ErrorAssertionFunc + }{ + { + name: "round1 always be first", + fields: fid, + args: args{ + in0: "", + }, + want: "127.0.0.1", + wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + return true + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &RoundRobinRule{ + BaseRule: tt.fields.BaseRule, + cycleCounter: tt.fields.cycleCounter, + } + for _, v := range []string{"127.0.0.1", "127.0.0.2", "127.0.0.3", "127.0.0.1", "127.0.0.2"} { + got, err := r.Choose(tt.args.in0) + if !tt.wantErr(t, err, fmt.Sprintf("Choose(%v)", tt.args.in0)) { + return + } + assert.Equalf(t, v, got.(*StatusServer).Host, "Choose(%v)", tt.args.in0) + } + }) + } +} diff --git a/eventmesh-sdk-go/grpc/loadbalancer/status_server.go b/eventmesh-sdk-go/grpc/loadbalancer/status_server.go new file mode 100644 index 0000000000..d43d419ac7 --- /dev/null +++ b/eventmesh-sdk-go/grpc/loadbalancer/status_server.go @@ -0,0 +1,43 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package loadbalancer + +import "fmt" + +// StatusServer server with status check +type StatusServer struct { + // ReadyForService indicate the remote is connected + // and ready for service for client + ReadyForService bool + // Host holds the eventmesh server host + Host string + // RealServer holds the grpc client, producer/consumer/heartbeat + RealServer interface{} +} + +// NewStatusServer create new status server +func NewStatusServer(in interface{}, host string) *StatusServer { + return &StatusServer{ + RealServer: in, + Host: host, + ReadyForService: true, + } +} + +// String return the description about the server +func (s *StatusServer) String() string { + return fmt.Sprintf("removeAddr:%s, readyForService:%v", s.Host, s.ReadyForService) +} diff --git a/eventmesh-sdk-go/grpc/loadbalancer/status_server_test.go b/eventmesh-sdk-go/grpc/loadbalancer/status_server_test.go new file mode 100644 index 0000000000..fa78212cea --- /dev/null +++ b/eventmesh-sdk-go/grpc/loadbalancer/status_server_test.go @@ -0,0 +1,55 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package loadbalancer + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestStatusServer_String(t *testing.T) { + type fields struct { + ReadyForService bool + Host string + RealServer interface{} + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "test string", + fields: fields{ + RealServer: "srv", + ReadyForService: true, + Host: "127.0.0.1", + }, + want: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &StatusServer{ + ReadyForService: tt.fields.ReadyForService, + Host: tt.fields.Host, + RealServer: tt.fields.RealServer, + } + assert.NotEmpty(t, s.String(), "String()") + t.Logf(s.String()) + }) + } +} diff --git a/eventmesh-sdk-go/grpc/msg.go b/eventmesh-sdk-go/grpc/msg.go new file mode 100644 index 0000000000..08bc8492ab --- /dev/null +++ b/eventmesh-sdk-go/grpc/msg.go @@ -0,0 +1,123 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grpc + +import ( + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/conf" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" + "time" +) + +// SimpleMessageBuilder used to build the simple message +type SimpleMessageBuilder struct { + *proto.SimpleMessage +} + +// NewMessageBuilder +func NewMessageBuilder() *SimpleMessageBuilder { + return &SimpleMessageBuilder{SimpleMessage: &proto.SimpleMessage{}} +} + +// WithHeader set the header for message +func (m *SimpleMessageBuilder) WithHeader(h *proto.RequestHeader) *SimpleMessageBuilder { + m.Header = h + return m +} + +// WithProducerGroup set the message producer group +func (m *SimpleMessageBuilder) WithProducerGroup(grp string) *SimpleMessageBuilder { + m.ProducerGroup = grp + return m +} + +// WithTopic set the topic +func (m *SimpleMessageBuilder) WithTopic(topic string) *SimpleMessageBuilder { + m.Topic = topic + return m +} + +// WithContent set the content to message +func (m *SimpleMessageBuilder) WithContent(content string) *SimpleMessageBuilder { + m.Content = content + return m +} + +// WithTTL set the message ttl +func (m *SimpleMessageBuilder) WithTTL(ttl time.Duration) *SimpleMessageBuilder { + m.Ttl = fmt.Sprintf("%v", ttl.Seconds()) + return m +} + +// WithTag set the tag for message +func (m *SimpleMessageBuilder) WithTag(tag string) *SimpleMessageBuilder { + m.Tag = tag + return m +} + +// WithUniqueID set the uniq id for message +func (m *SimpleMessageBuilder) WithUniqueID(id string) *SimpleMessageBuilder { + m.UniqueId = id + return m +} + +// WithSeqNO set the sequence no for message +func (m *SimpleMessageBuilder) WithSeqNO(no string) *SimpleMessageBuilder { + m.SeqNum = no + return m +} + +// WithProperties set the properties for message +func (m *SimpleMessageBuilder) WithProperties(props map[string]string) *SimpleMessageBuilder { + m.Properties = props + return m +} + +// CreateHeader create msg header +func CreateHeader(cfg *conf.GRPCConfig) *proto.RequestHeader { + return &proto.RequestHeader{ + Env: cfg.ENV, + Region: cfg.Region, + Idc: cfg.IDC, + Ip: utils.HostIPV4(), + Pid: utils.CurrentPID(), + Sys: cfg.SYS, + Username: cfg.Username, + Password: cfg.Password, + Language: conf.Language, + ProtocolType: EventmeshMessage, + ProtocolDesc: conf.ProtocolDesc, + ProtocolVersion: conf.ProtocolVersion, + } +} + +// GetTTLWithDefault return the ttl for the given msg, if err occurred return default +func GetTTLWithDefault(msg *proto.SimpleMessage, def time.Duration) time.Duration { + if msg == nil { + return def + } + val, ok := msg.Properties[EVENTMESH_MESSAGE_CONST_TTL] + if !ok { + return def + } + + tm, err := time.ParseDuration(val) + if err != nil { + return def + } + return tm +} diff --git a/eventmesh-sdk-go/grpc/option.go b/eventmesh-sdk-go/grpc/option.go new file mode 100644 index 0000000000..c5942f1b3a --- /dev/null +++ b/eventmesh-sdk-go/grpc/option.go @@ -0,0 +1,45 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grpc + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/id" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/seq" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" +) + +// GRPCOption option to set up the option for grpc client +type GRPCOption func(*eventMeshGRPCClient) + +// WithLogger set the logger for client, replace with the default +func WithLogger(l log.Logger) GRPCOption { + return func(client *eventMeshGRPCClient) { + log.SetLogger(l) + } +} + +// WithIDG setup the id generate api +func WithIDG(i id.Interface) GRPCOption { + return func(client *eventMeshGRPCClient) { + client.idg = i + } +} + +func WithSeq(i seq.Interface) GRPCOption { + return func(client *eventMeshGRPCClient) { + client.seqg = i + } +} diff --git a/eventmesh-sdk-go/grpc/producer.go b/eventmesh-sdk-go/grpc/producer.go new file mode 100644 index 0000000000..f4d77a5616 --- /dev/null +++ b/eventmesh-sdk-go/grpc/producer.go @@ -0,0 +1,92 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grpc + +import ( + "context" + "fmt" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/grpc/proto" + "google.golang.org/grpc" +) + +var ( + ErrNoMeshServer = fmt.Errorf("no event mesh server provided") + ErrLoadBalancer = fmt.Errorf("can not peek status server from loadbalancer") + + // LoadBalancerInput key set in the context, used to store the parameter + // into context, such as clientIP in IPHash + LoadBalancerInput = "LoadBalancerInput" +) + +// eventMeshProducer producer for eventmesh +type eventMeshProducer struct { + // client grpc producer client + client proto.PublisherServiceClient +} + +// newProducer create new producer instance to send events +func newProducer(grpcConn *grpc.ClientConn) (*eventMeshProducer, error) { + return &eventMeshProducer{ + client: proto.NewPublisherServiceClient(grpcConn), + }, nil +} + +// Close recover all resource hold in the producer +func (e *eventMeshProducer) Close() error { + log.Infof("close eventmesh producer") + return nil +} + +// Publish Async event publish +func (e *eventMeshProducer) Publish(ctx context.Context, msg *proto.SimpleMessage, opts ...grpc.CallOption) (*proto.Response, error) { + log.Infof("publish event:%v", msg.String()) + resp, err := e.client.Publish(ctx, msg, opts...) + if err != nil { + log.Warnf("failed to publish msg, err:%v", err) + return nil, err + } + + log.Infof("success publish msg:%s", msg.String()) + return resp, nil +} + +// RequestReply Sync event publish +func (e *eventMeshProducer) RequestReply(ctx context.Context, msg *proto.SimpleMessage, opts ...grpc.CallOption) (*proto.SimpleMessage, error) { + log.Infof("request reply event:%v", msg.String()) + resp, err := e.client.RequestReply(ctx, msg, opts...) + if err != nil { + log.Warnf("failed to request reply msg, err:%v", err) + return nil, err + } + + log.Infof("success request reply event") + return resp, nil +} + +// BatchPublish Async batch event publish +func (e *eventMeshProducer) BatchPublish(ctx context.Context, msg *proto.BatchMessage, opts ...grpc.CallOption) (*proto.Response, error) { + log.Infof("request batch publish event:%v", msg.String()) + resp, err := e.client.BatchPublish(ctx, msg, opts...) + if err != nil { + log.Warnf("failed to batch publish msg, err:%v", err) + return nil, err + } + + log.Infof("success batch publish event") + return resp, nil +} diff --git a/eventmesh-sdk-go/grpc/proto/README.md b/eventmesh-sdk-go/grpc/proto/README.md new file mode 100644 index 0000000000..8210f63c86 --- /dev/null +++ b/eventmesh-sdk-go/grpc/proto/README.md @@ -0,0 +1,20 @@ +how to generate proto go files +--- +generate go files by the protoc-gen-go owned by Google + +1. install the latest protoc-gen-go and protoc-gen-go-grpc +``` +go install google.golang.org/protobuf/cmd/protoc-gen-go +go install google.golang.org/grpc/cmd/protoc-gen-go-grpc +``` +2. run command +``` +protoc --go_out=. eventmesh-client.proto +protoc --go-grpc_out=. eventmesh-client.proto +``` + +if you use the latest version protoc-gen-go, and generate by the old command, you will got these error: +``` +--go_out: protoc-gen-go: plugins are not supported; use 'protoc --go-grpc_out=...' to generate gRPC +``` + diff --git a/eventmesh-sdk-go/grpc/proto/eventmesh-client.pb.go b/eventmesh-sdk-go/grpc/proto/eventmesh-client.pb.go new file mode 100644 index 0000000000..a3e79e4f29 --- /dev/null +++ b/eventmesh-sdk-go/grpc/proto/eventmesh-client.pb.go @@ -0,0 +1,1485 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.19.4 +// source: eventmesh-client.proto + +//package eventmesh.common.protocol.grpc; +// +//option java_multiple_files = true; +//option java_package = "org.apache.eventmesh.common.protocol.grpc.protos"; +//option java_outer_classname = "EventmeshGrpc"; + +// make sure the protoc and protoc-gen-go is installed on your machine, and has set +// its directory into path +// download protoc: https://github.com/protocolbuffers/protobuf/releases +// install protoc-gen-go: go install google.golang.org/protobuf/cmd/protoc-gen-go +// generate go code by protoc: protoc --go_out=. eventmesh-client.proto + +package proto + +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 Subscription_SubscriptionItem_SubscriptionMode int32 + +const ( + Subscription_SubscriptionItem_CLUSTERING Subscription_SubscriptionItem_SubscriptionMode = 0 + Subscription_SubscriptionItem_BROADCASTING Subscription_SubscriptionItem_SubscriptionMode = 1 +) + +// Enum value maps for Subscription_SubscriptionItem_SubscriptionMode. +var ( + Subscription_SubscriptionItem_SubscriptionMode_name = map[int32]string{ + 0: "CLUSTERING", + 1: "BROADCASTING", + } + Subscription_SubscriptionItem_SubscriptionMode_value = map[string]int32{ + "CLUSTERING": 0, + "BROADCASTING": 1, + } +) + +func (x Subscription_SubscriptionItem_SubscriptionMode) Enum() *Subscription_SubscriptionItem_SubscriptionMode { + p := new(Subscription_SubscriptionItem_SubscriptionMode) + *p = x + return p +} + +func (x Subscription_SubscriptionItem_SubscriptionMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Subscription_SubscriptionItem_SubscriptionMode) Descriptor() protoreflect.EnumDescriptor { + return file_eventmesh_client_proto_enumTypes[0].Descriptor() +} + +func (Subscription_SubscriptionItem_SubscriptionMode) Type() protoreflect.EnumType { + return &file_eventmesh_client_proto_enumTypes[0] +} + +func (x Subscription_SubscriptionItem_SubscriptionMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Subscription_SubscriptionItem_SubscriptionMode.Descriptor instead. +func (Subscription_SubscriptionItem_SubscriptionMode) EnumDescriptor() ([]byte, []int) { + return file_eventmesh_client_proto_rawDescGZIP(), []int{4, 0, 0} +} + +type Subscription_SubscriptionItem_SubscriptionType int32 + +const ( + Subscription_SubscriptionItem_ASYNC Subscription_SubscriptionItem_SubscriptionType = 0 + Subscription_SubscriptionItem_SYNC Subscription_SubscriptionItem_SubscriptionType = 1 +) + +// Enum value maps for Subscription_SubscriptionItem_SubscriptionType. +var ( + Subscription_SubscriptionItem_SubscriptionType_name = map[int32]string{ + 0: "ASYNC", + 1: "SYNC", + } + Subscription_SubscriptionItem_SubscriptionType_value = map[string]int32{ + "ASYNC": 0, + "SYNC": 1, + } +) + +func (x Subscription_SubscriptionItem_SubscriptionType) Enum() *Subscription_SubscriptionItem_SubscriptionType { + p := new(Subscription_SubscriptionItem_SubscriptionType) + *p = x + return p +} + +func (x Subscription_SubscriptionItem_SubscriptionType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Subscription_SubscriptionItem_SubscriptionType) Descriptor() protoreflect.EnumDescriptor { + return file_eventmesh_client_proto_enumTypes[1].Descriptor() +} + +func (Subscription_SubscriptionItem_SubscriptionType) Type() protoreflect.EnumType { + return &file_eventmesh_client_proto_enumTypes[1] +} + +func (x Subscription_SubscriptionItem_SubscriptionType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Subscription_SubscriptionItem_SubscriptionType.Descriptor instead. +func (Subscription_SubscriptionItem_SubscriptionType) EnumDescriptor() ([]byte, []int) { + return file_eventmesh_client_proto_rawDescGZIP(), []int{4, 0, 1} +} + +type Heartbeat_ClientType int32 + +const ( + Heartbeat_PUB Heartbeat_ClientType = 0 + Heartbeat_SUB Heartbeat_ClientType = 1 +) + +// Enum value maps for Heartbeat_ClientType. +var ( + Heartbeat_ClientType_name = map[int32]string{ + 0: "PUB", + 1: "SUB", + } + Heartbeat_ClientType_value = map[string]int32{ + "PUB": 0, + "SUB": 1, + } +) + +func (x Heartbeat_ClientType) Enum() *Heartbeat_ClientType { + p := new(Heartbeat_ClientType) + *p = x + return p +} + +func (x Heartbeat_ClientType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Heartbeat_ClientType) Descriptor() protoreflect.EnumDescriptor { + return file_eventmesh_client_proto_enumTypes[2].Descriptor() +} + +func (Heartbeat_ClientType) Type() protoreflect.EnumType { + return &file_eventmesh_client_proto_enumTypes[2] +} + +func (x Heartbeat_ClientType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Heartbeat_ClientType.Descriptor instead. +func (Heartbeat_ClientType) EnumDescriptor() ([]byte, []int) { + return file_eventmesh_client_proto_rawDescGZIP(), []int{5, 0} +} + +type RequestHeader struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Env string `protobuf:"bytes,1,opt,name=env,proto3" json:"env,omitempty"` + Region string `protobuf:"bytes,2,opt,name=region,proto3" json:"region,omitempty"` + Idc string `protobuf:"bytes,3,opt,name=idc,proto3" json:"idc,omitempty"` + Ip string `protobuf:"bytes,4,opt,name=ip,proto3" json:"ip,omitempty"` + Pid string `protobuf:"bytes,5,opt,name=pid,proto3" json:"pid,omitempty"` + Sys string `protobuf:"bytes,6,opt,name=sys,proto3" json:"sys,omitempty"` + Username string `protobuf:"bytes,7,opt,name=username,proto3" json:"username,omitempty"` + Password string `protobuf:"bytes,8,opt,name=password,proto3" json:"password,omitempty"` + Language string `protobuf:"bytes,9,opt,name=language,proto3" json:"language,omitempty"` + ProtocolType string `protobuf:"bytes,10,opt,name=protocolType,proto3" json:"protocolType,omitempty"` + ProtocolVersion string `protobuf:"bytes,11,opt,name=protocolVersion,proto3" json:"protocolVersion,omitempty"` + ProtocolDesc string `protobuf:"bytes,12,opt,name=protocolDesc,proto3" json:"protocolDesc,omitempty"` +} + +func (x *RequestHeader) Reset() { + *x = RequestHeader{} + if protoimpl.UnsafeEnabled { + mi := &file_eventmesh_client_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestHeader) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestHeader) ProtoMessage() {} + +func (x *RequestHeader) ProtoReflect() protoreflect.Message { + mi := &file_eventmesh_client_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 RequestHeader.ProtoReflect.Descriptor instead. +func (*RequestHeader) Descriptor() ([]byte, []int) { + return file_eventmesh_client_proto_rawDescGZIP(), []int{0} +} + +func (x *RequestHeader) GetEnv() string { + if x != nil { + return x.Env + } + return "" +} + +func (x *RequestHeader) GetRegion() string { + if x != nil { + return x.Region + } + return "" +} + +func (x *RequestHeader) GetIdc() string { + if x != nil { + return x.Idc + } + return "" +} + +func (x *RequestHeader) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *RequestHeader) GetPid() string { + if x != nil { + return x.Pid + } + return "" +} + +func (x *RequestHeader) GetSys() string { + if x != nil { + return x.Sys + } + return "" +} + +func (x *RequestHeader) GetUsername() string { + if x != nil { + return x.Username + } + return "" +} + +func (x *RequestHeader) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *RequestHeader) GetLanguage() string { + if x != nil { + return x.Language + } + return "" +} + +func (x *RequestHeader) GetProtocolType() string { + if x != nil { + return x.ProtocolType + } + return "" +} + +func (x *RequestHeader) GetProtocolVersion() string { + if x != nil { + return x.ProtocolVersion + } + return "" +} + +func (x *RequestHeader) GetProtocolDesc() string { + if x != nil { + return x.ProtocolDesc + } + return "" +} + +type SimpleMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Header *RequestHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` + ProducerGroup string `protobuf:"bytes,2,opt,name=producerGroup,proto3" json:"producerGroup,omitempty"` + Topic string `protobuf:"bytes,3,opt,name=topic,proto3" json:"topic,omitempty"` + Content string `protobuf:"bytes,4,opt,name=content,proto3" json:"content,omitempty"` + Ttl string `protobuf:"bytes,5,opt,name=ttl,proto3" json:"ttl,omitempty"` + UniqueId string `protobuf:"bytes,6,opt,name=uniqueId,proto3" json:"uniqueId,omitempty"` + SeqNum string `protobuf:"bytes,7,opt,name=seqNum,proto3" json:"seqNum,omitempty"` + Tag string `protobuf:"bytes,8,opt,name=tag,proto3" json:"tag,omitempty"` + Properties map[string]string `protobuf:"bytes,9,rep,name=properties,proto3" json:"properties,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *SimpleMessage) Reset() { + *x = SimpleMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_eventmesh_client_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SimpleMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SimpleMessage) ProtoMessage() {} + +func (x *SimpleMessage) ProtoReflect() protoreflect.Message { + mi := &file_eventmesh_client_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 SimpleMessage.ProtoReflect.Descriptor instead. +func (*SimpleMessage) Descriptor() ([]byte, []int) { + return file_eventmesh_client_proto_rawDescGZIP(), []int{1} +} + +func (x *SimpleMessage) GetHeader() *RequestHeader { + if x != nil { + return x.Header + } + return nil +} + +func (x *SimpleMessage) GetProducerGroup() string { + if x != nil { + return x.ProducerGroup + } + return "" +} + +func (x *SimpleMessage) GetTopic() string { + if x != nil { + return x.Topic + } + return "" +} + +func (x *SimpleMessage) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *SimpleMessage) GetTtl() string { + if x != nil { + return x.Ttl + } + return "" +} + +func (x *SimpleMessage) GetUniqueId() string { + if x != nil { + return x.UniqueId + } + return "" +} + +func (x *SimpleMessage) GetSeqNum() string { + if x != nil { + return x.SeqNum + } + return "" +} + +func (x *SimpleMessage) GetTag() string { + if x != nil { + return x.Tag + } + return "" +} + +func (x *SimpleMessage) GetProperties() map[string]string { + if x != nil { + return x.Properties + } + return nil +} + +type BatchMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Header *RequestHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` + ProducerGroup string `protobuf:"bytes,2,opt,name=producerGroup,proto3" json:"producerGroup,omitempty"` + Topic string `protobuf:"bytes,3,opt,name=topic,proto3" json:"topic,omitempty"` + MessageItem []*BatchMessage_MessageItem `protobuf:"bytes,4,rep,name=messageItem,proto3" json:"messageItem,omitempty"` +} + +func (x *BatchMessage) Reset() { + *x = BatchMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_eventmesh_client_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchMessage) ProtoMessage() {} + +func (x *BatchMessage) ProtoReflect() protoreflect.Message { + mi := &file_eventmesh_client_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 BatchMessage.ProtoReflect.Descriptor instead. +func (*BatchMessage) Descriptor() ([]byte, []int) { + return file_eventmesh_client_proto_rawDescGZIP(), []int{2} +} + +func (x *BatchMessage) GetHeader() *RequestHeader { + if x != nil { + return x.Header + } + return nil +} + +func (x *BatchMessage) GetProducerGroup() string { + if x != nil { + return x.ProducerGroup + } + return "" +} + +func (x *BatchMessage) GetTopic() string { + if x != nil { + return x.Topic + } + return "" +} + +func (x *BatchMessage) GetMessageItem() []*BatchMessage_MessageItem { + if x != nil { + return x.MessageItem + } + return nil +} + +type Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RespCode string `protobuf:"bytes,1,opt,name=respCode,proto3" json:"respCode,omitempty"` + RespMsg string `protobuf:"bytes,2,opt,name=respMsg,proto3" json:"respMsg,omitempty"` + RespTime string `protobuf:"bytes,3,opt,name=respTime,proto3" json:"respTime,omitempty"` +} + +func (x *Response) Reset() { + *x = Response{} + if protoimpl.UnsafeEnabled { + mi := &file_eventmesh_client_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Response) ProtoMessage() {} + +func (x *Response) ProtoReflect() protoreflect.Message { + mi := &file_eventmesh_client_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 Response.ProtoReflect.Descriptor instead. +func (*Response) Descriptor() ([]byte, []int) { + return file_eventmesh_client_proto_rawDescGZIP(), []int{3} +} + +func (x *Response) GetRespCode() string { + if x != nil { + return x.RespCode + } + return "" +} + +func (x *Response) GetRespMsg() string { + if x != nil { + return x.RespMsg + } + return "" +} + +func (x *Response) GetRespTime() string { + if x != nil { + return x.RespTime + } + return "" +} + +type Subscription struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Header *RequestHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` + ConsumerGroup string `protobuf:"bytes,2,opt,name=consumerGroup,proto3" json:"consumerGroup,omitempty"` + SubscriptionItems []*Subscription_SubscriptionItem `protobuf:"bytes,3,rep,name=subscriptionItems,proto3" json:"subscriptionItems,omitempty"` + Url string `protobuf:"bytes,4,opt,name=url,proto3" json:"url,omitempty"` + Reply *Subscription_Reply `protobuf:"bytes,5,opt,name=reply,proto3" json:"reply,omitempty"` +} + +func (x *Subscription) Reset() { + *x = Subscription{} + if protoimpl.UnsafeEnabled { + mi := &file_eventmesh_client_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Subscription) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Subscription) ProtoMessage() {} + +func (x *Subscription) ProtoReflect() protoreflect.Message { + mi := &file_eventmesh_client_proto_msgTypes[4] + 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 Subscription.ProtoReflect.Descriptor instead. +func (*Subscription) Descriptor() ([]byte, []int) { + return file_eventmesh_client_proto_rawDescGZIP(), []int{4} +} + +func (x *Subscription) GetHeader() *RequestHeader { + if x != nil { + return x.Header + } + return nil +} + +func (x *Subscription) GetConsumerGroup() string { + if x != nil { + return x.ConsumerGroup + } + return "" +} + +func (x *Subscription) GetSubscriptionItems() []*Subscription_SubscriptionItem { + if x != nil { + return x.SubscriptionItems + } + return nil +} + +func (x *Subscription) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *Subscription) GetReply() *Subscription_Reply { + if x != nil { + return x.Reply + } + return nil +} + +type Heartbeat struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Header *RequestHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` + ClientType Heartbeat_ClientType `protobuf:"varint,2,opt,name=clientType,proto3,enum=eventmesh.common.protocol.grpc.Heartbeat_ClientType" json:"clientType,omitempty"` + ProducerGroup string `protobuf:"bytes,3,opt,name=producerGroup,proto3" json:"producerGroup,omitempty"` + ConsumerGroup string `protobuf:"bytes,4,opt,name=consumerGroup,proto3" json:"consumerGroup,omitempty"` + HeartbeatItems []*Heartbeat_HeartbeatItem `protobuf:"bytes,5,rep,name=heartbeatItems,proto3" json:"heartbeatItems,omitempty"` +} + +func (x *Heartbeat) Reset() { + *x = Heartbeat{} + if protoimpl.UnsafeEnabled { + mi := &file_eventmesh_client_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Heartbeat) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Heartbeat) ProtoMessage() {} + +func (x *Heartbeat) ProtoReflect() protoreflect.Message { + mi := &file_eventmesh_client_proto_msgTypes[5] + 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 Heartbeat.ProtoReflect.Descriptor instead. +func (*Heartbeat) Descriptor() ([]byte, []int) { + return file_eventmesh_client_proto_rawDescGZIP(), []int{5} +} + +func (x *Heartbeat) GetHeader() *RequestHeader { + if x != nil { + return x.Header + } + return nil +} + +func (x *Heartbeat) GetClientType() Heartbeat_ClientType { + if x != nil { + return x.ClientType + } + return Heartbeat_PUB +} + +func (x *Heartbeat) GetProducerGroup() string { + if x != nil { + return x.ProducerGroup + } + return "" +} + +func (x *Heartbeat) GetConsumerGroup() string { + if x != nil { + return x.ConsumerGroup + } + return "" +} + +func (x *Heartbeat) GetHeartbeatItems() []*Heartbeat_HeartbeatItem { + if x != nil { + return x.HeartbeatItems + } + return nil +} + +type BatchMessage_MessageItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Content string `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"` + Ttl string `protobuf:"bytes,2,opt,name=ttl,proto3" json:"ttl,omitempty"` + UniqueId string `protobuf:"bytes,3,opt,name=uniqueId,proto3" json:"uniqueId,omitempty"` + SeqNum string `protobuf:"bytes,4,opt,name=seqNum,proto3" json:"seqNum,omitempty"` + Tag string `protobuf:"bytes,5,opt,name=tag,proto3" json:"tag,omitempty"` + Properties map[string]string `protobuf:"bytes,6,rep,name=properties,proto3" json:"properties,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *BatchMessage_MessageItem) Reset() { + *x = BatchMessage_MessageItem{} + if protoimpl.UnsafeEnabled { + mi := &file_eventmesh_client_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BatchMessage_MessageItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BatchMessage_MessageItem) ProtoMessage() {} + +func (x *BatchMessage_MessageItem) ProtoReflect() protoreflect.Message { + mi := &file_eventmesh_client_proto_msgTypes[7] + 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 BatchMessage_MessageItem.ProtoReflect.Descriptor instead. +func (*BatchMessage_MessageItem) Descriptor() ([]byte, []int) { + return file_eventmesh_client_proto_rawDescGZIP(), []int{2, 0} +} + +func (x *BatchMessage_MessageItem) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *BatchMessage_MessageItem) GetTtl() string { + if x != nil { + return x.Ttl + } + return "" +} + +func (x *BatchMessage_MessageItem) GetUniqueId() string { + if x != nil { + return x.UniqueId + } + return "" +} + +func (x *BatchMessage_MessageItem) GetSeqNum() string { + if x != nil { + return x.SeqNum + } + return "" +} + +func (x *BatchMessage_MessageItem) GetTag() string { + if x != nil { + return x.Tag + } + return "" +} + +func (x *BatchMessage_MessageItem) GetProperties() map[string]string { + if x != nil { + return x.Properties + } + return nil +} + +type Subscription_SubscriptionItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Topic string `protobuf:"bytes,1,opt,name=topic,proto3" json:"topic,omitempty"` + Mode Subscription_SubscriptionItem_SubscriptionMode `protobuf:"varint,2,opt,name=mode,proto3,enum=eventmesh.common.protocol.grpc.Subscription_SubscriptionItem_SubscriptionMode" json:"mode,omitempty"` + Type Subscription_SubscriptionItem_SubscriptionType `protobuf:"varint,3,opt,name=type,proto3,enum=eventmesh.common.protocol.grpc.Subscription_SubscriptionItem_SubscriptionType" json:"type,omitempty"` +} + +func (x *Subscription_SubscriptionItem) Reset() { + *x = Subscription_SubscriptionItem{} + if protoimpl.UnsafeEnabled { + mi := &file_eventmesh_client_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Subscription_SubscriptionItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Subscription_SubscriptionItem) ProtoMessage() {} + +func (x *Subscription_SubscriptionItem) ProtoReflect() protoreflect.Message { + mi := &file_eventmesh_client_proto_msgTypes[9] + 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 Subscription_SubscriptionItem.ProtoReflect.Descriptor instead. +func (*Subscription_SubscriptionItem) Descriptor() ([]byte, []int) { + return file_eventmesh_client_proto_rawDescGZIP(), []int{4, 0} +} + +func (x *Subscription_SubscriptionItem) GetTopic() string { + if x != nil { + return x.Topic + } + return "" +} + +func (x *Subscription_SubscriptionItem) GetMode() Subscription_SubscriptionItem_SubscriptionMode { + if x != nil { + return x.Mode + } + return Subscription_SubscriptionItem_CLUSTERING +} + +func (x *Subscription_SubscriptionItem) GetType() Subscription_SubscriptionItem_SubscriptionType { + if x != nil { + return x.Type + } + return Subscription_SubscriptionItem_ASYNC +} + +type Subscription_Reply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProducerGroup string `protobuf:"bytes,1,opt,name=producerGroup,proto3" json:"producerGroup,omitempty"` + Topic string `protobuf:"bytes,2,opt,name=topic,proto3" json:"topic,omitempty"` + Content string `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` + Ttl string `protobuf:"bytes,4,opt,name=ttl,proto3" json:"ttl,omitempty"` + UniqueId string `protobuf:"bytes,5,opt,name=uniqueId,proto3" json:"uniqueId,omitempty"` + SeqNum string `protobuf:"bytes,6,opt,name=seqNum,proto3" json:"seqNum,omitempty"` + Tag string `protobuf:"bytes,7,opt,name=tag,proto3" json:"tag,omitempty"` + Properties map[string]string `protobuf:"bytes,8,rep,name=properties,proto3" json:"properties,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Subscription_Reply) Reset() { + *x = Subscription_Reply{} + if protoimpl.UnsafeEnabled { + mi := &file_eventmesh_client_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Subscription_Reply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Subscription_Reply) ProtoMessage() {} + +func (x *Subscription_Reply) ProtoReflect() protoreflect.Message { + mi := &file_eventmesh_client_proto_msgTypes[10] + 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 Subscription_Reply.ProtoReflect.Descriptor instead. +func (*Subscription_Reply) Descriptor() ([]byte, []int) { + return file_eventmesh_client_proto_rawDescGZIP(), []int{4, 1} +} + +func (x *Subscription_Reply) GetProducerGroup() string { + if x != nil { + return x.ProducerGroup + } + return "" +} + +func (x *Subscription_Reply) GetTopic() string { + if x != nil { + return x.Topic + } + return "" +} + +func (x *Subscription_Reply) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *Subscription_Reply) GetTtl() string { + if x != nil { + return x.Ttl + } + return "" +} + +func (x *Subscription_Reply) GetUniqueId() string { + if x != nil { + return x.UniqueId + } + return "" +} + +func (x *Subscription_Reply) GetSeqNum() string { + if x != nil { + return x.SeqNum + } + return "" +} + +func (x *Subscription_Reply) GetTag() string { + if x != nil { + return x.Tag + } + return "" +} + +func (x *Subscription_Reply) GetProperties() map[string]string { + if x != nil { + return x.Properties + } + return nil +} + +type Heartbeat_HeartbeatItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Topic string `protobuf:"bytes,1,opt,name=topic,proto3" json:"topic,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` +} + +func (x *Heartbeat_HeartbeatItem) Reset() { + *x = Heartbeat_HeartbeatItem{} + if protoimpl.UnsafeEnabled { + mi := &file_eventmesh_client_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Heartbeat_HeartbeatItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Heartbeat_HeartbeatItem) ProtoMessage() {} + +func (x *Heartbeat_HeartbeatItem) ProtoReflect() protoreflect.Message { + mi := &file_eventmesh_client_proto_msgTypes[12] + 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 Heartbeat_HeartbeatItem.ProtoReflect.Descriptor instead. +func (*Heartbeat_HeartbeatItem) Descriptor() ([]byte, []int) { + return file_eventmesh_client_proto_rawDescGZIP(), []int{5, 0} +} + +func (x *Heartbeat_HeartbeatItem) GetTopic() string { + if x != nil { + return x.Topic + } + return "" +} + +func (x *Heartbeat_HeartbeatItem) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +var File_eventmesh_client_proto protoreflect.FileDescriptor + +var file_eventmesh_client_proto_rawDesc = []byte{ + 0x0a, 0x16, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2d, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, + 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x22, 0xc5, 0x02, 0x0a, 0x0d, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, + 0x76, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x12, 0x16, 0x0a, 0x06, + 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, + 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x69, 0x64, 0x63, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x79, 0x73, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x79, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, + 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, + 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x22, + 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x0c, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x44, 0x65, 0x73, 0x63, 0x18, 0x0c, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x44, 0x65, 0x73, 0x63, + 0x22, 0xa2, 0x03, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x45, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x70, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, + 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, + 0x10, 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x74, + 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x64, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x65, 0x71, 0x4e, 0x75, 0x6d, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, + 0x65, 0x71, 0x4e, 0x75, 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x5d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, + 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, + 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x98, 0x04, 0x0a, 0x0c, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x45, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, + 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x24, 0x0a, + 0x0d, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x5a, 0x0a, 0x0b, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, + 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x42, 0x61, 0x74, 0x63, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x0b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x49, 0x74, 0x65, 0x6d, 0x1a, 0xa8, 0x02, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, + 0x10, 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x74, + 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x65, 0x71, 0x4e, 0x75, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, + 0x65, 0x71, 0x4e, 0x75, 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x68, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x48, 0x2e, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x74, + 0x63, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, + 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x22, 0x5c, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, + 0x72, 0x65, 0x73, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x72, 0x65, 0x73, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x70, + 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x73, 0x70, 0x4d, + 0x73, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xf1, + 0x07, 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x45, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2d, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, + 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, + 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, + 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x6b, 0x0a, 0x11, + 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, + 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x11, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x48, 0x0a, 0x05, 0x72, + 0x65, 0x70, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x52, 0x05, + 0x72, 0x65, 0x70, 0x6c, 0x79, 0x1a, 0xcf, 0x02, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, + 0x70, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, + 0x12, 0x62, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x4e, + 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x53, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, + 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x62, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x4e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, + 0x6d, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x34, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x0a, + 0x43, 0x4c, 0x55, 0x53, 0x54, 0x45, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, + 0x42, 0x52, 0x4f, 0x41, 0x44, 0x43, 0x41, 0x53, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x22, 0x27, + 0x0a, 0x10, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x00, 0x12, 0x08, 0x0a, + 0x04, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x01, 0x1a, 0xd8, 0x02, 0x0a, 0x05, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, + 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x18, 0x0a, + 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x6e, 0x69, + 0x71, 0x75, 0x65, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x6e, 0x69, + 0x71, 0x75, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x4e, 0x75, 0x6d, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x71, 0x4e, 0x75, 0x6d, 0x12, 0x10, 0x0a, + 0x03, 0x74, 0x61, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, + 0x62, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x08, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, + 0x69, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0xae, 0x03, 0x0a, 0x09, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, + 0x12, 0x45, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2d, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, + 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x54, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x34, 0x2e, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x65, 0x61, + 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, + 0x0d, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x73, + 0x75, 0x6d, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x5f, 0x0a, 0x0e, 0x68, 0x65, 0x61, + 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x37, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x2e, 0x48, 0x65, 0x61, + 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x0e, 0x68, 0x65, 0x61, 0x72, + 0x74, 0x62, 0x65, 0x61, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x1a, 0x37, 0x0a, 0x0d, 0x48, 0x65, + 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x74, + 0x6f, 0x70, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, + 0x63, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x75, 0x72, 0x6c, 0x22, 0x1e, 0x0a, 0x0a, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x07, 0x0a, 0x03, 0x50, 0x55, 0x42, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x53, 0x55, + 0x42, 0x10, 0x01, 0x32, 0xcc, 0x02, 0x0a, 0x10, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, + 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x62, 0x0a, 0x07, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x73, 0x68, 0x12, 0x2d, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x1a, 0x28, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x0c, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2d, 0x2e, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, + 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x2d, 0x2e, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x66, 0x0a, 0x0c, 0x62, 0x61, + 0x74, 0x63, 0x68, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x2c, 0x2e, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x74, 0x63, + 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x28, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x32, 0xd1, 0x02, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x63, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x12, 0x2c, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x1a, 0x28, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x0f, 0x73, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x2c, + 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x2d, 0x2e, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, + 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, + 0x65, 0x0a, 0x0b, 0x75, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x2c, + 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x28, 0x2e, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x74, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, + 0x65, 0x61, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x60, 0x0a, 0x09, 0x68, 0x65, + 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x29, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, + 0x65, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, + 0x61, 0x74, 0x1a, 0x28, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x09, 0x5a, 0x07, + 0x2e, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_eventmesh_client_proto_rawDescOnce sync.Once + file_eventmesh_client_proto_rawDescData = file_eventmesh_client_proto_rawDesc +) + +func file_eventmesh_client_proto_rawDescGZIP() []byte { + file_eventmesh_client_proto_rawDescOnce.Do(func() { + file_eventmesh_client_proto_rawDescData = protoimpl.X.CompressGZIP(file_eventmesh_client_proto_rawDescData) + }) + return file_eventmesh_client_proto_rawDescData +} + +var file_eventmesh_client_proto_enumTypes = make([]protoimpl.EnumInfo, 3) +var file_eventmesh_client_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_eventmesh_client_proto_goTypes = []interface{}{ + (Subscription_SubscriptionItem_SubscriptionMode)(0), // 0: eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionMode + (Subscription_SubscriptionItem_SubscriptionType)(0), // 1: eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionType + (Heartbeat_ClientType)(0), // 2: eventmesh.common.protocol.grpc.Heartbeat.ClientType + (*RequestHeader)(nil), // 3: eventmesh.common.protocol.grpc.RequestHeader + (*SimpleMessage)(nil), // 4: eventmesh.common.protocol.grpc.SimpleMessage + (*BatchMessage)(nil), // 5: eventmesh.common.protocol.grpc.BatchMessage + (*Response)(nil), // 6: eventmesh.common.protocol.grpc.Response + (*Subscription)(nil), // 7: eventmesh.common.protocol.grpc.Subscription + (*Heartbeat)(nil), // 8: eventmesh.common.protocol.grpc.Heartbeat + nil, // 9: eventmesh.common.protocol.grpc.SimpleMessage.PropertiesEntry + (*BatchMessage_MessageItem)(nil), // 10: eventmesh.common.protocol.grpc.BatchMessage.MessageItem + nil, // 11: eventmesh.common.protocol.grpc.BatchMessage.MessageItem.PropertiesEntry + (*Subscription_SubscriptionItem)(nil), // 12: eventmesh.common.protocol.grpc.Subscription.SubscriptionItem + (*Subscription_Reply)(nil), // 13: eventmesh.common.protocol.grpc.Subscription.Reply + nil, // 14: eventmesh.common.protocol.grpc.Subscription.Reply.PropertiesEntry + (*Heartbeat_HeartbeatItem)(nil), // 15: eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem +} +var file_eventmesh_client_proto_depIdxs = []int32{ + 3, // 0: eventmesh.common.protocol.grpc.SimpleMessage.header:type_name -> eventmesh.common.protocol.grpc.RequestHeader + 9, // 1: eventmesh.common.protocol.grpc.SimpleMessage.properties:type_name -> eventmesh.common.protocol.grpc.SimpleMessage.PropertiesEntry + 3, // 2: eventmesh.common.protocol.grpc.BatchMessage.header:type_name -> eventmesh.common.protocol.grpc.RequestHeader + 10, // 3: eventmesh.common.protocol.grpc.BatchMessage.messageItem:type_name -> eventmesh.common.protocol.grpc.BatchMessage.MessageItem + 3, // 4: eventmesh.common.protocol.grpc.Subscription.header:type_name -> eventmesh.common.protocol.grpc.RequestHeader + 12, // 5: eventmesh.common.protocol.grpc.Subscription.subscriptionItems:type_name -> eventmesh.common.protocol.grpc.Subscription.SubscriptionItem + 13, // 6: eventmesh.common.protocol.grpc.Subscription.reply:type_name -> eventmesh.common.protocol.grpc.Subscription.Reply + 3, // 7: eventmesh.common.protocol.grpc.Heartbeat.header:type_name -> eventmesh.common.protocol.grpc.RequestHeader + 2, // 8: eventmesh.common.protocol.grpc.Heartbeat.clientType:type_name -> eventmesh.common.protocol.grpc.Heartbeat.ClientType + 15, // 9: eventmesh.common.protocol.grpc.Heartbeat.heartbeatItems:type_name -> eventmesh.common.protocol.grpc.Heartbeat.HeartbeatItem + 11, // 10: eventmesh.common.protocol.grpc.BatchMessage.MessageItem.properties:type_name -> eventmesh.common.protocol.grpc.BatchMessage.MessageItem.PropertiesEntry + 0, // 11: eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.mode:type_name -> eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionMode + 1, // 12: eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.type:type_name -> eventmesh.common.protocol.grpc.Subscription.SubscriptionItem.SubscriptionType + 14, // 13: eventmesh.common.protocol.grpc.Subscription.Reply.properties:type_name -> eventmesh.common.protocol.grpc.Subscription.Reply.PropertiesEntry + 4, // 14: eventmesh.common.protocol.grpc.PublisherService.publish:input_type -> eventmesh.common.protocol.grpc.SimpleMessage + 4, // 15: eventmesh.common.protocol.grpc.PublisherService.requestReply:input_type -> eventmesh.common.protocol.grpc.SimpleMessage + 5, // 16: eventmesh.common.protocol.grpc.PublisherService.batchPublish:input_type -> eventmesh.common.protocol.grpc.BatchMessage + 7, // 17: eventmesh.common.protocol.grpc.ConsumerService.subscribe:input_type -> eventmesh.common.protocol.grpc.Subscription + 7, // 18: eventmesh.common.protocol.grpc.ConsumerService.subscribeStream:input_type -> eventmesh.common.protocol.grpc.Subscription + 7, // 19: eventmesh.common.protocol.grpc.ConsumerService.unsubscribe:input_type -> eventmesh.common.protocol.grpc.Subscription + 8, // 20: eventmesh.common.protocol.grpc.HeartbeatService.heartbeat:input_type -> eventmesh.common.protocol.grpc.Heartbeat + 6, // 21: eventmesh.common.protocol.grpc.PublisherService.publish:output_type -> eventmesh.common.protocol.grpc.Response + 4, // 22: eventmesh.common.protocol.grpc.PublisherService.requestReply:output_type -> eventmesh.common.protocol.grpc.SimpleMessage + 6, // 23: eventmesh.common.protocol.grpc.PublisherService.batchPublish:output_type -> eventmesh.common.protocol.grpc.Response + 6, // 24: eventmesh.common.protocol.grpc.ConsumerService.subscribe:output_type -> eventmesh.common.protocol.grpc.Response + 4, // 25: eventmesh.common.protocol.grpc.ConsumerService.subscribeStream:output_type -> eventmesh.common.protocol.grpc.SimpleMessage + 6, // 26: eventmesh.common.protocol.grpc.ConsumerService.unsubscribe:output_type -> eventmesh.common.protocol.grpc.Response + 6, // 27: eventmesh.common.protocol.grpc.HeartbeatService.heartbeat:output_type -> eventmesh.common.protocol.grpc.Response + 21, // [21:28] is the sub-list for method output_type + 14, // [14:21] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name +} + +func init() { file_eventmesh_client_proto_init() } +func file_eventmesh_client_proto_init() { + if File_eventmesh_client_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_eventmesh_client_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RequestHeader); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventmesh_client_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SimpleMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventmesh_client_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventmesh_client_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventmesh_client_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Subscription); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventmesh_client_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Heartbeat); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventmesh_client_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BatchMessage_MessageItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventmesh_client_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Subscription_SubscriptionItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventmesh_client_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Subscription_Reply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventmesh_client_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Heartbeat_HeartbeatItem); 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_eventmesh_client_proto_rawDesc, + NumEnums: 3, + NumMessages: 13, + NumExtensions: 0, + NumServices: 3, + }, + GoTypes: file_eventmesh_client_proto_goTypes, + DependencyIndexes: file_eventmesh_client_proto_depIdxs, + EnumInfos: file_eventmesh_client_proto_enumTypes, + MessageInfos: file_eventmesh_client_proto_msgTypes, + }.Build() + File_eventmesh_client_proto = out.File + file_eventmesh_client_proto_rawDesc = nil + file_eventmesh_client_proto_goTypes = nil + file_eventmesh_client_proto_depIdxs = nil +} diff --git a/eventmesh-sdk-go/grpc/proto/eventmesh-client.proto b/eventmesh-sdk-go/grpc/proto/eventmesh-client.proto new file mode 100644 index 0000000000..349e8c1dc0 --- /dev/null +++ b/eventmesh-sdk-go/grpc/proto/eventmesh-client.proto @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto3"; + +//package eventmesh.common.protocol.grpc; +// +//option java_multiple_files = true; +//option java_package = "org.apache.eventmesh.common.protocol.grpc.protos"; +//option java_outer_classname = "EventmeshGrpc"; + +// make sure the protoc and protoc-gen-go is installed on your machine, and has set +// its directory into path +// download protoc: https://github.com/protocolbuffers/protobuf/releases +// install protoc-gen-go: go install google.golang.org/protobuf/cmd/protoc-gen-go +// generate go code by protoc: protoc --go_out=. eventmesh-client.proto + +package eventmesh.common.protocol.grpc; + +option go_package= ".;proto"; + +message RequestHeader { + string env = 1; + string region = 2; + string idc = 3; + string ip = 4; + string pid = 5; + string sys = 6; + string username = 7; + string password = 8; + string language = 9; + string protocolType = 10; + string protocolVersion = 11; + string protocolDesc = 12; +} + +message SimpleMessage { + RequestHeader header = 1; + string producerGroup = 2; + string topic = 3; + string content = 4; + string ttl = 5; + string uniqueId = 6; + string seqNum = 7; + string tag = 8; + map properties = 9; +} + +message BatchMessage { + RequestHeader header = 1; + string producerGroup = 2; + string topic = 3; + + message MessageItem { + string content = 1; + string ttl = 2; + string uniqueId = 3; + string seqNum = 4; + string tag = 5; + map properties = 6; + } + + repeated MessageItem messageItem = 4; +} + +message Response { + string respCode = 1; + string respMsg = 2; + string respTime = 3; +} + +message Subscription { + RequestHeader header = 1; + string consumerGroup = 2; + + message SubscriptionItem { + enum SubscriptionMode { + CLUSTERING = 0; + BROADCASTING = 1; + } + + enum SubscriptionType { + ASYNC = 0; + SYNC = 1; + } + + string topic = 1; + SubscriptionMode mode = 2; + SubscriptionType type = 3; + } + + repeated SubscriptionItem subscriptionItems = 3; + string url = 4; + + message Reply { + string producerGroup = 1; + string topic = 2; + string content = 3; + string ttl = 4; + string uniqueId = 5; + string seqNum = 6; + string tag = 7; + map properties = 8; + } + + Reply reply = 5; +} + +message Heartbeat { + enum ClientType { + PUB = 0; + SUB = 1; + } + + RequestHeader header = 1; + ClientType clientType = 2; + string producerGroup = 3; + string consumerGroup = 4; + + message HeartbeatItem { + string topic = 1; + string url = 2; + } + + repeated HeartbeatItem heartbeatItems = 5; +} + +service PublisherService { + // Async event publish + rpc publish(SimpleMessage) returns (Response); + + // Sync event publish + rpc requestReply(SimpleMessage) returns (SimpleMessage); + + // Async batch event publish + rpc batchPublish(BatchMessage) returns (Response); +} + +service ConsumerService { + // The subscribed event will be delivered by invoking the webhook url in the Subscription + rpc subscribe(Subscription) returns (Response); + + // The subscribed event will be delivered through stream of Message + rpc subscribeStream(stream Subscription) returns (stream SimpleMessage); + + rpc unsubscribe(Subscription) returns (Response); +} + +service HeartbeatService { + rpc heartbeat(Heartbeat) returns (Response); +} \ No newline at end of file diff --git a/eventmesh-sdk-go/grpc/proto/eventmesh-client_grpc.pb.go b/eventmesh-sdk-go/grpc/proto/eventmesh-client_grpc.pb.go new file mode 100644 index 0000000000..a61a9115eb --- /dev/null +++ b/eventmesh-sdk-go/grpc/proto/eventmesh-client_grpc.pb.go @@ -0,0 +1,479 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v3.19.4 +// source: eventmesh-client.proto + +package proto + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// PublisherServiceClient is the client API for PublisherService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type PublisherServiceClient interface { + // Async event publish + Publish(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*Response, error) + // Sync event publish + RequestReply(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) + // Async batch event publish + BatchPublish(ctx context.Context, in *BatchMessage, opts ...grpc.CallOption) (*Response, error) +} + +type publisherServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewPublisherServiceClient(cc grpc.ClientConnInterface) PublisherServiceClient { + return &publisherServiceClient{cc} +} + +func (c *publisherServiceClient) Publish(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*Response, error) { + out := new(Response) + err := c.cc.Invoke(ctx, "/eventmesh.common.protocol.grpc.PublisherService/publish", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *publisherServiceClient) RequestReply(ctx context.Context, in *SimpleMessage, opts ...grpc.CallOption) (*SimpleMessage, error) { + out := new(SimpleMessage) + err := c.cc.Invoke(ctx, "/eventmesh.common.protocol.grpc.PublisherService/requestReply", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *publisherServiceClient) BatchPublish(ctx context.Context, in *BatchMessage, opts ...grpc.CallOption) (*Response, error) { + out := new(Response) + err := c.cc.Invoke(ctx, "/eventmesh.common.protocol.grpc.PublisherService/batchPublish", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// PublisherServiceServer is the server API for PublisherService service. +// All implementations must embed UnimplementedPublisherServiceServer +// for forward compatibility +type PublisherServiceServer interface { + // Async event publish + Publish(context.Context, *SimpleMessage) (*Response, error) + // Sync event publish + RequestReply(context.Context, *SimpleMessage) (*SimpleMessage, error) + // Async batch event publish + BatchPublish(context.Context, *BatchMessage) (*Response, error) + mustEmbedUnimplementedPublisherServiceServer() +} + +// UnimplementedPublisherServiceServer must be embedded to have forward compatible implementations. +type UnimplementedPublisherServiceServer struct { +} + +func (UnimplementedPublisherServiceServer) Publish(context.Context, *SimpleMessage) (*Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method Publish not implemented") +} +func (UnimplementedPublisherServiceServer) RequestReply(context.Context, *SimpleMessage) (*SimpleMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method RequestReply not implemented") +} +func (UnimplementedPublisherServiceServer) BatchPublish(context.Context, *BatchMessage) (*Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method BatchPublish not implemented") +} +func (UnimplementedPublisherServiceServer) mustEmbedUnimplementedPublisherServiceServer() {} + +// UnsafePublisherServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to PublisherServiceServer will +// result in compilation errors. +type UnsafePublisherServiceServer interface { + mustEmbedUnimplementedPublisherServiceServer() +} + +func RegisterPublisherServiceServer(s grpc.ServiceRegistrar, srv PublisherServiceServer) { + s.RegisterService(&PublisherService_ServiceDesc, srv) +} + +func _PublisherService_Publish_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PublisherServiceServer).Publish(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/eventmesh.common.protocol.grpc.PublisherService/publish", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PublisherServiceServer).Publish(ctx, req.(*SimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _PublisherService_RequestReply_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SimpleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PublisherServiceServer).RequestReply(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/eventmesh.common.protocol.grpc.PublisherService/requestReply", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PublisherServiceServer).RequestReply(ctx, req.(*SimpleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _PublisherService_BatchPublish_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(BatchMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PublisherServiceServer).BatchPublish(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/eventmesh.common.protocol.grpc.PublisherService/batchPublish", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PublisherServiceServer).BatchPublish(ctx, req.(*BatchMessage)) + } + return interceptor(ctx, in, info, handler) +} + +// PublisherService_ServiceDesc is the grpc.ServiceDesc for PublisherService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var PublisherService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "eventmesh.common.protocol.grpc.PublisherService", + HandlerType: (*PublisherServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "publish", + Handler: _PublisherService_Publish_Handler, + }, + { + MethodName: "requestReply", + Handler: _PublisherService_RequestReply_Handler, + }, + { + MethodName: "batchPublish", + Handler: _PublisherService_BatchPublish_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "eventmesh-client.proto", +} + +// ConsumerServiceClient is the client API for ConsumerService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type ConsumerServiceClient interface { + // The subscribed event will be delivered by invoking the webhook url in the Subscription + Subscribe(ctx context.Context, in *Subscription, opts ...grpc.CallOption) (*Response, error) + // The subscribed event will be delivered through stream of Message + SubscribeStream(ctx context.Context, opts ...grpc.CallOption) (ConsumerService_SubscribeStreamClient, error) + Unsubscribe(ctx context.Context, in *Subscription, opts ...grpc.CallOption) (*Response, error) +} + +type consumerServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewConsumerServiceClient(cc grpc.ClientConnInterface) ConsumerServiceClient { + return &consumerServiceClient{cc} +} + +func (c *consumerServiceClient) Subscribe(ctx context.Context, in *Subscription, opts ...grpc.CallOption) (*Response, error) { + out := new(Response) + err := c.cc.Invoke(ctx, "/eventmesh.common.protocol.grpc.ConsumerService/subscribe", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *consumerServiceClient) SubscribeStream(ctx context.Context, opts ...grpc.CallOption) (ConsumerService_SubscribeStreamClient, error) { + stream, err := c.cc.NewStream(ctx, &ConsumerService_ServiceDesc.Streams[0], "/eventmesh.common.protocol.grpc.ConsumerService/subscribeStream", opts...) + if err != nil { + return nil, err + } + x := &consumerServiceSubscribeStreamClient{stream} + return x, nil +} + +type ConsumerService_SubscribeStreamClient interface { + Send(*Subscription) error + Recv() (*SimpleMessage, error) + grpc.ClientStream +} + +type consumerServiceSubscribeStreamClient struct { + grpc.ClientStream +} + +func (x *consumerServiceSubscribeStreamClient) Send(m *Subscription) error { + return x.ClientStream.SendMsg(m) +} + +func (x *consumerServiceSubscribeStreamClient) Recv() (*SimpleMessage, error) { + m := new(SimpleMessage) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *consumerServiceClient) Unsubscribe(ctx context.Context, in *Subscription, opts ...grpc.CallOption) (*Response, error) { + out := new(Response) + err := c.cc.Invoke(ctx, "/eventmesh.common.protocol.grpc.ConsumerService/unsubscribe", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ConsumerServiceServer is the server API for ConsumerService service. +// All implementations must embed UnimplementedConsumerServiceServer +// for forward compatibility +type ConsumerServiceServer interface { + // The subscribed event will be delivered by invoking the webhook url in the Subscription + Subscribe(context.Context, *Subscription) (*Response, error) + // The subscribed event will be delivered through stream of Message + SubscribeStream(ConsumerService_SubscribeStreamServer) error + Unsubscribe(context.Context, *Subscription) (*Response, error) + mustEmbedUnimplementedConsumerServiceServer() +} + +// UnimplementedConsumerServiceServer must be embedded to have forward compatible implementations. +type UnimplementedConsumerServiceServer struct { +} + +func (UnimplementedConsumerServiceServer) Subscribe(context.Context, *Subscription) (*Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method Subscribe not implemented") +} +func (UnimplementedConsumerServiceServer) SubscribeStream(ConsumerService_SubscribeStreamServer) error { + return status.Errorf(codes.Unimplemented, "method SubscribeStream not implemented") +} +func (UnimplementedConsumerServiceServer) Unsubscribe(context.Context, *Subscription) (*Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method Unsubscribe not implemented") +} +func (UnimplementedConsumerServiceServer) mustEmbedUnimplementedConsumerServiceServer() {} + +// UnsafeConsumerServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ConsumerServiceServer will +// result in compilation errors. +type UnsafeConsumerServiceServer interface { + mustEmbedUnimplementedConsumerServiceServer() +} + +func RegisterConsumerServiceServer(s grpc.ServiceRegistrar, srv ConsumerServiceServer) { + s.RegisterService(&ConsumerService_ServiceDesc, srv) +} + +func _ConsumerService_Subscribe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Subscription) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ConsumerServiceServer).Subscribe(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/eventmesh.common.protocol.grpc.ConsumerService/subscribe", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ConsumerServiceServer).Subscribe(ctx, req.(*Subscription)) + } + return interceptor(ctx, in, info, handler) +} + +func _ConsumerService_SubscribeStream_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(ConsumerServiceServer).SubscribeStream(&consumerServiceSubscribeStreamServer{stream}) +} + +type ConsumerService_SubscribeStreamServer interface { + Send(*SimpleMessage) error + Recv() (*Subscription, error) + grpc.ServerStream +} + +type consumerServiceSubscribeStreamServer struct { + grpc.ServerStream +} + +func (x *consumerServiceSubscribeStreamServer) Send(m *SimpleMessage) error { + return x.ServerStream.SendMsg(m) +} + +func (x *consumerServiceSubscribeStreamServer) Recv() (*Subscription, error) { + m := new(Subscription) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _ConsumerService_Unsubscribe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Subscription) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ConsumerServiceServer).Unsubscribe(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/eventmesh.common.protocol.grpc.ConsumerService/unsubscribe", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ConsumerServiceServer).Unsubscribe(ctx, req.(*Subscription)) + } + return interceptor(ctx, in, info, handler) +} + +// ConsumerService_ServiceDesc is the grpc.ServiceDesc for ConsumerService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var ConsumerService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "eventmesh.common.protocol.grpc.ConsumerService", + HandlerType: (*ConsumerServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "subscribe", + Handler: _ConsumerService_Subscribe_Handler, + }, + { + MethodName: "unsubscribe", + Handler: _ConsumerService_Unsubscribe_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "subscribeStream", + Handler: _ConsumerService_SubscribeStream_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "eventmesh-client.proto", +} + +// HeartbeatServiceClient is the client API for HeartbeatService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type HeartbeatServiceClient interface { + Heartbeat(ctx context.Context, in *Heartbeat, opts ...grpc.CallOption) (*Response, error) +} + +type heartbeatServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewHeartbeatServiceClient(cc grpc.ClientConnInterface) HeartbeatServiceClient { + return &heartbeatServiceClient{cc} +} + +func (c *heartbeatServiceClient) Heartbeat(ctx context.Context, in *Heartbeat, opts ...grpc.CallOption) (*Response, error) { + out := new(Response) + err := c.cc.Invoke(ctx, "/eventmesh.common.protocol.grpc.HeartbeatService/heartbeat", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// HeartbeatServiceServer is the server API for HeartbeatService service. +// All implementations must embed UnimplementedHeartbeatServiceServer +// for forward compatibility +type HeartbeatServiceServer interface { + Heartbeat(context.Context, *Heartbeat) (*Response, error) + mustEmbedUnimplementedHeartbeatServiceServer() +} + +// UnimplementedHeartbeatServiceServer must be embedded to have forward compatible implementations. +type UnimplementedHeartbeatServiceServer struct { +} + +func (UnimplementedHeartbeatServiceServer) Heartbeat(context.Context, *Heartbeat) (*Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method Heartbeat not implemented") +} +func (UnimplementedHeartbeatServiceServer) mustEmbedUnimplementedHeartbeatServiceServer() {} + +// UnsafeHeartbeatServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to HeartbeatServiceServer will +// result in compilation errors. +type UnsafeHeartbeatServiceServer interface { + mustEmbedUnimplementedHeartbeatServiceServer() +} + +func RegisterHeartbeatServiceServer(s grpc.ServiceRegistrar, srv HeartbeatServiceServer) { + s.RegisterService(&HeartbeatService_ServiceDesc, srv) +} + +func _HeartbeatService_Heartbeat_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Heartbeat) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HeartbeatServiceServer).Heartbeat(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/eventmesh.common.protocol.grpc.HeartbeatService/heartbeat", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HeartbeatServiceServer).Heartbeat(ctx, req.(*Heartbeat)) + } + return interceptor(ctx, in, info, handler) +} + +// HeartbeatService_ServiceDesc is the grpc.ServiceDesc for HeartbeatService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var HeartbeatService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "eventmesh.common.protocol.grpc.HeartbeatService", + HandlerType: (*HeartbeatServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "heartbeat", + Handler: _HeartbeatService_Heartbeat_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "eventmesh-client.proto", +} diff --git a/eventmesh-sdk-go/grpc/protocol_type.go b/eventmesh-sdk-go/grpc/protocol_type.go new file mode 100644 index 0000000000..636d4cdb74 --- /dev/null +++ b/eventmesh-sdk-go/grpc/protocol_type.go @@ -0,0 +1,25 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grpc + +var ( + // EventmeshMessage eventmesh message protocol type + EventmeshMessage = "eventmeshmessage" + // cloudeventsMessage support later + cloudeventsMessage = "cloudevents" + // OpenMessage open message support later + OpenMessage = "openmessage" +) diff --git a/eventmesh-sdk-go/http/abstract_http_client.go b/eventmesh-sdk-go/http/abstract_http_client.go new file mode 100644 index 0000000000..2232d31130 --- /dev/null +++ b/eventmesh-sdk-go/http/abstract_http_client.go @@ -0,0 +1,58 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package http + +import ( + gcommon "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/conf" + nethttp "net/http" + "time" +) + +type AbstractHttpClient struct { + EventMeshHttpClientConfig conf.EventMeshHttpClientConfig + HttpClient *nethttp.Client +} + +func NewAbstractHttpClient(eventMeshHttpClientConfig conf.EventMeshHttpClientConfig) *AbstractHttpClient { + c := &AbstractHttpClient{EventMeshHttpClientConfig: eventMeshHttpClientConfig} + c.HttpClient = c.SetHttpClient() + return c +} + +func (c *AbstractHttpClient) Close() { + // Http Client does not need to close explicitly +} + +func (c *AbstractHttpClient) SetHttpClient() *nethttp.Client { + if !c.EventMeshHttpClientConfig.UseTls() { + return &nethttp.Client{Timeout: 100 * time.Second} + } + + // Use TLS + return &nethttp.Client{Timeout: 100 * time.Second} +} + +func (c *AbstractHttpClient) SelectEventMesh() string { + // FIXME Add load balance support + uri := c.EventMeshHttpClientConfig.LiteEventMeshAddr() + + if c.EventMeshHttpClientConfig.UseTls() { + return gcommon.Constants.HTTPS_PROTOCOL_PREFIX + uri + } + + return gcommon.Constants.HTTP_PROTOCOL_PREFIX + uri +} diff --git a/eventmesh-sdk-go/http/conf/eventmesh_http_client_config.go b/eventmesh-sdk-go/http/conf/eventmesh_http_client_config.go new file mode 100644 index 0000000000..d0a232a103 --- /dev/null +++ b/eventmesh-sdk-go/http/conf/eventmesh_http_client_config.go @@ -0,0 +1,159 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package conf + +type EventMeshHttpClientConfig struct { + //The event server address list + // If it's a cluster, please use ; to split, and the address format is related to loadBalanceType. + // E.g. + // If you use Random strategy, the format like: 127.0.0.1:10105;127.0.0.2:10105 + // If you use weighted round robin or weighted random strategy, the format like: 127.0.0.1:10105:1;127.0.0.2:10105:2 + liteEventMeshAddr string + // TODO support load balance + //loadBalanceType string + consumeThreadCore int + consumeThreadMax int + env string + consumerGroup string + producerGroup string + idc string + ip string + pid string + sys string + userName string + password string + useTls bool +} + +func (e *EventMeshHttpClientConfig) LiteEventMeshAddr() string { + return e.liteEventMeshAddr +} + +func (e *EventMeshHttpClientConfig) SetLiteEventMeshAddr(liteEventMeshAddr string) { + e.liteEventMeshAddr = liteEventMeshAddr +} + +func (e *EventMeshHttpClientConfig) ConsumeThreadCore() int { + return e.consumeThreadCore +} + +func (e *EventMeshHttpClientConfig) SetConsumeThreadCore(consumeThreadCore int) { + e.consumeThreadCore = consumeThreadCore +} + +func (e *EventMeshHttpClientConfig) ConsumeThreadMax() int { + return e.consumeThreadMax +} + +func (e *EventMeshHttpClientConfig) SetConsumeThreadMax(consumeThreadMax int) { + e.consumeThreadMax = consumeThreadMax +} + +func (e *EventMeshHttpClientConfig) Env() string { + return e.env +} + +func (e *EventMeshHttpClientConfig) SetEnv(env string) { + e.env = env +} + +func (e *EventMeshHttpClientConfig) ConsumerGroup() string { + return e.consumerGroup +} + +func (e *EventMeshHttpClientConfig) SetConsumerGroup(consumerGroup string) { + e.consumerGroup = consumerGroup +} + +func (e *EventMeshHttpClientConfig) ProducerGroup() string { + return e.producerGroup +} + +func (e *EventMeshHttpClientConfig) SetProducerGroup(producerGroup string) { + e.producerGroup = producerGroup +} + +func (e *EventMeshHttpClientConfig) Idc() string { + return e.idc +} + +func (e *EventMeshHttpClientConfig) SetIdc(idc string) { + e.idc = idc +} + +func (e *EventMeshHttpClientConfig) Ip() string { + return e.ip +} + +func (e *EventMeshHttpClientConfig) SetIp(ip string) { + e.ip = ip +} + +func (e *EventMeshHttpClientConfig) Pid() string { + return e.pid +} + +func (e *EventMeshHttpClientConfig) SetPid(pid string) { + e.pid = pid +} + +func (e *EventMeshHttpClientConfig) Sys() string { + return e.sys +} + +func (e *EventMeshHttpClientConfig) SetSys(sys string) { + e.sys = sys +} + +func (e *EventMeshHttpClientConfig) UserName() string { + return e.userName +} + +func (e *EventMeshHttpClientConfig) SetUserName(userName string) { + e.userName = userName +} + +func (e *EventMeshHttpClientConfig) Password() string { + return e.password +} + +func (e *EventMeshHttpClientConfig) SetPassword(password string) { + e.password = password +} + +func (e *EventMeshHttpClientConfig) UseTls() bool { + return e.useTls +} + +func (e *EventMeshHttpClientConfig) SetUseTls(useTls bool) { + e.useTls = useTls +} + +var DefaultEventMeshHttpClientConfig = EventMeshHttpClientConfig{ + liteEventMeshAddr: "127.0.0.1:10105", + consumeThreadCore: 2, + consumeThreadMax: 5, + env: "", + consumerGroup: "DefaultConsumerGroup", + producerGroup: "DefaultProducerGroup", + idc: "", + ip: "", + pid: "", + sys: "", + userName: "", + password: "", + useTls: false, +} diff --git a/eventmesh-sdk-go/http/consumer/eventmesh_http_consumer.go b/eventmesh-sdk-go/http/consumer/eventmesh_http_consumer.go new file mode 100644 index 0000000000..cbb26df6f6 --- /dev/null +++ b/eventmesh-sdk-go/http/consumer/eventmesh_http_consumer.go @@ -0,0 +1,110 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package consumer + +import ( + gcommon "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/http/body/client" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/http/common" + gutils "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/conf" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/model" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/utils" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + nethttp "net/http" + "strconv" + "time" +) + +type EventMeshHttpConsumer struct { + *http.AbstractHttpClient + subscriptions []protocol.SubscriptionItem +} + +func NewEventMeshHttpConsumer(eventMeshHttpClientConfig conf.EventMeshHttpClientConfig) *EventMeshHttpConsumer { + c := &EventMeshHttpConsumer{AbstractHttpClient: http.NewAbstractHttpClient(eventMeshHttpClientConfig)} + c.subscriptions = make([]protocol.SubscriptionItem, 1000) + return c +} + +func (e *EventMeshHttpConsumer) HeartBeat(topicList []protocol.SubscriptionItem, subscribeUrl string) { + + // FIXME check topicList, subscribeUrl is not blank + + for range time.Tick(time.Duration(gcommon.Constants.HEARTBEAT) * time.Millisecond) { + + var heartbeatEntities []client.HeartbeatEntity + for _, item := range topicList { + entity := client.HeartbeatEntity{Topic: item.Topic, Url: subscribeUrl} + heartbeatEntities = append(heartbeatEntities, entity) + } + + requestParam := e.buildCommonRequestParam() + requestParam.AddHeader(common.ProtocolKey.REQUEST_CODE, strconv.Itoa(common.DefaultRequestCode.HEARTBEAT.RequestCode)) + // FIXME Java is name of SUB name + //requestParam.AddBody(client.HeartbeatRequestBodyKey.CLIENTTYPE, common.DefaultClientType.SUB.name()) + requestParam.AddBody(client.HeartbeatRequestBodyKey.CLIENTTYPE, "SUB") + requestParam.AddBody(client.HeartbeatRequestBodyKey.HEARTBEATENTITIES, gutils.MarshalJsonString(heartbeatEntities)) + + target := e.SelectEventMesh() + resp := utils.HttpPost(e.HttpClient, target, requestParam) + var ret http.EventMeshRetObj + gutils.UnMarshalJsonString(resp, &ret) + if ret.RetCode != common.DefaultEventMeshRetCode.SUCCESS.RetCode { + log.Fatalf("Request failed, error code: %d", ret.RetCode) + } + + } + +} + +func (e *EventMeshHttpConsumer) Subscribe(topicList []protocol.SubscriptionItem, subscribeUrl string) { + + // FIXME check topicList, subscribeUrl is not blank + + requestParam := e.buildCommonRequestParam() + requestParam.AddHeader(common.ProtocolKey.REQUEST_CODE, strconv.Itoa(common.DefaultRequestCode.SUBSCRIBE.RequestCode)) + requestParam.AddBody(client.SubscribeRequestBodyKey.TOPIC, gutils.MarshalJsonString(topicList)) + requestParam.AddBody(client.SubscribeRequestBodyKey.URL, subscribeUrl) + requestParam.AddBody(client.SubscribeRequestBodyKey.CONSUMERGROUP, e.EventMeshHttpClientConfig.ConsumerGroup()) + + target := e.SelectEventMesh() + resp := utils.HttpPost(e.HttpClient, target, requestParam) + var ret http.EventMeshRetObj + gutils.UnMarshalJsonString(resp, &ret) + if ret.RetCode != common.DefaultEventMeshRetCode.SUCCESS.RetCode { + log.Fatalf("Request failed, error code: %d", ret.RetCode) + } + e.subscriptions = append(e.subscriptions, topicList...) +} + +func (e *EventMeshHttpConsumer) buildCommonRequestParam() *model.RequestParam { + param := model.NewRequestParam(nethttp.MethodPost) + param.AddHeader(common.ProtocolKey.ClientInstanceKey.ENV, e.EventMeshHttpClientConfig.Env()) + param.AddHeader(common.ProtocolKey.ClientInstanceKey.IDC, e.EventMeshHttpClientConfig.Idc()) + param.AddHeader(common.ProtocolKey.ClientInstanceKey.IP, e.EventMeshHttpClientConfig.Ip()) + param.AddHeader(common.ProtocolKey.ClientInstanceKey.PID, e.EventMeshHttpClientConfig.Pid()) + param.AddHeader(common.ProtocolKey.ClientInstanceKey.SYS, e.EventMeshHttpClientConfig.Sys()) + param.AddHeader(common.ProtocolKey.ClientInstanceKey.USERNAME, e.EventMeshHttpClientConfig.UserName()) + param.AddHeader(common.ProtocolKey.ClientInstanceKey.PASSWORD, e.EventMeshHttpClientConfig.Password()) + param.AddHeader(common.ProtocolKey.VERSION, common.DefaultProtocolVersion.V1.Version()) + param.AddHeader(common.ProtocolKey.LANGUAGE, gcommon.Constants.LANGUAGE_GO) + param.SetTimeout(gcommon.Constants.DEFAULT_HTTP_TIME_OUT) + param.AddBody(client.HeartbeatRequestBodyKey.CONSUMERGROUP, e.EventMeshHttpClientConfig.ConsumerGroup()) + return param +} diff --git a/eventmesh-sdk-go/http/eventmesh_ret_obj.go b/eventmesh-sdk-go/http/eventmesh_ret_obj.go new file mode 100644 index 0000000000..b92113cf0d --- /dev/null +++ b/eventmesh-sdk-go/http/eventmesh_ret_obj.go @@ -0,0 +1,22 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package http + +type EventMeshRetObj struct { + ResTime int64 `json:"resTime"` + RetCode int `json:"retCode"` + RetMsg string `json:"retMsg"` +} diff --git a/eventmesh-sdk-go/http/model/request_param.go b/eventmesh-sdk-go/http/model/request_param.go new file mode 100644 index 0000000000..1606aea9c5 --- /dev/null +++ b/eventmesh-sdk-go/http/model/request_param.go @@ -0,0 +1,68 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package model + +type HttpMethod string + +type RequestParam struct { + queryParams map[string][]string + httpMethod HttpMethod + body map[string]string + headers map[string]string + timeout int64 +} + +func NewRequestParam(httpMethod HttpMethod) *RequestParam { + return &RequestParam{httpMethod: httpMethod} +} + +func (r *RequestParam) QueryParams() map[string][]string { + return r.queryParams +} + +func (r *RequestParam) SetQueryParams(queryParams map[string][]string) { + r.queryParams = queryParams +} + +func (r *RequestParam) Body() map[string]string { + return r.body +} + +func (r *RequestParam) AddBody(key, value string) { + if r.body == nil { + r.body = make(map[string]string) + } + r.body[key] = value +} + +func (r *RequestParam) Headers() map[string]string { + return r.headers +} + +func (r *RequestParam) AddHeader(key string, object interface{}) { + if r.headers == nil { + r.headers = make(map[string]string) + } + r.headers[key] = object.(string) +} + +func (r *RequestParam) Timeout() int64 { + return r.timeout +} + +func (r *RequestParam) SetTimeout(timeout int64) { + r.timeout = timeout +} diff --git a/eventmesh-sdk-go/http/producer/cloudevent_producer.go b/eventmesh-sdk-go/http/producer/cloudevent_producer.go new file mode 100644 index 0000000000..815e665875 --- /dev/null +++ b/eventmesh-sdk-go/http/producer/cloudevent_producer.go @@ -0,0 +1,101 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package producer + +import ( + gcommon "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/http/common" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/http/message" + gutils "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/utils" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/conf" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/model" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/utils" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + cloudevents "github.com/cloudevents/sdk-go/v2" + + nethttp "net/http" + "strconv" +) + +type CloudEventProducer struct { + *http.AbstractHttpClient +} + +func NewCloudEventProducer(eventMeshHttpClientConfig conf.EventMeshHttpClientConfig) *CloudEventProducer { + c := &CloudEventProducer{AbstractHttpClient: http.NewAbstractHttpClient(eventMeshHttpClientConfig)} + return c +} + +func (c *CloudEventProducer) Publish(event cloudevents.Event) { + enhancedEvent := c.enhanceCloudEvent(event) + requestParam := c.buildCommonPostParam(enhancedEvent) + requestParam.AddHeader(common.ProtocolKey.REQUEST_CODE, strconv.Itoa(common.DefaultRequestCode.MSG_SEND_ASYNC.RequestCode)) + + target := c.SelectEventMesh() + resp := utils.HttpPost(c.HttpClient, target, requestParam) + var ret http.EventMeshRetObj + gutils.UnMarshalJsonString(resp, &ret) + if ret.RetCode != common.DefaultEventMeshRetCode.SUCCESS.RetCode { + log.Fatalf("Request failed, error code: %d", ret.RetCode) + } +} + +func (c *CloudEventProducer) buildCommonPostParam(event cloudevents.Event) *model.RequestParam { + + eventBytes, err := event.MarshalJSON() + if err != nil { + log.Fatalf("Failed to marshal cloudevent") + } + content := string(eventBytes) + + requestParam := model.NewRequestParam(nethttp.MethodPost) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.ENV, c.EventMeshHttpClientConfig.Env()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.IDC, c.EventMeshHttpClientConfig.Idc()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.IP, c.EventMeshHttpClientConfig.Ip()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.PID, c.EventMeshHttpClientConfig.Pid()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.SYS, c.EventMeshHttpClientConfig.Sys()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.USERNAME, c.EventMeshHttpClientConfig.UserName()) + requestParam.AddHeader(common.ProtocolKey.ClientInstanceKey.PASSWORD, c.EventMeshHttpClientConfig.Password()) + requestParam.AddHeader(common.ProtocolKey.LANGUAGE, gcommon.Constants.LANGUAGE_GO) + // FIXME Improve constants + requestParam.AddHeader(common.ProtocolKey.PROTOCOL_TYPE, "cloudevents") + requestParam.AddHeader(common.ProtocolKey.PROTOCOL_DESC, "http") + requestParam.AddHeader(common.ProtocolKey.PROTOCOL_VERSION, event.SpecVersion()) + + // todo: move producerGroup tp header + requestParam.AddBody(message.SendMessageRequestBodyKey.PRODUCERGROUP, c.EventMeshHttpClientConfig.ProducerGroup()) + requestParam.AddBody(message.SendMessageRequestBodyKey.CONTENT, content) + + return requestParam +} + +func (c *CloudEventProducer) enhanceCloudEvent(event cloudevents.Event) cloudevents.Event { + event.SetExtension(common.ProtocolKey.ClientInstanceKey.ENV, c.EventMeshHttpClientConfig.Env()) + event.SetExtension(common.ProtocolKey.ClientInstanceKey.IDC, c.EventMeshHttpClientConfig.Idc()) + event.SetExtension(common.ProtocolKey.ClientInstanceKey.IP, c.EventMeshHttpClientConfig.Ip()) + event.SetExtension(common.ProtocolKey.ClientInstanceKey.PID, c.EventMeshHttpClientConfig.Pid()) + event.SetExtension(common.ProtocolKey.ClientInstanceKey.SYS, c.EventMeshHttpClientConfig.Sys()) + // FIXME Random string + event.SetExtension(common.ProtocolKey.ClientInstanceKey.BIZSEQNO, "333333") + event.SetExtension(common.ProtocolKey.ClientInstanceKey.UNIQUEID, "444444") + event.SetExtension(common.ProtocolKey.LANGUAGE, gcommon.Constants.LANGUAGE_GO) + // FIXME Java is name of spec version name + //event.SetExtension(common.ProtocolKey.PROTOCOL_DESC, event.SpecVersion()) + event.SetExtension(common.ProtocolKey.PROTOCOL_VERSION, event.SpecVersion()) + + return event +} diff --git a/eventmesh-sdk-go/http/producer/eventmesh_http_producer.go b/eventmesh-sdk-go/http/producer/eventmesh_http_producer.go new file mode 100644 index 0000000000..e4eb3c43dd --- /dev/null +++ b/eventmesh-sdk-go/http/producer/eventmesh_http_producer.go @@ -0,0 +1,42 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package producer + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/conf" + cloudevents "github.com/cloudevents/sdk-go/v2" +) + +type EventMeshHttpProducer struct { + cloudEventProducer *CloudEventProducer +} + +func NewEventMeshHttpProducer(eventMeshHttpClientConfig conf.EventMeshHttpClientConfig) *EventMeshHttpProducer { + return &EventMeshHttpProducer{ + cloudEventProducer: NewCloudEventProducer(eventMeshHttpClientConfig), + } +} + +func (e *EventMeshHttpProducer) Publish(eventMeshMessage interface{}) { + + // FIXME Check eventMeshMessage is not nil + + // CloudEvent + if _, ok := eventMeshMessage.(cloudevents.Event); ok { + event := eventMeshMessage.(cloudevents.Event) + e.cloudEventProducer.Publish(event) + } +} diff --git a/eventmesh-sdk-go/http/producer/eventmesh_protocol_producer.go b/eventmesh-sdk-go/http/producer/eventmesh_protocol_producer.go new file mode 100644 index 0000000000..de56476b75 --- /dev/null +++ b/eventmesh-sdk-go/http/producer/eventmesh_protocol_producer.go @@ -0,0 +1,20 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package producer + +type EventMeshProtocolProducer interface { + Publish(eventMeshMessage interface{}) +} diff --git a/eventmesh-sdk-go/http/utils/http_utils.go b/eventmesh-sdk-go/http/utils/http_utils.go new file mode 100644 index 0000000000..e11913271b --- /dev/null +++ b/eventmesh-sdk-go/http/utils/http_utils.go @@ -0,0 +1,56 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utils + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/http/model" + "io/ioutil" + nethttp "net/http" + "net/url" + "strings" +) + +func HttpPost(client *nethttp.Client, uri string, requestParam *model.RequestParam) string { + + data := url.Values{} + body := requestParam.Body() + for key := range body { + data.Set(key, body[key]) + } + + req, err := nethttp.NewRequest(nethttp.MethodPost, uri, strings.NewReader(data.Encode())) + if err != nil { + } + + req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") + + headers := requestParam.Headers() + for header := range headers { + req.Header[header] = []string{headers[header]} + } + + resp, err := client.Do(req) + if err != nil { + } + + defer resp.Body.Close() + + respBody, err := ioutil.ReadAll(resp.Body) + if err != nil { + } + + return string(respBody) +} diff --git a/eventmesh-sdk-go/log/logger.go b/eventmesh-sdk-go/log/logger.go new file mode 100644 index 0000000000..e500511dcf --- /dev/null +++ b/eventmesh-sdk-go/log/logger.go @@ -0,0 +1,163 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package log + +import ( + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "time" +) + +var ( + // _defaultLogger global log instance, default to zap.log + _defaultLogger Logger = &DefaultLogger{ + SugaredLogger: func() *zap.SugaredLogger { + encoder := zapcore.EncoderConfig{ + TimeKey: "ts", + LevelKey: "level", + NameKey: "logger", + CallerKey: "caller", + MessageKey: "msg", + StacktraceKey: "stacktrace", + LineEnding: zapcore.DefaultLineEnding, + EncodeLevel: zapcore.CapitalLevelEncoder, + EncodeTime: func(time time.Time, encoder zapcore.PrimitiveArrayEncoder) { + encoder.AppendString(time.Format("2006-01-02 15:04:05.000")) + }, + EncodeDuration: zapcore.SecondsDurationEncoder, + EncodeCaller: zapcore.ShortCallerEncoder, + } + l, _ := zap.Config{ + Level: zap.NewAtomicLevelAt(zap.InfoLevel), + Development: false, + Sampling: &zap.SamplingConfig{ + Initial: 100, + Thereafter: 100, + }, + Encoding: "console", + EncoderConfig: encoder, + OutputPaths: []string{"stderr"}, + ErrorOutputPaths: []string{"stderr"}, + }.Build([]zap.Option{zap.AddCallerSkip(2)}...) + return l.Sugar() + }(), + } +) + +// SetLogger set the log +func SetLogger(l Logger) { + _defaultLogger = l +} + +func Debugf(template string, args ...interface{}) { + _defaultLogger.Debugf(template, args...) +} + +func Infof(template string, args ...interface{}) { + _defaultLogger.Infof(template, args...) +} + +// Warnf uses fmt.Sprintf to log a templated message. +func Warnf(template string, args ...interface{}) { + _defaultLogger.Warnf(template, args...) +} + +// Errorf uses fmt.Sprintf to log a templated message. +func Errorf(template string, args ...interface{}) { + _defaultLogger.Errorf(template, args...) +} + +// DPanicf uses fmt.Sprintf to log a templated message. In development, the +// log then panics. (See DPanicLevel for details.) +func DPanicf(template string, args ...interface{}) { + _defaultLogger.DPanicf(template, args...) +} + +// Panicf uses fmt.Sprintf to log a templated message, then panics. +func Panicf(template string, args ...interface{}) { + _defaultLogger.Panicf(template, args...) +} + +// Fatalf uses fmt.Sprintf to log a templated message, then calls os.Exit. +func Fatalf(template string, args ...interface{}) { + _defaultLogger.Fatalf(template, args...) +} + +// Logger define the log api for eventmesh +type Logger interface { + // Debugf uses fmt.Sprintf to log a templated message. + // DebugLevel logs are typically voluminous, and are usually disabled in + // production. + Debugf(template string, args ...interface{}) + + // Infof uses fmt.Sprintf to log a templated message. + // InfoLevel is the default logging priority. + Infof(template string, args ...interface{}) + + // Warnf uses fmt.Sprintf to log a templated message. + // WarnLevel logs are more important than Info, but don't need individual + // human review. + Warnf(template string, args ...interface{}) + + // Errorf uses fmt.Sprintf to log a templated message. + // ErrorLevel logs are high-priority. If an application is running smoothly, + // it shouldn't generate any error-level logs. + Errorf(template string, args ...interface{}) + + // DPanicf uses fmt.Sprintf to log a templated message. In development, the + // DPanicLevel logs are particularly important errors. In development the + // log panics after writing the message. + DPanicf(template string, args ...interface{}) + + // Panicf uses fmt.Sprintf to log a templated message, then panics. + Panicf(template string, args ...interface{}) + + // Fatalf uses fmt.Sprintf to log a templated message, then calls os.Exit. + Fatalf(template string, args ...interface{}) +} + +// DefaultLogger write log by zap log +type DefaultLogger struct { + *zap.SugaredLogger +} + +func (s *DefaultLogger) Debugf(template string, args ...interface{}) { + s.SugaredLogger.Debugf(template, args...) +} + +func (s *DefaultLogger) Infof(template string, args ...interface{}) { + s.SugaredLogger.Infof(template, args...) +} + +func (s *DefaultLogger) Warnf(template string, args ...interface{}) { + s.SugaredLogger.Warnf(template, args...) +} + +func (s *DefaultLogger) Errorf(template string, args ...interface{}) { + s.SugaredLogger.Errorf(template, args...) +} + +func (s *DefaultLogger) DPanicf(template string, args ...interface{}) { + s.SugaredLogger.DPanicf(template, args...) +} + +func (s *DefaultLogger) Panicf(template string, args ...interface{}) { + s.SugaredLogger.Panicf(template, args...) +} + +func (s *DefaultLogger) Fatalf(template string, args ...interface{}) { + s.SugaredLogger.Fatalf(template, args...) +} diff --git a/eventmesh-sdk-go/tcp/cloudevent_tcp_client.go b/eventmesh-sdk-go/tcp/cloudevent_tcp_client.go new file mode 100644 index 0000000000..b868f04ecb --- /dev/null +++ b/eventmesh-sdk-go/tcp/cloudevent_tcp_client.go @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tcp + +import ( + gtcp "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/conf" +) + +type CloudEventTCPClient struct { + cloudEventTCPPubClient *CloudEventTCPPubClient + cloudEventTCPSubClient *CloudEventTCPSubClient +} + +func NewCloudEventTCPClient(eventMeshTcpClientConfig conf.EventMeshTCPClientConfig) *CloudEventTCPClient { + return &CloudEventTCPClient{ + cloudEventTCPPubClient: NewCloudEventTCPPubClient(eventMeshTcpClientConfig), + cloudEventTCPSubClient: NewCloudEventTCPSubClient(eventMeshTcpClientConfig), + } +} + +func (c *CloudEventTCPClient) Init() { + c.cloudEventTCPPubClient.init() + c.cloudEventTCPSubClient.init() +} + +func (c *CloudEventTCPClient) Publish(message interface{}, timeout int64) gtcp.Package { + return c.cloudEventTCPPubClient.publish(message, timeout) +} + +func (c *CloudEventTCPClient) GetPubClient() EventMeshTCPPubClient { + return c.cloudEventTCPPubClient +} + +func (c *CloudEventTCPClient) GetSubClient() EventMeshTCPSubClient { + return c.cloudEventTCPSubClient +} diff --git a/eventmesh-sdk-go/tcp/cloudevent_tcp_pub_client.go b/eventmesh-sdk-go/tcp/cloudevent_tcp_pub_client.go new file mode 100644 index 0000000000..b2a793a172 --- /dev/null +++ b/eventmesh-sdk-go/tcp/cloudevent_tcp_pub_client.go @@ -0,0 +1,46 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tcp + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/conf" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/utils" +) + +type CloudEventTCPPubClient struct { + *BaseTCPClient +} + +func NewCloudEventTCPPubClient(eventMeshTcpClientConfig conf.EventMeshTCPClientConfig) *CloudEventTCPPubClient { + return &CloudEventTCPPubClient{BaseTCPClient: NewBaseTCPClient(eventMeshTcpClientConfig)} +} + +func (c CloudEventTCPPubClient) init() { + c.Open() + c.Hello() + c.Heartbeat() +} + +func (c CloudEventTCPPubClient) reconnect() { + c.Reconnect() + c.Heartbeat() +} + +func (c CloudEventTCPPubClient) publish(message interface{}, timeout int64) tcp.Package { + msg := utils.BuildPackage(message, tcp.DefaultCommand.ASYNC_MESSAGE_TO_SERVER) + return c.IO(msg, timeout) +} diff --git a/eventmesh-sdk-go/tcp/cloudevent_tcp_sub_client.go b/eventmesh-sdk-go/tcp/cloudevent_tcp_sub_client.go new file mode 100644 index 0000000000..813cb595db --- /dev/null +++ b/eventmesh-sdk-go/tcp/cloudevent_tcp_sub_client.go @@ -0,0 +1,41 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tcp + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/conf" +) + +type CloudEventTCPSubClient struct { + *BaseTCPClient +} + +func NewCloudEventTCPSubClient(eventMeshTcpClientConfig conf.EventMeshTCPClientConfig) *CloudEventTCPSubClient { + return &CloudEventTCPSubClient{BaseTCPClient: NewBaseTCPClient(eventMeshTcpClientConfig)} +} + +func (c CloudEventTCPSubClient) init() { + //panic("implement me") +} + +func (c CloudEventTCPSubClient) subscribe(topic string, subscriptionMode protocol.SubscriptionMode, subscriptionType protocol.SubscriptionType) { + panic("implement me") +} + +func (c CloudEventTCPSubClient) unsubscribe() { + panic("implement me") +} diff --git a/eventmesh-sdk-go/tcp/common/eventmesh_common.go b/eventmesh-sdk-go/tcp/common/eventmesh_common.go new file mode 100644 index 0000000000..39efb28864 --- /dev/null +++ b/eventmesh-sdk-go/tcp/common/eventmesh_common.go @@ -0,0 +1,37 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package common + +var EventMeshCommon = struct { + // Timeout time shared by the server + DEFAULT_TIME_OUT_MILLS int + + // User agent + USER_AGENT_PURPOSE_PUB string + USER_AGENT_PURPOSE_SUB string + + // Protocol type + CLOUD_EVENTS_PROTOCOL_NAME string + EM_MESSAGE_PROTOCOL_NAME string + OPEN_MESSAGE_PROTOCOL_NAME string +}{ + DEFAULT_TIME_OUT_MILLS: 20 * 1000, + USER_AGENT_PURPOSE_PUB: "pub", + USER_AGENT_PURPOSE_SUB: "sub", + CLOUD_EVENTS_PROTOCOL_NAME: "cloudevents", + EM_MESSAGE_PROTOCOL_NAME: "eventmeshmessage", + OPEN_MESSAGE_PROTOCOL_NAME: "openmessage", +} diff --git a/eventmesh-sdk-go/tcp/common/request_context.go b/eventmesh-sdk-go/tcp/common/request_context.go new file mode 100644 index 0000000000..0b67ab26f6 --- /dev/null +++ b/eventmesh-sdk-go/tcp/common/request_context.go @@ -0,0 +1,75 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package common + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" + "sync" +) + +type RequestContext struct { + key interface{} + request tcp.Package + response tcp.Package + wg sync.WaitGroup +} + +func (r *RequestContext) Key() interface{} { + return r.key +} + +func (r *RequestContext) SetKey(key interface{}) { + r.key = key +} + +func (r *RequestContext) Request() tcp.Package { + return r.request +} + +func (r *RequestContext) SetRequest(request tcp.Package) { + r.request = request +} + +func (r *RequestContext) Response() tcp.Package { + return r.response +} + +func (r *RequestContext) SetResponse(response tcp.Package) { + r.response = response +} + +func (r *RequestContext) Wg() sync.WaitGroup { + return r.wg +} + +func (r *RequestContext) SetWg(wg sync.WaitGroup) { + r.wg = wg +} + +func (r *RequestContext) Finish(message tcp.Package) { + r.response = message + //r.wg.Done() +} + +func GetRequestContextKey(request tcp.Package) interface{} { + return request.Header.Seq +} + +func NewRequestContext(key interface{}, request tcp.Package, latch int) *RequestContext { + ctx := &RequestContext{key: key, request: request} + //ctx.Wg().Add(latch) + return ctx +} diff --git a/eventmesh-sdk-go/tcp/conf/eventmesh_tcp_client_config.go b/eventmesh-sdk-go/tcp/conf/eventmesh_tcp_client_config.go new file mode 100644 index 0000000000..9cf5dd5a1f --- /dev/null +++ b/eventmesh-sdk-go/tcp/conf/eventmesh_tcp_client_config.go @@ -0,0 +1,52 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package conf + +import "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" + +type EventMeshTCPClientConfig struct { + host string + port int + userAgent tcp.UserAgent +} + +func NewEventMeshTCPClientConfig(host string, port int, userAgent tcp.UserAgent) *EventMeshTCPClientConfig { + return &EventMeshTCPClientConfig{host: host, port: port, userAgent: userAgent} +} + +func (e *EventMeshTCPClientConfig) Host() string { + return e.host +} + +func (e *EventMeshTCPClientConfig) SetHost(host string) { + e.host = host +} + +func (e *EventMeshTCPClientConfig) Port() int { + return e.port +} + +func (e *EventMeshTCPClientConfig) SetPort(port int) { + e.port = port +} + +func (e *EventMeshTCPClientConfig) UserAgent() tcp.UserAgent { + return e.userAgent +} + +func (e *EventMeshTCPClientConfig) SetUserAgent(userAgent tcp.UserAgent) { + e.userAgent = userAgent +} diff --git a/eventmesh-sdk-go/tcp/eventmesh_tcp_client.go b/eventmesh-sdk-go/tcp/eventmesh_tcp_client.go new file mode 100644 index 0000000000..0a7c589159 --- /dev/null +++ b/eventmesh-sdk-go/tcp/eventmesh_tcp_client.go @@ -0,0 +1,25 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tcp + +import gtcp "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" + +type EventMeshTCPClient interface { + Init() + Publish(msg interface{}, timeout int64) gtcp.Package + GetPubClient() EventMeshTCPPubClient + GetSubClient() EventMeshTCPSubClient +} diff --git a/eventmesh-sdk-go/tcp/eventmesh_tcp_client_factory.go b/eventmesh-sdk-go/tcp/eventmesh_tcp_client_factory.go new file mode 100644 index 0000000000..7256c87f60 --- /dev/null +++ b/eventmesh-sdk-go/tcp/eventmesh_tcp_client_factory.go @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tcp + +import ( + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/conf" +) + +func CreateEventMeshTCPClient(eventMeshTcpClientConfig conf.EventMeshTCPClientConfig, messageType protocol.MessageType) EventMeshTCPClient { + + if messageType == protocol.DefaultMessageType.CloudEvent { + return NewCloudEventTCPClient(eventMeshTcpClientConfig) + } + + return nil +} diff --git a/eventmesh-sdk-go/tcp/eventmesh_tcp_pub_client.go b/eventmesh-sdk-go/tcp/eventmesh_tcp_pub_client.go new file mode 100644 index 0000000000..6dd0bc47a3 --- /dev/null +++ b/eventmesh-sdk-go/tcp/eventmesh_tcp_pub_client.go @@ -0,0 +1,24 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tcp + +import gtcp "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" + +type EventMeshTCPPubClient interface { + init() + reconnect() + publish(message interface{}, timeout int64) gtcp.Package +} diff --git a/eventmesh-sdk-go/tcp/eventmesh_tcp_sub_client.go b/eventmesh-sdk-go/tcp/eventmesh_tcp_sub_client.go new file mode 100644 index 0000000000..98be7bba2f --- /dev/null +++ b/eventmesh-sdk-go/tcp/eventmesh_tcp_sub_client.go @@ -0,0 +1,24 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tcp + +import "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol" + +type EventMeshTCPSubClient interface { + init() + subscribe(topic string, subscriptionMode protocol.SubscriptionMode, subscriptionType protocol.SubscriptionType) + unsubscribe() +} diff --git a/eventmesh-sdk-go/tcp/tcp_client.go b/eventmesh-sdk-go/tcp/tcp_client.go new file mode 100644 index 0000000000..afd6342b2d --- /dev/null +++ b/eventmesh-sdk-go/tcp/tcp_client.go @@ -0,0 +1,145 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tcp + +import ( + "bufio" + "bytes" + "io" + "math/rand" + "net" + "strconv" + + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp/codec" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/common" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/conf" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/utils" +) + +type BaseTCPClient struct { + clientNo int + host string + port int + useAgent tcp.UserAgent + conn net.Conn +} + +func NewBaseTCPClient(eventMeshTcpClientConfig conf.EventMeshTCPClientConfig) *BaseTCPClient { + return &BaseTCPClient{ + clientNo: rand.Intn(10000), + host: eventMeshTcpClientConfig.Host(), + port: eventMeshTcpClientConfig.Port(), + useAgent: eventMeshTcpClientConfig.UserAgent(), + } +} + +func (c *BaseTCPClient) Open() { + eventMeshIpAndPort := c.host + ":" + strconv.Itoa(c.port) + conn, err := net.Dial("tcp", eventMeshIpAndPort) + if err != nil { + log.Errorf("Failed to dial") + } + c.conn = conn + + go c.read() +} + +func (c *BaseTCPClient) Close() { + if c.conn != nil { + err := c.conn.Close() + if err != nil { + log.Errorf("Failed to close connection") + } + c.Goodbye() + } +} + +func (c *BaseTCPClient) Heartbeat() { + msg := utils.BuildHeartBeatPackage() + c.IO(msg, 1000) +} + +func (c *BaseTCPClient) Hello() { + msg := utils.BuildHelloPackage(c.useAgent) + c.IO(msg, 1000) +} + +func (c *BaseTCPClient) Reconnect() { + +} + +func (c *BaseTCPClient) Goodbye() { + +} + +func (c *BaseTCPClient) IsActive() { + +} + +func (c *BaseTCPClient) read() error { + for { + var buf bytes.Buffer + for { + reader := bufio.NewReader(c.conn) + msg, isPrefix, err := reader.ReadLine() + if err != nil { + if err == io.EOF { + break + } + return err + } + + buf.Write(msg) + if !isPrefix { + break + } + } + + go c.handleRead(&buf) + } +} + +func (c *BaseTCPClient) handleRead(in *bytes.Buffer) { + decoded := codec.DecodePackage(in) + log.Panicf("Read from server: %v", decoded) + // TODO Handle according to the command +} + +func (c *BaseTCPClient) write(message []byte) (int, error) { + writer := bufio.NewWriter(c.conn) + n, err := writer.Write(message) + if err == nil { + err = writer.Flush() + } + return n, err +} + +func (c *BaseTCPClient) Send(message tcp.Package) { + out := codec.EncodePackage(message) + _, err := c.write(out.Bytes()) + if err != nil { + log.Fatalf("Failed to write to peer") + } +} + +func (c *BaseTCPClient) IO(message tcp.Package, timeout int64) tcp.Package { + key := common.GetRequestContextKey(message) + ctx := common.NewRequestContext(key, message, 1) + c.Send(message) + return ctx.Response() +} diff --git a/eventmesh-sdk-go/tcp/utils/message_utils.go b/eventmesh-sdk-go/tcp/utils/message_utils.go new file mode 100644 index 0000000000..7a8a7cd098 --- /dev/null +++ b/eventmesh-sdk-go/tcp/utils/message_utils.go @@ -0,0 +1,60 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utils + +import ( + gcommon "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/common/protocol/tcp" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/log" + "github.com/apache/incubator-eventmesh/eventmesh-sdk-go/tcp/common" + cloudevents "github.com/cloudevents/sdk-go/v2" +) + +func BuildPackage(message interface{}, command tcp.Command) tcp.Package { + // FIXME Support random sequence + header := tcp.NewHeader(command, 0, "", "22222") + pkg := tcp.NewPackage(header) + + if _, ok := message.(cloudevents.Event); ok { + event := message.(cloudevents.Event) + eventBytes, err := event.MarshalJSON() + if err != nil { + log.Fatalf("Failed to marshal cloud event") + } + + pkg.Header.PutProperty(gcommon.Constants.PROTOCOL_TYPE, common.EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME) + pkg.Header.PutProperty(gcommon.Constants.PROTOCOL_VERSION, event.SpecVersion()) + pkg.Header.PutProperty(gcommon.Constants.PROTOCOL_DESC, "tcp") + pkg.Body = eventBytes + } + + return pkg +} + +func BuildHelloPackage(agent tcp.UserAgent) tcp.Package { + // FIXME Support random sequence + header := tcp.NewHeader(tcp.DefaultCommand.HELLO_REQUEST, 0, "", "22222") + msg := tcp.NewPackage(header) + msg.Body = agent + return msg +} + +func BuildHeartBeatPackage() tcp.Package { + // FIXME Support random sequence + header := tcp.NewHeader(tcp.DefaultCommand.HEARTBEAT_REQUEST, 0, "", "22222") + msg := tcp.NewPackage(header) + return msg +}