diff --git a/src/downloaders.go b/src/downloaders.go index eef7fdb..647aeae 100644 --- a/src/downloaders.go +++ b/src/downloaders.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "encoding/base64" "fmt" "io" @@ -9,6 +10,7 @@ import ( "os/exec" "path/filepath" "strings" + "time" ) func removeBOM(input []byte) []byte { @@ -99,11 +101,8 @@ func downloadFile(item Item, jobInfo *JobInfo) error { cmd := exec.Command("bash", "-c", command) - jobsMutex.Lock() - jobInfo.Cmd = cmd - jobsMutex.Unlock() - - cmd.Stdout = os.Stdout + var outputBuffer bytes.Buffer + cmd.Stdout = io.MultiWriter(os.Stdout, &outputBuffer) cmd.Stderr = os.Stderr err = cmd.Start() @@ -116,6 +115,16 @@ func downloadFile(item Item, jobInfo *JobInfo) error { done <- cmd.Wait() }() + go func() { + for { + if outputBuffer.Len() > 0 { + broadcast(outputBuffer.Bytes()) + outputBuffer.Reset() + } + time.Sleep(1 * time.Second) + } + }() + select { case <-jobInfo.AbortChan: if cmd.Process != nil { diff --git a/src/go.mod b/src/go.mod index bc9873f..38e8b9d 100644 --- a/src/go.mod +++ b/src/go.mod @@ -11,6 +11,7 @@ require ( require ( github.com/asticode/go-astikit v0.20.0 // indirect github.com/asticode/go-astits v1.8.0 // indirect + github.com/gorilla/websocket v1.5.3 golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect golang.org/x/text v0.3.2 // indirect ) diff --git a/src/go.sum b/src/go.sum index 97fe73a..68a64b8 100644 --- a/src/go.sum +++ b/src/go.sum @@ -10,6 +10,8 @@ github.com/beevik/etree v1.4.1 h1:PmQJDDYahBGNKDcpdX8uPy1xRCwoCGVUiW669MEirVI= github.com/beevik/etree v1.4.1/go.mod h1:gPNJNaBGVZ9AwsidazFZyygnd+0pAU38N4D+WemwKNs= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/pkg/exec v0.0.0-20150614095509-0bd164ad2a5a h1:EN123kAtAAE2pg/+TvBsUBZfHCWNNFyL2ZBPPfNWAc0= github.com/pkg/exec v0.0.0-20150614095509-0bd164ad2a5a/go.mod h1:b95YoNrAnScjaWG+asr8lxqlrsPUcT2ZEBcjvVGshMo= github.com/pkg/profile v1.4.0/go.mod h1:NWz/XGvpEW1FyYQ7fCx4dqYBLlfTcE+A9FLAkNKqjFE= diff --git a/src/handlers.go b/src/handlers.go index c5e2e5f..ee72dae 100644 --- a/src/handlers.go +++ b/src/handlers.go @@ -9,6 +9,9 @@ import ( "os" "path/filepath" "strings" + "sync" + + "github.com/gorilla/websocket" ) type ProgressInfo struct { @@ -354,3 +357,42 @@ func updateProgress(filename string, value float64, currentFile string) { } } } + +var upgrader = websocket.Upgrader{} +var clients = make(map[*websocket.Conn]bool) +var mu sync.Mutex + +func handleWebSocket(w http.ResponseWriter, r *http.Request) { + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + fmt.Println("Error while upgrading connection:", err) + return + } + defer conn.Close() + + mu.Lock() + clients[conn] = true + mu.Unlock() + + for { + if _, _, err := conn.NextReader(); err != nil { + break + } + } + + mu.Lock() + delete(clients, conn) + mu.Unlock() +} + +func broadcast(message []byte) { + mu.Lock() + defer mu.Unlock() + + for client := range clients { + if err := client.WriteMessage(websocket.TextMessage, message); err != nil { + client.Close() + delete(clients, client) + } + } +} diff --git a/src/main.go b/src/main.go index 7feea87..8f955e1 100644 --- a/src/main.go +++ b/src/main.go @@ -77,6 +77,7 @@ func startWebServer() { http.HandleFunc("/pause", handlePause) http.HandleFunc("/resume", handleResume) http.HandleFunc("/clear-completed", handleClearCompleted) + http.HandleFunc("/ws", handleWebSocket) fmt.Println("Starting web server on http://0.0.0.0:8080") http.ListenAndServe(":8080", nil) diff --git a/src/templates/progress b/src/templates/progress index f3c710d..74e23e9 100644 --- a/src/templates/progress +++ b/src/templates/progress @@ -68,7 +68,7 @@ #abort-button:hover { background-color: #d32f2f; } - #pause-button, #resume-button { + #pause-button, #resume-button, #toggle-console { background-color: #4CAF50; color: white; border: none; @@ -77,7 +77,7 @@ border-radius: 4px; cursor: pointer; } - #pause-button:hover, #resume-button:hover { + #pause-button:hover, #resume-button:hover, #toggle-console:hover { background-color: #45a049; } #resume-button { @@ -96,6 +96,17 @@ #back-button:hover { background-color: #1976D2; } + #console { + display: none; /* Initially hidden */ + background-color: black; + color: white; + height: 300px; /* Adjust height as needed */ + overflow-y: scroll; + white-space: pre; /* Preserve whitespace */ + font-family: monospace; /* Use monospace font */ + margin-top: 10px; + border: 1px solid #ccc; + } @media (max-width: 600px) { body { padding: 10px; @@ -128,8 +139,10 @@ + +