Skip to content

Commit 805dac6

Browse files
committed
Add stubs
Closes #26
1 parent 04b7d0d commit 805dac6

23 files changed

+608
-44
lines changed

.github/fmt/entrypoint.sh

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,17 @@
22

33
source .github/lib.sh
44

5-
if [[ $(gofmt -l -s .) != "" ]]; then
6-
echo "files are not formatted correctly"
7-
echo "please run:"
8-
echo "gofmt -w -s ."
9-
exit 1
10-
fi
5+
gofmt -w -s .
6+
go run go.coder.com/go-tools/cmd/goimports -w "-local=$(go list -m)" .
7+
go run mvdan.cc/sh/cmd/shfmt -w -s -sr .
118

12-
out=$(go run golang.org/x/tools/cmd/goimports -l -local=nhooyr.io/ws .)
13-
if [[ $out != "" ]]; then
14-
echo "imports are not formatted correctly"
15-
echo "please run:"
16-
echo "goimports -w -local=nhooyr.io/ws ."
17-
exit 1
18-
fi
19-
20-
out=$(go run mvdan.cc/sh/cmd/shfmt -l -s -sr .)
21-
if [[ $out != "" ]]; then
22-
echo "shell scripts are not formatted correctly"
9+
if [[ $CI ]] && unstaged_files; then
10+
set +x
11+
echo
12+
echo "files are not formatted correctly"
2313
echo "please run:"
24-
echo "shfmt -w -s -sr ."
14+
echo "./test.sh"
15+
echo
16+
git status
2517
exit 1
2618
fi

.github/lib.sh

100755100644
Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,17 @@
33
set -euxo pipefail
44

55
export GO111MODULE=on
6-
export GOFLAGS=-mod=readonly
6+
export PAGER=cat
7+
8+
# shellcheck disable=SC2034
9+
# CI is used by the scripts that source this file.
10+
CI=${GITHUB_ACTION-}
11+
12+
if [[ $CI ]]; then
13+
export GOFLAGS=-mod=readonly
14+
fi
15+
16+
function unstaged_files() {
17+
[[ $(git ls-files --other --modified --exclude-standard) != "" ]]
18+
}
19+

.github/test/entrypoint.sh

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,38 @@
22

33
source .github/lib.sh
44

5-
function gomod_help() {
5+
# Unfortunately, this is the only way to ensure go.mod and go.sum are correct.
6+
# See https://github.com/golang/go/issues/27005
7+
go list ./... > /dev/null
8+
go mod tidy
9+
10+
go install golang.org/x/tools/cmd/stringer
11+
go generate ./...
12+
13+
if [[ $CI ]] && unstaged_files; then
14+
set +x
615
echo
7-
echo "you may need to update go.mod/go.sum via:"
8-
echo "go list all > /dev/null"
9-
echo "go mod tidy"
16+
echo "generated code needs an update"
17+
echo "please run:"
18+
echo "./test.sh"
1019
echo
11-
echo "or git add files to staging"
20+
git status
1221
exit 1
13-
}
14-
15-
go list ./... > /dev/null || gomod_help
16-
go mod tidy
17-
18-
# Until https://github.com/golang/go/issues/27005 the previous command can actually modify go.sum so we need to ensure its not changed.
19-
if [[ $(git diff --name-only) != "" ]]; then
20-
git diff
21-
gomod_help
2222
fi
2323

24-
mapfile -t scripts <<< "$(find . -type f -name "*.sh")"
25-
shellcheck "${scripts[@]}"
24+
(
25+
shopt -s globstar nullglob dotglob
26+
shellcheck ./**/*.sh
27+
)
2628

2729
go vet -composites=false ./...
2830

29-
go test -race -v -coverprofile=coverage.out -vet=off ./...
31+
COVERAGE_PROFILE=$(mktemp)
32+
go test -race -v "-coverprofile=${COVERAGE_PROFILE}" -vet=off ./...
33+
go tool cover "-func=${COVERAGE_PROFILE}"
3034

