package gws import ( "bufio" "crypto/tls" "net" "net/http" "time" "github.com/klauspost/compress/flate" "github.com/lxzan/gws/internal" ) const ( defaultParallelGolimit = 8 defaultCompressLevel = flate.BestSpeed defaultReadMaxPayloadSize = 16 * 1024 * 1024 defaultWriteMaxPayloadSize = 16 * 1024 * 1024 defaultCompressThreshold = 512 defaultCompressorPoolSize = 32 defaultReadBufferSize = 4 * 1024 defaultWriteBufferSize = 4 * 1024 defaultHandshakeTimeout = 5 * time.Second defaultDialTimeout = 5 * time.Second ) type ( // PermessageDeflate å缩æå±é ç½® // 对äºgws client, 建议å¼å¯ä¸ä¸ææ¥ç®¡, ä¸ä¿®æ¹æ»å¨çªå£ææ°, æä¾æ好çå ¼å®¹æ§. // 对äºgws server, å¦æå¼å¯ä¸ä¸ææ¥ç®¡, æ¯ä¸ªè¿æ¥ä¼å ç¨æ´å¤å å, åçé ç½®æ»å¨çªå£ææ°. // For gws client, it is recommended to enable contextual takeover and not modify the sliding window index to provide the best compatibility. // For gws server, if you turn on context-side takeover, each connection takes up more memory, configure the sliding window index appropriately. PermessageDeflate struct { // æ¯å¦å¼å¯å缩 // Whether to turn on compression Enabled bool // åç¼©çº§å« // Compress level Level int // å缩éå¼, é¿åº¦å°äºéå¼çæ¶æ¯ä¸ä¼è¢«å缩 // Compression threshold, messages below the threshold will not be compressed Threshold int // å缩å¨å åæ± å¤§å° // æ°å¼è¶å¤§ç«äºçæ¦çè¶å°, ä½æ¯ä¼è费大éå å // Compressor memory pool size // The higher the value the lower the probability of competition, but it will consume a lot of memory PoolSize int // æå¡ç«¯ä¸ä¸ææ¥ç®¡ // Server side context takeover ServerContextTakeover bool // 客æ·ç«¯ä¸ä¸ææ¥ç®¡ // Client side context takeover ClientContextTakeover bool // æå¡ç«¯æ»å¨çªå£ææ° // åå¼èå´ 8<=n<=15, 表示pow(2,n)个åè // The server-side sliding window index // Range 8<=n<=15, means pow(2,n) bytes. ServerMaxWindowBits int // 客æ·ç«¯æ»å¨çªå£ææ° // åå¼èå´ 8<=x<=15, 表示pow(2,n)个åè // The client-side sliding window index // Range 8<=n<=15, means pow(2,n) bytes. ClientMaxWindowBits int } Config struct { // bufio.Readerå åæ± brPool *internal.Pool[*bufio.Reader] // å缩å¨æ»å¨çªå£å åæ± cswPool *internal.Pool[[]byte] // 解åå¨æ»å¨çªå£å åæ± dswPool *internal.Pool[[]byte] // æ¯å¦å¼å¯å¹¶è¡æ¶æ¯å¤ç // Whether to enable parallel message processing ParallelEnabled bool // (å个è¿æ¥)ç¨äºå¹¶è¡æ¶æ¯å¤ççåç¨æ°ééå¶ // Limit on the number of concurrent goroutine used for parallel message processing (single connection) ParallelGolimit int // æ大读åçæ¶æ¯å 容é¿åº¦ // Maximum read message content length ReadMaxPayloadSize int // 读ç¼å²åºçå¤§å° // Size of the read buffer ReadBufferSize int // æ大åå ¥çæ¶æ¯å 容é¿åº¦ // Maximum length of written message content WriteMaxPayloadSize int // åç¼å²åºç大å°, v1.4.5çæ¬æ¤åæ°è¢«åºå¼ // Deprecated: Size of the write buffer, v1.4.5 version of this parameter is deprecated WriteBufferSize int // æ¯å¦æ£æ¥ææ¬utf8ç¼ç , å ³éæ§è½ä¼å¥½ç¹ // Whether to check the text utf8 encoding, turn off the performance will be better CheckUtf8Enabled bool // æ¶æ¯åè°(OnMessage)çæ¢å¤ç¨åº // Message callback (OnMessage) recovery program Recovery func(logger Logger) // æ¥å¿å·¥å · // Logging tools Logger Logger } ServerOption struct { config *Config // åç¼å²åºç大å°, v1.4.5çæ¬æ¤åæ°è¢«åºå¼ // Deprecated: Size of the write buffer, v1.4.5 version of this parameter is deprecated WriteBufferSize int PermessageDeflate PermessageDeflate ParallelEnabled bool ParallelGolimit int ReadMaxPayloadSize int ReadBufferSize int WriteMaxPayloadSize int CheckUtf8Enabled bool Logger Logger Recovery func(logger Logger) // TLS设置 TlsConfig *tls.Config // æ¡æè¶ æ¶æ¶é´ HandshakeTimeout time.Duration // WebSocketååè®®, æ¡æ失败ä¼æå¼è¿æ¥ // WebSocket sub-protocol, handshake failure disconnects the connection SubProtocols []string // é¢å¤çååºå¤´(å¯è½ä¸å客æ·ç«¯æ¯æ) // Additional response headers (may not be supported by the client) // https://www.rfc-editor.org/rfc/rfc6455.html#section-1.3 ResponseHeader http.Header // é´æ // Authentication of requests for connection establishment Authorize func(r *http.Request, session SessionStorage) bool // å建sessionåå¨ç©ºé´ // ç¨äºèªå®ä¹SessionStorageå®ç° // For custom SessionStorage implementations NewSession func() SessionStorage } ) func (c *ServerOption) deleteProtectedHeaders() { c.ResponseHeader.Del(internal.Upgrade.Key) c.ResponseHeader.Del(internal.Connection.Key) c.ResponseHeader.Del(internal.SecWebSocketAccept.Key) c.ResponseHeader.Del(internal.SecWebSocketExtensions.Key) c.ResponseHeader.Del(internal.SecWebSocketProtocol.Key) } func initServerOption(c *ServerOption) *ServerOption { if c == nil { c = new(ServerOption) } if c.ReadMaxPayloadSize <= 0 { c.ReadMaxPayloadSize = defaultReadMaxPayloadSize } if c.ParallelGolimit <= 0 { c.ParallelGolimit = defaultParallelGolimit } if c.ReadBufferSize <= 0 { c.ReadBufferSize = defaultReadBufferSize } if c.WriteMaxPayloadSize <= 0 { c.WriteMaxPayloadSize = defaultWriteMaxPayloadSize } if c.WriteBufferSize <= 0 { c.WriteBufferSize = defaultWriteBufferSize } if c.Authorize == nil { c.Authorize = func(r *http.Request, session SessionStorage) bool { return true } } if c.NewSession == nil { c.NewSession = func() SessionStorage { return newSmap() } } if c.ResponseHeader == nil { c.ResponseHeader = http.Header{} } if c.HandshakeTimeout <= 0 { c.HandshakeTimeout = defaultHandshakeTimeout } if c.Logger == nil { c.Logger = defaultLogger } if c.Recovery == nil { c.Recovery = func(logger Logger) {} } if c.PermessageDeflate.Enabled { if c.PermessageDeflate.ServerMaxWindowBits < 8 || c.PermessageDeflate.ServerMaxWindowBits > 15 { c.PermessageDeflate.ServerMaxWindowBits = internal.SelectValue(c.PermessageDeflate.ServerContextTakeover, 12, 15) } if c.PermessageDeflate.ClientMaxWindowBits < 8 || c.PermessageDeflate.ClientMaxWindowBits > 15 { c.PermessageDeflate.ClientMaxWindowBits = internal.SelectValue(c.PermessageDeflate.ClientContextTakeover, 12, 15) } if c.PermessageDeflate.Threshold <= 0 { c.PermessageDeflate.Threshold = defaultCompressThreshold } if c.PermessageDeflate.Level == 0 { c.PermessageDeflate.Level = defaultCompressLevel } if c.PermessageDeflate.PoolSize <= 0 { c.PermessageDeflate.PoolSize = defaultCompressorPoolSize } c.PermessageDeflate.PoolSize = internal.ToBinaryNumber(c.PermessageDeflate.PoolSize) } c.deleteProtectedHeaders() c.config = &Config{ ParallelEnabled: c.ParallelEnabled, ParallelGolimit: c.ParallelGolimit, ReadMaxPayloadSize: c.ReadMaxPayloadSize, ReadBufferSize: c.ReadBufferSize, WriteMaxPayloadSize: c.WriteMaxPayloadSize, WriteBufferSize: c.WriteBufferSize, CheckUtf8Enabled: c.CheckUtf8Enabled, Recovery: c.Recovery, Logger: c.Logger, brPool: internal.NewPool(func() *bufio.Reader { return bufio.NewReaderSize(nil, c.ReadBufferSize) }), } if c.PermessageDeflate.Enabled { if c.PermessageDeflate.ServerContextTakeover { windowSize := internal.BinaryPow(c.PermessageDeflate.ServerMaxWindowBits) c.config.cswPool = internal.NewPool[[]byte](func() []byte { return make([]byte, 0, windowSize) }) } if c.PermessageDeflate.ClientContextTakeover { windowSize := internal.BinaryPow(c.PermessageDeflate.ClientMaxWindowBits) c.config.dswPool = internal.NewPool[[]byte](func() []byte { return make([]byte, 0, windowSize) }) } } return c } // è·åéç¨é ç½® func (c *ServerOption) getConfig() *Config { return c.config } type ClientOption struct { // åç¼å²åºç大å°, v1.4.5çæ¬æ¤åæ°è¢«åºå¼ // Deprecated: Size of the write buffer, v1.4.5 version of this parameter is deprecated WriteBufferSize int PermessageDeflate PermessageDeflate ParallelEnabled bool ParallelGolimit int ReadMaxPayloadSize int ReadBufferSize int WriteMaxPayloadSize int CheckUtf8Enabled bool Logger Logger Recovery func(logger Logger) // è¿æ¥å°å, ä¾å¦ wss://example.com/connect // server address, eg: wss://example.com/connect Addr string // é¢å¤ç请æ±å¤´ // extra request header RequestHeader http.Header // æ¡æè¶ æ¶æ¶é´ HandshakeTimeout time.Duration // TLS设置 TlsConfig *tls.Config // æ¨å·å¨ // é»è®¤æ¯è¿ånet.Dialerå®ä¾, ä¹å¯ä»¥ç¨äºè®¾ç½®ä»£ç. // The default is to return the net.Dialer instance // Can also be used to set a proxy, for example // NewDialer: func() (proxy.Dialer, error) { // return proxy.SOCKS5("tcp", "127.0.0.1:1080", nil, nil) // }, NewDialer func() (Dialer, error) // å建sessionåå¨ç©ºé´ // ç¨äºèªå®ä¹SessionStorageå®ç° // For custom SessionStorage implementations NewSession func() SessionStorage } func initClientOption(c *ClientOption) *ClientOption { if c == nil { c = new(ClientOption) } if c.ReadMaxPayloadSize <= 0 { c.ReadMaxPayloadSize = defaultReadMaxPayloadSize } if c.ParallelGolimit <= 0 { c.ParallelGolimit = defaultParallelGolimit } if c.ReadBufferSize <= 0 { c.ReadBufferSize = defaultReadBufferSize } if c.WriteMaxPayloadSize <= 0 { c.WriteMaxPayloadSize = defaultWriteMaxPayloadSize } if c.WriteBufferSize <= 0 { c.WriteBufferSize = defaultWriteBufferSize } if c.HandshakeTimeout <= 0 { c.HandshakeTimeout = defaultHandshakeTimeout } if c.RequestHeader == nil { c.RequestHeader = http.Header{} } if c.NewDialer == nil { c.NewDialer = func() (Dialer, error) { return &net.Dialer{Timeout: defaultDialTimeout}, nil } } if c.NewSession == nil { c.NewSession = func() SessionStorage { return newSmap() } } if c.Logger == nil { c.Logger = defaultLogger } if c.Recovery == nil { c.Recovery = func(logger Logger) {} } if c.PermessageDeflate.Enabled { if c.PermessageDeflate.ServerMaxWindowBits < 8 || c.PermessageDeflate.ServerMaxWindowBits > 15 { c.PermessageDeflate.ServerMaxWindowBits = 15 } if c.PermessageDeflate.ClientMaxWindowBits < 8 || c.PermessageDeflate.ClientMaxWindowBits > 15 { c.PermessageDeflate.ClientMaxWindowBits = 15 } if c.PermessageDeflate.Threshold <= 0 { c.PermessageDeflate.Threshold = defaultCompressThreshold } if c.PermessageDeflate.Level == 0 { c.PermessageDeflate.Level = defaultCompressLevel } c.PermessageDeflate.PoolSize = 1 } return c } func (c *ClientOption) getConfig() *Config { config := &Config{ ParallelEnabled: c.ParallelEnabled, ParallelGolimit: c.ParallelGolimit, ReadMaxPayloadSize: c.ReadMaxPayloadSize, ReadBufferSize: c.ReadBufferSize, WriteMaxPayloadSize: c.WriteMaxPayloadSize, WriteBufferSize: c.WriteBufferSize, CheckUtf8Enabled: c.CheckUtf8Enabled, Recovery: c.Recovery, Logger: c.Logger, } return config }