diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index c218829..709a816 100755 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -163,7 +163,7 @@ function AppContent() { } /> - } /> + } /> diff --git a/frontend/src/Settings.tsx b/frontend/src/Settings.tsx index 6379329..bac849a 100644 --- a/frontend/src/Settings.tsx +++ b/frontend/src/Settings.tsx @@ -22,6 +22,7 @@ import { useDispatch, useSelector } from "react-redux"; import { debounceTime, distinctUntilChanged, map, of, takeWhile } from "rxjs"; import { CliArguments } from "./features/core/argsParser"; import I18nBuilder from "./features/core/intl"; +import { RPCClient } from "./features/core/rpcClient"; import { LanguageUnion, setCliArgs, @@ -38,7 +39,7 @@ import { updated } from "./features/status/statusSlice"; import { RootState } from "./stores/store"; import { validateDomain, validateIP } from "./utils"; -export default function Settings() { +export default function Settings({ socket }: { socket: WebSocket }) { const settings = useSelector((state: RootState) => state.settings) const status = useSelector((state: RootState) => state.status) const dispatch = useDispatch() @@ -46,6 +47,7 @@ export default function Settings() { const [invalidIP, setInvalidIP] = useState(false); const i18n = useMemo(() => new I18nBuilder(settings.language), [settings.language]) + const client = useMemo(() => new RPCClient(socket), [settings.serverAddr, settings.serverPort]) const cliArgs = useMemo(() => new CliArguments().fromString(settings.cliArgs), [settings.cliArgs]) /** * Update the server ip address state and localstorage whenever the input value changes. @@ -107,7 +109,7 @@ export default function Settings() { * Send via WebSocket a message in order to update the yt-dlp binary from server */ const updateBinary = () => { - + client.updateExecutable().then(() => dispatch(updated())) } return ( diff --git a/frontend/src/features/core/rpcClient.ts b/frontend/src/features/core/rpcClient.ts index b693ac7..3ca0363 100644 --- a/frontend/src/features/core/rpcClient.ts +++ b/frontend/src/features/core/rpcClient.ts @@ -92,6 +92,13 @@ export class RPCClient { }) } + public updateExecutable() { + return this.sendHTTP({ + method: 'Service.UpdateExecutable', + params: [] + }) + } + public decode(data: any): RPCResponse { return JSON.parse(data) } diff --git a/server/process.go b/server/process.go index 2f73768..f7cff0b 100644 --- a/server/process.go +++ b/server/process.go @@ -4,6 +4,7 @@ import ( "bufio" "fmt" "regexp" + "syscall" "github.com/goccy/go-json" @@ -89,6 +90,8 @@ func (p *Process) Start(path, filename string) { // ----------------- main block ----------------- // cmd := exec.Command(cfg.GetConfig().DownloaderPath, params...) + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + r, err := cmd.StdoutPipe() if err != nil { log.Panicln(err) @@ -107,6 +110,8 @@ func (p *Process) Start(path, filename string) { // spawn a goroutine that retrieves the info for the download go func() { cmd := exec.Command(cfg.GetConfig().DownloaderPath, p.url, "-J") + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + stdout, err := cmd.Output() if err != nil { log.Println("Cannot retrieve info for", p.url) @@ -132,8 +137,8 @@ func (p *Process) Start(path, filename string) { cmd.Wait() }() - // do the unmarshal operation every 500ms (consumer) - go rx.Debounce(time.Millisecond*500, eventChan, func(text string) { + // do the unmarshal operation every 250ms (consumer) + go rx.Debounce(time.Millisecond*250, eventChan, func(text string) { stdout := ProgressTemplate{} err := json.Unmarshal([]byte(text), &stdout) if err == nil { @@ -162,7 +167,11 @@ func (p *Process) Complete() { // Kill a process and remove it from the memory func (p *Process) Kill() error { - err := p.proc.Kill() + pgid, err := syscall.Getpgid(p.proc.Pid) + if err != nil { + return err + } + err = syscall.Kill(-pgid, syscall.SIGTERM) p.mem.Delete(p.id) log.Printf("Killed process %s\n", p.id) return err diff --git a/server/service.go b/server/service.go index bdf87ae..62bb73c 100644 --- a/server/service.go +++ b/server/service.go @@ -31,7 +31,7 @@ type DownloadSpecificArgs struct { // Exec spawns a Process. // The result of the execution is the newly spawned process Id. func (t *Service) Exec(args DownloadSpecificArgs, result *string) error { - log.Printf("Spawning new process for %s\n", args.URL) + log.Println("Spawning new process for", args.URL) p := Process{mem: &db, url: args.URL, params: args.Params} p.Start(args.Path, args.Rename) *result = p.id @@ -66,6 +66,7 @@ func (t *Service) Running(args NoArgs, running *Running) error { // Kill kills a process given its id and remove it from the memoryDB func (t *Service) Kill(args string, killed *string) error { + log.Println("Trying killing process with id", args) proc := db.Get(args) var err error if proc != nil { @@ -77,6 +78,7 @@ func (t *Service) Kill(args string, killed *string) error { // KillAll kills all process unconditionally and removes them from // the memory db func (t *Service) KillAll(args NoArgs, killed *string) error { + log.Println("Killing all spawned processes", args) keys := db.Keys() var err error for _, key := range keys { @@ -102,6 +104,7 @@ func (t *Service) DirectoryTree(args NoArgs, tree *[]string) error { } func (t *Service) UpdateExecutable(args NoArgs, updated *bool) error { + log.Println("Updating yt-dlp executable to the latest release") err := updater.UpdateExecutable() if err != nil { *updated = true