From b307b475131604cad9f43f1f30cc757725eca80e Mon Sep 17 00:00:00 2001 From: Anmol Sethi <hi@nhooyr.io> Date: Mon, 13 Apr 2020 21:22:14 -0400 Subject: [PATCH] Improve docs and fix examples Closes #207 --- README.md | 17 +-- ci/test.mk | 2 +- example_test.go | 120 +++++++++--------- examples/README.md | 4 + {chat-example => examples/chat}/README.md | 0 {chat-example => examples/chat}/chat.go | 0 {chat-example => examples/chat}/chat_test.go | 0 {chat-example => examples/chat}/go.sum | 0 {chat-example => examples/chat}/index.css | 0 {chat-example => examples/chat}/index.html | 0 {chat-example => examples/chat}/index.js | 0 {chat-example => examples/chat}/main.go | 0 example_echo_test.go => examples/echo/echo.go | 4 +- 13 files changed, 78 insertions(+), 69 deletions(-) create mode 100644 examples/README.md rename {chat-example => examples/chat}/README.md (100%) rename {chat-example => examples/chat}/chat.go (100%) rename {chat-example => examples/chat}/chat_test.go (100%) rename {chat-example => examples/chat}/go.sum (100%) rename {chat-example => examples/chat}/index.css (100%) rename {chat-example => examples/chat}/index.html (100%) rename {chat-example => examples/chat}/index.js (100%) rename {chat-example => examples/chat}/main.go (100%) rename example_echo_test.go => examples/echo/echo.go (99%) diff --git a/README.md b/README.md index 2d71ce0..3debf2f 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,9 @@ go get nhooyr.io/websocket - Minimal and idiomatic API - First class [context.Context](https://blog.golang.org/context) support - Fully passes the WebSocket [autobahn-testsuite](https://github.com/crossbario/autobahn-testsuite) -- Thorough unit tests with [90% coverage](https://coveralls.io/github/nhooyr/websocket) -- [Minimal dependencies](https://pkg.go.dev/nhooyr.io/websocket?tab=imports) -- JSON and protobuf helpers in the [wsjson](https://pkg.go.dev/nhooyr.io/websocket/wsjson?tab=doc) and [wspb](https://pkg.go.dev/nhooyr.io/websocket/wspb?tab=doc) subpackages +- Thorough tests with [90% coverage](https://coveralls.io/github/nhooyr/websocket) +- [Zero dependencies](https://pkg.go.dev/nhooyr.io/websocket?tab=imports) +- JSON and protobuf helpers in the [wsjson](https://pkg.go.dev/nhooyr.io/websocket/wsjson) and [wspb](https://pkg.go.dev/nhooyr.io/websocket/wspb) subpackages - Zero alloc reads and writes - Concurrent writes - [Close handshake](https://godoc.org/nhooyr.io/websocket#Conn.Close) @@ -32,9 +32,10 @@ go get nhooyr.io/websocket ## Examples -For a production quality example that demonstrates the complete API, see the [echo example](https://godoc.org/nhooyr.io/websocket#example-package--Echo). +For a production quality example that demonstrates the complete API, see the +[echo example](./examples/echo). -For a full stack example, see [./chat-example](./chat-example). +For a full stack example, see the [chat example](./examples/chat). ### Server @@ -98,7 +99,7 @@ Advantages of nhooyr.io/websocket: - [net.Conn](https://godoc.org/nhooyr.io/websocket#NetConn) wrapper - Zero alloc reads and writes ([gorilla/websocket#535](https://github.com/gorilla/websocket/issues/535)) - Full [context.Context](https://blog.golang.org/context) support -- Dials use [net/http.Client](https://golang.org/pkg/net/http/#Client) +- Dial uses [net/http.Client](https://golang.org/pkg/net/http/#Client) - Will enable easy HTTP/2 support in the future - Gorilla writes directly to a net.Conn and so duplicates features of net/http.Client. - Concurrent writes @@ -111,7 +112,7 @@ Advantages of nhooyr.io/websocket: - Gorilla's implementation is slower and uses [unsafe](https://golang.org/pkg/unsafe/). - Full [permessage-deflate](https://tools.ietf.org/html/rfc7692) compression extension support - Gorilla only supports no context takeover mode - - We use [klauspost/compress](https://github.com/klauspost/compress) for much lower memory usage ([gorilla/websocket#203](https://github.com/gorilla/websocket/issues/203)) + - We use a vendored [klauspost/compress](https://github.com/klauspost/compress) for much lower memory usage ([gorilla/websocket#203](https://github.com/gorilla/websocket/issues/203)) - [CloseRead](https://godoc.org/nhooyr.io/websocket#Conn.CloseRead) helper ([gorilla/websocket#492](https://github.com/gorilla/websocket/issues/492)) - Actively maintained ([gorilla/websocket#370](https://github.com/gorilla/websocket/issues/370)) @@ -120,7 +121,7 @@ Advantages of nhooyr.io/websocket: [golang.org/x/net/websocket](https://godoc.org/golang.org/x/net/websocket) is deprecated. See [golang/go/issues/18152](https://github.com/golang/go/issues/18152). -The [net.Conn](https://godoc.org/nhooyr.io/websocket#NetConn) wrapper will ease in transitioning +The [net.Conn](https://godoc.org/nhooyr.io/websocket#NetConn) can help in transitioning to nhooyr.io/websocket. #### gobwas/ws diff --git a/ci/test.mk b/ci/test.mk index 291d6be..b2f92b7 100644 --- a/ci/test.mk +++ b/ci/test.mk @@ -14,4 +14,4 @@ gotest: go test -timeout=30m -covermode=atomic -coverprofile=ci/out/coverage.prof -coverpkg=./... $${GOTESTFLAGS-} ./... sed -i '/stringer\.go/d' ci/out/coverage.prof sed -i '/nhooyr.io\/websocket\/internal\/test/d' ci/out/coverage.prof - sed -i '/chat-example/d' ci/out/coverage.prof + sed -i '/example/d' ci/out/coverage.prof diff --git a/example_test.go b/example_test.go index 39de0b8..632c4d6 100644 --- a/example_test.go +++ b/example_test.go @@ -4,17 +4,16 @@ import ( "context" "log" "net/http" - "os" - "os/signal" "time" "nhooyr.io/websocket" "nhooyr.io/websocket/wsjson" ) -// This example accepts a WebSocket connection, reads a single JSON -// message from the client and then closes the connection. func ExampleAccept() { + // This handler accepts a WebSocket connection, reads a single JSON + // message from the client and then closes the connection. + fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { c, err := websocket.Accept(w, r, nil) if err != nil { @@ -40,9 +39,10 @@ func ExampleAccept() { log.Fatal(err) } -// This example dials a server, writes a single JSON message and then -// closes the connection. func ExampleDial() { + // Dials a server, writes a single JSON message and then + // closes the connection. + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() @@ -60,9 +60,10 @@ func ExampleDial() { c.Close(websocket.StatusNormalClosure, "") } -// This example dials a server and then expects to be disconnected with status code -// websocket.StatusNormalClosure. func ExampleCloseStatus() { + // Dials a server and then expects to be disconnected with status code + // websocket.StatusNormalClosure. + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() @@ -78,9 +79,9 @@ func ExampleCloseStatus() { } } -// This example shows how to correctly handle a WebSocket connection -// on which you will only write and do not expect to read data messages. func Example_writeOnly() { + // This handler demonstrates how to correctly handle a write only WebSocket connection. + // i.e you only expect to write messages and do not expect to read any messages. fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { c, err := websocket.Accept(w, r, nil) if err != nil { @@ -116,9 +117,9 @@ func Example_writeOnly() { log.Fatal(err) } -// This example demonstrates how to safely accept cross origin WebSockets -// from the origin example.com. func Example_crossOrigin() { + // This handler demonstrates how to safely accept cross origin WebSockets + // from the origin example.com. fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { c, err := websocket.Accept(w, r, &websocket.AcceptOptions{ OriginPatterns: []string{"example.com"}, @@ -141,52 +142,57 @@ func Example_crossOrigin() { // for 10 seconds. // If you CTRL+C while a connection is open, it will wait at most 30s // for all connections to terminate before shutting down. -func ExampleGrace() { - fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - c, err := websocket.Accept(w, r, nil) - if err != nil { - log.Println(err) - return - } - defer c.Close(websocket.StatusInternalError, "the sky is falling") - - ctx := c.CloseRead(r.Context()) - select { - case <-ctx.Done(): - case <-time.After(time.Second * 10): - } - - c.Close(websocket.StatusNormalClosure, "") - }) - - var g websocket.Grace - s := &http.Server{ - Handler: g.Handler(fn), - ReadTimeout: time.Second * 15, - WriteTimeout: time.Second * 15, - } - - errc := make(chan error, 1) - go func() { - errc <- s.ListenAndServe() - }() - - sigs := make(chan os.Signal, 1) - signal.Notify(sigs, os.Interrupt) - select { - case err := <-errc: - log.Printf("failed to listen and serve: %v", err) - case sig := <-sigs: - log.Printf("terminating: %v", sig) - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) - defer cancel() - s.Shutdown(ctx) - g.Shutdown(ctx) -} +// func ExampleGrace() { +// fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// c, err := websocket.Accept(w, r, nil) +// if err != nil { +// log.Println(err) +// return +// } +// defer c.Close(websocket.StatusInternalError, "the sky is falling") +// +// ctx := c.CloseRead(r.Context()) +// select { +// case <-ctx.Done(): +// case <-time.After(time.Second * 10): +// } +// +// c.Close(websocket.StatusNormalClosure, "") +// }) +// +// var g websocket.Grace +// s := &http.Server{ +// Handler: g.Handler(fn), +// ReadTimeout: time.Second * 15, +// WriteTimeout: time.Second * 15, +// } +// +// errc := make(chan error, 1) +// go func() { +// errc <- s.ListenAndServe() +// }() +// +// sigs := make(chan os.Signal, 1) +// signal.Notify(sigs, os.Interrupt) +// select { +// case err := <-errc: +// log.Printf("failed to listen and serve: %v", err) +// case sig := <-sigs: +// log.Printf("terminating: %v", sig) +// } +// +// ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) +// defer cancel() +// s.Shutdown(ctx) +// g.Shutdown(ctx) +// } // This example demonstrates full stack chat with an automated test. func Example_fullStackChat() { - // https://github.com/nhooyr/websocket/tree/master/chat-example + // https://github.com/nhooyr/websocket/tree/master/examples/chat +} + +// This example demonstrates a echo server. +func Example_echo() { + // https://github.com/nhooyr/websocket/tree/master/examples/echo } diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..3cb437a --- /dev/null +++ b/examples/README.md @@ -0,0 +1,4 @@ +# Examples + +This directory contains more involved examples unsuitable +for display with godoc. diff --git a/chat-example/README.md b/examples/chat/README.md similarity index 100% rename from chat-example/README.md rename to examples/chat/README.md diff --git a/chat-example/chat.go b/examples/chat/chat.go similarity index 100% rename from chat-example/chat.go rename to examples/chat/chat.go diff --git a/chat-example/chat_test.go b/examples/chat/chat_test.go similarity index 100% rename from chat-example/chat_test.go rename to examples/chat/chat_test.go diff --git a/chat-example/go.sum b/examples/chat/go.sum similarity index 100% rename from chat-example/go.sum rename to examples/chat/go.sum diff --git a/chat-example/index.css b/examples/chat/index.css similarity index 100% rename from chat-example/index.css rename to examples/chat/index.css diff --git a/chat-example/index.html b/examples/chat/index.html similarity index 100% rename from chat-example/index.html rename to examples/chat/index.html diff --git a/chat-example/index.js b/examples/chat/index.js similarity index 100% rename from chat-example/index.js rename to examples/chat/index.js diff --git a/chat-example/main.go b/examples/chat/main.go similarity index 100% rename from chat-example/main.go rename to examples/chat/main.go diff --git a/example_echo_test.go b/examples/echo/echo.go similarity index 99% rename from example_echo_test.go rename to examples/echo/echo.go index fb212c1..0f31235 100644 --- a/example_echo_test.go +++ b/examples/echo/echo.go @@ -1,6 +1,4 @@ -// +build !js - -package websocket_test +package main import ( "context" -- GitLab