Add pinging to command example

This commit is contained in:
Gary Burd 2015-10-18 18:17:26 -07:00
parent 7f59b56ea4
commit d14d8b4715
1 changed files with 33 additions and 10 deletions

View File

@ -30,11 +30,19 @@ const (
// Maximum message size allowed from peer. // Maximum message size allowed from peer.
maxMessageSize = 8192 maxMessageSize = 8192
// Time allowed to read the next pong message from the peer.
pongWait = 60 * time.Second
// Send pings to peer with this period. Must be less than pongWait.
pingPeriod = (pongWait * 9) / 10
) )
func pumpStdin(ws *websocket.Conn, w io.Writer) { func pumpStdin(ws *websocket.Conn, w io.Writer) {
defer ws.Close() defer ws.Close()
ws.SetReadLimit(maxMessageSize) ws.SetReadLimit(maxMessageSize)
ws.SetReadDeadline(time.Now().Add(pongWait))
ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
for { for {
_, message, err := ws.ReadMessage() _, message, err := ws.ReadMessage()
if err != nil { if err != nil {
@ -45,11 +53,13 @@ func pumpStdin(ws *websocket.Conn, w io.Writer) {
break break
} }
} }
log.Println("exit stdin pump")
} }
func pumpStdout(ws *websocket.Conn, r io.Reader, done chan struct{}) { func pumpStdout(ws *websocket.Conn, r io.Reader, done chan struct{}) {
defer ws.Close() defer func() {
ws.Close()
close(done)
}()
s := bufio.NewScanner(r) s := bufio.NewScanner(r)
for s.Scan() { for s.Scan() {
ws.SetWriteDeadline(time.Now().Add(writeWait)) ws.SetWriteDeadline(time.Now().Add(writeWait))
@ -60,8 +70,21 @@ func pumpStdout(ws *websocket.Conn, r io.Reader, done chan struct{}) {
if s.Err() != nil { if s.Err() != nil {
log.Println("scan:", s.Err()) log.Println("scan:", s.Err())
} }
close(done) }
log.Println("exit stdout pump")
func ping(ws *websocket.Conn, done chan struct{}) {
ticker := time.NewTicker(pingPeriod)
defer ticker.Stop()
for {
select {
case <-ticker.C:
if err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWait)); err != nil {
log.Println("ping:", err)
}
case <-done:
return
}
}
} }
func internalError(ws *websocket.Conn, msg string, err error) { func internalError(ws *websocket.Conn, msg string, err error) {
@ -112,33 +135,33 @@ func serveWs(w http.ResponseWriter, r *http.Request) {
inr.Close() inr.Close()
outw.Close() outw.Close()
done := make(chan struct{}) stdoutDone := make(chan struct{})
go pumpStdout(ws, outr, done) go pumpStdout(ws, outr, stdoutDone)
go ping(ws, stdoutDone)
pumpStdin(ws, inw) pumpStdin(ws, inw)
// Some commands will exit when stdin is closed. // Some commands will exit when stdin is closed.
inw.Close() inw.Close()
// Other comamnds need a bonk on the head. // Other commands need a bonk on the head.
if err := proc.Signal(os.Interrupt); err != nil { if err := proc.Signal(os.Interrupt); err != nil {
log.Println("inter:", err) log.Println("inter:", err)
} }
select { select {
case <-done: case <-stdoutDone:
case <-time.After(time.Second): case <-time.After(time.Second):
// A bigger bonk on the head. // A bigger bonk on the head.
if err := proc.Signal(os.Kill); err != nil { if err := proc.Signal(os.Kill); err != nil {
log.Println("term:", err) log.Println("term:", err)
} }
<-done <-stdoutDone
} }
if _, err := proc.Wait(); err != nil { if _, err := proc.Wait(); err != nil {
log.Println("wait:", err) log.Println("wait:", err)
} }
log.Println("exiting handler")
} }
func serveHome(w http.ResponseWriter, r *http.Request) { func serveHome(w http.ResponseWriter, r *http.Request) {