github.com/cloudwego/kitex@v0.9.0/pkg/remote/trans/nphttp2/grpc/framer.go (about) 1 /* 2 * Copyright 2022 CloudWeGo Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package grpc 18 19 import ( 20 "io" 21 "net" 22 23 "github.com/cloudwego/netpoll" 24 "golang.org/x/net/http2/hpack" 25 26 "github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/grpc/grpcframe" 27 ) 28 29 type framer struct { 30 *grpcframe.Framer 31 reader netpoll.Reader 32 writer *bufWriter 33 } 34 35 func newFramer(conn net.Conn, writeBufferSize, readBufferSize, maxHeaderListSize uint32) *framer { 36 var r netpoll.Reader 37 if npConn, ok := conn.(interface{ Reader() netpoll.Reader }); ok { 38 r = npConn.Reader() 39 } else { 40 r = netpoll.NewReader(conn) 41 } 42 w := newBufWriter(conn, int(writeBufferSize)) 43 fr := &framer{ 44 reader: r, 45 writer: w, 46 Framer: grpcframe.NewFramer(w, r), 47 } 48 fr.SetMaxReadFrameSize(http2MaxFrameLen) 49 // Opt-in to Frame reuse API on framer to reduce garbage. 50 // Frames aren't safe to read from after a subsequent call to ReadFrame. 51 fr.SetReuseFrames() 52 fr.MaxHeaderListSize = maxHeaderListSize 53 fr.ReadMetaHeaders = hpack.NewDecoder(http2InitHeaderTableSize, nil) 54 return fr 55 } 56 57 type bufWriter struct { 58 writer io.Writer 59 buf []byte 60 offset int 61 batchSize int 62 err error 63 } 64 65 func newBufWriter(writer io.Writer, batchSize int) *bufWriter { 66 return &bufWriter{ 67 buf: make([]byte, batchSize*2), 68 batchSize: batchSize, 69 writer: writer, 70 } 71 } 72 73 func (w *bufWriter) Write(b []byte) (n int, err error) { 74 if w.err != nil { 75 return 0, w.err 76 } 77 if w.batchSize == 0 { // buffer has been disabled. 78 return w.writer.Write(b) 79 } 80 for len(b) > 0 { 81 nn := copy(w.buf[w.offset:], b) 82 b = b[nn:] 83 w.offset += nn 84 n += nn 85 if w.offset >= w.batchSize { 86 err = w.Flush() 87 } 88 } 89 return n, err 90 } 91 92 func (w *bufWriter) Flush() error { 93 if w.err != nil { 94 return w.err 95 } 96 if w.offset == 0 { 97 return nil 98 } 99 _, w.err = w.writer.Write(w.buf[:w.offset]) 100 w.offset = 0 101 return w.err 102 }