Browse Source

socket: Start overhaul of sockets and writing

tags/v0.7.0
Daniel Oaks 7 years ago
parent
commit
de4db1c6ef
2 changed files with 59 additions and 12 deletions
  1. 1
    0
      irc/client.go
  2. 58
    12
      irc/socket.go

+ 1
- 0
irc/client.go View File

@@ -75,6 +75,7 @@ type Client struct {
75 75
 func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
76 76
 	now := time.Now()
77 77
 	socket := NewSocket(conn)
78
+	go socket.RunSocketWriter()
78 79
 	client := &Client{
79 80
 		atime:          now,
80 81
 		authorized:     server.password == nil,

+ 58
- 12
irc/socket.go View File

@@ -10,9 +10,11 @@ import (
10 10
 	"crypto/tls"
11 11
 	"encoding/hex"
12 12
 	"errors"
13
+	"fmt"
13 14
 	"io"
14 15
 	"net"
15 16
 	"strings"
17
+	"sync"
16 18
 	"time"
17 19
 )
18 20
 
@@ -27,23 +29,25 @@ type Socket struct {
27 29
 	Closed bool
28 30
 	conn   net.Conn
29 31
 	reader *bufio.Reader
32
+
33
+	lineToSendExists chan bool
34
+	linesToSend      []string
35
+	linesToSendMutex sync.Mutex
30 36
 }
31 37
 
32 38
 // NewSocket returns a new Socket.
33 39
 func NewSocket(conn net.Conn) Socket {
34 40
 	return Socket{
35
-		conn:   conn,
36
-		reader: bufio.NewReader(conn),
41
+		conn:             conn,
42
+		reader:           bufio.NewReader(conn),
43
+		lineToSendExists: make(chan bool),
37 44
 	}
38 45
 }
39 46
 
40 47
 // Close stops a Socket from being able to send/receive any more data.
41 48
 func (socket *Socket) Close() {
42
-	if socket.Closed {
43
-		return
44
-	}
45 49
 	socket.Closed = true
46
-	socket.conn.Close()
50
+	// socket will close once all data has been sent
47 51
 }
48 52
 
49 53
 // CertFP returns the fingerprint of the certificate provided by the client.
@@ -104,15 +108,57 @@ func (socket *Socket) Write(data string) error {
104 108
 		return io.EOF
105 109
 	}
106 110
 
107
-	// write data
108
-	_, err := socket.conn.Write([]byte(data))
109
-	if err != nil {
110
-		socket.Close()
111
-		return err
112
-	}
111
+	socket.linesToSendMutex.Lock()
112
+	socket.linesToSend = append(socket.linesToSend, data)
113
+	socket.linesToSendMutex.Unlock()
114
+	go socket.fillLineToSendExists()
115
+
113 116
 	return nil
114 117
 }
115 118
 
119
+// fillLineToSendExists only exists because you can't goroutine single statements.
120
+func (socket *Socket) fillLineToSendExists() {
121
+	socket.lineToSendExists <- true
122
+}
123
+
124
+// RunSocketWriter starts writing messages to the outgoing socket.
125
+func (socket *Socket) RunSocketWriter() {
126
+	var errOut bool
127
+	for {
128
+		// wait for new lines
129
+		select {
130
+		case <-socket.lineToSendExists:
131
+			socket.linesToSendMutex.Lock()
132
+
133
+			// get data
134
+			data := socket.linesToSend[0]
135
+			if len(socket.linesToSend) > 1 {
136
+				socket.linesToSend = socket.linesToSend[1:]
137
+			} else {
138
+				socket.linesToSend = []string{}
139
+			}
140
+
141
+			// write data
142
+			_, err := socket.conn.Write([]byte(data))
143
+			if err != nil {
144
+				errOut = true
145
+				fmt.Println(err.Error())
146
+				break
147
+			}
148
+			socket.linesToSendMutex.Unlock()
149
+		}
150
+		if errOut {
151
+			// error out, bad stuff happened
152
+			break
153
+		}
154
+	}
155
+	//TODO(dan): empty socket.lineToSendExists queue
156
+	socket.conn.Close()
157
+	if !socket.Closed {
158
+		socket.Closed = true
159
+	}
160
+}
161
+
116 162
 // WriteLine writes the given line out of Socket.
117 163
 func (socket *Socket) WriteLine(line string) error {
118 164
 	return socket.Write(line + "\r\n")

Loading…
Cancel
Save