Repository: gammazero/nexus (go)

Issue:
Floating point arguments
There is no `wamp.AsFloat64` function. That would be useful.

Pull request description:
Benchmark
Fix #71 

Patch:
diff --git a/transport/websocketpeer.go b/transport/websocketpeer.go
index c0c8ce5..28d70ce 100644
--- a/transport/websocketpeer.go
+++ b/transport/websocketpeer.go
@@ -6,6 +6,7 @@ import (
 	"fmt"
 	"net"
 	"net/http"
+	"strings"
 	"time"
 
 	"github.com/gammazero/nexus/stdlog"
@@ -167,7 +168,9 @@ func (w *websocketPeer) sendHandler() {
 		}
 
 		if err = w.conn.WriteMessage(w.payloadType, b); err != nil {
-			w.log.Print(err)
+			if !strings.HasSuffix(err.Error(), "close sent") {
+				w.log.Print(err)
+			}
 		}
 	}
 }
diff --git a/wamp/dict.go b/wamp/dict.go
index df3f3df..9695c52 100644
--- a/wamp/dict.go
+++ b/wamp/dict.go
@@ -157,16 +157,41 @@ func AsInt64(v interface{}) (int64, bool) {
 		return int64(v), true
 	case int32:
 		return int64(v), true
-	case float64:
-		return int64(v), true
 	case uint:
 		return int64(v), true
 	case uint32:
 		return int64(v), true
+	case float64:
+		return int64(v), true
+	case float32:
+		return int64(v), true
 	}
 	return 0, false
 }
 
