Browse Source

b1 Message format.

--unset 2 years ago
commit
6deabb3ca8
3 changed files with 169 additions and 0 deletions
  1. 7 0
      b1/b1.go
  2. 111 0
      b1/message.go
  3. 51 0
      b1/message_test.go

+ 7 - 0
b1/b1.go

@@ -0,0 +1,7 @@
+package b1
+
+const ( // Ascii standard values for message types, prefixed with b1
+	INQ = 0xb1000005
+	ACK = 0xb1000006
+	NAK = 0xb1000015
+)

+ 111 - 0
b1/message.go

@@ -0,0 +1,111 @@
+package b1
+
+import (
+	"encoding/binary"
+	"fmt"
+	"io"
+)
+
+type Wire struct {
+	Len  uint8
+	Text [127]rune
+}
+
+func MakeWire(s string) Wire {
+	l := len(s)
+	ss := Wire{}
+	if l > len(ss.Text) {
+		l = len(ss.Text)
+	}
+	ss.Len = uint8(l)
+	copy(ss.Text[:], ([]rune(s))[0:l])
+	return ss
+}
+
+func (ss Wire) String() string {
+	return string(ss.Text[:ss.Len])
+}
+
+type Attr struct {
+	Name  Wire
+	Value Wire
+}
+
+type MessageHeader struct {
+	Kind       int64
+	From       int64
+	To         int64
+	Method     Wire
+	AttrCount  int8
+	BodyLength int64
+}
+
+type Message struct {
+	MessageHeader
+	attrs []Attr
+	body  []byte
+}
+
+func (m Message) MarshalTo(w io.Writer) error {
+	err := binary.Write(w, binary.LittleEndian, m.MessageHeader)
+	if err != nil {
+		return err
+	}
+	for i := 0; i < int(m.AttrCount) && i < len(m.attrs); i++ {
+		attr := m.attrs[i]
+		err = binary.Write(w, binary.LittleEndian, attr)
+		if err != nil {
+			return err
+		}
+	}
+	if m.BodyLength > 0 {
+		l, err := w.Write(m.body[0:m.BodyLength])
+		if l != int(m.BodyLength) {
+			return fmt.Errorf("Message partial write: %d %d", l, m.BodyLength)
+		}
+		return err
+	}
+	return nil
+}
+
+func (m *Message) UnmarshalFrom(w io.Reader) error {
+	err := binary.Read(w, binary.LittleEndian, &m.MessageHeader)
+	if err != nil {
+		return err
+	}
+	if m.AttrCount < 0 {
+		return fmt.Errorf("Negative attr count.")
+	}
+	if m.BodyLength > (2 << 16) {
+		return fmt.Errorf("Body too long.")
+	}
+
+	m.attrs = make([]Attr, m.AttrCount)
+	m.body = make([]byte, m.BodyLength)
+	for i := 0; i < int(m.AttrCount); i++ {
+		err = binary.Read(w, binary.LittleEndian, &m.attrs[i])
+		if err != nil {
+			return err
+		}
+	}
+	if m.BodyLength > 0 {
+		l, err := w.Read(m.body)
+		if l != int(m.BodyLength) {
+			return fmt.Errorf("Message partial read: %d %d", l, m.BodyLength)
+		}
+		return err
+	}
+	return nil
+}
+
+func MakeMessage(kind, from, to int64, method string, body []byte, attrs ...string) Message {
+	mh := MessageHeader{kind, from, to, MakeWire(method), int8(len(attrs) / 2), int64(len(body))}
+	mm := Message{}
+	mm.MessageHeader = mh
+	mm.attrs = make([]Attr, len(attrs)/2)
+	for i := 1; i < len(attrs); i += 2 {
+		mm.attrs[i/2] = Attr{MakeWire(attrs[i-1]), MakeWire(attrs[i])}
+	}
+	mm.body = body
+	return mm
+}

+ 51 - 0
b1/message_test.go

@@ -0,0 +1,51 @@
+package b1_test
+
+import (
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"src.eruta.nl/beoran/bdjncl/b1"
+)
+
+func ExampleMessage() {
+	tm := b1.MakeMessage(123, 1, 2, "/jobs", []byte("body text"), "key1", "val1", "key2", "val2")
+	ss := b1.MakeWire("Hello B1.")
+	buf := bytes.Buffer{}
+	err := binary.Write(&buf, binary.LittleEndian, ss)
+	if err != nil {
+		fmt.Printf("error: %s\n", err)
+	}
+	s2 := b1.Wire{}
+	err = binary.Read(&buf, binary.LittleEndian, &s2)
+	if err != nil {
+		fmt.Printf("error: %s\n", err)
+	}
+
+	fmt.Println(s2.Len)
+
+	fmt.Println(s2.String())
+
+	buf = bytes.Buffer{}
+	err = binary.Write(&buf, binary.LittleEndian, tm.MessageHeader)
+	if err != nil {
+		fmt.Printf("error: %s\n", err)
+	}
+	t2 := b1.MessageHeader{}
+	err = binary.Read(&buf, binary.LittleEndian, &t2)
+	if err != nil {
+		fmt.Printf("error: %s\n", err)
+	}
+	fmt.Println(t2.Method.String())
+	buf = bytes.Buffer{}
+	tm.MarshalTo(&buf)
+	m2 := b1.Message{}
+	err = m2.UnmarshalFrom(&buf)
+	if err != nil {
+		fmt.Printf("error: %s\n", err)
+	}
+	fmt.Println(m2.Method)
+	//output: 9
+	//Hello B1.
+	///jobs
+	///jobs
+}