skip to Main Content

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


  1. Chosen as BEST ANSWER

    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!


  2. func pumpStdout(ws *websocket.Conn, r io.ReadCloser, done chan struct{}) {
    defer ws.Close()
    defer r.Close()
    
    buf := make([]byte, 1024)
    for {
        n, err := r.Read(buf)
        if err != nil {
            fmt.Println(err)
            break
        }
    
        output := buf[:n]
        if _, err := ws.Write(output); err != nil {
            fmt.Println(err)
            break
        }
        
        // Flush the output buffer
        if fw, ok := ws.UnderlyingConn().(*net.TCPConn); ok {
            if err := fw.SetWriteDeadline(time.Now().Add(writeWait)); err != nil {
                fmt.Println(err)
                break
            }
            if err := fw.Flush(); err != nil {
                fmt.Println(err)
                break
            }
        }
    }
    
    done <- struct{}{}
    

    }

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search