github.com/hack0072008/kafka-go@v1.0.1/protocol/response.go (about)

     1  package protocol
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  )
     7  
     8  func ReadResponse(r io.Reader, apiKey ApiKey, apiVersion int16) (correlationID int32, msg Message, err error) {
     9  	if i := int(apiKey); i < 0 || i >= len(apiTypes) {
    10  		err = fmt.Errorf("unsupported api key: %d", i)
    11  		return
    12  	}
    13  
    14  	t := &apiTypes[apiKey]
    15  	if t == nil {
    16  		err = fmt.Errorf("unsupported api: %s", apiNames[apiKey])
    17  		return
    18  	}
    19  
    20  	minVersion := t.minVersion()
    21  	maxVersion := t.maxVersion()
    22  
    23  	if apiVersion < minVersion || apiVersion > maxVersion {
    24  		err = fmt.Errorf("unsupported %s version: v%d not in range v%d-v%d", apiKey, apiVersion, minVersion, maxVersion)
    25  		return
    26  	}
    27  
    28  	d := &decoder{reader: r, remain: 4}
    29  	size := d.readInt32()
    30  
    31  	if err = d.err; err != nil {
    32  		err = dontExpectEOF(err)
    33  		return
    34  	}
    35  
    36  	d.remain = int(size)
    37  	correlationID = d.readInt32()
    38  
    39  	res := &t.responses[apiVersion-minVersion]
    40  
    41  	if res.flexible {
    42  		// In the flexible case, there's a tag buffer at the end of the response header
    43  		taggedCount := int(d.readUnsignedVarInt())
    44  		for i := 0; i < taggedCount; i++ {
    45  			d.readUnsignedVarInt() // tagID
    46  			size := d.readUnsignedVarInt()
    47  
    48  			// Just throw away the values for now
    49  			d.read(int(size))
    50  		}
    51  	}
    52  
    53  	msg = res.new()
    54  	res.decode(d, valueOf(msg))
    55  	d.discardAll()
    56  
    57  	if err = d.err; err != nil {
    58  		err = dontExpectEOF(err)
    59  	}
    60  
    61  	return
    62  }
    63  
    64  func WriteResponse(w io.Writer, apiVersion int16, correlationID int32, msg Message) error {
    65  	apiKey := msg.ApiKey()
    66  
    67  	if i := int(apiKey); i < 0 || i >= len(apiTypes) {
    68  		return fmt.Errorf("unsupported api key: %d", i)
    69  	}
    70  
    71  	t := &apiTypes[apiKey]
    72  	if t == nil {
    73  		return fmt.Errorf("unsupported api: %s", apiNames[apiKey])
    74  	}
    75  
    76  	minVersion := t.minVersion()
    77  	maxVersion := t.maxVersion()
    78  
    79  	if apiVersion < minVersion || apiVersion > maxVersion {
    80  		return fmt.Errorf("unsupported %s version: v%d not in range v%d-v%d", apiKey, apiVersion, minVersion, maxVersion)
    81  	}
    82  
    83  	r := &t.responses[apiVersion-minVersion]
    84  	v := valueOf(msg)
    85  	b := newPageBuffer()
    86  	defer b.unref()
    87  
    88  	e := &encoder{writer: b}
    89  	e.writeInt32(0) // placeholder for the response size
    90  	e.writeInt32(correlationID)
    91  	if r.flexible {
    92  		// Flexible messages use extra space for a tag buffer,
    93  		// which begins with a size value. Since we're not writing any fields into the
    94  		// latter, we can just write zero for now.
    95  		//
    96  		// See
    97  		// https://cwiki.apache.org/confluence/display/KAFKA/KIP-482%3A+The+Kafka+Protocol+should+Support+Optional+Tagged+Fields
    98  		// for details.
    99  		e.writeUnsignedVarInt(0)
   100  	}
   101  	r.encode(e, v)
   102  	err := e.err
   103  
   104  	if err == nil {
   105  		size := packUint32(uint32(b.Size()) - 4)
   106  		b.WriteAt(size[:], 0)
   107  		_, err = b.WriteTo(w)
   108  	}
   109  
   110  	return err
   111  }