feat: http&ws compression (#569)

This commit is contained in:
HAOYUatHZ 2023-11-20 16:39:12 +08:00 committed by GitHub
parent 6f99663b3b
commit 5ffd345358
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 5 deletions

View file

@ -18,6 +18,8 @@ package rpc
import ( import (
"bytes" "bytes"
"compress/gzip"
"compress/zlib"
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
@ -28,6 +30,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
"strings"
"sync" "sync"
"time" "time"
) )
@ -243,7 +246,8 @@ func (hc *httpConn) doRequest(ctx context.Context, msg interface{}) (io.ReadClos
Body: body, Body: body,
} }
} }
return resp.Body, nil // use encoding if set
return newDecodeCompression(resp.Header.Get("Content-Encoding"), resp.Body)
} }
// httpServerConn turns a HTTP connection into a Conn. // httpServerConn turns a HTTP connection into a Conn.
@ -253,6 +257,28 @@ type httpServerConn struct {
r *http.Request r *http.Request
} }
func newDecodeCompression(decoding string, rc io.ReadCloser) (io.ReadCloser, error) {
tps := strings.Split(strings.TrimSpace(strings.ToLower(decoding)), ",")
var res io.ReadCloser
switch tps[0] {
case "gzip":
gz, err := gzip.NewReader(rc)
if err != nil {
return nil, err
}
res = gz
case "deflate":
zl, err := zlib.NewReader(rc)
if err != nil {
return nil, err
}
res = zl
default:
res = rc
}
return res, nil
}
func newHTTPServerConn(r *http.Request, w http.ResponseWriter) ServerCodec { func newHTTPServerConn(r *http.Request, w http.ResponseWriter) ServerCodec {
body := io.LimitReader(r.Body, maxRequestContentLength) body := io.LimitReader(r.Body, maxRequestContentLength)
conn := &httpServerConn{Reader: body, Writer: w, r: r} conn := &httpServerConn{Reader: body, Writer: w, r: r}

View file

@ -17,7 +17,9 @@
package rpc package rpc
import ( import (
"compress/flate"
"context" "context"
"errors"
"io" "io"
"sync" "sync"
"sync/atomic" "sync/atomic"
@ -51,6 +53,9 @@ type Server struct {
run atomic.Bool run atomic.Bool
batchItemLimit int batchItemLimit int
batchResponseLimit int batchResponseLimit int
// Add compressionLevel inorder to enable set it when open websocket server.
compressionLevel int
} }
// NewServer creates a new server instance with no registered handlers. // NewServer creates a new server instance with no registered handlers.
@ -127,6 +132,15 @@ func (s *Server) untrackCodec(codec ServerCodec) {
delete(s.codecs, codec) delete(s.codecs, codec)
} }
// SetCompressionLevel set compression level (-2 ~ 9), this function only works on websocket.
func (s *Server) SetCompressionLevel(level int) error {
if !(flate.HuffmanOnly <= level && level <= flate.BestCompression) {
return errors.New("websocket: invalid compression level")
}
s.compressionLevel = level
return nil
}
// serveSingleRequest reads and processes a single RPC request from the given codec. This // serveSingleRequest reads and processes a single RPC request from the given codec. This
// is used to serve HTTP connections. Subscriptions and reverse calls are not allowed in // is used to serve HTTP connections. Subscriptions and reverse calls are not allowed in
// this mode. // this mode.

View file

@ -17,6 +17,7 @@
package rpc package rpc
import ( import (
"compress/flate"
"context" "context"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
@ -48,7 +49,9 @@ var wsBufferPool = new(sync.Pool)
// allowedOrigins should be a comma-separated list of allowed origin URLs. // allowedOrigins should be a comma-separated list of allowed origin URLs.
// To allow connections with any origin, pass "*". // To allow connections with any origin, pass "*".
func (s *Server) WebsocketHandler(allowedOrigins []string) http.Handler { func (s *Server) WebsocketHandler(allowedOrigins []string) http.Handler {
enableCompression := s.compressionLevel != flate.NoCompression
var upgrader = websocket.Upgrader{ var upgrader = websocket.Upgrader{
EnableCompression: enableCompression,
ReadBufferSize: wsReadBuffer, ReadBufferSize: wsReadBuffer,
WriteBufferSize: wsWriteBuffer, WriteBufferSize: wsWriteBuffer,
WriteBufferPool: wsBufferPool, WriteBufferPool: wsBufferPool,
@ -60,6 +63,9 @@ func (s *Server) WebsocketHandler(allowedOrigins []string) http.Handler {
log.Debug("WebSocket upgrade failed", "err", err) log.Debug("WebSocket upgrade failed", "err", err)
return return
} }
if enableCompression {
_ = conn.SetCompressionLevel(s.compressionLevel)
}
codec := newWebsocketCodec(conn, r.Host, r.Header, wsDefaultReadLimit) codec := newWebsocketCodec(conn, r.Host, r.Header, wsDefaultReadLimit)
s.ServeCodec(codec, 0) s.ServeCodec(codec, 0)
}) })