i want to make a application whith golang that can exec sql or command through websocket,i use package "github.com/gorilla/websocket","os/exec","os",
i have finished redis-cli and mongoshell.
but when i use mysql client to connect with mysql, i can’t recieve message from the progress.but when i only set the progress(mysql client) output to stdout,it can display.And when an error sql send to the progress,it closed by unknown.
it can be recurrent through the example of github.com/gorilla/websocket,
https://github.com/gorilla/websocket/blob/master/examples/command/main.go
and this is my code
package main
import (
"flag"
"fmt"
"io"
"log"
"net/http"
"os/exec"
"time"
"github.com/gorilla/websocket"
)
var (
addr = flag.String("addr", "127.0.0.1:8080", "http service address")
)
const (
// Time allowed to write a message to the peer.
writeWait = 10 * time.Second
// Maximum message size allowed from peer.
maxMessageSize = 8192
// Time allowed to read the next pong message from the peer.
pongWait = 20 * time.Second
// Send pings to peer with this period. Must be less than pongWait.
pingPeriod = (pongWait * 9) / 10
)
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)
}
done <- struct{}{}
case <-done:
return
}
}
}
func pumpStdin(ws *websocket.Conn, w io.Writer) {
defer ws.Close()
ws.SetReadLimit(maxMessageSize)
ws.SetReadDeadline(time.Now().Add(pongWait))
ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
for {
_, message, err := ws.ReadMessage()
if err != nil {
break
}
message = append(message, 'n')
if _, err := w.Write(message); err != nil {
break
}
}
}
func pumpStdout(ws *websocket.Conn, r io.ReadCloser, done chan struct{}) {
for {
x := make([]byte, 1024)
n, err := r.Read(x)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(x[:n]))
}
}
var upgrader = websocket.Upgrader{}
func serveWs(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("upgrade:", err)
return
}
defer ws.Close()
stopchan := make(chan struct{})
cmd := exec.Command("/usr/bin/mysql", "-h127.0.0.1", "-ppassword", "-P3306", "-uroot")
cmdin, err := cmd.StdinPipe()
if err != nil {
fmt.Println(err)
}
cmdout, err := cmd.StdoutPipe()
if err!=nil{
fmt.Println(err)
}
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
go ping(ws, stopchan)
go pumpStdout(ws, cmdout, stopchan)
pumpStdin(ws, cmdin)
if err = cmd.Wait(); err != nil {
fmt.Println(err)
}
}
func main() {
flag.Parse()
http.HandleFunc("/ws", serveWs)
log.Fatal(http.ListenAndServe(*addr, nil))
}
2
Answers
i found that the mysql client have buffer open,when i give a arg --unbuffered,the output will send to my pumpStdout. and the progress exit also can fix with add an arg,--force. and all this works. and if you have better solution,tell me,thank you!
}