package tanja import ( "bufio" "encoding/json" "errors" "io" . "strconv" ) type linkMsgPatternsync bool type linkMsgRegister struct { pid int32 pat Tuple } type linkMsgRegdone struct{} type linkMsgUnregister int32 type linkMsgTuple struct { tid int32 tup Tuple } type linkMsgReply struct { tid int32 tup Tuple } type linkMsgClose int32 type linkMsgJSON struct { m interface{} } // Make sure JSON arrays are read as tuples. For anything else, just use the // generic to-interface{} conversion. func (j *linkMsgJSON) UnmarshalJSON(data []byte) (err error) { if data[0] == '[' { var t Tuple err = json.Unmarshal(data, &t) j.m = t } else { err = json.Unmarshal(data, &j.m) } return } func linkMsgRead(rd *bufio.Reader) (msg interface{}, err error) { var line []byte var prefix bool line, prefix, err = rd.ReadLine() if prefix || err != nil { if err == nil { err = errors.New("Read buffer overflow.") } return } var m []linkMsgJSON if err = json.Unmarshal(line, &m); err != nil || len(m) < 1 { if len(m) < 1 { err = errors.New("Invalid message type.") } return } // Validate and convert typ, ok := m[0].m.(float64) if !ok { err = errors.New("Invalid message type.") return } // Copy-pasting is bad, mkay? switch int32(typ) { case 1: // patternsync if len(m) != 2 { err = errors.New("Invalid number of arguments for the patternsync message.") } else if val, ok := m[1].m.(bool); ok { msg = linkMsgPatternsync(val) } else { err = errors.New("Invalid type of second argument to the patternsync message.") } case 2: // register var pid float64 var pat Tuple if len(m) != 3 { err = errors.New("Invalid number of arguments for the register message.") } else if pid, ok = m[1].m.(float64); !ok { err = errors.New("Invalid type of second argument to the patternsync message.") } else if pat, ok = m[2].m.(Tuple); !ok { err = errors.New("Invalid type of third argument to the patternsync message.") } else { msg = &linkMsgRegister{int32(pid), pat} } case 3: // regdone if len(m) != 1 { err = errors.New("Invalid number of arguments for the regdone message.") } else { msg = linkMsgRegdone{} } case 4: // unregister if len(m) != 2 { err = errors.New("Invalid number of arguments for the unregister message.") } else if val, ok := m[1].m.(float64); ok { msg = linkMsgUnregister(int32(val)) } else { err = errors.New("Invalid type of second argument to the unregister message.") } case 5: // tuple var tid float64 var tup Tuple if len(m) != 3 { err = errors.New("Invalid number of arguments for the tuple message.") } else if tid, ok = m[1].m.(float64); !ok { err = errors.New("Invalid type of second argument to the tuple message.") } else if tup, ok = m[2].m.(Tuple); !ok { err = errors.New("Invalid type of third argument to the tuple message.") } else { msg = &linkMsgTuple{int32(tid), tup} } case 6: // reply var tid float64 var tup Tuple if len(m) != 3 { err = errors.New("Invalid number of arguments for the reply message.") } else if tid, ok = m[1].m.(float64); !ok { err = errors.New("Invalid type of second argument to the reply message.") } else if tup, ok = m[2].m.(Tuple); !ok { err = errors.New("Invalid type of third argument to the reply message.") } else { msg = &linkMsgReply{int32(tid), tup} } case 7: // close if len(m) != 2 { err = errors.New("Invalid number of arguments for the close message.") } else if val, ok := m[1].m.(float64); ok { msg = linkMsgClose(int32(val)) } else { err = errors.New("Invalid type of second argument to the close message.") } } // Ignore unknown messages by returning nil without error return } func linkMsgWrite(wr io.Writer, msg interface{}) (int, error) { // Somewhat low-level, but oh well var buf []byte switch m := msg.(type) { case linkMsgPatternsync: if m { buf = append(buf, []byte("[1,true]\n")...) } else { buf = append(buf, []byte("[1,false]\n")...) } case *linkMsgRegister: buf = append(buf, []byte("[2,")...) buf = append(buf, []byte(FormatInt(int64(m.pid), 10))...) buf = append(buf, ',') dat, _ := json.Marshal(m.pat) buf = append(buf, dat...) buf = append(buf, []byte("]\n")...) case linkMsgRegdone: buf = append(buf, []byte("[3]\n")...) case linkMsgUnregister: buf = append(buf, []byte("[4,")...) buf = append(buf, []byte(FormatInt(int64(m), 10))...) buf = append(buf, []byte("]\n")...) case *linkMsgTuple: buf = append(buf, []byte("[5,")...) buf = append(buf, []byte(FormatInt(int64(m.tid), 10))...) buf = append(buf, ',') dat, _ := json.Marshal(m.tup) buf = append(buf, dat...) buf = append(buf, []byte("]\n")...) case *linkMsgReply: buf = append(buf, []byte("[6,")...) buf = append(buf, []byte(FormatInt(int64(m.tid), 10))...) buf = append(buf, ',') dat, _ := json.Marshal(m.tup) buf = append(buf, dat...) buf = append(buf, []byte("]\n")...) case linkMsgClose: buf = append(buf, []byte("[7,")...) buf = append(buf, []byte(FormatInt(int64(m), 10))...) buf = append(buf, []byte("]\n")...) } return wr.Write(buf) }