diff --git a/rpc/core_client/ws_client.go b/rpc/core_client/ws_client.go index 1db273ae0..5a719525e 100644 --- a/rpc/core_client/ws_client.go +++ b/rpc/core_client/ws_client.go @@ -3,6 +3,7 @@ package core_client import ( "net/http" "strings" + "time" "github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/gorilla/websocket" . "github.com/tendermint/tendermint/common" @@ -12,8 +13,11 @@ import ( "github.com/tendermint/tendermint/wire" ) -const wsEventsChannelCapacity = 10 -const wsResultsChannelCapacity = 10 +const ( + wsEventsChannelCapacity = 10 + wsResultsChannelCapacity = 10 + wsWriteTimeoutSeconds = 10 +) type WSClient struct { QuitService @@ -53,6 +57,14 @@ func (wsc *WSClient) dial() error { if err != nil { return err } + // Set the ping/pong handlers + con.SetPingHandler(func(m string) error { + con.WriteControl(websocket.PongMessage, []byte(m), time.Now().Add(time.Second*wsWriteTimeoutSeconds)) + return nil + }) + con.SetPongHandler(func(m string) error { + return nil + }) wsc.Conn = con return nil } @@ -65,14 +77,14 @@ func (wsc *WSClient) receiveEventsRoutine() { for { _, data, err := wsc.ReadMessage() if err != nil { - log.Info(Fmt("WSClient failed to read message: %v", err)) + log.Info("WSClient failed to read message", "error", err, "data", string(data)) wsc.Stop() break } else { var response ctypes.Response wire.ReadJSON(&response, data, &err) if err != nil { - log.Info(Fmt("WSClient failed to parse message: %v", err)) + log.Info("WSClient failed to parse message", "error", err) wsc.Stop() break } diff --git a/wire/reflect.go b/wire/reflect.go index f8f916f37..d964d585a 100644 --- a/wire/reflect.go +++ b/wire/reflect.go @@ -93,7 +93,7 @@ var ( ) const ( - rfc2822 = "Mon Jan 02 15:04:05 -0700 2006" + iso8601 = "2006-01-02T15:04:05.000Z" // forced microseconds ) // NOTE: do not access typeInfos directly, but call GetTypeInfo() @@ -731,7 +731,7 @@ func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *erro return } log.Info(Fmt("Read time: %v", str)) - t, err_ := time.Parse(rfc2822, str) + t, err_ := time.Parse(iso8601, str) if err_ != nil { *err = err_ return @@ -908,8 +908,8 @@ func writeReflectJSON(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, case reflect.Struct: if rt == timeType { // Special case: time.Time - t := rv.Interface().(time.Time) - str := t.Format(rfc2822) + t := rv.Interface().(time.Time).UTC() + str := t.Format(iso8601) jsonBytes, err_ := json.Marshal(str) if err_ != nil { *err = err_ diff --git a/wire/reflect_test.go b/wire/reflect_test.go index 751e87a81..b21b8bf2a 100644 --- a/wire/reflect_test.go +++ b/wire/reflect_test.go @@ -51,6 +51,7 @@ var _ = RegisterInterface( ConcreteType{&Viper{}, AnimalTypeViper}, ) +// TODO: add assertions here ... func TestAnimalInterface(t *testing.T) { var foo Animal @@ -100,7 +101,7 @@ func constructBasic() interface{} { SimpleStruct{ String: "String", Bytes: []byte("Bytes"), - Time: time.Unix(123, 0), + Time: time.Unix(123, 456789999), }, } return cat @@ -118,8 +119,8 @@ func validateBasic(o interface{}, t *testing.T) { if string(cat.Bytes) != "Bytes" { t.Errorf("Expected cat.Bytes == 'Bytes', got %X", cat.Bytes) } - if cat.Time.Unix() != 123 { - t.Errorf("Expected cat.Time == 'Unix(123)', got %v", cat.Time) + if cat.Time.UnixNano() != 123456000000 { // Only milliseconds + t.Errorf("Expected cat.Time.UnixNano() == 123456000000, got %v", cat.Time.UnixNano()) } } diff --git a/wire/time.go b/wire/time.go index c4a573345..fde8b8ae5 100644 --- a/wire/time.go +++ b/wire/time.go @@ -3,15 +3,25 @@ package wire import ( "io" "time" + + . "github.com/tendermint/tendermint/common" ) -// Time +/* +Writes nanoseconds since epoch but with millisecond precision. +This is to ease compatibility with Javascript etc. +*/ func WriteTime(t time.Time, w io.Writer, n *int64, err *error) { - WriteInt64(t.UnixNano(), w, n, err) + nanosecs := t.UnixNano() + millisecs := nanosecs / 1000000 + WriteInt64(millisecs*1000000, w, n, err) } func ReadTime(r io.Reader, n *int64, err *error) time.Time { t := ReadInt64(r, n, err) + if t%1000000 != 0 { + PanicSanity("Time cannot have sub-millisecond precision") + } return time.Unix(0, t) }