nhooyr / websocket Goto Github PK
View Code? Open in Web Editor NEWMinimal and idiomatic WebSocket library for Go
License: ISC License
Minimal and idiomatic WebSocket library for Go
License: ISC License
Using wstest
adds like 50s to the tests right now.
Its not a good experience and the code using it is very janky.
I'd rather write pure Go tests now that the library is fairly stable.
See #57
Some websocket implementations cannot handle fragmented messages and the current API only allows writing fragmented messages because you write all your data first to a writer and then call close which writes a continuation fin frame.
It may also be good for performance.
I'm not going to expose an API for this right now, opening this issue to see how badly its wanted.
Not sure if the performance decrease is worth it as most of the time you'll be parsing the frame anyway so you'll know if it is invalid.
If compression is negotiated, I think we should compress all text frames by default. Of course if the frame is small, we will not compress it.
So the compress function on the writer would not be exposed.
Blocked on the drafts and Go support.
The purpose of Sec-Websocket-Key is not really clear to me.
Get gometalinter running on CI, ensure we're caching stuff and everything is fast.
Maybe want to use Circle CI instead, their docs for this sort of thing were much better and they allow running gometalinter concurrently.
The same overview that is in the README.md should be duplicated on the godoc.
Need to make sure the API/lib is as simple as possible while not sacrificing any reasonable performance.
In interest of making tests pass, I didn't write a lot of the code in websocket.go as nice as I would have wanted.
Will need to fix this.
See golang/go#31391
Very unfortunate.
See https://tools.ietf.org/html/rfc7692
Investigate whether we want this.
see shields.io
Related #3
For cleaner tests.
Don't want to have to copy this code from gobwas/ws or gorilla/websocket as then there are licensing issues and I do not want to write and maintain my own version.
I've reported golang/go#31586
websocket is too general.
Can't really support the current API, browser API is different and much less expressive.
E.g. why functional options over options structure, why things work the way they do, the different trade offs I made.
See also google/go-cloud#908
Using this simple program:
package main
import (
"context"
"encoding/json"
"errors"
"flag"
"log"
"time"
"nhooyr.io/websocket"
)
var flagRemote = flag.String("r", "", "remote url")
func main() {
flag.Parse()
if err := run(); err != nil {
log.Fatalf("error: %v", err)
}
}
func run() error {
if *flagRemote == "" {
return errors.New("must provide remote url via -r")
}
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
c, _, err := websocket.Dial(ctx, *flagRemote)
if err != nil {
return err
}
defer c.Close(websocket.StatusInternalError, "")
// write initial message
w, err := c.Write(ctx, websocket.MessageText)
if err != nil {
return err
}
if _, err = w.Write([]byte(`{"id":1,"method":"Target.getTargets","params":{}}`)); err != nil {
return err
}
if err = w.Close(); err != nil {
return err
}
log.Printf("wrote Target.getTargets message")
// read response
jc := websocket.JSONConn{
Conn: c,
}
var v interface{}
err = jc.Read(ctx, &v)
if err != nil {
log.Fatalf("failed to read json: %v", err)
}
buf, err := json.Marshal(v)
if err != nil {
return err
}
log.Printf("received %s", string(buf))
return c.Close(websocket.StatusNormalClosure, "")
}
And using it with Google Chrome's DevTools Protocol, on sending a simple message via this command:
Starting Chrome:
ken@ken-desktop:~/src/go/src/github.com/kenshaw/wstest$ google-chrome --headless --remote-debugging-port=0 --disable-gpu
DevTools listening on ws://127.0.0.1:32831/devtools/browser/4f7e048b-1c84-4f05-a7fe-39fd624fb07e
And then running the simple Go test program above:
ken@ken-desktop:~/src/go/src/github.com/kenshaw/wstest$ go build && ./wstest -r 'ws://127.0.0.1:32831/devtools/browser/4f7e048b-1c84-4f05-a7fe-39fd624fb07e'
2019/04/20 20:10:49 wrote Target.getTargets message
2019/04/20 20:10:49 failed to read json: failed to read json: websocket: failed to read message: websocket: connection broken: failed to read header: EOF
ken@ken-desktop:~/src/go/src/github.com/kenshaw/wstest$
Expected output: the response from Chrome, looking something like the following:
{"id":1,"result":{"targetInfos":[{"targetId":"D18C239D31BAB5964945BD536DD9C987","type":"page","title":"","url":"about:blank","attached":false,"browserContextId":"FECF894940A790B796F6A86E836A8242"}]}}
Note: both the gobwas/ws
and gorilla/websocket
packages work with Chrome's DevTools Protocol.
I've attempted to look through the nhooyr.io/websocket
package to determine what the cause is, but have not been able to track down what the issue is. My guess is that it's a non-standard header or some such that Chrome is returning.
Perhaps I'm not using the package properly, if so, I apologize in advance, however I believe I correctly followed the examples provided in the package. Appreciate any pointers to doing this properly -- I'm also willing to help debug this issue. Thanks in advance!
I think it's a little awkward and inflexible. Maybe its better to have devs verify the origin themselves if its not equal to r.Host and then pass an option like websocket.AcceptInsecureOrigin()
Opportunities for optimization available in
Should we add a code path for fast reads and writes without allocating a reader or writer?
like:
type frame struct {
opcode opcode
p []byte
}
func (c *Conn) Write2(ctx context.Context, dataType DataType, msg []byte) error {
err := c.write2(ctx, dataType, msg)
if err != nil {
return xerrors.Errorf("failed to write message: %w", err)
}
return nil
}
func (c *Conn) write2(ctx context.Context, dataType DataType, msg []byte) error {
select {
case <-c.closed:
return c.closeErr
case <-ctx.Done():
return ctx.Err()
case c.write <- frame{
opcode: opcode(dataType),
p: msg,
}:
select {
case <-c.closed:
return c.closeErr
case <-ctx.Done():
return ctx.Err()
case <-c.writeDone:
return nil
}
}
}
func (c *Conn) Read2(ctx context.Context, msg []byte) (DataType, int, error) {
dataType, n, err := c.read2(ctx, msg)
if err != nil {
return 0, 0, xerrors.Errorf("failed to read message: %w", err)
}
return dataType, n, nil
}
func (c *Conn) read2(ctx context.Context, msg []byte) (DataType, int, error) {
select {
case <-c.closed:
return 0, 0, c.closeErr
case <-ctx.Done():
return 0, 0, xerrors.Errorf("failed to read: %w", ctx.Err())
case c.read <- msg:
select {
case <-c.closed:
return 0, 0, c.closeErr
case <-ctx.Done():
return 0, 0, xerrors.Errorf("failed to read: %w", ctx.Err())
case r := <-c.readDone:
return r.dataType, r.n, nil
}
}
}
Would actually be a wrapper around the Conn like JSONConn though.
Not sure how beneficial this will really be. I really do not want to expose a toggle.
Will wait to see what happens with golang/go#22618
Will be a fun exercise for me.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.