func doParseCommand(parser *parser, buf *streambuf.Buffer) parseResult { // check if binary + text command and dispatch if !buf.Avail(2) { return parser.needMore() } magic := buf.Bytes()[0] isBinary := magic == memcacheMagicRequest || magic == memcacheMagicResponse if isBinary { return parser.contWith(buf, parseStateBinaryCommand) } return parser.contWith(buf, parseStateTextCommand) }
func readMessageType(buf *streambuf.Buffer) (byte, error) { if !buf.Avail(2) { return 0, nil } version, _ := buf.ReadNetUint8At(0) if version != '2' { return 0, errors.New("version error") } code, _ := buf.ReadNetUint8At(1) return code, nil }
func parseBinaryCommand(parser *parser, buf *streambuf.Buffer) parseResult { debug("on binary message") if !buf.Avail(memcacheHeaderSize) { return parser.needMore() } msg := parser.message msg.isBinary = true magic, _ := buf.ReadNetUint8At(0) switch magic { case MemcacheMagicRequest: msg.IsRequest = true case MemcacheMagicResponse: msg.IsRequest = false default: return parser.failing(ErrInvalidMemcacheMagic) } opcode, _ := buf.ReadNetUint8At(1) keyLen, err := buf.ReadNetUint16At(2) extraLen, _ := buf.ReadNetUint8At(4) if err != nil { return parser.failing(err) } debug("magic: %v", magic) debug("opcode: %v", opcode) debug("extra len: %v", extraLen) debug("key len: %v", keyLen) totalHeaderLen := memcacheHeaderSize + int(extraLen) + int(keyLen) debug("total header len: %v", totalHeaderLen) if !buf.Avail(totalHeaderLen) { return parser.needMore() } command := memcacheBinaryCommandTable[memcacheOpcode(opcode)] if command == nil { debug("unknown command") command = binaryUnknownCommand } msg.opcode = memcacheOpcode(opcode) msg.command = command msg.isQuiet = isQuietOpcode(msg.opcode) return parser.contWithShallow(buf, command.parse) }
func readMessage(buf *streambuf.Buffer) (*message, error) { if !buf.Avail(2) { return nil, nil } version, _ := buf.ReadNetUint8At(0) if version != '2' { return nil, errors.New("version error") } code, _ := buf.ReadNetUint8At(1) switch code { case 'W': if !buf.Avail(6) { return nil, nil } size, _ := buf.ReadNetUint32At(2) buf.Advance(6) buf.Reset() return &message{code: code, size: size}, buf.Err() case 'C': if !buf.Avail(6) { return nil, nil } len, _ := buf.ReadNetUint32At(2) if !buf.Avail(int(len) + 6) { return nil, nil } buf.Advance(6) tmp, _ := buf.Collect(int(len)) buf.Reset() dataBuf := streambuf.New(nil) // decompress data decomp, err := zlib.NewReader(streambuf.NewFixed(tmp)) if err != nil { return nil, err } // dataBuf.ReadFrom(streambuf.NewFixed(tmp)) dataBuf.ReadFrom(decomp) decomp.Close() // unpack data dataBuf.Fix() var events []*message for dataBuf.Len() > 0 { version, _ := dataBuf.ReadNetUint8() if version != '2' { return nil, errors.New("version error 2") } code, _ := dataBuf.ReadNetUint8() if code != 'J' { return nil, errors.New("expected json data frame") } seq, _ := dataBuf.ReadNetUint32() payloadLen, _ := dataBuf.ReadNetUint32() jsonRaw, _ := dataBuf.Collect(int(payloadLen)) var doc interface{} err = json.Unmarshal(jsonRaw, &doc) if err != nil { return nil, err } events = append(events, &message{ code: code, seq: seq, doc: doc.(map[string]interface{}), }) } return &message{code: 'C', events: events}, nil default: return nil, errors.New("unknown code") } }