You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
3.6 KiB
114 lines
3.6 KiB
package protocol
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
)
|
|
|
|
// handleDescribeCluster implements the DescribeCluster API (key 60, versions 0-1)
|
|
// This API is used by Java AdminClient for broker discovery (KIP-919)
|
|
// Response format (flexible, all versions):
|
|
//
|
|
// ThrottleTimeMs(int32) + ErrorCode(int16) + ErrorMessage(compact nullable string) +
|
|
// [v1+: EndpointType(int8)] + ClusterId(compact string) + ControllerId(int32) +
|
|
// Brokers(compact array) + ClusterAuthorizedOperations(int32) + TaggedFields
|
|
func (h *Handler) handleDescribeCluster(correlationID uint32, apiVersion uint16, requestBody []byte) ([]byte, error) {
|
|
|
|
// Parse request fields (all flexible format)
|
|
offset := 0
|
|
|
|
// IncludeClusterAuthorizedOperations (bool - 1 byte)
|
|
if offset >= len(requestBody) {
|
|
return nil, fmt.Errorf("incomplete DescribeCluster request")
|
|
}
|
|
includeAuthorizedOps := requestBody[offset] != 0
|
|
offset++
|
|
|
|
// EndpointType (int8, v1+)
|
|
var endpointType int8 = 1 // Default: brokers
|
|
if apiVersion >= 1 {
|
|
if offset >= len(requestBody) {
|
|
return nil, fmt.Errorf("incomplete DescribeCluster v1+ request")
|
|
}
|
|
endpointType = int8(requestBody[offset])
|
|
offset++
|
|
}
|
|
|
|
// Tagged fields at end of request
|
|
// (We don't parse them, just skip)
|
|
|
|
|
|
// Build response
|
|
response := make([]byte, 0, 256)
|
|
|
|
// ThrottleTimeMs (int32)
|
|
response = append(response, 0, 0, 0, 0)
|
|
|
|
// ErrorCode (int16) - no error
|
|
response = append(response, 0, 0)
|
|
|
|
// ErrorMessage (compact nullable string) - null
|
|
response = append(response, 0x00) // varint 0 = null
|
|
|
|
// EndpointType (int8, v1+)
|
|
if apiVersion >= 1 {
|
|
response = append(response, byte(endpointType))
|
|
}
|
|
|
|
// ClusterId (compact string)
|
|
clusterID := "seaweedfs-kafka-gateway"
|
|
response = append(response, CompactArrayLength(uint32(len(clusterID)))...)
|
|
response = append(response, []byte(clusterID)...)
|
|
|
|
// ControllerId (int32) - use broker ID 1
|
|
controllerIDBytes := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(controllerIDBytes, uint32(1))
|
|
response = append(response, controllerIDBytes...)
|
|
|
|
// Brokers (compact array)
|
|
// Get advertised address
|
|
host, port := h.GetAdvertisedAddress(h.GetGatewayAddress())
|
|
|
|
// Broker count (compact array length)
|
|
response = append(response, CompactArrayLength(1)...) // 1 broker
|
|
|
|
// Broker 0: BrokerId(int32) + Host(compact string) + Port(int32) + Rack(compact nullable string) + TaggedFields
|
|
brokerIDBytes := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(brokerIDBytes, uint32(1))
|
|
response = append(response, brokerIDBytes...) // BrokerId = 1
|
|
|
|
// Host (compact string)
|
|
response = append(response, CompactArrayLength(uint32(len(host)))...)
|
|
response = append(response, []byte(host)...)
|
|
|
|
// Port (int32) - validate port range
|
|
if port < 0 || port > 65535 {
|
|
return nil, fmt.Errorf("invalid port number: %d", port)
|
|
}
|
|
portBytes := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(portBytes, uint32(port))
|
|
response = append(response, portBytes...)
|
|
|
|
// Rack (compact nullable string) - null
|
|
response = append(response, 0x00) // varint 0 = null
|
|
|
|
// Per-broker tagged fields
|
|
response = append(response, 0x00) // Empty tagged fields
|
|
|
|
// ClusterAuthorizedOperations (int32) - -2147483648 (INT32_MIN) means not included
|
|
authOpsBytes := make([]byte, 4)
|
|
if includeAuthorizedOps {
|
|
// For now, return 0 (no operations authorized)
|
|
binary.BigEndian.PutUint32(authOpsBytes, 0)
|
|
} else {
|
|
// -2147483648 = INT32_MIN = operations not included
|
|
binary.BigEndian.PutUint32(authOpsBytes, 0x80000000)
|
|
}
|
|
response = append(response, authOpsBytes...)
|
|
|
|
// Response-level tagged fields (flexible response)
|
|
response = append(response, 0x00) // Empty tagged fields
|
|
|
|
|
|
return response, nil
|
|
}
|