Need help displaying the execution output of a shell command, e.g. rsync. that takes a while to run

agolangf · 2018-03-03 00:30:10 · 617 次点击    
这是一个分享于 2018-03-03 00:30:10 的资源,其中的信息可能已经有所发展或是发生改变。

Basically, user provides a list of files to copy from dest1 to dest2. rsync is fired off by pressing the submitting the button, and I want the realtime output of STDOUT/STDERR display in the same page. I would also be saving this execution as a blob in a MySQL DB. WebSockets?


评论:

AG_Clinton:

I did almost exactly that with a python script that ran rsync. I'll show you a very stripped down version of what I have. This is my first time doing something like this and I'm still a beginner, but figured I'd share what worked for me. I used gorilla websockets. I'm sure it could be simplified quite a bit as well.

var (
    SyncOutput              = make(chan string)
    SyncClients             = make(map[*websocket.Conn]bool)
    SyncClientsLock         = sync.RWMutex{}
    FileSyncing             = false
    FileSyncLock            = sync.RWMutex{}
)
var upgrader = websocket.Upgrader{
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
}
go WatchOutPutChannel()

func runSync() {
    cmd := exec.Command("python", "-u", config.SyncFilesScript)
    stdout, err := cmd.StdoutPipe()
    if err != nil {
        fmt.Println(fmt.Sprintf("Error: %s", err))
    }
    FileSyncLock.Lock()
    FileSyncing = true
    FileSyncLock.Unlock()
    err = cmd.Start()
    go WatchOutPut(stdout)
}
func WatchOutPut(out io.Reader) {
    scanner := bufio.NewScanner(out)
    for scanner.Scan() {
        SyncOutput <- scanner.Text()
    }
    FileSyncLock.Lock()
    FileSyncing = false
    FileSyncLock.Unlock()
    SyncOutput <- "Sync Finished"
}
func WatchOutPutChannel() {
    for {
        output := <-SyncOutput
        SyncClientsLock.RLock()
        for client := range SyncClients {
            client.WriteMessage(1, []byte(output))
        }
        SyncClientsLock.RUnlock()
    }
}
func wsHandlerSync(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        fmt.Println("Failed to set websocket upgrade: %+v", err)
        return
    }
    SyncClientsLock.Lock()
    SyncClients[conn] = true
    SyncClientsLock.Unlock()
    for {
        _, _, err := conn.ReadMessage()
        if err != nil {
            break
        }
    }
    SyncClientsLock.Lock()
    delete(SyncClients, conn)
    SyncClientsLock.Unlock()
    conn.Close()
}
dazealex:

Thank you kind sir! Much appreciated.

toolateforTeddy:

Websockets seems like a good plan.

I like gorilla websockets.

dazealex:

Any examples?


入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

617 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传