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

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
}