Parcourir la source

partial refactor of Client to accommodate generic task

logicp il y a 4 ans
Parent
commit
997e05b0f3
6 fichiers modifiés avec 162 ajouts et 56 suppressions
  1. 16 14
      include/client/client.hpp
  2. 7 1
      include/task/instagram_task.hpp
  3. 20 5
      include/task/task.hpp
  4. 2 3
      src/argdialog.cpp
  5. 109 31
      src/client.cpp
  6. 8 2
      src/instagram_task.cpp

+ 16 - 14
include/client/client.hpp

@@ -1,22 +1,23 @@
 #ifndef CLIENT_HPP
 #define CLIENT_HPP
 
-#include <QDialog>
 #include <QComboBox>
-#include <QPushButton>
-#include <QMessageBox>
-#include <QLineEdit>
-#include <QUuid>
+#include <QDialog>
 #include <QLabel>
-#include <QString>
-#include <QVector>
+#include <QLineEdit>
+#include <QMessageBox>
+#include <QMetaType>
+#include <QPushButton>
 #include <QQueue>
+#include <QString>
 #include <QThread>
-#include <QMetaType>
-#include <thread>
+#include <QUuid>
+#include <QVector>
+#include <headers/util.hpp>
+#include <include/task/task.hpp>
 #include <string>
+#include <thread>
 #include <utility>
-#include <headers/util.hpp>
 
 static constexpr int MESSAGE_UPDATE_TYPE = 1;
 static constexpr int COMMANDS_UPDATE_TYPE = 2;
