func (dec *sioDecoder) Decode() (messages []Message, err error) { messages = make([]Message, 0, 1) var c rune L: for { if dec.state == sioDecodeStateBegin { dec.msg = &sioMessage{} dec.state = sioDecodeStateHeaderBegin dec.buf.Reset() } c, _, err = dec.src.ReadRune() if err != nil { break } switch dec.state { case sioDecodeStateHeaderBegin: dec.buf.WriteRune(c) if dec.buf.Len() == len(sioFrameDelim) { if !bytes.Equal(dec.buf.Bytes(), sioFrameDelim) { dec.Reset() return nil, errors.New("Malformed header") } dec.state = sioDecodeStateLength dec.buf.Reset() } continue case sioDecodeStateLength: if c >= '0' && c <= '9' { dec.buf.WriteRune(c) continue } if dec.length, err = strconv.Atoi(dec.buf.String()); err != nil { dec.Reset() return nil, err } dec.buf.Reset() dec.state = sioDecodeStateHeaderEnd fallthrough case sioDecodeStateHeaderEnd: dec.buf.WriteRune(c) if dec.buf.Len() < len(sioFrameDelim) { continue } if !bytes.Equal(dec.buf.Bytes(), sioFrameDelim) { dec.Reset() return nil, errors.New("Malformed header") } dec.state = sioDecodeStateData dec.buf.Reset() if dec.length > 0 { continue } fallthrough case sioDecodeStateData: if dec.length > 0 { dec.buf.WriteRune(c) dec.length-- utf8str := utf8string.NewString(dec.src.String()) if utf8str.RuneCount() >= dec.length { str := utf8str.Slice(0, dec.length) dec.buf.WriteString(str) dec.src.Next(len(str)) dec.length = 0 } else { break L } } data := dec.buf.Bytes() dec.msg.typ = sioMessageTypeMessage if bytes.HasPrefix(data, sioFrameDelimJSON) { dec.msg.annotations = make(map[string]string) dec.msg.annotations[SIOAnnotationJSON] = "" data = data[len(sioFrameDelimJSON):] } else if bytes.HasPrefix(data, sioFrameDelimHeartbeat) { dec.msg.typ = sioMessageTypeHeartbeat data = data[len(sioFrameDelimHeartbeat):] } dec.msg.data = make([]byte, len(data)) copy(dec.msg.data, data) messages = append(messages, dec.msg) dec.state = sioDecodeStateBegin dec.buf.Reset() continue } dec.buf.WriteRune(c) } if err == io.EOF { err = nil } return }
func (dec *sioStreamingDecoder) Decode() (messages []Message, err error) { messages = make([]Message, 0, 1) var c rune var typ uint64 L: for { c, _, err = dec.src.ReadRune() if err != nil { break } if dec.state == sioStreamingDecodeStateBegin { dec.msg = &sioMessage{} dec.state = sioStreamingDecodeStateType dec.buf.Reset() } switch dec.state { case sioStreamingDecodeStateType: if c == ':' { if typ, err = strconv.ParseUint(dec.buf.String(), 10, 0); err != nil { dec.Reset() return nil, err } dec.msg.typ = uint8(typ) dec.buf.Reset() dec.state = sioStreamingDecodeStateLength continue } case sioStreamingDecodeStateLength: if c == ':' { if dec.length, err = strconv.Atoi(dec.buf.String()); err != nil { dec.Reset() return nil, err } dec.buf.Reset() switch dec.msg.typ { case sioMessageTypeMessage: dec.state = sioStreamingDecodeStateAnnotationKey case sioMessageTypeDisconnect: dec.state = sioStreamingDecodeStateTrailer default: dec.state = sioStreamingDecodeStateData } continue } case sioStreamingDecodeStateAnnotationKey: dec.length-- switch c { case ':': if dec.buf.Len() == 0 { dec.state = sioStreamingDecodeStateData } else { dec.key = dec.buf.String() dec.buf.Reset() dec.state = sioStreamingDecodeStateAnnotationValue } continue case '\n': if dec.buf.Len() == 0 { dec.Reset() return nil, errors.New("expecting key, but got...") } dec.key = dec.buf.String() if dec.msg.annotations == nil { dec.msg.annotations = make(map[string]string) } dec.msg.annotations[dec.key] = "" dec.buf.Reset() continue } case sioStreamingDecodeStateAnnotationValue: dec.length-- if c == '\n' || c == ':' { dec.value = dec.buf.String() if dec.msg.annotations == nil { dec.msg.annotations = make(map[string]string) } dec.msg.annotations[dec.key] = dec.value dec.buf.Reset() if c == '\n' { dec.state = sioStreamingDecodeStateAnnotationKey } else { dec.state = sioStreamingDecodeStateData } continue } case sioStreamingDecodeStateData: if dec.length > 0 { dec.buf.WriteRune(c) dec.length-- utf8str := utf8string.NewString(dec.src.String()) if utf8str.RuneCount() >= dec.length { str := utf8str.Slice(0, dec.length) dec.buf.WriteString(str) dec.src.Next(len(str)) dec.length = 0 continue } else { break L } } data := dec.buf.Bytes() dec.msg.data = make([]byte, len(data)) copy(dec.msg.data, data) dec.buf.Reset() dec.state = sioStreamingDecodeStateTrailer fallthrough case sioStreamingDecodeStateTrailer: if c == ',' { messages = append(messages, dec.msg) dec.state = sioStreamingDecodeStateBegin continue } else { dec.Reset() return nil, errors.New("Expecting trailer but got... " + string(c)) } } dec.buf.WriteRune(c) } if err == io.EOF { err = nil } return }