// Skeleton to part 7 of the Whispering Gophers code lab. // // This program extends part 6 by adding a Peers type. // The rest of the code is left as-is, so functionally there is no change. // // However we have added a peers_test.go file, so that running // go test // from the package directory will test your implementation of the Peers type. // package main import ( "bufio" "encoding/json" "flag" "fmt" "log" "net" "os" "sync" "code.osinet.fr/fgm/whispering_gophers/util" ) var ( listenAddr = flag.String("listen", "", "peer host:port") peerAddr = flag.String("peer", "", "peer host:port") self string ) type Message struct { Addr string Body string } func main() { flag.Parse() var l net.Listener var err error // Create a new listener using util.Listen and put it in a variable named l. if *listenAddr == "" { l, err = util.ListenOnFirstUsableInterface() } else { l, err = net.Listen("tcp4", *listenAddr) } if err != nil { log.Fatal(err) } self = l.Addr().String() log.Println("Listening on", self) go dial(*peerAddr) go readInput() for { c, err := l.Accept() if err != nil { log.Fatal(err) } go serve(c) } } type Peers struct { m map[string]chan<- Message mu sync.RWMutex } // Add creates and returns a new channel for the given peer address. // If an address already exists in the registry, it returns nil. func (p *Peers) Add(addr string) <-chan Message { // Take the write lock on p.mu. Unlock it before returning (using defer). p.mu.Lock() defer p.mu.Unlock() // Check if the address is already in the peers map under the key addr. // If it is, return nil. _, ok := p.m[addr] if ok { return nil } // Make a new channel of messages peer := make(chan Message) // Add it to the peers map p.m[addr] = peer // Return the newly created channel. return peer } // Remove deletes the specified peer from the registry. func (p *Peers) Remove(addr string) { // Take the write lock on p.mu. Unlock it before returning (using defer). p.mu.Lock() defer p.mu.Unlock() // Delete the peer from the peers map. delete(p.m, addr) } // List returns a slice of all active peer channels. func (p *Peers) List() []chan<- Message { // Take the read lock on p.mu. Unlock it before returning (using defer). p.mu.Lock() defer p.mu.Unlock() // Declare a slice of chan<- Message. channels := make([]chan<- Message, 0, len(p.m)) /* Iterate over the map using range */ for _, v := range p.m { // Append each channel into the slice. channels = append(channels, v) } // Return the slice. return channels } func serve(c net.Conn) { defer c.Close() d := json.NewDecoder(c) for { var m Message err := d.Decode(&m) if err != nil { log.Println(err) return } fmt.Printf("%#v\n", m) } } var peer = make(chan Message) func readInput() { s := bufio.NewScanner(os.Stdin) for s.Scan() { m := Message{ Addr: self, Body: s.Text(), } peer <- m } if err := s.Err(); err != nil { log.Fatal(err) } os.Exit(0) } func dial(addr string) { c, err := net.Dial("tcp", addr) if err != nil { log.Println(addr, err) return } defer c.Close() e := json.NewEncoder(c) for m := range peer { err := e.Encode(m) if err != nil { log.Println(addr, err) return } } }