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.
		
		
		
		
		
			
		
			
				
					
					
						
							112 lines
						
					
					
						
							3.6 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							112 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
							 | 
						|
								}
							 |