iris/websocket/serializer.go
2016-05-30 17:08:09 +03:00

146 lines
3.7 KiB
Go

package websocket
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"github.com/kataras/iris/utils"
)
/*
serializer, [de]serialize the messages from the client to the server and from the server to the client
*/
// The same values are exists on client side also
const (
stringMessageType messageType = iota
intMessageType
boolMessageType
bytesMessageType
jsonMessageType
)
const (
prefix = "iris-websocket-message:"
separator = ";"
prefixLen = len(prefix)
separatorLen = len(separator)
prefixAndSepIdx = prefixLen + separatorLen - 1
prefixIdx = prefixLen - 1
separatorIdx = separatorLen - 1
)
var (
separatorByte = separator[0]
buf = utils.NewBufferPool(256)
prefixBytes = []byte(prefix)
)
type (
messageType uint8
)
func (m messageType) String() string {
return strconv.Itoa(int(m))
}
func (m messageType) Name() string {
if m == stringMessageType {
return "string"
} else if m == intMessageType {
return "int"
} else if m == boolMessageType {
return "bool"
} else if m == bytesMessageType {
return "[]byte"
} else if m == jsonMessageType {
return "json"
}
return "Invalid(" + m.String() + ")"
}
// serialize serializes a custom websocket message from server to be delivered to the client
// returns the string form of the message
// Supported data types are: string, int, bool, bytes and JSON.
func serialize(event string, data interface{}) (string, error) {
var msgType messageType
var dataMessage string
if s, ok := data.(string); ok {
msgType = stringMessageType
dataMessage = s
} else if i, ok := data.(int); ok {
msgType = intMessageType
dataMessage = strconv.Itoa(i)
} else if b, ok := data.(bool); ok {
msgType = boolMessageType
dataMessage = strconv.FormatBool(b)
} else if by, ok := data.([]byte); ok {
msgType = bytesMessageType
dataMessage = string(by)
} else {
//we suppose is json
res, err := json.Marshal(data)
if err != nil {
return "", err
}
msgType = jsonMessageType
dataMessage = string(res)
}
b := buf.Get()
b.WriteString(prefix)
b.WriteString(event)
b.WriteString(separator)
b.WriteString(msgType.String())
b.WriteString(separator)
b.WriteString(dataMessage)
dataMessage = b.String()
buf.Put(b)
return dataMessage, nil
}
// deserialize deserializes a custom websocket message from the client
// ex: iris-websocket-message;chat;4;themarshaledstringfromajsonstruct will return 'hello' as string
// Supported data types are: string, int, bool, bytes and JSON.
func deserialize(event string, websocketMessage string) (message interface{}, err error) {
t, formaterr := strconv.Atoi(websocketMessage[prefixAndSepIdx+len(event)+1 : prefixAndSepIdx+len(event)+2]) // in order to iris-websocket-message;user;-> 4
if formaterr != nil {
return nil, formaterr
}
_type := messageType(t)
_message := websocketMessage[prefixAndSepIdx+len(event)+3:] // in order to iris-websocket-message;user;4; -> themarshaledstringfromajsonstruct
if _type == stringMessageType {
message = string(_message)
} else if _type == intMessageType {
message, err = strconv.Atoi(_message)
} else if _type == boolMessageType {
message, err = strconv.ParseBool(_message)
} else if _type == bytesMessageType {
message = []byte(_message)
} else if _type == jsonMessageType {
err = json.Unmarshal([]byte(_message), message)
} else {
return nil, fmt.Errorf("Type %s is invalid for message: %s", _type.Name(), websocketMessage)
}
return
}
// getCustomEvent return empty string when the websocketMessage is native message
func getCustomEvent(websocketMessage string) string {
if len(websocketMessage) < prefixAndSepIdx {
return ""
}
s := websocketMessage[prefixAndSepIdx:]
evt := s[:strings.IndexByte(s, separatorByte)]
return evt
}