Documentation
¶
Overview ¶
Example (CrossOrigin) ¶
package main
import (
"log"
"net/http"
"github.com/coder/websocket"
)
func main() {
// 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"},
})
if err != nil {
log.Println(err)
return
}
c.Close(websocket.StatusNormalClosure, "cross origin WebSocket accepted")
})
err := http.ListenAndServe("localhost:8080", fn)
log.Fatal(err)
}
Example (Echo) ¶
This example demonstrates a echo server.
package main
import ()
func main() {
// https://github.com/nhooyr/websocket/tree/master/internal/examples/echo
}
Example (FullStackChat) ¶
This example demonstrates full stack chat with an automated test.
package main
import ()
func main() {
// https://github.com/nhooyr/websocket/tree/master/internal/examples/chat
}
Example (WriteOnly) ¶
package main
import (
"context"
"log"
"net/http"
"time"
"github.com/coder/websocket"
"github.com/coder/websocket/wsjson"
)
func main() {
// 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 {
log.Println(err)
return
}
defer c.CloseNow()
ctx, cancel := context.WithTimeout(r.Context(), time.Minute*10)
defer cancel()
ctx = c.CloseRead(ctx)
t := time.NewTicker(time.Second * 30)
defer t.Stop()
for {
select {
case <-ctx.Done():
c.Close(websocket.StatusNormalClosure, "")
return
case <-t.C:
err = wsjson.Write(ctx, c, "hi")
if err != nil {
log.Println(err)
return
}
}
}
})
err := http.ListenAndServe("localhost:8080", fn)
log.Fatal(err)
}
Index ¶
- func NetConn(ctx context.Context, c *Conn, msgType MessageType) net.Conn
- type AcceptOptions
- type CloseError
- type CompressionMode
- type Conn
- func (c *Conn) Close(code StatusCode, reason string) error
- func (c *Conn) CloseNow() error
- func (c *Conn) CloseRead(ctx context.Context) context.Context
- func (c *Conn) Ping(ctx context.Context) error
- func (c *Conn) Read(ctx context.Context) (MessageType, []byte, error)
- func (c *Conn) Reader(ctx context.Context) (MessageType, io.Reader, error)
- func (c *Conn) SetReadLimit(n int64)
- func (c *Conn) Subprotocol() string
- func (c *Conn) Write(ctx context.Context, typ MessageType, p []byte) error
- func (c *Conn) Writer(ctx context.Context, typ MessageType) (io.WriteCloser, error)
- type DialOptions
- type MessageType
- type StatusCode
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NetConn ¶
NetConn converts a *websocket.Conn into a net.Conn.
It's for tunneling arbitrary protocols over WebSockets. Few users of the library will need this but it's tricky to implement correctly and so provided in the library. See https://github.com/nhooyr/websocket/issues/100.
Every Write to the net.Conn will correspond to a message write of the given type on *websocket.Conn.
The passed ctx bounds the lifetime of the net.Conn. If cancelled, all reads and writes on the net.Conn will be cancelled.
If a message is read that is not of the correct type, the connection will be closed with StatusUnsupportedData and an error will be returned.
Close will close the *websocket.Conn with StatusNormalClosure.
When a deadline is hit and there is an active read or write goroutine, the connection will be closed. This is different from most net.Conn implementations where only the reading/writing goroutines are interrupted but the connection is kept alive.
The Addr methods will return the real addresses for connections obtained from websocket.Accept. But for connections obtained from websocket.Dial, a mock net.Addr will be returned that gives "websocket" for Network() and "websocket/unknown-addr" for String(). This is because websocket.Dial only exposes a io.ReadWriteCloser instead of the full net.Conn to us.
When running as WASM, the Addr methods will always return the mock address described above.
A received StatusNormalClosure or StatusGoingAway close frame will be translated to io.EOF when reading.
Furthermore, the ReadLimit is set to -1 to disable it.
Types ¶
type AcceptOptions ¶
type AcceptOptions struct {
Subprotocols []string
InsecureSkipVerify bool
OriginPatterns []string
CompressionMode CompressionMode
CompressionThreshold int
}
AcceptOptions represents Accept's options.
type CloseError ¶
type CloseError struct {
Code StatusCode
Reason string
}
CloseError is returned when the connection is closed with a status and reason.
Use Go 1.13's errors.As to check for this error. Also see the CloseStatus helper.
func (CloseError) Error ¶
func (ce CloseError) Error() string
type CompressionMode ¶
type CompressionMode int
CompressionMode represents the modes available to the deflate extension. See https://tools.ietf.org/html/rfc7692 Works in all browsers except Safari which does not implement the deflate extension.
const ( // CompressionNoContextTakeover grabs a new flate.Reader and flate.Writer as needed // for every message. This applies to both server and client side. // // This means less efficient compression as the sliding window from previous messages // will not be used but the memory overhead will be lower if the connections // are long lived and seldom used. // // The message will only be compressed if greater than 512 bytes. CompressionNoContextTakeover CompressionMode = iota // CompressionContextTakeover uses a flate.Reader and flate.Writer per connection. // This enables reusing the sliding window from previous messages. // As most WebSocket protocols are repetitive, this can be very efficient. // It carries an overhead of 8 kB for every connection compared to CompressionNoContextTakeover. // // If the peer negotiates NoContextTakeover on the client or server side, it will be // used instead as this is required by the RFC. CompressionContextTakeover // CompressionDisabled disables the deflate extension. // // Use this if you are using a predominantly binary protocol with very // little duplication in between messages or CPU and memory are more // important than bandwidth. CompressionDisabled )
type Conn ¶
type Conn struct {
// contains filtered or unexported fields
}
Conn provides a wrapper around the browser WebSocket API.
func Accept ¶
func Accept(w http.ResponseWriter, r *http.Request, opts *AcceptOptions) (*Conn, error)
Accept is stubbed out for Wasm.
Example ¶
package main
import (
"context"
"log"
"net/http"
"time"
"github.com/coder/websocket"
"github.com/coder/websocket/wsjson"
)
func main() {
// 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 {
log.Println(err)
return
}
defer c.CloseNow()
ctx, cancel := context.WithTimeout(r.Context(), time.Second*10)
defer cancel()
var v interface{}
err = wsjson.Read(ctx, c, &v)
if err != nil {
log.Println(err)
return
}
c.Close(websocket.StatusNormalClosure, "")
})
err := http.ListenAndServe("localhost:8080", fn)
log.Fatal(err)
}
func Dial ¶
Dial creates a new WebSocket connection to the given url with the given options. The passed context bounds the maximum time spent waiting for the connection to open. The returned *http.Response is always nil or a mock. It's only in the signature to match the core API.
Example ¶
package main
import (
"context"
"log"
"time"
"github.com/coder/websocket"
"github.com/coder/websocket/wsjson"
)
func main() {
// Dials a server, writes a single JSON message and then
// closes the connection.
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
c, _, err := websocket.Dial(ctx, "ws://localhost:8080", nil)
if err != nil {
log.Fatal(err)
}
defer c.CloseNow()
err = wsjson.Write(ctx, c, "hi")
if err != nil {
log.Fatal(err)
}
c.Close(websocket.StatusNormalClosure, "")
}
func (*Conn) Close ¶
func (c *Conn) Close(code StatusCode, reason string) error
Close closes the WebSocket with the given code and reason. It will wait until the peer responds with a close frame or the connection is closed. It thus performs the full WebSocket close handshake.
func (*Conn) CloseNow ¶
CloseNow closes the WebSocket connection without attempting a close handshake. Use when you do not want the overhead of the close handshake.
note: No different from Close(StatusGoingAway, "") in WASM as there is no way to close a WebSocket without the close handshake.
func (*Conn) Ping ¶
Ping is mocked out for Wasm.
Example ¶
package main
import (
"context"
"log"
"time"
"github.com/coder/websocket"
)
func main() {
// Dials a server and pings it 5 times.
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
c, _, err := websocket.Dial(ctx, "ws://localhost:8080", nil)
if err != nil {
log.Fatal(err)
}
defer c.CloseNow()
// Required to read the Pongs from the server.
ctx = c.CloseRead(ctx)
for i := 0; i < 5; i++ {
err = c.Ping(ctx)
if err != nil {
log.Fatal(err)
}
}
c.Close(websocket.StatusNormalClosure, "")
}
func (*Conn) Read ¶
Read attempts to read a message from the connection. The maximum time spent waiting is bounded by the context.
func (*Conn) Reader ¶
Reader attempts to read a message from the connection. The maximum time spent waiting is bounded by the context.
func (*Conn) SetReadLimit ¶
SetReadLimit implements *Conn.SetReadLimit for wasm.
func (*Conn) Subprotocol ¶
Subprotocol returns the negotiated subprotocol. An empty string means the default protocol.
func (*Conn) Write ¶
Write writes a message of the given type to the connection. Always non blocking.
func (*Conn) Writer ¶
func (c *Conn) Writer(ctx context.Context, typ MessageType) (io.WriteCloser, error)
Writer returns a writer to write a WebSocket data message to the connection. It buffers the entire message in memory and then sends it when the writer is closed.
type DialOptions ¶
type DialOptions struct {
// Subprotocols lists the subprotocols to negotiate with the server.
Subprotocols []string
}
DialOptions represents the options available to pass to Dial.
type MessageType ¶
type MessageType int
MessageType represents the type of a WebSocket message. See https://tools.ietf.org/html/rfc6455#section-5.6
const ( // MessageText is for UTF-8 encoded text messages like JSON. MessageText MessageType = iota + 1 // MessageBinary is for binary messages like protobufs. MessageBinary )
MessageType constants.
func (MessageType) String ¶
func (i MessageType) String() string
type StatusCode ¶
type StatusCode int
StatusCode represents a WebSocket status code. https://tools.ietf.org/html/rfc6455#section-7.4
const ( StatusNormalClosure StatusCode = 1000 StatusGoingAway StatusCode = 1001 StatusProtocolError StatusCode = 1002 StatusUnsupportedData StatusCode = 1003 // StatusNoStatusRcvd cannot be sent in a close message. // It is reserved for when a close message is received without // a status code. StatusNoStatusRcvd StatusCode = 1005 // StatusAbnormalClosure is exported for use only with Wasm. // In non Wasm Go, the returned error will indicate whether the // connection was closed abnormally. StatusAbnormalClosure StatusCode = 1006 StatusInvalidFramePayloadData StatusCode = 1007 StatusPolicyViolation StatusCode = 1008 StatusMessageTooBig StatusCode = 1009 StatusMandatoryExtension StatusCode = 1010 StatusInternalError StatusCode = 1011 StatusServiceRestart StatusCode = 1012 StatusTryAgainLater StatusCode = 1013 StatusBadGateway StatusCode = 1014 // StatusTLSHandshake is only exported for use with Wasm. // In non Wasm Go, the returned error will indicate whether there was // a TLS handshake failure. StatusTLSHandshake StatusCode = 1015 )
https://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number
These are only the status codes defined by the protocol.
You can define custom codes in the 3000-4999 range. The 3000-3999 range is reserved for use by libraries, frameworks and applications. The 4000-4999 range is reserved for private use.
func CloseStatus ¶
func CloseStatus(err error) StatusCode
CloseStatus is a convenience wrapper around Go 1.13's errors.As to grab the status code from a CloseError.
-1 will be returned if the passed error is nil or not a CloseError.
Example ¶
package main
import (
"context"
"log"
"time"
"github.com/coder/websocket"
)
func main() {
// Dials a server and then expects to be disconnected with status code
// websocket.StatusNormalClosure.
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
c, _, err := websocket.Dial(ctx, "ws://localhost:8080", nil)
if err != nil {
log.Fatal(err)
}
defer c.CloseNow()
_, _, err = c.Reader(ctx)
if websocket.CloseStatus(err) != websocket.StatusNormalClosure {
log.Fatalf("expected to be disconnected with StatusNormalClosure but got: %v", err)
}
}
func (StatusCode) String ¶
func (i StatusCode) String() string
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
test
Package test contains subpackages only used in tests.
|
Package test contains subpackages only used in tests. |
|
wsjs
Package wsjs implements typed access to the browser javascript WebSocket API.
|
Package wsjs implements typed access to the browser javascript WebSocket API. |
|
thirdparty
module
|
|
|
Package wsjson provides helpers for reading and writing JSON messages.
|
Package wsjson provides helpers for reading and writing JSON messages. |