Skip to content

Commit

Permalink
readme: improve compression example
Browse files Browse the repository at this point in the history
  • Loading branch information
gobwas committed Jul 11, 2021
1 parent 3e35716 commit 26e4a44
Showing 1 changed file with 79 additions and 1 deletion.
80 changes: 79 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ Extension][rfc-pmce].

It provides minimalistic I/O wrappers to be used in conjunction with any
deflate implementation (for example, the standard library's
[compress/flate][compress/flate].
[compress/flate][compress/flate]).

It is also compatible with `wsutil`'s reader and writer by providing
`wsflate.MessageState` type, which implements `wsutil.SendExtension` and
Expand Down Expand Up @@ -453,6 +453,84 @@ func main() {
}
```

You can use compression with `wsutil` package this way:

```go
// Upgrade somehow and negotiate compression to get the conn...

// Initialize flate reader. We are using nil as a source io.Reader because
// we will Reset() it in the message i/o loop below.
fr := wsflate.NewReader(nil, func(r io.Reader) wsflate.Decompressor {
return flate.NewReader(r)
})
// Initialize flate writer. We are using nil as a destination io.Writer
// because we will Reset() it in the message i/o loop below.
fw := wsflate.NewWriter(nil, func(w io.Writer) wsflate.Compressor {
f, _ := flate.NewWriter(w, 9)
return f
})

// Declare compression message state variable.
//
// It has two goals:
// - Allow users to check whether received message is compressed or not.
// - Help wsutil.Reader and wsutil.Writer to set/unset appropriate
// WebSocket header bits while writing next frame to the wire (it
// implements wsutil.RecvExtension and wsutil.SendExtension).
var msg wsflate.MessageState

// Initialize WebSocket reader as previously.
// Please note the use of Reader.Extensions field as well as
// of ws.StateExtended flag.
rd := &wsutil.Reader{
Source: conn,
State: ws.StateServerSide | ws.StateExtended,
Extensions: []wsutil.RecvExtension{
&msg,
},
}

// Initialize WebSocket writer with ws.StateExtended flag as well.
wr := wsutil.NewWriter(conn, ws.StateServerSide|ws.StateExtended, 0)
// Use the message state as wsutil.SendExtension.
wr.SetExtensions(&msg)

for {
h, err := rd.NextFrame()
if err != nil {
// handle error.
}
if h.OpCode.IsControl() {
// handle control frame.
}
if !msg.IsCompressed() {
// handle uncompressed frame (skipped for the sake of example
// simplicity).
}

// Reset the writer to echo same op code.
wr.Reset(h.OpCode)

// Reset both flate reader and writer to start the new round of i/o.
fr.Reset(rd)
fw.Reset(wr)

// Copy whole message from reader to writer decompressing it and
// compressing again.
if _, err := io.Copy(fw, fr); err != nil {
// handle error.
}
// Flush any remaining buffers from flate writer to WebSocket writer.
if err := fw.Close(); err != nil {
// handle error.
}
// Flush the whole WebSocket message to the wire.
if err := wr.Flush(); err != nil {
// handle error.
}
}
```


[rfc-url]: https://tools.ietf.org/html/rfc6455
[rfc-pmce]: https://tools.ietf.org/html/rfc7692#section-7
Expand Down

0 comments on commit 26e4a44

Please sign in to comment.