Created
July 21, 2015 20:04
-
-
Save wyattjoh/7081262cc69fff221269 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"fmt" | |
"io" | |
"log" | |
"net" | |
"os" | |
"strings" | |
"time" | |
) | |
type Client struct { | |
conn net.Conn | |
nickname string | |
ch chan string | |
closed chan bool | |
} | |
func main() { | |
ln, err := net.Listen("tcp", "127.0.0.1:6000") | |
if err != nil { | |
fmt.Println(err) | |
os.Exit(1) | |
} | |
msgchan := make(chan string) | |
addchan := make(chan Client) | |
rmchan := make(chan Client) | |
go handleMessages(msgchan, addchan, rmchan) | |
for { | |
conn, err := ln.Accept() | |
if err != nil { | |
fmt.Println(err) | |
continue | |
} | |
go handleConnection(conn, msgchan, addchan, rmchan) | |
} | |
} | |
func (c Client) ReadLinesInto(ch chan<- string) { | |
bufc := bufio.NewReader(c.conn) | |
for { | |
c.conn.SetReadDeadline(time.Now().Add(5 * time.Second)) | |
line, err := bufc.ReadString('\n') | |
if err != nil { | |
log.Printf("Client %s: An error occured during reading: %s", c.nickname, err.Error()) | |
if err == io.EOF { | |
// mark the channel as closed | |
c.closed <- true | |
// break from the for loop to exit this routine | |
break | |
} | |
continue | |
} | |
ch <- fmt.Sprintf("%s: %s", c.nickname, line) | |
} | |
} | |
func (c Client) WriteLinesFrom(ch <-chan string) { | |
for { | |
var msg string | |
select { | |
case msg = <-ch: | |
_, err := io.WriteString(c.conn, msg) | |
if err != nil { | |
return | |
} | |
case <-c.closed: | |
// the connection was closed | |
return | |
} | |
} | |
// for msg := range ch { | |
// _, err := io.WriteString(c.conn, msg) | |
// if err != nil { | |
// return | |
// } | |
// } | |
} | |
func promptNick(c net.Conn, bufc *bufio.Reader) string { | |
io.WriteString(c, "\033[1;30;41mWelcome to the fancy demo chat!\033[0m\n") | |
io.WriteString(c, "What is your nick? ") | |
nick, _, _ := bufc.ReadLine() | |
return string(nick) | |
} | |
func handleConnection(c net.Conn, msgchan chan<- string, addchan chan<- Client, rmchan chan<- Client) { | |
bufc := bufio.NewReader(c) | |
defer c.Close() | |
client := Client{ | |
conn: c, | |
nickname: promptNick(c, bufc), | |
ch: make(chan string), | |
closed: make(chan bool), | |
} | |
if strings.TrimSpace(client.nickname) == "" { | |
io.WriteString(c, "Invalid Username\n") | |
return | |
} | |
// Register user | |
addchan <- client | |
defer func() { | |
msgchan <- fmt.Sprintf("User %s left the chat room.\n", client.nickname) | |
log.Printf("Connection from %v closed.\n", c.RemoteAddr()) | |
rmchan <- client | |
}() | |
io.WriteString(c, fmt.Sprintf("Welcome, %s!\n\n", client.nickname)) | |
msgchan <- fmt.Sprintf("New user %s has joined the chat room.\n", client.nickname) | |
// I/O | |
go client.ReadLinesInto(msgchan) | |
client.WriteLinesFrom(client.ch) | |
} | |
func handleMessages(msgchan <-chan string, addchan <-chan Client, rmchan <-chan Client) { | |
clients := make(map[net.Conn]chan<- string) | |
for { | |
select { | |
case msg := <-msgchan: | |
log.Printf("New message: %s", msg) | |
for _, ch := range clients { | |
go func(mch chan<- string) { mch <- "\033[1;33;40m" + msg + "\033[m" }(ch) | |
} | |
case client := <-addchan: | |
log.Printf("New client: %v\n", client.conn) | |
clients[client.conn] = client.ch | |
case client := <-rmchan: | |
log.Printf("Client disconnects: %v\n", client.conn) | |
delete(clients, client.conn) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment