github.com/hoveychen/kafka-go@v0.4.42/protocol/request.go (about) 1 package protocol 2 3 import ( 4 "fmt" 5 "io" 6 ) 7 8 func ReadRequest(r io.Reader) (apiVersion int16, correlationID int32, clientID string, msg Message, err error) { 9 d := &decoder{reader: r, remain: 4} 10 size := d.readInt32() 11 12 if err = d.err; err != nil { 13 err = dontExpectEOF(err) 14 return 15 } 16 17 d.remain = int(size) 18 apiKey := ApiKey(d.readInt16()) 19 apiVersion = d.readInt16() 20 correlationID = d.readInt32() 21 clientID = d.readString() 22 23 if i := int(apiKey); i < 0 || i >= len(apiTypes) { 24 err = fmt.Errorf("unsupported api key: %d", i) 25 return 26 } 27 28 if err = d.err; err != nil { 29 err = dontExpectEOF(err) 30 return 31 } 32 33 t := &apiTypes[apiKey] 34 if t == nil { 35 err = fmt.Errorf("unsupported api: %s", apiNames[apiKey]) 36 return 37 } 38 39 minVersion := t.minVersion() 40 maxVersion := t.maxVersion() 41 42 if apiVersion < minVersion || apiVersion > maxVersion { 43 err = fmt.Errorf("unsupported %s version: v%d not in range v%d-v%d", apiKey, apiVersion, minVersion, maxVersion) 44 return 45 } 46 47 req := &t.requests[apiVersion-minVersion] 48 49 if req.flexible { 50 // In the flexible case, there's a tag buffer at the end of the request header 51 taggedCount := int(d.readUnsignedVarInt()) 52 for i := 0; i < taggedCount; i++ { 53 d.readUnsignedVarInt() // tagID 54 size := d.readUnsignedVarInt() 55 56 // Just throw away the values for now 57 d.read(int(size)) 58 } 59 } 60 61 msg = req.new() 62 req.decode(d, valueOf(msg)) 63 d.discardAll() 64 65 if err = d.err; err != nil { 66 err = dontExpectEOF(err) 67 } 68 69 return 70 } 71 72 func WriteRequest(w io.Writer, apiVersion int16, correlationID int32, clientID string, msg Message) error { 73 apiKey := msg.ApiKey() 74 75 if i := int(apiKey); i < 0 || i >= len(apiTypes) { 76 return fmt.Errorf("unsupported api key: %d", i) 77 } 78 79 t := &apiTypes[apiKey] 80 if t == nil { 81 return fmt.Errorf("unsupported api: %s", apiNames[apiKey]) 82 } 83 84 minVersion := t.minVersion() 85 maxVersion := t.maxVersion() 86 87 if apiVersion < minVersion || apiVersion > maxVersion { 88 return fmt.Errorf("unsupported %s version: v%d not in range v%d-v%d", apiKey, apiVersion, minVersion, maxVersion) 89 } 90 91 r := &t.requests[apiVersion-minVersion] 92 v := valueOf(msg) 93 b := newPageBuffer() 94 defer b.unref() 95 96 e := &encoder{writer: b} 97 e.writeInt32(0) // placeholder for the request size 98 e.writeInt16(int16(apiKey)) 99 e.writeInt16(apiVersion) 100 e.writeInt32(correlationID) 101 102 if r.flexible { 103 // Flexible messages use a nullable string for the client ID, then extra space for a 104 // tag buffer, which begins with a size value. Since we're not writing any fields into the 105 // latter, we can just write zero for now. 106 // 107 // See 108 // https://cwiki.apache.org/confluence/display/KAFKA/KIP-482%3A+The+Kafka+Protocol+should+Support+Optional+Tagged+Fields 109 // for details. 110 e.writeNullString(clientID) 111 e.writeUnsignedVarInt(0) 112 } else { 113 // Technically, recent versions of kafka interpret this field as a nullable 114 // string, however kafka 0.10 expected a non-nullable string and fails with 115 // a NullPointerException when it receives a null client id. 116 e.writeString(clientID) 117 } 118 r.encode(e, v) 119 err := e.err 120 121 if err == nil { 122 size := packUint32(uint32(b.Size()) - 4) 123 b.WriteAt(size[:], 0) 124 _, err = b.WriteTo(w) 125 } 126 127 return err 128 }