Sfoglia il codice sorgente

major work on refactor
some additions to the Task and Task argument interface, for dealing with files
partially modified client to deal with new interface

still remaining:
- deleting files from task upon deletion in argdialog ui
- handling of messages in Client to process queue appropriately

logicp 4 anni fa
parent
commit
2062ff154c

+ 3 - 6
include/client/client.hpp

@@ -24,10 +24,7 @@ static constexpr int COMMANDS_UPDATE_TYPE = 2;
 static constexpr int EVENT_UPDATE_TYPE = 3;
 static constexpr int PROCESS_REQUEST_TYPE = 4;
 
-enum TaskType {
-    INSTAGRAM = 1,
-    OTHER = 2
-};
+using namespace Scheduler;
 
 namespace TaskCode {
 static constexpr int IGTASKBYTE = 0xFF;
@@ -72,7 +69,7 @@ class Client : public QDialog {
   QString getAppName(int mask);
   int getSelectedApp();
   // Move this to private after moving responsibilities to Client
-  void scheduleTask(Scheduler::Task* task, bool file_pending);
+  void scheduleTask(Scheduler::Task* task);
   MessageHandler createMessageHandler(std::function<void()> cb);
 
  public slots:
@@ -96,7 +93,7 @@ class Client : public QDialog {
   int argc;
   char** argv;
   int m_client_socket_fd;
-  std::vector<std::string> m_task;
+  Task* m_outbound_task;
   bool executing;
   bool file_was_sent;
   CommandMap m_commands;

+ 2 - 0
include/task/instagram_task.hpp

@@ -25,6 +25,8 @@ class InstagramTask : public Scheduler::Task {
   virtual const QVector<Scheduler::KFileData> getFiles() override;
   virtual Scheduler::TaskType getType() override;
   virtual void setArgument(QString name, Scheduler::TypeVariant arg) override;
+  virtual void setArgument(QString name, Scheduler::KFileData file) override;
+  virtual bool hasFiles() override;
   virtual bool isReady() override;
   virtual void clear() override;
   virtual void setDefaultValues() override;

+ 33 - 1
include/task/task.hpp

@@ -65,7 +65,7 @@ class Task;
 using TaskQueue = QQueue<Task*>;
 using ArgumentType = const char*;
 using ArgumentValues = QVector<const QString>;
-using TypeVariant = std::variant<bool, int, QString, QVector<QString>, std::vector<KFileData>>;
+using TypeVariant = std::variant<bool, int, QString, QVector<QString>, QVector<KFileData>>;
 using TaskIterator = std::vector<std::unique_ptr<TaskArgumentBase>>::iterator;
 using TaskArguments = std::vector<std::unique_ptr<TaskArgumentBase>>;
 
@@ -76,7 +76,10 @@ class TaskArgumentBase {
  public:
   virtual const QString text() = 0;
   virtual const QString getStringValue() = 0;
+  virtual uint8_t getTypeIndex();
   virtual TypeVariant getValue() = 0;
+  virtual void insert(QString value) = 0;
+  virtual void insert(KFileData file) = 0;
   virtual void setValue(TypeVariant v) = 0;
   virtual bool isContainer() = 0;
   virtual void clear() = 0;
@@ -170,6 +173,32 @@ class TaskArgument : TaskArgumentBase {
     return (isIndex(value.index(), VariantIndex::STRVEC) || isIndex(value.index(), VariantIndex::FILEVEC));
   }
 
+  /**
+   * @brief insert
+   * @param value
+   */
+  virtual void insert(QString value) override {
+
+  }
+
+  /**
+   * @brief insert
+   * @param file
+   */
+  virtual void insert(KFileData file) override {
+    if (value.index() == VariantIndex::FILEVEC) {
+      std::get<VariantIndex::FILEVEC>(value).push_back(file);
+    }
+  }
+
+  /**
+   * @brief getTypeIndex
+   * @return
+   */
+  virtual uint8_t getTypeIndex() override {
+    return value.index();
+  }
+
  private:
   QString name;
   ArgumentType type;
@@ -185,6 +214,7 @@ class Task {
   Task(KFileData);
   Task(QVector<KFileData>);
   virtual void setArgument(QString name, TypeVariant arg) = 0;
+  virtual void setArgument(QString name, Scheduler::KFileData file) = 0;
   virtual const TaskArguments getTaskArguments() = 0;
   virtual TypeVariant getTaskArgument(QString name) = 0;
   virtual ArgumentValues getArgumentValues() = 0;
@@ -192,6 +222,8 @@ class Task {
   virtual void defineTaskArguments() = 0;
   virtual void setDefaultValues() = 0;
   virtual const QVector<KFileData> getFiles() = 0;
+  virtual void addFile(KFileData file) = 0;
+  virtual bool hasFiles() = 0;
   virtual bool isReady() = 0;
   virtual void clear() = 0;
   virtual ~Task(){};

+ 2 - 18
include/ui/argdialog.h

@@ -9,29 +9,15 @@
 #include <QMessageBox>
 #include <QPushButton>
 #include <headers/util.hpp>
+#include <include/task/instagram_task.hpp>
 #include <include/task/task.hpp>
 #include <string_view>
 #include <unordered_map>
 
 using namespace Scheduler;
 
-namespace Args {
-const QString HEADER_TYPE = "header";
-const QString DESCRIPTION_TYPE = "description";
-const QString HASHTAG_TYPE = "hashtag";
-const QString PROMOTE_TYPE = "promote/share";
-const QString LINK_BIO_TYPE = "link/bio";
-const QString REQUESTED_BY_TYPE = "requested by";
-}  // namespace Args
-
 typedef std::string Str;
 
-typedef struct KFile {
-  QString name;
-  QString path;
-  FileType type;
-} KFile;
-
 typedef struct IGPost {
   std::string header = "Learn to speak like native Korean speakers 🙆‍♀️🇰🇷";
   std::string description;
@@ -41,7 +27,6 @@ typedef struct IGPost {
   std::vector<std::string> hashtags;
   std::vector<std::string> requested_by;
   const char *requested_by_phrase = "The phrase was requested by ";
-  std::vector<KFile> files;
   std::string user;
   bool is_video;
   bool isReady() {
@@ -69,8 +54,7 @@ class ArgDialog : public QDialog {
   ~ArgDialog();
 
  signals:
-  void uploadFiles(QVector<KFileData> files);
-  void taskRequestReady(Task task, bool file_pending);
+  void taskRequestReady(Scheduler::Task *task);
 
  private:
   void clearPost();

+ 45 - 37
src/argdialog.cpp

@@ -15,36 +15,60 @@ ArgDialog::ArgDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ArgDialog),
 
   ui->argCommandButtons->button(QDialogButtonBox::Close)
       ->setStyleSheet(QString("background:%1").arg("#2f535f"));
+
   QObject::connect(ui->addFile, &QPushButton::clicked, this, [this]() {
     KFileDialog file_dialog{};
     auto file_path = file_dialog.openFileDialog(m_file_path);
     qDebug() << "Selected file:" << file_path;
+
     if (file_path.size() > 0) {
       auto slash_index = file_path.lastIndexOf("/") + 1;
       QString file_name = file_path.right(file_path.size() - slash_index);
       QString dir = file_path.left(slash_index);
-      qDebug() << "Dir is " << dir;
-      QMimeDatabase db;
-      auto is_video = db.mimeTypeForFile(file_path).name().contains("video");
-      addItem(file_name, "file");
-      m_ig_post.files.push_back(
-          KFile{.name = file_name, .path = file_path, .type = is_video ? FileType::VIDEO : FileType::IMAGE});
+      QFile file(file_path);
+
+      if (file.open(QIODevice::ReadOnly)) {
+        QMimeDatabase db;
+        auto is_video = db.mimeTypeForFile(file_path).name().contains("video");
+        addItem(file_name, "file");
+        m_task->setArgument("files", Scheduler::KFileData{
+                                         .name = file_name,
+                                         .type = is_video ? FileType::VIDEO : FileType::IMAGE,
+                                         .path = file_path,
+                                         .bytes = file.readAll()});
 
-      if (is_video) {
-        qDebug() << "File discovered to be video";
-        m_ig_post.is_video = true; // rename to "sending_video"
-        QString preview_filename = FileUtils::generatePreview(file_path, file_name);
-        // TODO: create some way of verifying preview generation was successful
-        addFile("assets/previews/" + preview_filename);
-        addItem(preview_filename, "file");
-        addFile("assets/previews/" + preview_filename);
-        m_ig_post.files.push_back(KFile{.name = preview_filename,
-                                        .path = QCoreApplication::applicationDirPath()
-                                                + "/assets/previews/" + preview_filename,
-                                        .type = is_video ? FileType::VIDEO : FileType::IMAGE});
+        if (is_video) {
+          qDebug() << "File discovered to be video";
+          m_task->setArgument("is_video", true);
+          QString preview_filename = FileUtils::generatePreview(file_path, file_name);
+
+          auto preview_file_path = QCoreApplication::applicationDirPath()
+                                   + "/assets/previews/" + preview_filename;
+          file.setFileName(preview_file_path);
+          if (file.open(QIODevice::ReadOnly)) {
+            // TODO: create some way of verifying preview generation was successful
+            addFile("assets/previews/" + preview_filename);
+            addItem(preview_filename, "file");
+            addFile("assets/previews/" + preview_filename);
+            m_task->setArgument("files", Scheduler::KFileData{
+                                             .name = preview_filename,
+                                             .type = is_video ? FileType::VIDEO : FileType::IMAGE,
+                                             .path = preview_file_path,
+                                             .bytes = file.readAll()});
+          } else {
+            qDebug() << "Could not add preview image for video";
+            QMessageBox::warning(this, tr("File Error"), tr("Could not add preview image for video"));
+          }
+        } else {
+          addFile(file_path);
+        }
       } else {
-        addFile(file_path);
+        qDebug() << "Unable to open selected file";
+        QMessageBox::warning(this, tr("File Error"), tr("Unable to open selected file"));
       }
+    } else {
+      qDebug() << "Could not read the file path";
+      QMessageBox::warning(this, tr("File Error"), tr("Could not read the file path"));
     }
   });
 
@@ -100,25 +124,9 @@ ArgDialog::ArgDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ArgDialog),
                        &QDialogButtonBox::clicked),
                    this, [this](QAbstractButton *button) {
                      if (button->text() == "Save") {
-                       if (m_ig_post.isReady()) {
+                       if (m_task->isReady()) {
                          setTaskArguments();
-                         QVector<KFileData> k_file_v{};
-                         k_file_v.reserve(m_ig_post.files.size());
-
-                         for (const auto &kfile : m_ig_post.files) {
-                           QFile file(kfile.path);
-                           if (file.open(QIODevice::ReadOnly)) {
-                             k_file_v.push_back(KFileData{
-                                 .name = kfile.name, .type = kfile.type, .path = kfile.path, .bytes = file.readAll()});
-                           } else {
-                             QMessageBox::warning(this, tr("File Error"), tr("Unable to read file"));
-                           }
-                         }
-
-                         if (!k_file_v.empty()) {
-                           emit ArgDialog::uploadFiles(k_file_v);
-                         }
-                         emit ArgDialog::taskRequestReady(m_task, true);
+                         emit ArgDialog::taskRequestReady(m_task);
                        }
                        clearPost(); // reset m_ig_post to default values
                      }

+ 43 - 122
src/client.cpp

@@ -232,112 +232,43 @@ std::string getTaskFileInfo(std::vector<SentFile> files) {
 
 /**
  * @brief Client::sendTaskEncoded
- * @param [in] {TaskType}                 type The type of task
- * @param [in] {std::vector<std::string>} args The task arguments
- */
-void Client::sendTaskEncoded(TaskType type, std::vector<std::string> args) {
-    if (type == TaskType::INSTAGRAM) {
-      if (args.size() < 8) {
-        qDebug() << "Not enough arguments to send an IGTask";
-        return;
-      }
-        auto file_info = builder.CreateString(getTaskFileInfo(sent_files));
-        auto time = builder.CreateString(args.at(0).c_str(), args.at(0).size());
-        auto description = builder.CreateString(args.at(1).c_str(), args.at(1).size());
-        auto hashtags = builder.CreateString(args.at(2).c_str(), args.at(2).size());
-        auto requested_by = builder.CreateString(args.at(3).c_str(), args.at(3).size());
-        auto requested_by_phrase = builder.CreateString(args.at(4).c_str(), args.at(4).size());
-        auto promote_share = builder.CreateString(args.at(5).c_str(), args.at(5).size());
-        auto link_bio = builder.CreateString(args.at(6).c_str(), args.at(6).size());
-        auto is_video = args.at(7) == "1";
-        auto header = builder.CreateString(args.at(8).c_str(), args.at(8).size());
-        auto user = builder.CreateString(args.at(9).c_str(), args.at(9).size());
-
-        flatbuffers::Offset<IGTask> ig_task =
-            CreateIGTask(builder, 96, file_info, time, description, hashtags,
-                         requested_by, requested_by_phrase, promote_share,
-                         link_bio, is_video, 16, header, user);
-
-        builder.Finish(ig_task);
-
-        uint8_t* encoded_message_buffer = builder.GetBufferPointer();
-        uint32_t size = builder.GetSize();
-
-        uint8_t send_buffer[MAX_PACKET_SIZE];
-        memset(send_buffer, 0, MAX_PACKET_SIZE);
-        send_buffer[0] = (size >> 24) & 0xFF;
-        send_buffer[1] = (size >> 16) & 0xFF;
-        send_buffer[2] = (size >> 8) & 0xFF;
-        send_buffer[3] = size & 0xFF;
-        send_buffer[4] = (TaskCode::IGTASKBYTE & 0xFF);
-
-        std::memcpy(send_buffer + 5, encoded_message_buffer, size);
-        qDebug() << "Ready to send:";
-        std::string message_to_send{};
-        for (unsigned int i = 0; i < (size + 5); i++) {
-            message_to_send += (char)*(send_buffer + i);
-            qDebug() << (char)*(send_buffer + i);
-        }
-        qDebug() << "Final size: " << (size + 5);
-        // Send start operation
-        ::send(m_client_socket_fd, send_buffer, size + 5, 0);
-        builder.Clear();
-        sent_files.clear();
-        m_task.clear();
-        if (!m_task_queue.isEmpty()) {
-          auto task = m_task_queue.dequeue();
-          if (!task.files.empty() && !outgoing_files.empty()) {
-            qDebug() << "There are still outgoing files left over from last "
-                        "task which were never sent. They are being deleted";
-            outgoing_files.clear();
-          }
-          // We simply need to send files. Once the last file is sent, Client
-          // will check the value of m_task and send it to Server.
-          m_task = task.args;
-          sendFiles(task.files);
-        }
-    }
-}
-
-/**
- * @brief Client::sendTaskEncoded
- * @param [in] {TaskType}                 type The type of task
- * @param [in] {std::vector<std::string>} args The task arguments
+ * @param [in] {Scheduler::Task*} task The task arguments
  */
 void Client::sendTaskEncoded(Scheduler::Task* task) {
   if (task->getType() == Scheduler::TaskType::INSTAGRAM) {
-    auto file_info = builder.CreateString(getTaskFileInfo(sent_files));
-    auto time =
-        builder.CreateString(std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("datetime")).constData());
-    auto description = builder.CreateString(
-        std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("description")).constData());
-    auto hashtags =
-        builder.CreateString(std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("hashtags")).constData());
-    auto requested_by = builder.CreateString(
-        std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("requested_by")).constData());
-    auto requested_by_phrase = builder.CreateString(
-        std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("requested_by_phrase")).constData());
-    auto promote_share = builder.CreateString(
-        std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("promote_share")).constData());
-    auto link_bio = builder.CreateString(
-        std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("link_in_bio")).constData());
-    auto is_video = std::get<Scheduler::VariantIndex::BOOLEAN>(task->getTaskArgument("is_video"));
-    auto header =
-        builder.CreateString(std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("header")).constData());
-    auto user =
-        builder.CreateString(std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("user")).constData());
-
     flatbuffers::Offset<IGTask> ig_task =
-        CreateIGTask(builder, 96, file_info, time, description, hashtags, requested_by, requested_by_phrase,
-                     promote_share, link_bio, is_video, 16, header, user);
-
+        CreateIGTask(
+            builder,
+            96,
+            builder.CreateString(getTaskFileInfo(sent_files)),
+            builder.CreateString(
+                std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("datetime")).constData()),
+            builder.CreateString(
+                std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("description")).constData()),
+            builder.CreateString(
+                std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("hashtags")).constData()),
+            builder.CreateString(
+                std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("requested_by_phrase")).constData()),
+            builder.CreateString(
+                std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("requested_by_phrase")).constData()),
+            builder.CreateString(
+                std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("promote_share")).constData()),
+            builder.CreateString(
+                std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("link_in_bio")).constData()),
+            std::get<Scheduler::VariantIndex::BOOLEAN>(task->getTaskArgument("is_video")),
+            std::get<Scheduler::VariantIndex::INTEGER>(task->getTaskArgument("mask")),
+            builder.CreateString(
+                std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("header")).constData()),
+            builder.CreateString(
+                std::get<Scheduler::VariantIndex::QSTRING>(task->getTaskArgument("user")).constData()));
     builder.Finish(ig_task);
 
     uint8_t* encoded_message_buffer = builder.GetBufferPointer();
     uint32_t size = builder.GetSize();
