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

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