+func AsFloat64(v interface{}) (float64, bool) {
+	switch v := v.(type) {
+	case float64:
+		return v, true
+	case float32:
+		return float64(v), true
+	case int64:
+		return float64(v), true
+	case ID:
+		return float64(v), true
+	case uint64:
+		return float64(v), true
+	case int:
+		return float64(v), true
+	case int32:
+		return float64(v), true
+	case uint:
+		return float64(v), true
+	case uint32:
+		return float64(v), true
+	}
+	return 0.0, false
+}
 func AsDict(v interface{}) (Dict, bool) {
 	n := NormalizeDict(v)
 	return n, n != nil


Test patch:
diff --git a/aat/benchmark_test.go b/aat/benchmark_test.go
new file mode 100644
index 0000000..9222133
--- /dev/null
+++ b/aat/benchmark_test.go
@@ -0,0 +1,106 @@
+package aat
+
+import (
+	"sync"
+	"testing"
+
+	"github.com/gammazero/nexus/client"
+	"github.com/gammazero/nexus/wamp"
+)
+
+const benchMsgCount = 5
+
+func BenchmarkPub2Sub(b *testing.B) {
+	benchPubSub(2, b)
+}
+
+func BenchmarkPub4Sub(b *testing.B) {
+	benchPubSub(4, b)
+}
+
+func BenchmarkPub8Sub(b *testing.B) {
+	benchPubSub(4, b)
+}
+
+func BenchmarkPub16Sub(b *testing.B) {
+	benchPubSub(16, b)
+}
+
+func BenchmarkPub32Sub(b *testing.B) {
+	benchPubSub(32, b)
+}
+
+func BenchmarkPub64Sub(b *testing.B) {
+	benchPubSub(64, b)
+}
+
+func BenchmarkPub128Sub(b *testing.B) {
+	benchPubSub(128, b)
+}
+
+func BenchmarkPub256Sub(b *testing.B) {
+	benchPubSub(256, b)
+}
+
+func BenchmarkPub512Sub(b *testing.B) {
+	benchPubSub(512, b)
+}
+
+func benchPubSub(subCount int, b *testing.B) {
+	var allDone sync.WaitGroup
+
+	evtHandler := func(args wamp.List, kwargs wamp.Dict, details wamp.Dict) {
+		allDone.Done()
+	}
+
+	subs := make([]*client.Client, subCount)
+	for i := range subs {
+		subs[i] = connectSubscriber(evtHandler)
+	}
+
+	// Connect publisher session.
+	publisher, err := connectClient()
+	if err != nil {
+		panic("Failed to connect client: " + err.Error())
+	}
+
+	args := wamp.List{"hello world"}
+	recvCount := subCount * benchMsgCount
+
+	b.ResetTimer()
+
+	// Start workers, and have them all wait on a channel before completing.
+	for i := 0; i < b.N; i++ {
+		allDone.Add(recvCount)
+		for j := 0; j < benchMsgCount; j++ {
+			// Publish an event to topic.
+			err = publisher.Publish(testTopic, nil, args, nil)
+			if err != nil {
+				panic("Error waiting for published response: " + err.Error())
+			}
+		}
+		// Wait until all subscribers got the message.
+		allDone.Wait()
+	}
+
+	publisher.Close()
+	for i := range subs {
+		subs[i].Unsubscribe(testTopic)
+		subs[i].Close()
+	}
+}
+
+func connectSubscriber(fn client.EventHandler) *client.Client {
+	// Connect subscriber session.
+	subscriber, err := connectClient()
+	if err != nil {
+		panic("Failed to connect client: " + err.Error())
+	}
+
+	// Subscribe to event.
+	err = subscriber.Subscribe(testTopic, fn, nil)
+	if err != nil {
+		panic("subscribe error: " + err.Error())
+	}
+	return subscriber
+}
diff --git a/aat/pubsub_test.go b/aat/pubsub_test.go
index 2d0d01a..f8b5330 100644
--- a/aat/pubsub_test.go
+++ b/aat/pubsub_test.go
@@ -46,7 +46,7 @@ func TestPubSub(t *testing.T) {
 	if err != nil {
 		t.Fatal("Failed to connect client:", err)
 	}
-	// Publish an event to something that matches by wildcard.
+	// Publish an event to topic.
 	err = publisher.Publish(testTopic, wamp.Dict{wamp.OptAcknowledge: true},
 		wamp.List{"hello world"}, nil)
 	if err != nil {
diff --git a/wamp/dict_test.go b/wamp/dict_test.go
index d311b7b..cadee0a 100644
--- a/wamp/dict_test.go
+++ b/wamp/dict_test.go
@@ -271,9 +271,13 @@ func TestConversion(t *testing.T) {
 		t.Error("Should fail converting int to URI")
 	}
 
-	if _, ok = AsInt64(int64(num)); !ok {
+	var i64 int64
+	if i64, ok = AsInt64(int64(num)); !ok {
 		t.Error("ID conversion failed")
 	}
+	if i64 != int64(num) {
+		t.Error("Wrong number")
+	}
 	if _, ok = AsInt64(ID(num)); !ok {
 		t.Error("ID conversion failed")
 	}
@@ -298,13 +302,62 @@ func TestConversion(t *testing.T) {
 	if _, ok = AsInt64(uint64(num)); !ok {
 		t.Error("ID conversion failed")
 	}
-	if _, ok = AsInt64(float64(num)); !ok {
+	if _, ok = AsInt64(float32(num)); !ok {
+		t.Error("ID conversion failed")
+	}
+	if i64, ok = AsInt64(float64(num)); !ok {
 		t.Error("ID conversion failed")
 	}
+	if i64 != int64(num) {
+		t.Error("Wrong number")
+	}
 	if _, ok = AsInt64(str); ok {
 		t.Error("Invalid ID conversion")
 	}
 
+	var f64 float64
+	if f64, ok = AsFloat64(float64(num)); !ok {
+		t.Error("ID conversion failed")
+	}
+	if f64 != float64(num) {
+		t.Error("Wrong number")
+	}
+	if _, ok = AsFloat64(float32(num)); !ok {
+		t.Error("ID conversion failed")
+	}
+	if _, ok = AsFloat64(ID(num)); !ok {
+		t.Error("ID conversion failed")
+	}
+	if _, ok = AsFloat64(uint64(num)); !ok {
+		t.Error("ID conversion failed")
+	}
+	if _, ok = AsFloat64(int(num)); !ok {
+		t.Error("ID conversion failed")
+	}
+	if _, ok = AsFloat64(int32(num)); !ok {
+		t.Error("ID conversion failed")
+	}
+	if _, ok = AsFloat64(int64(num)); !ok {
+		t.Error("ID conversion failed")
+	}
+	if _, ok = AsFloat64(uint(num)); !ok {
+		t.Error("ID conversion failed")
+	}
+	if _, ok = AsFloat64(uint32(num)); !ok {
+		t.Error("ID conversion failed")
+	}
+	if _, ok = AsFloat64(uint64(num)); !ok {
+		t.Error("ID conversion failed")
+	}
+	if f64, ok = AsFloat64(int64(num)); !ok {
+		t.Error("ID conversion failed")
+	}
+	if f64 != float64(num) {
+		t.Error("Wrong number")
+	}
+	if _, ok = AsFloat64(str); ok {
+		t.Error("Invalid ID conversion")
+	}
 }
 
 func BenchmarkNormalized(b *testing.B) {