31-
if [[ -z ${GITHUB_ACTION-} ]]; then
32-
go tool cover -html=coverage.out
33-
else
35+
if [[ $CI ]]; then
3436
bash <(curl -s https://codecov.io/bash)
37+
else
38+
go tool cover "-html=${COVERAGE_PROFILE}" -o=coverage.html
3539
fi
36-
37-
rm coverage.out

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
coverage.html

accept.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package ws
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
)
7+
8+
// AcceptOption is an option that can be passed to Accept.
9+
type AcceptOption interface {
10+
acceptOption()
11+
fmt.Stringer
12+
}
13+
14+
// AcceptSubprotocols list the subprotocols that Accept will negotiate with a client.
15+
// The first protocol that a client supports will be negotiated.
16+
// Pass "" as a subprotocol if you would like to allow the default protocol.
17+
func AcceptSubprotocols(subprotocols ...string) AcceptOption {
18+
panic("TODO")
19+
}
20+
21+
// AcceptOrigins lists the origins that Accept will accept.
22+
// Accept will always accept r.Host as the origin so you do not need to
23+
// specify that with this option.
24+
// Use this option with caution to avoid exposing your WebSocket
25+
// server to a CSRF attack.
26+
// See https://stackoverflow.com/a/37837709/4283659
27+
func AcceptOrigins(origins ...string) AcceptOption {
28+
panic("TODO")
29+
}
30+
31+
// Accept accepts a WebSocket handshake from a client and upgrades the
32+
// the connection to WebSocket.
33+
// Accept will reject the handshake if the Origin is not the same as the Host unless
34+
// InsecureAcceptOrigin is passed.
35+
func Accept(w http.ResponseWriter, r *http.Request, opts ...AcceptOption) (*Conn, error) {
36+
panic("TODO")
37+
}

dataframe.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package ws
2+
3+
import (
4+
"nhooyr.io/ws/wscore"
5+
)
6+
7+
// DataType represents the Opcode of a WebSocket data frame.
8+
//go:generate stringer -type=DataType
9+
type DataType int
10+
11+
const (
12+
Text DataType = DataType(wscore.OpText)
13+
Binary DataType = DataType(wscore.OpBinary)
14+
)

dataframe_string.go

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dial.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package ws
2+
3+
import (
4+
"context"
5+
"encoding/base64"
6+
"fmt"
7+
"net/http"
8+
)
9+
10+
// DialOption represents a dial option that can be passed to Dial.
11+
type DialOption interface {
12+
dialOption()
13+
fmt.Stringer
14+
}
15+
16+
// DialHTTPClient is the http client used for the handshake.
17+
// Its Transport must use HTTP/1.1 and must return writable bodies
18+
// for WebSocket handshakes.
19+
// http.Transport does this correctly.
20+
func DialHTTPClient(h *http.Client) DialOption {
21+
panic("TODO")
22+
}
23+
24+
// DialHeader are the HTTP headers included in the handshake request.
25+
func DialHeader(h http.Header) DialOption {
26+
panic("TODO")
27+
}
28+
29+
// DialSubprotocols accepts a slice of protcols to include in the Sec-WebSocket-Protocol header.
30+
func DialSubprotocols(subprotocols ...string) DialOption {
31+
panic("TODO")
32+
}
33+
34+
// We use this key for all client requests as the Sec-WebSocket-Key header is useless.
35+
// See https://stackoverflow.com/a/37074398/4283659.
36+
var secWebSocketKey = base64.StdEncoding.EncodeToString(make([]byte, 16))
37+
38+
// Dial performs a websocket handshake on the given url with the given options.
39+
func Dial(ctx context.Context, u string, opts ...DialOption) (*Conn, *http.Response, error) {
40+
panic("TODO")
41+
}

doc.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Package ws implements the WebSocket protocol defined in RFC 6455.
2+
package ws

