|
@@ -4,92 +4,74 @@ import (
|
4
|
4
|
"bufio"
|
5
|
5
|
"io"
|
6
|
6
|
"net"
|
|
7
|
+ "strings"
|
7
|
8
|
)
|
8
|
9
|
|
9
|
|
-const (
|
10
|
|
- R = '→'
|
11
|
|
- W = '←'
|
12
|
|
-)
|
13
|
|
-
|
|
10
|
+// Socket represents an IRC socket.
|
14
|
11
|
type Socket struct {
|
15
|
|
- closed bool
|
16
|
|
- conn net.Conn
|
17
|
|
- scanner *bufio.Scanner
|
18
|
|
- writer *bufio.Writer
|
|
12
|
+ Closed bool
|
|
13
|
+ conn net.Conn
|
|
14
|
+ reader *bufio.Reader
|
19
|
15
|
}
|
20
|
16
|
|
21
|
|
-func NewSocket(conn net.Conn) *Socket {
|
22
|
|
- return &Socket{
|
23
|
|
- conn: conn,
|
24
|
|
- scanner: bufio.NewScanner(conn),
|
25
|
|
- writer: bufio.NewWriter(conn),
|
|
17
|
+// NewSocket returns a new Socket.
|
|
18
|
+func NewSocket(conn net.Conn) Socket {
|
|
19
|
+ return Socket{
|
|
20
|
+ conn: conn,
|
|
21
|
+ reader: bufio.NewReader(conn),
|
26
|
22
|
}
|
27
|
23
|
}
|
28
|
24
|
|
29
|
|
-func (socket *Socket) String() string {
|
30
|
|
- return socket.conn.RemoteAddr().String()
|
31
|
|
-}
|
32
|
|
-
|
|
25
|
+// Close stops a Socket from being able to send/receive any more data.
|
33
|
26
|
func (socket *Socket) Close() {
|
34
|
|
- if socket.closed {
|
|
27
|
+ if socket.Closed {
|
35
|
28
|
return
|
36
|
29
|
}
|
37
|
|
- socket.closed = true
|
|
30
|
+ socket.Closed = true
|
38
|
31
|
socket.conn.Close()
|
39
|
|
- Log.debug.Printf("%s closed", socket)
|
40
|
32
|
}
|
41
|
33
|
|
42
|
|
-func (socket *Socket) Read() (line string, err error) {
|
43
|
|
- if socket.closed {
|
44
|
|
- err = io.EOF
|
45
|
|
- return
|
|
34
|
+// Read returns a single IRC line from a Socket.
|
|
35
|
+func (socket *Socket) Read() (string, error) {
|
|
36
|
+ if socket.Closed {
|
|
37
|
+ return "", io.EOF
|
46
|
38
|
}
|
47
|
39
|
|
48
|
|
- for socket.scanner.Scan() {
|
49
|
|
- line = socket.scanner.Text()
|
50
|
|
- if len(line) == 0 {
|
51
|
|
- continue
|
52
|
|
- }
|
53
|
|
- Log.debug.Printf("%s → %s", socket, line)
|
54
|
|
- return
|
55
|
|
- }
|
|
40
|
+ lineBytes, err := socket.reader.ReadBytes('\n')
|
56
|
41
|
|
57
|
|
- err = socket.scanner.Err()
|
58
|
|
- socket.isError(err, R)
|
59
|
|
- if err == nil {
|
60
|
|
- err = io.EOF
|
61
|
|
- }
|
62
|
|
- return
|
63
|
|
-}
|
|
42
|
+ // convert bytes to string
|
|
43
|
+ line := string(lineBytes[:])
|
64
|
44
|
|
65
|
|
-func (socket *Socket) Write(line string) (err error) {
|
66
|
|
- if socket.closed {
|
67
|
|
- err = io.EOF
|
68
|
|
- return
|
|
45
|
+ // read last message properly (such as ERROR/QUIT/etc), just fail next reads/writes
|
|
46
|
+ if err == io.EOF {
|
|
47
|
+ socket.Close()
|
69
|
48
|
}
|
70
|
49
|
|
71
|
|
- if _, err = socket.writer.WriteString(line); socket.isError(err, W) {
|
72
|
|
- return
|
|
50
|
+ if err == io.EOF && strings.TrimSpace(line) != "" {
|
|
51
|
+ // don't do anything
|
|
52
|
+ } else if err != nil {
|
|
53
|
+ return "", err
|
73
|
54
|
}
|
74
|
55
|
|
75
|
|
- if _, err = socket.writer.WriteString(CRLF); socket.isError(err, W) {
|
76
|
|
- return
|
77
|
|
- }
|
|
56
|
+ return strings.TrimRight(line, "\r\n"), nil
|
|
57
|
+}
|
78
|
58
|
|
79
|
|
- if err = socket.writer.Flush(); socket.isError(err, W) {
|
80
|
|
- return
|
|
59
|
+// Write sends the given string out of Socket.
|
|
60
|
+func (socket *Socket) Write(data string) error {
|
|
61
|
+ if socket.Closed {
|
|
62
|
+ return io.EOF
|
81
|
63
|
}
|
82
|
64
|
|
83
|
|
- Log.debug.Printf("%s ← %s", socket, line)
|
84
|
|
- return
|
85
|
|
-}
|
86
|
|
-
|
87
|
|
-func (socket *Socket) isError(err error, dir rune) bool {
|
|
65
|
+ // write data
|
|
66
|
+ _, err := socket.conn.Write([]byte(data))
|
88
|
67
|
if err != nil {
|
89
|
|
- if err != io.EOF {
|
90
|
|
- Log.debug.Printf("%s %c error: %s", socket, dir, err)
|
91
|
|
- }
|
92
|
|
- return true
|
|
68
|
+ socket.Close()
|
|
69
|
+ return err
|
93
|
70
|
}
|
94
|
|
- return false
|
|
71
|
+ return nil
|
|
72
|
+}
|
|
73
|
+
|
|
74
|
+// WriteLine writes the given line out of Socket.
|
|
75
|
+func (socket *Socket) WriteLine(line string) error {
|
|
76
|
+ return socket.Write(line + "\r\n")
|
95
|
77
|
}
|