Skip to content

Commit 8239e31

Browse files
committed
Improve docs
Closes #66
1 parent c7ee8af commit 8239e31

File tree

7 files changed

+57
-73
lines changed

7 files changed

+57
-73
lines changed

.github/ISSUE_TEMPLATE/bug_report.md

Lines changed: 0 additions & 24 deletions
This file was deleted.

.github/ISSUE_TEMPLATE/feature_request.md

Lines changed: 0 additions & 20 deletions
This file was deleted.

README.md

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
websocket is a minimal and idiomatic WebSocket library for Go.
66

7-
At minimum Go 1.12 is required as websocket uses a new [feature](https://github.com/golang/go/issues/26937#issuecomment-415855861) in net/http
7+
Go 1.12 is required as it uses a new [feature](https://github.com/golang/go/issues/26937#issuecomment-415855861) in net/http
88
to perform WebSocket handshakes.
99

1010
This library is not final and the API is subject to change.
@@ -19,13 +19,11 @@ go get nhooyr.io/websocket
1919

2020
## Features
2121

22-
- Full support of the WebSocket protocol
23-
- Zero dependencies outside of the stdlib
24-
- Very minimal and carefully considered API
25-
- context.Context is first class
26-
- net/http is used for WebSocket dials and upgrades
22+
- Minimal yet pragmatic API
23+
- First class context.Context support
2724
- Thoroughly tested, fully passes the [autobahn-testsuite](https://github.com/crossbario/autobahn-testsuite)
28-
- All returned errors include detailed context
25+
- Concurrent writes
26+
- Zero dependencies outside of the stdlib
2927

3028
## Roadmap
3129

@@ -97,45 +95,45 @@ c.Close(websocket.StatusNormalClosure, "")
9795

9896
## Design considerations
9997

100-
- Minimal API is easier to maintain and for others to learn
98+
- Minimal API is easier to maintain and learn
10199
- Context based cancellation is more ergonomic and robust than setting deadlines
102-
- No pings or pongs because TCP keep alives work fine for HTTP/1.1 and they do not make
100+
- No ping support because TCP keep alives work fine for HTTP/1.1 and they do not make
103101
sense with HTTP/2 (see #1)
104102
- net.Conn is never exposed as WebSocket's over HTTP/2 will not have a net.Conn.
105-
- Functional options make the API very clean and easy to extend
103+
- Structures are nicer than functional options, see [google/go-cloud#908](https://github.com/google/go-cloud/issues/908#issuecomment-445034143)
106104
- Using net/http's Client for dialing means we do not have to reinvent dialing hooks
107-
and configurations. Just pass in a custom net/http client if you want custom dialing.
105+
and configurations like other WebSocket libraries
108106

109107
## Comparison
110108

111109
While I believe nhooyr/websocket has a better API than existing libraries,
112110
both gorilla/websocket and gobwas/ws were extremely useful in implementing the
113-
WebSocket protocol correctly so big thanks to the authors of both. In particular,
111+
WebSocket protocol correctly so **big thanks** to the authors of both. In particular,
114112
I made sure to go through the issue tracker of gorilla/websocket to make sure
115-
I implemented details correctly.
113+
I implemented details correctly and understood how people were using the package
114+
in production.
116115

117116
### gorilla/websocket
118117

119118
https://github.com/gorilla/websocket
120119

121-
This package is the community standard but it is very old and over time
122-
has accumulated cruft. There are many ways to do the same thing and the API
123-
is not clear. Just compare the godoc of
120+
This package is the community standard but it is 6 years old and over time
121+
has accumulated cruft. There are many ways to do the same thing, usage is not clear
122+
and there are some rough edges. Just compare the godoc of
124123
[nhooyr/websocket](godoc.org/github.com/nhooyr/websocket) side by side with
125124
[gorilla/websocket](godoc.org/github.com/gorilla/websocket).
126125

127126
The API for nhooyr/websocket has been designed such that there is only one way to do things
128-
which makes using it correctly and safely much easier.
129-
130-
In terms of lines of code, this library is around 2000 whereas gorilla/websocket is
131-
at 7000. So while the API for nhooyr/websocket is simpler, the implementation is also
132-
significantly simpler and easier to test which reduces the surface are of bugs.
127+
which makes it easy to use correctly.
133128

134129
Furthermore, nhooyr/websocket has support for newer Go idioms such as context.Context and
135130
also uses net/http's Client and ResponseWriter directly for WebSocket handshakes.
136131
gorilla/websocket writes its handshakes directly to a net.Conn which means
137132
it has to reinvent hooks for TLS and proxying and prevents support of HTTP/2.
138133

134+
Another advantage of nhooyr/websocket is that it supports multiple concurrent writers out
135+
of the box.
136+
139137
### x/net/websocket
140138

141139
https://godoc.org/golang.org/x/net/websocket
@@ -149,12 +147,12 @@ See https://github.com/golang/go/issues/18152
149147
https://github.com/gobwas/ws
150148

151149
This library has an extremely flexible API but that comes at the cost of usability
152-
and clarity. Its not clear what the best way to do anything is.
150+
and clarity.
153151

154152
This library is fantastic in terms of performance. The author put in significant
155153
effort to ensure its speed and I have applied as many of its optimizations as
156-
I could into nhooyr/websocket.
154+
I could into nhooyr/websocket. Definitely check out his fantastic [blog post](https://medium.freecodecamp.org/million-websockets-and-go-cc58418460bb) about performant WebSocket servers.
157155

158156
If you want a library that gives you absolute control over everything, this is the library,
159-
but for most users, the API provided by nhooyr/websocket will definitely fit better as it will
160-
be just as performant but much easier to use correctly.
157+
but for most users, the API provided by nhooyr/websocket will fit better as it is just as
158+
performant but much easier to use correctly and idiomatic.

doc.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22
//
33
// See https://tools.ietf.org/html/rfc6455
44
//
5-
// The echo example is the best way to understand how to correctly use the library.
5+
// Please see https://nhooyr.io/websocket for thorough overview docs and a
6+
// comparison with existing implementations.
7+
//
8+
// Conn, Dial, and Accept are the main entrypoints into this package. Use Dial to dial
9+
// a WebSocket server, Accept to accept a WebSocket client dial and then Conn to interact
10+
// with the resulting WebSocket connections.
611
//
7-
// Please see https://nhooyr.io/websocket for detailed design docs and a comparison with existing
8-
// libraries.
12+
// The echo example is the best way to understand how to correctly use the library.
913
package websocket

docs/CONTRIBUTING.md renamed to docs/contributing.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
# Contributing Guidelines
1+
# Contributing
2+
3+
## Issues
4+
5+
Please be as descriptive as possible with your description.
6+
7+
## Pull requests
28

39
Please split up changes into several small descriptive commits.
410

example_echo_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@ import (
1717
"nhooyr.io/websocket"
1818
)
1919

20+
// Example_echo starts a WebSocket echo server and
21+
// then dials the server and sends 5 different messages
22+
// and prints out the server's responses.
2023
func Example_echo() {
24+
// First we listen on port 0, that means the OS will
25+
// assign us a random free port. This is the listener
26+
// the server will serve on and the client will connect to.
2127
l, err := net.Listen("tcp", "localhost:0")
2228
if err != nil {
2329
log.Fatalf("failed to listen: %v", err)
@@ -37,13 +43,15 @@ func Example_echo() {
3743
}
3844
defer s.Close()
3945

46+
// This starts the echo server on the listener.
4047
go func() {
4148
err := s.Serve(l)
4249
if err != http.ErrServerClosed {
4350
log.Fatalf("failed to listen and serve: %v", err)
4451
}
4552
}()
4653

54+
// Now we dial the server and send the messages.
4755
err = client("ws://" + l.Addr().String())
4856
if err != nil {
4957
log.Fatalf("client failed: %v", err)
@@ -57,6 +65,9 @@ func Example_echo() {
5765
// {"i":4}
5866
}
5967

68+
// echoServer is the WebSocket echo server implementation.
69+
// It ensures the client speaks the echo subprotocol and
70+
// only allows one message every 100ms with a 10 message burst.
6071
func echoServer(w http.ResponseWriter, r *http.Request) error {
6172
c, err := websocket.Accept(w, r, websocket.AcceptOptions{
6273
Subprotocols: []string{"echo"},
@@ -82,6 +93,10 @@ func echoServer(w http.ResponseWriter, r *http.Request) error {
8293
}
8394
}
8495

96+
// echo reads from the websocket connection and then writes
97+
// the received message back to it.
98+
// It only waits 1 minute to read and write the message and
99+
// limits the received message to 32768 bytes.
85100
func echo(ctx context.Context, c *websocket.Conn, l *rate.Limiter) error {
86101
ctx, cancel := context.WithTimeout(ctx, time.Minute)
87102
defer cancel()
@@ -111,6 +126,9 @@ func echo(ctx context.Context, c *websocket.Conn, l *rate.Limiter) error {
111126
return err
112127
}
113128

129+
// client dials the WebSocket echo server at the given url.
130+
// It then sends it 5 different messages and echo's the server's
131+
// response to each.
114132
func client(url string) error {
115133
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
116134
defer cancel()

websocket.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,8 @@ func (c *Conn) writeControl(ctx context.Context, opcode opcode, p []byte) error
429429
// a WebSocket message of type dataType to the connection.
430430
// Ensure you close the writer once you have written the entire message.
431431
// Concurrent calls to Writer are ok.
432+
// Writer will block if there is another goroutine with an open writer
433+
// until writer is closed.
432434
func (c *Conn) Writer(ctx context.Context, typ MessageType) (io.WriteCloser, error) {
433435
select {
434436
case <-c.closed:

0 commit comments

Comments
 (0)