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 }