github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/talks/2012/chat/markov/chat.go (about)

     1  // +build OMIT
     2  
     3  package main
     4  
     5  import (
     6  	"fmt"
     7  	"io"
     8  	"log"
     9  	"net/http"
    10  	"time"
    11  
    12  	"golang.org/x/net/websocket"
    13  )
    14  
    15  const listenAddr = "localhost:4000"
    16  
    17  func main() {
    18  	http.HandleFunc("/", rootHandler)
    19  	http.Handle("/socket", websocket.Handler(socketHandler))
    20  	err := http.ListenAndServe(listenAddr, nil)
    21  	if err != nil {
    22  		log.Fatal(err)
    23  	}
    24  }
    25  
    26  type socket struct {
    27  	io.Reader
    28  	io.Writer
    29  	done chan bool
    30  }
    31  
    32  func (s socket) Close() error {
    33  	s.done <- true
    34  	return nil
    35  }
    36  
    37  var chain = NewChain(2) // 2-word prefixes
    38  
    39  func socketHandler(ws *websocket.Conn) {
    40  	r, w := io.Pipe() // HL
    41  	go func() {       // HL
    42  		_, err := io.Copy(io.MultiWriter(w, chain), ws) // HL
    43  		w.CloseWithError(err)                           // HL
    44  	}() // HL
    45  	s := socket{r, ws, make(chan bool)}
    46  	go match(s)
    47  	<-s.done
    48  }
    49  
    50  var partner = make(chan io.ReadWriteCloser)
    51  
    52  func match(c io.ReadWriteCloser) {
    53  	fmt.Fprint(c, "Waiting for a partner...")
    54  	select {
    55  	case partner <- c:
    56  		// now handled by the other goroutine
    57  	case p := <-partner:
    58  		chat(p, c)
    59  	case <-time.After(5 * time.Second): // HL
    60  		chat(Bot(), c) // HL
    61  	}
    62  }
    63  
    64  func chat(a, b io.ReadWriteCloser) {
    65  	fmt.Fprintln(a, "Found one! Say hi.")
    66  	fmt.Fprintln(b, "Found one! Say hi.")
    67  	errc := make(chan error, 1)
    68  	go cp(a, b, errc)
    69  	go cp(b, a, errc)
    70  	if err := <-errc; err != nil {
    71  		log.Println(err)
    72  	}
    73  	a.Close()
    74  	b.Close()
    75  }
    76  
    77  func cp(w io.Writer, r io.Reader, errc chan<- error) {
    78  	_, err := io.Copy(w, r)
    79  	errc <- err
    80  }
    81  
    82  // Bot returns an io.ReadWriteCloser that responds to
    83  // each incoming write with a generated sentence.
    84  func Bot() io.ReadWriteCloser {
    85  	r, out := io.Pipe() // for outgoing data
    86  	return bot{r, out}
    87  }
    88  
    89  type bot struct {
    90  	io.ReadCloser
    91  	out io.Writer
    92  }
    93  
    94  func (b bot) Write(buf []byte) (int, error) {
    95  	go b.speak()
    96  	return len(buf), nil
    97  }
    98  
    99  func (b bot) speak() {
   100  	time.Sleep(time.Second)
   101  	msg := chain.Generate(10) // at most 10 words
   102  	b.out.Write([]byte(msg))
   103  }