-
-
Notifications
You must be signed in to change notification settings - Fork 17
/
conn.go
127 lines (107 loc) · 3.35 KB
/
conn.go
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
package irc
import (
"bufio"
"errors"
"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)
// WriteCallback is called for each outgoing message. It needs to write the
// message to the connection. Note that this API is not a part of the semver
// stability guarantee.
WriteCallback func(w *Writer, line string) error
// Internal fields
writer io.Writer
}
func defaultWriteCallback(w *Writer, line string) error {
_, err := w.RawWrite([]byte(line + "\r\n"))
return err
}
// NewWriter creates an irc.Writer from an io.Writer.
func NewWriter(w io.Writer) *Writer {
return &Writer{nil, defaultWriteCallback, w}
}
// RawWrite will write the given data to the underlying connection, skipping the
// WriteCallback. This is meant to be used by implementations of the
// WriteCallback to write data directly to the stream. Otherwise, it is
// recommended to avoid this function and use one of the other helpers. Also
// note that it will not append \r\n to the end of the line.
func (w *Writer) RawWrite(data []byte) (int, error) {
return w.writer.Write(data)
}
// 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.
// It ignores empty messages.
func (r *Reader) ReadMessage() (*Message, error) {
var msg *Message
// It's valid for a message to be empty. Clients should ignore these,
// so we do to be good citizens.
err := ErrZeroLengthMessage
for errors.Is(err, ErrZeroLengthMessage) {
var line string
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
msg, err = ParseMessage(line)
}
return msg, err
}