Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 30 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,12 @@ Planned milestones and features:

### Features

The library offers several advanced features, especially at websocket and ocpp-j level.
The library offers several advanced features, especially at `websocket` and `ocpp-j` level.

#### Automatic message validation

All incoming and outgoing messages are validated by default, using the [validator](gopkg.in/go-playground/validator)
package.
Constraints are defined on every request/response struct, as per OCPP specs.
package. Constraints are defined on every request/response struct, as per OCPP specs.

Validation may be disabled at a package level if needed:

Expand Down Expand Up @@ -89,21 +88,26 @@ Commonly used logging libraries, such as zap or logrus, adhere to this interface
If you are using a logger, that isn't conform, you can simply write an adapter between the `Logger` interface and your
own logging system.

#### Websocket ping-pong
### Websockets

#### Ping and pong messages

The websocket package supports configuring ping pong for both endpoints.

By default, the client sends a ping every 54 seconds and waits for a pong for 60 seconds, before timing out.
The values can be configured as follows:

```go
cfg := ws.NewClientTimeoutConfig()
cfg.PingPeriod = 10 * time.Second
cfg.PongWait = 20 * time.Second
websocketClient.SetTimeoutConfig(cfg)
```

By default, the server does not send out any pings and waits for a ping from the client for 60 seconds, before timing out.
By default, the server does not send out any pings and waits for a ping from the client for 60 seconds, before timing
out.
To configure the server to send out pings, the `PingPeriod` and `PongWait` must be set to a value greater than 0:

```go
cfg := ws.NewServerTimeoutConfig()
cfg.PingPeriod = 10 * time.Second
Expand All @@ -113,6 +117,27 @@ websocketServer.SetTimeoutConfig(cfg)

To disable sending ping messages, set the `PingPeriod` value to `0`.

#### Websocket compression

You can enable websocket compression on both the client and server side.
To enable compression on the client side, use the following code:

```go
websocketClient := ws.NewClient(
WithClientCompression(true),
)

```

To enable compression on the server side, use the following code:

```go
websocketServer := ws.NewServer(
ws.WithCompression(true),
)

```

## Contributing

Contributions are welcome! Please refer to the [testing](docs/testing.md) guide for instructions on how to run the
Expand Down
8 changes: 8 additions & 0 deletions ws/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,14 @@ func WithClientTLSConfig(tlsConfig *tls.Config) ClientOpt {
}
}

func WithClientCompression(enable bool) ClientOpt {
return func(c *client) {
c.dialOptions = append(c.dialOptions, func(dialer *websocket.Dialer) {
dialer.EnableCompression = enable
})
}
}

// NewClient creates a new websocket client.
//
// If the optional tlsConfig is not nil, and the server supports secure communication,
Expand Down
24 changes: 18 additions & 6 deletions ws/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,14 @@ type server struct {
basicAuthHandler func(username string, password string) bool
tlsCertificatePath string
tlsCertificateKey string
timeoutConfig ServerTimeoutConfig
upgrader websocket.Upgrader
errC chan error
connMutex sync.RWMutex
addr *net.TCPAddr
httpHandler *mux.Router
// enableCompression is used to enable or disable compression for the websocket connections.
enableCompression bool
timeoutConfig ServerTimeoutConfig
upgrader websocket.Upgrader
errC chan error
connMutex sync.RWMutex
addr *net.TCPAddr
httpHandler *mux.Router
}

// ServerOpt is a function that can be used to set options on a server during creation.
Expand All @@ -163,6 +165,14 @@ func WithServerTLSConfig(certificatePath string, certificateKey string, tlsConfi
}
}

// WithCompression enables or disables compression for the websocket connections.
// By default, compression is disabled.
func WithCompression(enabled bool) ServerOpt {
return func(s *server) {
s.enableCompression = enabled
}
}

// NewServer Creates a new websocket server.
//
// Additional options may be added using the AddOption function.
Expand Down Expand Up @@ -195,6 +205,8 @@ func NewServer(opts ...ServerOpt) Server {
for _, o := range opts {
o(s)
}

s.upgrader.EnableCompression = s.enableCompression
return s
}

Expand Down
25 changes: 25 additions & 0 deletions ws/websocket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,31 @@ func (s *WebSocketSuite) TestWebsocketChargePointIdResolverFailure() {
s.Equal("websocket: bad handshake", httpErr.Message)
}

func (s *WebSocketSuite) TestWebsocketEnableCompression() {
s.server = newWebsocketServer(s.T(), func(data []byte) ([]byte, error) {
s.Fail("no message should be received from client!")
return nil, nil
})
s.server.upgrader.EnableCompression = true
go s.server.Start(serverPort, serverPath)
time.Sleep(500 * time.Millisecond)

// Test message
s.client = newWebsocketClient(s.T(), func(data []byte) ([]byte, error) {
s.Fail("no message should be received from server!")
return nil, nil
})

host := fmt.Sprintf("localhost:%v", serverPort)
u := url.URL{Scheme: "ws", Host: host, Path: testPath}
s.client.AddOption(func(dialer *websocket.Dialer) {
dialer.EnableCompression = true
})
// Attempt to connect, expecting compression to be enabled
err := s.client.Start(u.String())
s.NoError(err)
}

func (s *WebSocketSuite) TestWebsocketBootRetries() {
verifyConnection := func(client *client, connected bool) {
maxAttempts := 20
Expand Down