@@ -71,13 +72,13 @@ class Client : public QDialog {
   QString getAppName(int mask);
   int getSelectedApp();
   // Move this to private after moving responsibilities to Client
-  void scheduleTask(std::vector<std::string> task_args, bool file_pending);
+  void scheduleTask(Scheduler::Task* task, bool file_pending);
   MessageHandler createMessageHandler(std::function<void()> cb);
 
  public slots:
   void sendMessage(const QString& s);
   void setSelectedApp(std::vector<QString> app_names);
-  void sendFiles(QVector<KFileData> files);
+  void sendFiles(Scheduler::Task* task);
   void ping();
 
  signals:
@@ -88,6 +89,7 @@ class Client : public QDialog {
   void sendEncoded(std::string message);
   void sendFileEncoded(QByteArray bytes);
   void sendTaskEncoded(TaskType type, std::vector<std::string> args);
+  void sendTaskEncoded(Scheduler::Task* task);
   void processFileQueue();
   void handleMessages();
   void sendPackets(uint8_t* data, int size);
@@ -100,8 +102,8 @@ class Client : public QDialog {
   CommandMap m_commands;
   CommandArgMap m_command_arg_map;
   std::vector<int> selected_commands;
-  QQueue<KFileData> outgoing_files;
+  QQueue<Scheduler::KFileData> outgoing_files;
   std::vector<SentFile> sent_files;
-  TaskQueue m_task_queue;
+  Scheduler::TaskQueue m_task_queue;
 };
 #endif // CLIENT_HPP

+ 7 - 1
include/task/instagram_task.hpp

@@ -4,6 +4,7 @@
 #include <include/task/task.hpp>
 #include <type_traits>
 
+namespace Scheduler {
 namespace Args {
 const QString HEADER_TYPE = "header";
 const QString DESCRIPTION_TYPE = "description";
@@ -12,13 +13,17 @@ const QString PROMOTE_TYPE = "promote/share";
 const QString LINK_BIO_TYPE = "link/bio";
 const QString REQUESTED_BY_TYPE = "requested by";
 }  // namespace Args
-
+}  // namespace Scheduler
 class InstagramTask : public Scheduler::Task {
  public:
+  InstagramTask(Scheduler::KFileData);
+  InstagramTask(QVector<Scheduler::KFileData>);
   virtual void defineTaskArguments() override;
   virtual const Scheduler::TaskArguments getTaskArguments() override;
   virtual Scheduler::TypeVariant getTaskArgument(QString name) override;
   virtual Scheduler::ArgumentValues getArgumentValues() override;
+  virtual const QVector<Scheduler::KFileData> getFiles() override;
+  virtual Scheduler::TaskType getType() override;
   virtual void setArgument(QString name, Scheduler::TypeVariant arg) override;
   virtual bool isReady() override;
   virtual void clear() override;
@@ -27,6 +32,7 @@ class InstagramTask : public Scheduler::Task {
 
  private:
   Scheduler::TaskArguments m_arguments;
+  QVector<Scheduler::KFileData> files;
 };
 
 #endif  // __INSTAGRAM_TASK_HPP

+ 20 - 5
include/task/task.hpp

@@ -10,6 +10,8 @@
 
 namespace Scheduler {
 
+enum TaskType { INSTAGRAM = 1, OTHER = 2 };
+
 /**
  * Files
  */
@@ -64,7 +66,7 @@ using ArgumentType = const char*;
 using TypeVariant = std::variant<bool, int, QString, QVector<QString>, std::vector<KFileData>>;
 using TaskIterator = std::vector<std::unique_ptr<TaskArgumentBase>>::iterator;
 using TaskArguments = std::vector<std::unique_ptr<TaskArgumentBase>>;
-using TaskQueue = QQueue<Task>;
+using TaskQueue = QQueue<Task*>;
 using ArgumentValues = QVector<const QString>;
 
 /**
@@ -115,15 +117,23 @@ class TaskArgument : TaskArgumentBase {
 
   virtual const QString getStringValue() override {
     if (isIndex(value.index(), VariantIndex::QSTRING)) {
-      return value;
+      return std::get<VariantIndex::QSTRING>(value);
     } else if (isIndex(value.index(), VariantIndex::BOOLEAN)) {
-      return QString::number(value);
+      return QString::number(std::get<VariantIndex::BOOLEAN>(value));
     } else if (isIndex(value.index(), VariantIndex::INTEGER)) {
-      return QString::number(value);
+      return QString::number(std::get<VariantIndex::INTEGER>(value));
     }
   }
 
-  virtual TypeVariant getValue() override { return std::get<value.index()>(value); }
+  virtual TypeVariant getValue() override {
+    if (isIndex(value.index(), VariantIndex::QSTRING)) {
+      return std::get<VariantIndex::QSTRING>(value);
+    } else if (isIndex(value.index(), VariantIndex::BOOLEAN)) {
+      return std::get<VariantIndex::BOOLEAN>(value);
+    } else if (isIndex(value.index(), VariantIndex::INTEGER)) {
+      return std::get<VariantIndex::INTEGER>(value);
+    }
+  }
 
   virtual void clear() override {
     if (isIndex(value.index(), VariantIndex::STRVEC)) {
@@ -154,12 +164,17 @@ class TaskArgument : TaskArgumentBase {
  */
 class Task {
  public:
+  Task(){};
+  Task(KFileData);
+  Task(QVector<KFileData>);
   virtual void setArgument(QString name, TypeVariant arg) = 0;
   virtual const TaskArguments getTaskArguments() = 0;
   virtual TypeVariant getTaskArgument(QString name) = 0;
   virtual ArgumentValues getArgumentValues() = 0;
+  virtual TaskType getType() = 0;
   virtual void defineTaskArguments() = 0;
   virtual void setDefaultValues() = 0;
+  virtual const QVector<KFileData> getFiles() = 0;
   virtual bool isReady() = 0;
   virtual void clear() = 0;
   virtual ~Task(){};

+ 2 - 3
src/argdialog.cpp

@@ -108,9 +108,8 @@ ArgDialog::ArgDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ArgDialog),
                          for (const auto &kfile : m_ig_post.files) {
                            QFile file(kfile.path);
                            if (file.open(QIODevice::ReadOnly)) {
-                             k_file_v.push_back(KFileData{.type = kfile.type,
-                                                          .name = kfile.name,
-                                                          .bytes = file.readAll()});
+                             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"));
                            }

+ 109 - 31
src/client.cpp

@@ -108,9 +108,9 @@ void Client::handleMessages() {
 }
 
 void Client::processFileQueue() {
-    KFileData outgoing_file = outgoing_files.dequeue();
-    sendFileEncoded(outgoing_file.bytes);
-    sent_files.push_back(SentFile{.name = outgoing_file.name, .type = outgoing_file.type });
+  Scheduler::KFileData outgoing_file = outgoing_files.dequeue();
+  sendFileEncoded(outgoing_file.bytes);
+  sent_files.push_back(SentFile{.name = outgoing_file.name, .type = outgoing_file.type});
 }
 /**
  * @brief Client::start
@@ -299,6 +299,80 @@ void Client::sendTaskEncoded(TaskType type, std::vector<std::string> args) {
     }
 }
 
+/**
+ * @brief Client::sendTaskEncoded
+ * @param [in] {TaskType}                 type The type of task
+ * @param [in] {std::vector<std::string>} args 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);
+
+    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();
+      // TODO work from here
+      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::sendPackets
  * @param [in] {uint8_t*} data A pointer to a buffer of bytes
@@ -456,39 +530,43 @@ 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(std::vector<std::string> task_args, bool file_pending) {
-    if (file_pending) {
-      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";
-        }
-      }
-    } else {
-        qDebug() << "Requesting a task to be scheduled";
-        sendTaskEncoded(TaskType::INSTAGRAM, task_args);
-    }
+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";
+    //      }
+    //    }
+  } else {
+    qDebug() << "Requesting a task to be scheduled";
+    sendTaskEncoded(task);
+  }
 }
 
 /**
  * @brief Client::sendFiles
  * @param [in] {QVector<const QByteArray} files The files to be sent
  */
-void Client::sendFiles(QVector<KFileData> files) {
-    if (outgoing_files.isEmpty()) {
-      file_was_sent = false;
-      for (const auto& file : files) {
-        outgoing_files.enqueue(std::move(file));
-        }
-        std::string send_file_operation = createOperation("FileUpload", {});
-        sendEncoded(send_file_operation);
-    } else {
-      // TODO: place in queue and check queue after we finish scheduling the
-      // task associated with the outgoing files
-      m_task_queue.enqueue(Task{.files = files});
-      qDebug() << "Still attempting to send a different file";
+void Client::sendFiles(Scheduler::Task* task) {
+  if (outgoing_files.isEmpty()) {
+    file_was_sent = false;
+    for (const auto& file : task->getFiles()) {
+      outgoing_files.enqueue(std::move(file));
     }
+    std::string send_file_operation = createOperation("FileUpload", {});
+    sendEncoded(send_file_operation);
+  } 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());
+    qDebug() << "Still attempting to send a different file";
+  }
 }

+ 8 - 2
src/instagram_task.cpp

@@ -16,6 +16,9 @@ static const uint8_t USER = 9;
 static const uint8_t IS_VIDEO = 10;
 }  // namespace TaskIndex
 
+InstagramTask::InstagramTask(KFileData k_file) : files({k_file}) {}
+InstagramTask::InstagramTask(QVector<KFileData> k_files) : files(k_files) {}
+
 void InstagramTask::defineTaskArguments() {
   std::vector<std::unique_ptr<TaskArgumentBase>> args{};
   args.emplace_back(std::make_unique<TaskArgument<QString>>("header", Type::TEXT, QString{}));
@@ -23,8 +26,7 @@ void InstagramTask::defineTaskArguments() {
   args.emplace_back(std::make_unique<TaskArgument<QString>>("datetime", Type::DATETIME, QString{}));
   args.emplace_back(std::make_unique<TaskArgument<QString>>("promote_share", Type::TEXT, QString{}));
   args.emplace_back(std::make_unique<TaskArgument<QString>>("link_in_bio", Type::TEXT, QString{}));
-  args.emplace_back(
-      std::make_unique<TaskArgument<std::vector<QString>>>("hashtags", Type::STRINGVECTOR, std::vector<QString>{}));
+  args.emplace_back(std::make_unique<TaskArgument<QString>>("hashtags", Type::TEXT, QString{}));
   args.emplace_back(
       std::make_unique<TaskArgument<std::vector<QString>>>("requested_by", Type::STRINGVECTOR, std::vector<QString>{}));
   args.emplace_back(std::make_unique<TaskArgument<QString>>("requested_by_phrase", Type::TEXT, QString{}));
@@ -73,6 +75,8 @@ ArgumentValues InstagramTask::getArgumentValues() {
   return values;
 }
 
+const QVector<KFileData> InstagramTask::getFiles() { return files; }
+
 void InstagramTask::setDefaultValues() {
   m_arguments.at(TaskIndex::HEADER)->setValue("Learn to speak like native Korean speakers 🙆‍♀️🇰🇷");
   m_arguments.at(TaskIndex::PROMOTE_SHARE)
@@ -82,6 +86,8 @@ void InstagramTask::setDefaultValues() {
   m_arguments.at(TaskIndex::REQUESTED_BY_PHRASE)->setValue("The phrase was requested by ");
 }
 
+Scheduler::TaskType getType() { return Scheduler::TaskType::INSTAGRAM; };
+
 void InstagramTask::clear() {
   for (const auto& argument : m_arguments) {
     argument->clear();