diff options
Diffstat (limited to 'vendor/github.com/sorcix/irc/stream.go')
-rw-r--r-- | vendor/github.com/sorcix/irc/stream.go | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/vendor/github.com/sorcix/irc/stream.go b/vendor/github.com/sorcix/irc/stream.go new file mode 100644 index 00000000..c4af9af1 --- /dev/null +++ b/vendor/github.com/sorcix/irc/stream.go @@ -0,0 +1,134 @@ +// Copyright 2014 Vic Demuzere +// +// Use of this source code is governed by the MIT license. + +package irc + +import ( + "bufio" + "io" + "net" + "sync" +) + +// Messages are delimited with CR and LF line endings, +// we're using the last one to split the stream. Both are removed +// during message parsing. +const delim byte = '\n' + +var endline = []byte("\r\n") + +// A Conn represents an IRC network protocol connection. +// It consists of an Encoder and Decoder to manage I/O. +type Conn struct { + Encoder + Decoder + + conn io.ReadWriteCloser +} + +// NewConn returns a new Conn using rwc for I/O. +func NewConn(rwc io.ReadWriteCloser) *Conn { + return &Conn{ + Encoder: Encoder{ + writer: rwc, + }, + Decoder: Decoder{ + reader: bufio.NewReader(rwc), + }, + conn: rwc, + } +} + +// Dial connects to the given address using net.Dial and +// then returns a new Conn for the connection. +func Dial(addr string) (*Conn, error) { + c, err := net.Dial("tcp", addr) + + if err != nil { + return nil, err + } + + return NewConn(c), nil +} + +// Close closes the underlying ReadWriteCloser. +func (c *Conn) Close() error { + return c.conn.Close() +} + +// A Decoder reads Message objects from an input stream. +type Decoder struct { + reader *bufio.Reader + line string + mu sync.Mutex +} + +// NewDecoder returns a new Decoder that reads from r. +func NewDecoder(r io.Reader) *Decoder { + return &Decoder{ + reader: bufio.NewReader(r), + } +} + +// Decode attempts to read a single Message from the stream. +// +// Returns a non-nil error if the read failed. +func (dec *Decoder) Decode() (m *Message, err error) { + + dec.mu.Lock() + dec.line, err = dec.reader.ReadString(delim) + dec.mu.Unlock() + + if err != nil { + return nil, err + } + + return ParseMessage(dec.line), nil +} + +// An Encoder writes Message objects to an output stream. +type Encoder struct { + writer io.Writer + mu sync.Mutex +} + +// NewEncoder returns a new Encoder that writes to w. +func NewEncoder(w io.Writer) *Encoder { + return &Encoder{ + writer: w, + } +} + +// Encode writes the IRC encoding of m to the stream. +// +// This method may be used from multiple goroutines. +// +// Returns an non-nil error if the write to the underlying stream stopped early. +func (enc *Encoder) Encode(m *Message) (err error) { + + _, err = enc.Write(m.Bytes()) + + return +} + +// Write writes len(p) bytes from p followed by CR+LF. +// +// This method can be used simultaneously from multiple goroutines, +// it guarantees to serialize access. However, writing a single IRC message +// using multiple Write calls will cause corruption. +func (enc *Encoder) Write(p []byte) (n int, err error) { + + enc.mu.Lock() + n, err = enc.writer.Write(p) + + if err != nil { + enc.mu.Unlock() + return + } + + _, err = enc.writer.Write(endline) + enc.mu.Unlock() + + return +} |