83 lines
1.5 KiB
Go
83 lines
1.5 KiB
Go
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)}
|
|
}
|
|
}
|