package proto import ( "bufio" "io" "sync" ) // Writer writes words to a RouterOS device. type Writer interface { BeginSentence() WriteWord(word string) EndSentence() error } type writer struct { *bufio.Writer err error sync.Mutex } // NewWriter returns a new Writer to write to w. func NewWriter(w io.Writer) Writer { return &writer{Writer: bufio.NewWriter(w)} } // BeginSentence prepares w for writing a sentence. func (w *writer) BeginSentence() { w.Lock() } // EndSentence writes the end-of-sentence marker (an empty word). // It returns the first error that occurred on calls to methods on w. func (w *writer) EndSentence() error { w.WriteWord("") w.flush() err := w.err w.Unlock() return err } // WriteWord writes one word. func (w *writer) WriteWord(word string) { b := []byte(word) w.write(encodeLength(len(b))) w.write(b) } func (w *writer) flush() { if w.err != nil { return } err := w.Flush() if err != nil { w.err = err } } func (w *writer) write(b []byte) { if w.err != nil { return } _, err := w.Write(b) if err != nil { w.err = err } } func encodeLength(l int) []byte { switch { case l < 0x80: return []byte{byte(l)} case l < 0x4000: return []byte{byte(l>>8) | 0x80, byte(l)} case l < 0x200000: return []byte{byte(l>>16) | 0xC0, byte(l >> 8), byte(l)} case l < 0x10000000: return []byte{byte(l>>24) | 0xE0, byte(l >> 16), byte(l >> 8), byte(l)} default: return []byte{0xF0, byte(l >> 24), byte(l >> 16), byte(l >> 8), byte(l)} } }