104 lines
2.5 KiB
Go
104 lines
2.5 KiB
Go
|
package irc
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
)
|
||
|
|
||
|
// Conn represents a simple IRC client. It embeds an irc.Reader and an
|
||
|
// irc.Writer.
|
||
|
type Conn struct {
|
||
|
*Reader
|
||
|
*Writer
|
||
|
}
|
||
|
|
||
|
// NewConn creates a new Conn
|
||
|
func NewConn(rw io.ReadWriter) *Conn {
|
||
|
return &Conn{
|
||
|
NewReader(rw),
|
||
|
NewWriter(rw),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Writer is the outgoing side of a connection.
|
||
|
type Writer struct {
|
||
|
// DebugCallback is called for each outgoing message. The name of this may
|
||
|
// not be stable.
|
||
|
DebugCallback func(line string)
|
||
|
|
||
|
// Internal fields
|
||
|
writer io.Writer
|
||
|
writeCallback func(w *Writer, line string) error
|
||
|
}
|
||
|
|
||
|
func defaultWriteCallback(w *Writer, line string) error {
|
||
|
_, err := w.writer.Write([]byte(line + "\r\n"))
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// NewWriter creates an irc.Writer from an io.Writer.
|
||
|
func NewWriter(w io.Writer) *Writer {
|
||
|
return &Writer{nil, w, defaultWriteCallback}
|
||
|
}
|
||
|
|
||
|
// Write is a simple function which will write the given line to the
|
||
|
// underlying connection.
|
||
|
func (w *Writer) Write(line string) error {
|
||
|
if w.DebugCallback != nil {
|
||
|
w.DebugCallback(line)
|
||
|
}
|
||
|
|
||
|
return w.writeCallback(w, line)
|
||
|
}
|
||
|
|
||
|
// Writef is a wrapper around the connection's Write method and
|
||
|
// fmt.Sprintf. Simply use it to send a message as you would normally
|
||
|
// use fmt.Printf.
|
||
|
func (w *Writer) Writef(format string, args ...interface{}) error {
|
||
|
return w.Write(fmt.Sprintf(format, args...))
|
||
|
}
|
||
|
|
||
|
// WriteMessage writes the given message to the stream
|
||
|
func (w *Writer) WriteMessage(m *Message) error {
|
||
|
return w.Write(m.String())
|
||
|
}
|
||
|
|
||
|
// Reader is the incoming side of a connection. The data will be
|
||
|
// buffered, so do not re-use the io.Reader used to create the
|
||
|
// irc.Reader.
|
||
|
type Reader struct {
|
||
|
// DebugCallback is called for each incoming message. The name of this may
|
||
|
// not be stable.
|
||
|
DebugCallback func(string)
|
||
|
|
||
|
// Internal fields
|
||
|
reader *bufio.Reader
|
||
|
}
|
||
|
|
||
|
// NewReader creates an irc.Reader from an io.Reader. Note that once a reader is
|
||
|
// passed into this function, you should no longer use it as it is being used
|
||
|
// inside a bufio.Reader so you cannot rely on only the amount of data for a
|
||
|
// Message being read when you call ReadMessage.
|
||
|
func NewReader(r io.Reader) *Reader {
|
||
|
return &Reader{
|
||
|
nil,
|
||
|
bufio.NewReader(r),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ReadMessage returns the next message from the stream or an error.
|
||
|
func (r *Reader) ReadMessage() (*Message, error) {
|
||
|
line, err := r.reader.ReadString('\n')
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if r.DebugCallback != nil {
|
||
|
r.DebugCallback(line)
|
||
|
}
|
||
|
|
||
|
// Parse the message from our line
|
||
|
return ParseMessage(line)
|
||
|
}
|