Skip to content

Instantly share code, notes, and snippets.

@fizx
Last active December 17, 2015 13:29
Show Gist options
  • Save fizx/5617728 to your computer and use it in GitHub Desktop.
Save fizx/5617728 to your computer and use it in GitHub Desktop.
package main
/**
* This is a little too permissive (and hacked together), but it illustrates
* the point of encoding a bufio.Scanner that is stateful, so that it can
* parse the redis protocol.
*/
import (
"bufio"
"bytes"
"fmt"
"strconv"
)
const (
Marker = iota
Int
Content
)
func newScanFunc() bufio.SplitFunc {
expected := Marker
var tmp int64 = -1
size := -1
dollar := false
return func(data []byte, atEOF bool) (advance int, token []byte, err error) {
switch expected {
case Marker:
fmt.Println("parsing marker")
advance, token, err = bufio.ScanBytes(data, atEOF)
expected = Int
dollar = !atEOF && data[0] == '$'
case Int:
fmt.Println("parsing int")
advance, token, err = bufio.ScanWords(data, atEOF)
advance += 1
if dollar {
tmp, err = strconv.ParseInt(string(token), 10, 32)
size = int(tmp)
expected = Content
} else {
expected = Marker
}
case Content:
fmt.Println("parsing content")
if len(data) < size {
if atEOF {
return 0, nil, fmt.Errorf("incomplete message at EOF")
} else {
return 0, nil, nil // ask to try again with more data
}
} else {
advance = size + 2
token = data[:size]
expected = Marker
}
}
return
}
}
func main() {
reader := bytes.NewBufferString("*1\r\n$11\r\nhello world\r\n*1\r\n$13\r\ngoodbye world\r\n")
scanner := bufio.NewScanner(reader)
scanner.Split(newScanFunc())
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment