From 9a44c9221139428fa4e3bdf560f6bfdc6fcbe75d Mon Sep 17 00:00:00 2001
From: flow <flowlnlnln@gmail.com>
Date: Thu, 2 Jun 2022 19:34:08 -0300
Subject: feat: add MultipleOptionsTask

This is a variation of a Sequential Task, in which a subtask failing
will prompt the next one to execute, and a subtask being successful will
stop the task.

This way, this can be used for easily managing fallbacks with tasks. :D

Signed-off-by: flow <flowlnlnln@gmail.com>
---
 launcher/tasks/MultipleOptionsTask.cpp | 48 ++++++++++++++++++++++++++++++++++
 launcher/tasks/MultipleOptionsTask.h   | 19 ++++++++++++++
 launcher/tasks/SequentialTask.h        | 14 +++++-----
 3 files changed, 74 insertions(+), 7 deletions(-)
 create mode 100644 launcher/tasks/MultipleOptionsTask.cpp
 create mode 100644 launcher/tasks/MultipleOptionsTask.h

(limited to 'launcher/tasks')

diff --git a/launcher/tasks/MultipleOptionsTask.cpp b/launcher/tasks/MultipleOptionsTask.cpp
new file mode 100644
index 00000000..6e853568
--- /dev/null
+++ b/launcher/tasks/MultipleOptionsTask.cpp
@@ -0,0 +1,48 @@
+#include "MultipleOptionsTask.h"
+
+#include <QDebug>
+
+MultipleOptionsTask::MultipleOptionsTask(QObject* parent, const QString& task_name) : SequentialTask(parent, task_name) {}
+
+void MultipleOptionsTask::startNext()
+{
+    Task* previous = nullptr;
+    if (m_currentIndex != -1) {
+        previous = m_queue[m_currentIndex].get();
+        disconnect(previous, 0, this, 0);
+    }
+
+    m_currentIndex++;
+    if ((previous && previous->wasSuccessful())) {
+        emitSucceeded();
+        return;
+    }
+
+    Task::Ptr next = m_queue[m_currentIndex];
+
+    connect(next.get(), &Task::failed, this, &MultipleOptionsTask::subTaskFailed);
+    connect(next.get(), &Task::succeeded, this, &MultipleOptionsTask::startNext);
+
+    connect(next.get(), &Task::status, this, &MultipleOptionsTask::subTaskStatus);
+    connect(next.get(), &Task::stepStatus, this, &MultipleOptionsTask::subTaskStatus);
+    
+    connect(next.get(), &Task::progress, this, &MultipleOptionsTask::subTaskProgress);
+
+    qDebug() << QString("Making attemp %1 out of %2").arg(m_currentIndex + 1).arg(m_queue.size());
+    setStatus(tr("Making attempt #%1 out of %2").arg(m_currentIndex + 1).arg(m_queue.size()));
+    setStepStatus(next->isMultiStep() ? next->getStepStatus() : next->getStatus());
+
+    next->start();
+}
+
+void MultipleOptionsTask::subTaskFailed(QString const& reason)
+{
+    qDebug() << QString("Failed attempt #%1 of %2. Reason: %3").arg(m_currentIndex + 1).arg(m_queue.size()).arg(reason);
+    if(m_currentIndex < m_queue.size() - 1) {
+        startNext();
+        return;
+    }
+
+    qWarning() << QString("All attempts have failed!");
+    emitFailed();
+}
diff --git a/launcher/tasks/MultipleOptionsTask.h b/launcher/tasks/MultipleOptionsTask.h
new file mode 100644
index 00000000..7c508b00
--- /dev/null
+++ b/launcher/tasks/MultipleOptionsTask.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "SequentialTask.h"
+
+/* This task type will attempt to do run each of it's subtasks in sequence,
+ * until one of them succeeds. When that happens, the remaining tasks will not run.
+ * */
+class MultipleOptionsTask : public SequentialTask
+{
+    Q_OBJECT
+public:
+    explicit MultipleOptionsTask(QObject *parent = nullptr, const QString& task_name = "");
+    virtual ~MultipleOptionsTask() = default;
+
+private
+slots:
+    void startNext() override;
+    void subTaskFailed(const QString &msg) override;
+};
diff --git a/launcher/tasks/SequentialTask.h b/launcher/tasks/SequentialTask.h
index 942ebec2..f5a58b1b 100644
--- a/launcher/tasks/SequentialTask.h
+++ b/launcher/tasks/SequentialTask.h
@@ -20,17 +20,17 @@ public:
 
     void addTask(Task::Ptr task);
 
-protected slots:
-    void executeTask() override;
 public slots:
     bool abort() override;
 
-private
+protected
 slots:
-    void startNext();
-    void subTaskFailed(const QString &msg);
-    void subTaskStatus(const QString &msg);
-    void subTaskProgress(qint64 current, qint64 total);
+    void executeTask() override;
+
+    virtual void startNext();
+    virtual void subTaskFailed(const QString &msg);
+    virtual void subTaskStatus(const QString &msg);
+    virtual void subTaskProgress(qint64 current, qint64 total);
 
 protected:
     void setStepStatus(QString status) { m_step_status = status; emit stepStatus(status); };
-- 
cgit