go-examples/chatserver/main.go

145 lines
2.9 KiB
Go
Raw Normal View History

2017-07-10 18:29:28 +00:00
package main
import (
"bufio"
"io"
"log"
"net"
)
type Client struct {
Connection *net.Conn
Name string
Send chan string
}
type Message struct {
cli *Client
message string
}
type Server struct {
net.Listener
Clients []Client
NewClients chan Client
NewMessages chan Message
}
func (cli Client) Prompt() string {
return "<" + cli.Name + "> "
}
func (cli Client) SendMessages() {
for msg := range cli.Send {
io.WriteString(*cli.Connection, msg)
}
}
func (cli Client) WaitMessage(server *Server) {
scanner := bufio.NewScanner(*cli.Connection)
io.WriteString(*cli.Connection, cli.Prompt())
for scanner.Scan() {
msg := Message{&cli, scanner.Text()}
if len(msg.message) > 0 {
log.Println("New message from", cli.Name, msg.message)
server.NewMessages <- msg
}
io.WriteString(*cli.Connection, cli.Prompt())
}
}
func NewServer(addr string) (*Server, error) {
ln, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
return &Server{
ln,
make([]Client, 0),
make(chan Client),
make(chan Message),
}, nil
}
func (server *Server) NewClient(conn *net.Conn) {
io.WriteString(*conn, "What is your name? ")
scanner := bufio.NewScanner(*conn)
for scanner.Scan() {
str := scanner.Text()
log.Println("New client", str)
cli := &Client{
conn,
str,
make(chan string),
}
server.NewClients <- *cli
return
}
}
func (server *Server) MessageDispatcher() {
for msg := range server.NewMessages {
log.Println("Dispatching message", msg.message, "from", msg.cli.Name)
for _, dest := range server.Clients {
if dest.Name != msg.cli.Name {
log.Println("Send message", msg.message, "from", msg.cli.Name, "to", dest.Name)
dest.Send <- "\n" + msg.cli.Prompt() + msg.message + "\n" + dest.Prompt()
}
}
}
}
func (server *Server) CreateClients() {
for cli := range server.NewClients {
exists := false
for _, c := range server.Clients {
if c.Name == cli.Name {
exists = true
}
}
if exists {
io.WriteString(*cli.Connection, "Name already in use\n")
go server.NewClient(cli.Connection)
} else {
server.Clients = append(server.Clients, cli)
log.Println("Client ready to chat", cli.Name)
log.Println(len(server.Clients), "clients connected")
go cli.WaitMessage(server)
go cli.SendMessages()
}
}
}
// wait connections from clients
func (server *Server) handle() {
for {
conn, err := server.Accept()
if err != nil {
log.Println("Connection error", err)
}
go server.NewClient(&conn)
// TODO disconnect?
}
defer server.stop()
}
func (server *Server) stop() {
// TODO close connections
defer server.Close()
}
func (server *Server) start() {
log.Println("Starting server...")
go server.MessageDispatcher()
go server.CreateClients() // create client one at a time (race condition)
server.handle()
}
func main() {
server, err := NewServer(":9000")
if err != nil {
panic(err)
}
server.start()
}