From 11537ad975c45a297004c2a2319d2b1463f695b1 Mon Sep 17 00:00:00 2001 From: Jeremy Latt Date: Thu, 13 Feb 2014 19:37:16 -0800 Subject: [PATCH] abstract net operations as Socket --- irc/client.go | 61 +++++---------------------- irc/socket.go | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 50 deletions(-) create mode 100644 irc/socket.go diff --git a/irc/client.go b/irc/client.go index ffce8323..4c4238b5 100644 --- a/irc/client.go +++ b/irc/client.go @@ -1,11 +1,9 @@ package irc import ( - "bufio" "fmt" "log" "net" - "strings" "time" ) @@ -14,7 +12,6 @@ type Client struct { away bool awayMessage string channels ChannelSet - conn net.Conn ctime time.Time destroyed bool hostname string @@ -28,6 +25,7 @@ type Client struct { registered bool replies chan Reply server *Server + socket *Socket authorized bool username string } @@ -37,16 +35,16 @@ func NewClient(server *Server, conn net.Conn) *Client { client := &Client{ atime: now, channels: make(ChannelSet), - conn: conn, ctime: now, hostname: AddrLookupHostname(conn.RemoteAddr()), replies: make(chan Reply), server: server, + socket: NewSocket(conn), } client.loginTimer = time.AfterFunc(LOGIN_TIMEOUT, client.Destroy) - go client.readConn() - go client.writeConn() + go client.readCommands() + go client.writeReplies() return client } @@ -91,23 +89,8 @@ func (client *Client) ConnectionClosed() { client.server.commands <- msg } -func (c *Client) readConn() { - recv := bufio.NewReader(c.conn) - - for { - line, err := recv.ReadString('\n') - if err != nil { - if DEBUG_NET { - log.Printf("%s → error: %s", c.conn.RemoteAddr(), err) - } - break - } - - line = strings.TrimSpace(line) - if DEBUG_NET { - log.Printf("%s → %s", c.conn.RemoteAddr(), line) - } - +func (c *Client) readCommands() { + for line := range c.socket.Read() { m, err := ParseCommand(line) if err != nil { switch err { @@ -125,36 +108,14 @@ func (c *Client) readConn() { c.ConnectionClosed() } -func (client *Client) maybeLogWriteError(err error) bool { - if err != nil { - if DEBUG_NET { - log.Printf("%s ← error: %s", client.conn.RemoteAddr(), err) - } - return true - } - return false -} - -func (client *Client) writeConn() { - send := bufio.NewWriter(client.conn) - +func (client *Client) writeReplies() { for reply := range client.replies { if DEBUG_CLIENT { log.Printf("%s ← %s", client, reply) } - for _, str := range reply.Format(client) { - if DEBUG_NET { - log.Printf("%s ← %s", client.conn.RemoteAddr(), str) - } - if _, err := send.WriteString(str); client.maybeLogWriteError(err) { - break - } - if _, err := send.WriteString(CRLF); client.maybeLogWriteError(err) { - break - } - if err := send.Flush(); client.maybeLogWriteError(err) { - break - } + + if err := client.socket.Write(reply.Format(client)); err != nil { + break } } client.ConnectionClosed() @@ -171,7 +132,7 @@ func (client *Client) Destroy() { client.destroyed = true - client.conn.Close() + client.socket.Close() close(client.replies) client.replies = nil diff --git a/irc/socket.go b/irc/socket.go new file mode 100644 index 00000000..63a5bebd --- /dev/null +++ b/irc/socket.go @@ -0,0 +1,114 @@ +package irc + +import ( + "bufio" + "io" + "log" + "net" + "strings" +) + +type Socket struct { + closed bool + conn net.Conn + reader *bufio.Reader + writer *bufio.Writer + send chan string + receive chan string +} + +func NewSocket(conn net.Conn) *Socket { + socket := &Socket{ + conn: conn, + reader: bufio.NewReader(conn), + receive: make(chan string), + send: make(chan string), + writer: bufio.NewWriter(conn), + } + + go socket.readLines() + go socket.writeLines() + + return socket +} + +func (socket *Socket) String() string { + return socket.conn.RemoteAddr().String() +} + +func (socket *Socket) Close() { + if socket.closed { + return + } + + if DEBUG_NET { + log.Printf("%s closed", socket) + } + + socket.closed = true + socket.conn.Close() + close(socket.send) + close(socket.receive) +} + +func (socket *Socket) Read() <-chan string { + return socket.receive +} + +func (socket *Socket) Write(lines []string) error { + for _, line := range lines { + if socket.closed { + return io.EOF + } + socket.send <- line + } + return nil +} + +func (socket *Socket) readLines() { + for !socket.closed { + line, err := socket.reader.ReadString('\n') + if err != nil { + if DEBUG_NET { + log.Printf("%s → error: %s", socket, err) + } + break + } + + line = strings.TrimSpace(line) + if DEBUG_NET { + log.Printf("%s → %s", socket, line) + } + + socket.receive <- line + } + socket.Close() +} + +func (socket *Socket) writeLines() { + for line := range socket.send { + if DEBUG_CLIENT { + log.Printf("%s ← %s", socket, line) + } + if _, err := socket.writer.WriteString(line); socket.maybeLogWriteError(err) { + break + } + if _, err := socket.writer.WriteString(CRLF); socket.maybeLogWriteError(err) { + break + } + if err := socket.writer.Flush(); socket.maybeLogWriteError(err) { + break + } + } + socket.Close() +} + +func (socket *Socket) maybeLogWriteError(err error) bool { + if err != nil { + if DEBUG_NET { + log.Printf("%s ← error: %s", socket, err) + } + return true + } + return false +}