1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 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
}
|