Skip to content

Implement core API for WASM #142

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 22, 2019
Merged

Implement core API for WASM #142

merged 5 commits into from
Sep 22, 2019

Conversation

nhooyr
Copy link
Contributor

@nhooyr nhooyr commented Sep 21, 2019

Closes #121

@nhooyr nhooyr force-pushed the wasm branch 2 times, most recently from bc1defe to b6caac6 Compare September 21, 2019 19:10
@nhooyr nhooyr marked this pull request as ready for review September 21, 2019 19:57
@nhooyr
Copy link
Contributor Author

nhooyr commented Sep 21, 2019

@albrow is it possible you could review this?

@nhooyr nhooyr changed the title Add WebSocket API Implement core API for WASM Sep 21, 2019
@nhooyr nhooyr force-pushed the wasm branch 2 times, most recently from dc34ee5 to cf3e427 Compare September 22, 2019 00:01
@nhooyr nhooyr force-pushed the wasm branch 5 times, most recently from 1b7cc02 to 52ff3bf Compare September 22, 2019 01:12
@nhooyr
Copy link
Contributor Author

nhooyr commented Sep 22, 2019

@coadler pls review if you can

@nhooyr nhooyr force-pushed the wasm branch 4 times, most recently from fe9ba71 to e301872 Compare September 22, 2019 01:27
Copy link
Contributor

@coadler coadler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good

ctx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()

b := make([]byte, 32768)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you used 1 << 40 above 32 << 10 would be consistent here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also just realized 1 << 40 is a terabyte, not a gigabyte lol.

@albrow
Copy link

albrow commented Sep 22, 2019

Sure. Should be able to review tomorrow.

@nhooyr nhooyr force-pushed the wasm branch 7 times, most recently from ab3489c to 06aa2f7 Compare September 22, 2019 02:23
@nhooyr nhooyr force-pushed the wasm branch 4 times, most recently from 6d131b8 to a9618cb Compare September 22, 2019 02:47
ci/wasm.sh Outdated
GOOS=js GOARCH=wasm go test -exec=wasmbrowsertest ./... -args "$WS_ECHO_SERVER_URL"

kill %1
wait -n || true
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will improve this test to assert proper closure of the connection.

@nhooyr
Copy link
Contributor Author

nhooyr commented Sep 22, 2019

Going to merge for now since I want to restructure the codebase but please review if you can @albrow. I'll fix anything you point out afterwards.

@nhooyr nhooyr merged commit 7b4bd30 into master Sep 22, 2019
@nhooyr nhooyr deleted the wasm branch September 22, 2019 17:24
Copy link

@albrow albrow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nhooyr looks pretty good overall. I just left some comments about build tags and not blocking inside of js.FuncOf.

Is there any plan to implement io.ReadWriteCloser on top of this API? that would be really helpful for a variety of use cases.

- First class [context.Context](https://blog.golang.org/context) support
- Thorough tests, fully passes the [autobahn-testsuite](https://github.com/crossbario/autobahn-testsuite)
- [Zero dependencies](https://godoc.org/nhooyr.io/websocket?imports)
- JSON and ProtoBuf helpers in the [wsjson](https://godoc.org/nhooyr.io/websocket/wsjson) and [wspb](https://godoc.org/nhooyr.io/websocket/wspb) subpackages
- Highly optimized by default
- Concurrent writes out of the box
- [Complete WASM](https://godoc.org/nhooyr.io/websocket#hdr-WASM) support
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This is an abbreviation (not an acronym) so it's usually spelled "Wasm".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

func (c *WebSocket) addEventListener(eventType string, fn func(e js.Value)) {
c.v.Call("addEventListener", eventType, js.FuncOf(func(this js.Value, args []js.Value) interface{} {
func (c WebSocket) addEventListener(eventType string, fn func(e js.Value)) func() {
f := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
fn(args[0])
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's really important to not block inside of a js.Func wrapped function. Doing so will block the JavaScript event loop and prevent any other JavaScript functions from running. You should almost always start a new goroutine inside of js.FuncOf.

For example:

	f := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		go fn(args[0])
		return nil
	})

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch, fixed.

func (c *WebSocket) SendText(v string) (err error) {
// SendText sends the given string as a text message
// on the WebSocket.
func (c WebSocket) SendText(v string) (err error) {
defer handleJSError(&err, nil)
c.v.Call("send", v)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have good test coverage for the SendText method? I've had a lot of trouble with things like this in the past because JavaScript does wonky and unexpected things with text encoding. The string you are trying to send might not end up being the same as what is received on the other end. It might even be better to just remove this method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link

@albrow albrow Sep 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nhooyr it looks like randString only includes hex characters? You should probably test with more unicode characters, in particular ones with higher code points. There can be differences in how these are encoded/interpreted in Go and JavaScript.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fair. I'll adjust it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in #148

@@ -0,0 +1,217 @@
package websocket // import "nhooyr.io/websocket"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this file have the build tag: +build js,wasm?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Files with _js are automatically compiled only for GOOS=js.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌 Combined with the other thread about not needing wasm in the build tags, this should be fine.

@@ -0,0 +1,58 @@
// +build js
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless you know that a file is compatible with GopherJS you usually want to use the build tag +build js,wasm. The addition of wasm clarifies for the Go compiler that this file is compatible with WebAssembly but tells the GopherJS compiler that the file is not compatible with GopherJS. This blog post explains the situation in a little more detail.

Basically it works like this:

Build tag Vanilla Go WebAssembly GopherJS
(none)
js
!js
js,wasm
js,!wasm

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The library should just work with GopherJS once gopherjs/gopherjs#929 is closed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It won't even compile on GopherJS versions that don't support Go 1.13 because we use the new wrapping functions in the errors package.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reason being syscall/js is shimmed by GopherJS so that it works the same as Go Wasm.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha. Seems fine if you are not supporting versions older than 1.13.

@nhooyr
Copy link
Contributor Author

nhooyr commented Sep 23, 2019

Is there any plan to implement io.ReadWriteCloser on top of this API? that would be really helpful for a variety of use cases.

Already implemented. websocket.NetConn is compiled into Wasm builds.

@nhooyr
Copy link
Contributor Author

nhooyr commented Sep 23, 2019

In this PR it wasn't but I made it work in follow up PR #146

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Compile for WebAssembly
4 participants