|
@@ -0,0 +1,174 @@
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "bufio"
|
|
|
+ "encoding/json"
|
|
|
+ "flag"
|
|
|
+ "fmt"
|
|
|
+ "log"
|
|
|
+ "net"
|
|
|
+ "os"
|
|
|
+ "sync"
|
|
|
+
|
|
|
+ "code.google.com/p/whispering-gophers/util"
|
|
|
+)
|
|
|
+
|
|
|
+var (
|
|
|
+ peerAddr = flag.String("peer", "", "peer host:port")
|
|
|
+ self string
|
|
|
+)
|
|
|
+
|
|
|
+type Message struct {
|
|
|
+ Addr string
|
|
|
+ Body string
|
|
|
+}
|
|
|
+
|
|
|
+func main() {
|
|
|
+ flag.Parse()
|
|
|
+
|
|
|
+ l, err := util.Listen()
|
|
|
+ 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)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+var peers Peers = Peers{m: make(map[string]chan<- Message)}
|
|
|
+
|
|
|
+type Peers struct {
|
|
|
+ m map[string]chan<- Message
|
|
|
+ mu sync.RWMutex
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func (p *Peers) Add(addr string) <-chan Message {
|
|
|
+ p.mu.Lock()
|
|
|
+ defer p.mu.Unlock()
|
|
|
+ if _, ok := p.m[addr]; ok {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ ch := make(chan Message)
|
|
|
+ p.m[addr] = ch
|
|
|
+ return ch
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func (p *Peers) Remove(addr string) {
|
|
|
+ p.mu.Lock()
|
|
|
+ defer p.mu.Unlock()
|
|
|
+ delete(p.m, addr)
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func (p *Peers) List() []chan<- Message {
|
|
|
+ p.mu.RLock()
|
|
|
+ defer p.mu.RUnlock()
|
|
|
+ l := make([]chan<- Message, 0, len(p.m))
|
|
|
+ for _, ch := range p.m {
|
|
|
+ l = append(l, ch)
|
|
|
+ }
|
|
|
+ return l
|
|
|
+}
|
|
|
+
|
|
|
+func broadcast(m Message) {
|
|
|
+
|
|
|
+ for k, v := range peers.m {
|
|
|
+
|
|
|
+
|
|
|
+ select {
|
|
|
+ case v <- m:
|
|
|
+ fmt.Printf("Sent %+v to %s", m, k)
|
|
|
+ default:
|
|
|
+ fmt.Printf("Failed sending to %s\n", k)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+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
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ go dial(m.Addr)
|
|
|
+ fmt.Printf("%#v\n", m)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func readInput() {
|
|
|
+ s := bufio.NewScanner(os.Stdin)
|
|
|
+ for s.Scan() {
|
|
|
+ m := Message{
|
|
|
+ Addr: self,
|
|
|
+ Body: s.Text(),
|
|
|
+ }
|
|
|
+ broadcast(m)
|
|
|
+ }
|
|
|
+ if err := s.Err(); err != nil {
|
|
|
+ log.Fatal(err)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func dial(addr string) {
|
|
|
+
|
|
|
+ if addr == self {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ ch := peers.Add(addr)
|
|
|
+
|
|
|
+
|
|
|
+ if ch == nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ defer peers.Remove(addr)
|
|
|
+
|
|
|
+ c, err := net.Dial("tcp", addr)
|
|
|
+ if err != nil {
|
|
|
+ log.Println(addr, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ defer c.Close()
|
|
|
+
|
|
|
+ e := json.NewEncoder(c)
|
|
|
+ for m := range ch {
|
|
|
+ err := e.Encode(m)
|
|
|
+ if err != nil {
|
|
|
+ log.Println(addr, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|