-
     uint8_t send_buffer[MAX_PACKET_SIZE];
+
     memset(send_buffer, 0, MAX_PACKET_SIZE);
+
     send_buffer[0] = (size >> 24) & 0xFF;
     send_buffer[1] = (size >> 16) & 0xFF;
     send_buffer[2] = (size >> 8) & 0xFF;
@@ -349,26 +280,23 @@ void Client::sendTaskEncoded(Scheduler::Task* task) {
     std::string message_to_send{};
     for (unsigned int i = 0; i < (size + 5); i++) {
       message_to_send += (char)*(send_buffer + i);
-      qDebug() << (char)*(send_buffer + i);
     }
     qDebug() << "Final size: " << (size + 5);
     // Send start operation
     ::send(m_client_socket_fd, send_buffer, size + 5, 0);
+    // Cleanup and process queue
     builder.Clear();
     sent_files.clear();
-    m_task.clear();
+    m_outbound_task = nullptr;
     if (!m_task_queue.isEmpty()) {
-      auto task = m_task_queue.dequeue();
+      m_outbound_task = m_task_queue.dequeue();
       // TODO work from here
-      if (!task.files.empty() && !outgoing_files.empty()) {
+      if (m_outbound_task->hasFiles() && !outgoing_files.empty()) {
         qDebug() << "There are still outgoing files left over from last "
                     "task which were never sent. They are being deleted";
         outgoing_files.clear();
       }
-      // We simply need to send files. Once the last file is sent, Client
-      // will check the value of m_task and send it to Server.
-      m_task = task.args;
-      sendFiles(task.files);
+      sendFiles(m_outbound_task);
     }
   }
 }
@@ -530,24 +458,17 @@ void Client::execute() {
  * @param [in] {std::vector<std::string>} task_args The task arguments
  * @param [in] {bool}                     file_pending A boolean indicating whether there are files being sent for this task
  */
-void Client::scheduleTask(Scheduler::Task* task, bool file_pending) {
-  m_task_queue.enqueue(*task);
-  if (file_pending) {
-    // Will this be handled automatically?
-    // Previously, we would sometimes have an outgoing task with nothing but files, and would then be providing the
-    // arguments for it later. For this reason, we would update the task, which would be in the task queue
-    //    if (m_task.empty()) {
-    //      m_task = task_args;
-    //    } else {
-    //      if (!m_task_queue.empty() && m_task_queue.front().args.empty()) {
-    //        m_task_queue.front().args.assign(task_args.begin(), task_args.end());
-    //      } else {
-    //        qDebug() << "Could not identify the queued task for updating";
-    //      }
-    //    }
+void Client::scheduleTask(Scheduler::Task* task) {
+  if (m_outbound_task == nullptr) {
+    m_outbound_task = std::move(task);
+    if (m_outbound_task->hasFiles()) {
+      sendFiles(m_outbound_task);
+    } else {
+      qDebug() << "Requesting a task to be scheduled";
+      sendTaskEncoded(m_outbound_task);
+    }
   } else {
-    qDebug() << "Requesting a task to be scheduled";
-    sendTaskEncoded(task);
+    m_task_queue.enqueue(task);
   }
 }
 
@@ -566,7 +487,7 @@ void Client::sendFiles(Scheduler::Task* task) {
   } else {
     // TODO: place in queue and check queue after we finish scheduling the
     // task associated with the outgoing files
-    m_task_queue.enqueue(task->getFiles());
+    m_task_queue.enqueue(task);
     qDebug() << "Still attempting to send a different file";
   }
 }

+ 23 - 0
src/instagram_task.cpp

@@ -82,6 +82,21 @@ void InstagramTask::setArgument(QString name, TypeVariant value) {
   }
 }
 
+/**
+ * @brief InstagramTask::setArgument
+ * @param name
+ * @param file
+ */
+void InstagramTask::setArgument(QString name, Scheduler::KFileData file) {
+  TaskIterator it =
+      std::find_if(m_arguments.begin(), m_arguments.end(), [name](auto argument) { return argument.text() == name; });
+  if (it != m_arguments.end() && it->get()->getTypeIndex() == Scheduler::VariantIndex::FILEVEC) {
+    it->get()->insert(file);
+  } else {
+    // Could not add file to container
+  }
+}
+
 /**
  * @brief InstagramTask::getTaskArgument
  * @param name
@@ -152,6 +167,14 @@ void InstagramTask::clear() {
   }
 }
 
+/**
+ * @brief InstagramTask::hasFiles
+ * @return
+ */
+bool InstagramTask::hasFiles() {
+  return !files.empty();
+}
+
 /**
  * @destructor
  */

+ 3 - 9
src/mainwindow.cpp

@@ -207,20 +207,14 @@ void MainWindow::connectClient() {
     }
   });
 
-  QObject::connect(
-      arg_ui, &ArgDialog::uploadFiles, this,
-      [this](QVector<KFileData> files) { q_client->sendFiles(files); });
-
   QObject::connect(
       arg_ui, &ArgDialog::taskRequestReady, this,
-      [this](Task task, bool file_pending) {
+      [this](Task* task) {
         auto mask = q_client->getSelectedApp();
         if (mask > -1) {
-          if (q_client->getAppName(mask) == "Instagram") {
             qDebug() << "Scheduling a task";
-            task.args.push_back(std::to_string(mask));
-            q_client->scheduleTask(task.args, file_pending);
-          }
+            task->setArgument("mask", mask);
+            q_client->scheduleTask(task);
         }
       });