learning_go/book_with_bridge/chat/main.go
Alexander Pivkin 9f41cbe454 sdf
2026-01-04 14:56:29 +03:00

134 lines
2.2 KiB
Go

package main
import (
"bufio"
"fmt"
"log"
"net"
"time"
)
type client struct {
_chan chan <- string
name string
}
var (
entering = make(chan client)
leaving = make(chan client)
messages = make(chan string)
cancel = make(chan time.Time)
)
func handleConn(conn net.Conn) {
defer conn.Close()
ch := make(chan string)
go clientWriter(conn,ch)
who := conn.RemoteAddr().String()
client := client{
_chan: ch,
name: who,
}
ch <- "You " + who
messages <- who + " connected"
entering <- client
inputChan := make(chan string)
timeout := time.NewTimer(40*time.Second)
defer timeout.Stop()
input := bufio.NewScanner(conn)
go func() {
log.Println("inside of goroutine")
for input.Scan() {
log.Println("inside of Scan for loop")
inputChan <- client.name + ": " + input.Text()
}
if err := input.Err(); err != nil {
log.Printf("Scanner error: %v", err)
} else {
log.Println("Scanner reached EOF (connection closed)")
}
log.Println("Closing input channel")
close(inputChan)
}()
loop:
for {
select {
case text,ok := <- inputChan:
if !ok {
leaving <- client
messages <- who + " disconnected"
break loop
}
if !timeout.Stop() {
<- timeout.C
}
timeout.Reset(40*time.Second)
messages <- text
case <- timeout.C:
ch <- "Connection timed out due to inactivity"
leaving <- client
messages <- who + " disconnected (timeout)"
break loop
}
}
}
func clientWriter(conn net.Conn, ch <- chan string) {
for msg := range ch {
fmt.Fprintln(conn,msg)
}
}
func broadcaster() {
clients := make(map[client]bool)
for {
select {
case msg := <- messages:
log.Println("Got a msg")
for cli := range clients {
cli._chan <- msg
}
case cli := <- entering:
cli._chan <- "List of connected clients"
for i := range clients {
cli._chan <- i.name
}
clients[cli] = true
case cli := <- leaving:
log.Printf("Deleting client %s")
delete(clients,cli)
close(cli._chan)
}
}
}
func main() {
listener,err := net.Listen("tcp",":9090")
if err != nil {
log.Fatalf("Error in Lister %v",err)
}
go broadcaster()
for {
conn,err := listener.Accept()
if err != nil {
log.Fatalf("Error in Accept %v",err)
continue
}
go handleConn(conn)
}
}