// +build ignore,OMIT package main import ( "fmt" "io" "log" "net/http" "time" "golang.org/x/net/websocket" ) const listenAddr = "localhost:4000" func main() { http.HandleFunc("/", rootHandler) http.Handle("/socket", websocket.Handler(socketHandler)) err := http.ListenAndServe(listenAddr, nil) if err != nil { log.Fatal(err) } } type socket struct { io.Reader io.Writer done chan bool } func (s socket) Close() error { s.done <- true return nil } var chain = NewChain(2) // 2-word prefixes func socketHandler(ws *websocket.Conn) { r, w := io.Pipe() // HL go func() { // HL _, err := io.Copy(io.MultiWriter(w, chain), ws) // HL w.CloseWithError(err) // HL }() // HL s := socket{r, ws, make(chan bool)} go match(s) <-s.done } var partner = make(chan io.ReadWriteCloser) func match(c io.ReadWriteCloser) { fmt.Fprint(c, "Waiting for a partner...") select { case partner <- c: // now handled by the other goroutine case p := <-partner: chat(p, c) case <-time.After(5 * time.Second): // HL chat(Bot(), c) // HL } } func chat(a, b io.ReadWriteCloser) { fmt.Fprintln(a, "Found one! Say hi.") fmt.Fprintln(b, "Found one! Say hi.") errc := make(chan error, 1) go cp(a, b, errc) go cp(b, a, errc) if err := <-errc; err != nil { log.Println(err) } a.Close() b.Close() } func cp(w io.Writer, r io.Reader, errc chan<- error) { _, err := io.Copy(w, r) errc <- err } // Bot returns an io.ReadWriteCloser that responds to // each incoming write with a generated sentence. func Bot() io.ReadWriteCloser { r, out := io.Pipe() // for outgoing data return bot{r, out} } type bot struct { io.ReadCloser out io.Writer } func (b bot) Write(buf []byte) (int, error) { go b.speak() return len(buf), nil } func (b bot) speak() { time.Sleep(time.Second) msg := chain.Generate(10) // at most 10 words b.out.Write([]byte(msg)) }