From f294d651a5bc5de8bc116f5c9716f5aee8092c8d Mon Sep 17 00:00:00 2001 From: Emin Date: Fri, 20 Oct 2023 11:36:07 +0300 Subject: [PATCH] Cancel button implemented. Fix predefined input fields. --- controller/sync_controller.go | 29 +++++++++++++++- internal/cancel.go | 17 +++++++--- internal/sync.go | 64 +++++++++++++++++++++++++++++++---- internal/sync_loop.go | 15 +++++--- templates/index.html | 30 ++++++++-------- 5 files changed, 124 insertions(+), 31 deletions(-) diff --git a/controller/sync_controller.go b/controller/sync_controller.go index 7561733..c958da2 100644 --- a/controller/sync_controller.go +++ b/controller/sync_controller.go @@ -62,7 +62,34 @@ func handleCancel(ctx *gin.Context) { internal.CancelTask(task) - log.Infof("%#v", task) + sourceServer := task.SourceServer + sourceAccount := task.SourceAccount + sourcePassword := task.SourcePassword + destinationServer := task.DestinationServer + destinationAccount := task.DestinationAccount + destinationPassword := task.DestinationPassword + + sourceDetails := internal.Credentials{ + Server: sourceServer, + Account: sourceAccount, + Password: sourcePassword, + } + + destinationDetails := internal.Credentials{ + Server: destinationServer, + Account: destinationAccount, + Password: destinationPassword, + } + + creds := struct { + Source internal.Credentials + Destination internal.Credentials + }{ + Source: sourceDetails, + Destination: destinationDetails, + } + + ctx.HTML(200, "sync_success.html", creds) } func handleRetry(ctx *gin.Context) { diff --git a/internal/cancel.go b/internal/cancel.go index ea8782a..bf7a4b5 100644 --- a/internal/cancel.go +++ b/internal/cancel.go @@ -1,12 +1,19 @@ package internal +// CancelTask cancels a task and removes it from channel func CancelTask(task *Task) { if task.Status != "In Progress" { updateTaskStatus(task, "Cancelled") - log.Debug(len(taskChan)) - _ = <-taskChan - log.Debug(len(taskChan)) - return - } + select { + case <-taskChan: + log.Info("Task cancelled: ", task.ID) + default: + log.Info("Task not found in channel: ", task.ID) + } + + } else { + cancel() + updateTaskStatus(task, "Cancelled") + } } diff --git a/internal/sync.go b/internal/sync.go index 2f9bc13..7361a9e 100644 --- a/internal/sync.go +++ b/internal/sync.go @@ -2,22 +2,57 @@ package internal import ( "bytes" + "context" "fmt" "io" "os" "os/exec" + "syscall" "time" ) -func syncIMAP(details *Task) error { +// func syncIMAP( ,details *Task) error { +// updateTaskStatus(details, "In Progress") + +// currentTime := time.Now().Format("2006.01.02_15:04:05") + +// logname := details.SourceAccount + "_" + details.DestinationAccount + "_" + currentTime + ".log" + +// cmd := exec.Command("imapsync", +// "--host1", details.SourceServer, +// "--user1", details.SourceAccount, +// "--password1", details.SourcePassword, +// "--host2", details.DestinationServer, +// "--user2", details.DestinationAccount, +// "--password2", details.DestinationPassword, +// "--logfile", logname) + +// updateTaskLogFile(details, logname) +// var stdBuffer bytes.Buffer +// mw := io.MultiWriter(os.Stdout, &stdBuffer) + +// cmd.Stdout = mw +// cmd.Stderr = mw + +// if err := cmd.Run(); err != nil { +// updateTaskStatus(details, "Error") +// return fmt.Errorf("error running imapsync: %w", err) +// } + +// updateTaskStatus(details, "Done") + +// return nil +// } + +func syncIMAP(ctx context.Context, details *Task) error { updateTaskStatus(details, "In Progress") currentTime := time.Now().Format("2006.01.02_15:04:05") logname := details.SourceAccount + "_" + details.DestinationAccount + "_" + currentTime + ".log" - cmd := exec.Command("imapsync", + cmd := exec.CommandContext(ctx, "imapsync", "--host1", details.SourceServer, "--user1", details.SourceAccount, "--password1", details.SourcePassword, @@ -33,12 +68,29 @@ func syncIMAP(details *Task) error { cmd.Stdout = mw cmd.Stderr = mw - if err := cmd.Run(); err != nil { + if err := cmd.Start(); err != nil { updateTaskStatus(details, "Error") - return fmt.Errorf("error running imapsync: %w", err) + return fmt.Errorf("error starting imapsync: %w", err) } - updateTaskStatus(details, "Done") + done := make(chan error, 1) + go func() { + done <- cmd.Wait() + }() - return nil + select { + case <-ctx.Done(): + if err := cmd.Process.Signal(syscall.SIGTERM); err != nil { + return fmt.Errorf("failed to terminate imapsync process: %w", err) + } + updateTaskStatus(details, "Cancelled") + return ctx.Err() + case err := <-done: + if err != nil { + updateTaskStatus(details, "Error") + return fmt.Errorf("error running imapsync: %w", err) + } + updateTaskStatus(details, "Done") + return nil + } } diff --git a/internal/sync_loop.go b/internal/sync_loop.go index 3e51cee..5af49c4 100644 --- a/internal/sync_loop.go +++ b/internal/sync_loop.go @@ -1,10 +1,14 @@ package internal import ( + "context" "os" "time" ) +var ctx context.Context +var cancel context.CancelFunc + func processPendingTasks() { for { // Get the index of the first pending task @@ -16,9 +20,12 @@ func processPendingTasks() { continue } - // syncIMAP(task) - simulateTask(task) - time.Sleep(100 * time.Millisecond) + log.Info("Processing task: ", task.ID) + ctx, cancel = context.WithCancel(context.Background()) + syncIMAP(ctx, task) + + // simulateTask(task) + time.Sleep(1000 * time.Millisecond) } } @@ -50,6 +57,6 @@ func simulateTask(task *Task) { logFile.WriteString("This is a test log file\n") updateTaskStatus(task, "In Progress") - time.Sleep(10000 * time.Millisecond) + time.Sleep(1000 * time.Millisecond) updateTaskStatus(task, "Done") } diff --git a/templates/index.html b/templates/index.html index b6c3015..f3f0632 100644 --- a/templates/index.html +++ b/templates/index.html @@ -64,13 +64,13 @@

Source Details

- +
- +
@@ -114,7 +114,7 @@

Destination Details

- +
@@ -126,8 +126,8 @@

User queue

- {{template "table_user.html"}} -
+ {{template "table_user.html"}} +
@@ -216,24 +216,24 @@

User queue

document.addEventListener('alpine:init', () => { Alpine.data('data', () => ({ model_open: '', - source_server: '', - source_account: '', - destination_server: '', - destination_account: '', + source_server: '{{.SourceDetails.Server}}', + source_account: '{{.SourceDetails.Account}}', + destination_server: '{{.DestinationDetails.Server}}', + destination_account: '{{.DestinationDetails.Account}}', source_validated: false, destination_validated: false, - showQueue(){ + showQueue() { if (this.source_validated === true && this.destination_validated === true) { - htmx.ajax('POST', "/api/search?exact=true&source_server="+this.source_server+"&source_account="+this.source_account+"&destination_server="+this.destination_server+"&destination_account="+this.destination_account+"", {target:'#table-body',swap:'innerHTML'}) + htmx.ajax('POST', "/api/search?exact=true&source_server=" + this.source_server + "&source_account=" + this.source_account + "&destination_server=" + this.destination_server + "&destination_account=" + this.destination_account + "", { target: '#table-body', swap: 'innerHTML' }) } }, init() { setInterval(() => { this.showQueue(); - }, 2000); + }, 60000); }, update_source_status(result) { @@ -245,7 +245,7 @@

User queue

this.showQueue(); }, } - + )) })