blob: d712b913acea88f0b0f416ba5f0d2fcc6d7054ed [file] [log] [blame]
// +build ignore,OMIT
package main
import (
"fmt"
"io"
"log"
"net"
"net/http"
"time"
"golang.org/x/net/websocket"
)
const listenAddr = "localhost:4000"
func main() {
go netListen() // HL
http.HandleFunc("/", rootHandler)
http.Handle("/socket", websocket.Handler(socketHandler))
err := http.ListenAndServe(listenAddr, nil)
if err != nil {
log.Fatal(err)
}
}
func netListen() {
l, err := net.Listen("tcp", "localhost:4001")
if err != nil {
log.Fatal(err)
}
for {
c, err := l.Accept()
if err != nil {
log.Fatal(err)
}
go match(c)
}
}
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()
go func() {
_, err := io.Copy(io.MultiWriter(w, chain), ws)
w.CloseWithError(err)
}()
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):
chat(Bot(), c)
}
}
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))
}