44 lines
1.7 KiB
Go
44 lines
1.7 KiB
Go
package ws
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// Conn is the minimal slice of *gorilla/websocket.Conn that the engine relies on.
|
|
// Depending on an interface (rather than the concrete type) lets the tests drive
|
|
// a Client with an in-memory fake connection, so the concurrency tests in #26 do
|
|
// not need real sockets.
|
|
//
|
|
// gorilla's contract: at most one goroutine may call the write methods at a time
|
|
// and at most one may call the read methods at a time, BUT Close and WriteControl
|
|
// may be called concurrently with everything else. The Client honours this by
|
|
// funnelling all WriteMessage calls through a single writer goroutine, while the
|
|
// ping loop uses WriteControl and shutdown uses Close.
|
|
type Conn interface {
|
|
ReadMessage() (messageType int, p []byte, err error)
|
|
WriteMessage(messageType int, data []byte) error
|
|
WriteControl(messageType int, data []byte, deadline time.Time) error
|
|
SetReadLimit(limit int64)
|
|
SetReadDeadline(t time.Time) error
|
|
SetWriteDeadline(t time.Time) error
|
|
SetPongHandler(h func(appData string) error)
|
|
Close() error
|
|
}
|
|
|
|
// newUUID returns a random RFC 4122 version 4 UUID. The original server used
|
|
// Node's crypto.randomUUID(); this keeps client ids in the same shape without a
|
|
// third-party dependency.
|
|
func newUUID() string {
|
|
var b [16]byte
|
|
if _, err := rand.Read(b[:]); err != nil {
|
|
// crypto/rand failing is catastrophic and not something a relay can recover
|
|
// from sensibly; surface it loudly rather than handing out a zero id.
|
|
panic(fmt.Sprintf("ws: cannot read random bytes for uuid: %v", err))
|
|
}
|
|
b[6] = (b[6] & 0x0f) | 0x40 // version 4
|
|
b[8] = (b[8] & 0x3f) | 0x80 // variant 10
|
|
return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:16])
|
|
}
|