example_test.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package ws_test
2+
3+
import (
4+
"context"
5+
"io"
6+
"log"
7+
"net/http"
8+
"time"
9+
10+
"golang.org/x/time/rate"
11+
"nhooyr.io/ws"
12+
"nhooyr.io/ws/wsjson"
13+
)
14+
15+
func ExampleEcho() {
16+
fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
17+
c, err := ws.Accept(w, r,
18+
ws.AcceptSubprotocols("echo"),
19+
)
20+
if err != nil {
21+
log.Printf("server handshake failed: %v", err)
22+
return
23+
}
24+
defer c.Close(ws.StatusInternalError, "")
25+
26+
ctx := context.Background()
27+
28+
echo := func() error {
29+
ctx, cancel := context.WithTimeout(ctx, time.Minute)
30+
defer cancel()
31+
32+
typ, r, err := c.ReadMessage(ctx)
33+
if err != nil {
34+
return err
35+
}
36+
37+
ctx, cancel = context.WithTimeout(ctx, time.Second*10)
38+
defer cancel()
39+
40+
r.SetContext(ctx)
41+
r.Limit(32768)
42+
43+
w := c.MessageWriter(ctx, typ)
44+
_, err = io.Copy(w, r)
45+
if err != nil {
46+
return err
47+
}
48+
49+
err = w.Close()
50+
if err != nil {
51+
return err
52+
}
53+
54+
return nil
55+
}
56+
57+
l := rate.NewLimiter(rate.Every(time.Millisecond*100), 10)
58+
for l.Allow() {
59+
err := echo()
60+
if err != nil {
61+
log.Printf("failed to read message: %v", err)
62+
return
63+
}
64+
}
65+
})
66+
// For production deployments, use a net/http.Server configured
67+
// with the appropriate timeouts.
68+
err := http.ListenAndServe("localhost:8080", fn)
69+
if err != nil {
70+
log.Fatalf("failed to listen and serve: %v", err)
71+
}
72+
}
73+
74+
func ExampleAccept() {
75+
fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
76+
c, err := ws.Accept(w, r,
77+
ws.AcceptSubprotocols("echo"),
78+
)
79+
if err != nil {
80+
log.Printf("server handshake failed: %v", err)
81+
return
82+
}
83+
defer c.Close(ws.StatusInternalError, "")
84+
85+
type myJsonStruct struct {
86+
MyField string `json:"my_field"`
87+
}
88+
err = wsjson.Write(c, myJsonStruct{
89+
MyField: "foo",
90+
})
91+
if err != nil {
92+
log.Printf("failed to write json struct: %v", err)
93+
return
94+
}
95+
96+
c.Close(ws.StatusNormalClosure, "")
97+
})
98+
// For production deployments, use a net/http.Server configured
99+
// with the appropriate timeouts.
100+
err := http.ListenAndServe("localhost:8080", fn)
101+
if err != nil {
102+
log.Fatalf("failed to listen and serve: %v", err)
103+
}
104+
}
105+
106+
func ExampleDial() {
107+
ctx := context.Background()
108+
ctx, cancel := context.WithTimeout(ctx, time.Minute)
109+
defer cancel()
110+
111+
c, _, err := ws.Dial(ctx, "ws://localhost:8080")
112+
if err != nil {
113+
log.Fatalf("failed to ws dial: %v", err)
114+
return
115+
}
116+
defer c.Close(ws.StatusInternalError, "")
117+
118+
type myJsonStruct struct {
119+
MyField string `json:"my_field"`
120+
}
121+
err = wsjson.Write(c, myJsonStruct{
122+
MyField: "foo",
123+
})
124+
if err != nil {
125+
log.Fatalf("failed to write json struct: %v", err)
126+
return
127+
}
128+
129+
c.Close(ws.StatusNormalClosure, "")
130+
}

0 commit comments

Comments
 (0)