summaryrefslogtreecommitdiff
path: root/src/github.h
blob: 0085fd5acb1f38c82564ec54177f4f4070466ae2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#pragma once

#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkAccessManager>
#include <QNetworkCookieJar>
#include <QNetworkReply>
#include <QTimer>
#include <functional>

class GitHubException : public std::exception
{
public:
  GitHubException(const QJsonObject& errorObj) : std::exception()
  {
    initMessage(errorObj);
  }

  virtual ~GitHubException() throw() override {}

  virtual const char* what() const throw() { return m_Message.constData(); }

private:
  void initMessage(const QJsonObject& obj)
  {
    if (obj.contains("http_status")) {
      m_Message = QString("HTTP Status %1: %2")
                      .arg(obj.value("http_status").toInt())
                      .arg(obj.value("reason").toString())
                      .toUtf8();
    } else if (obj.contains("parse_error")) {
      m_Message = QString("Parsing failed: %1")
                      .arg(obj.value("parse_error").toString())
                      .toUtf8();
    } else if (obj.contains("network_error")) {
      m_Message = QString("Network failed: %1")
                      .arg(obj.value("network_error").toString())
                      .toUtf8();
    } else {
      m_Message = "Unknown error";
    }
  }

  QByteArray m_Message;
};

class GitHub : public QObject
{

  Q_OBJECT

public:
  enum class Method
  {
    GET,
    POST
  };

  struct Repository
  {
    Repository(const QString& owner, const QString& project)
        : owner(owner), project(project)
    {}
    QString owner;
    QString project;
  };

public:
  GitHub(const char* clientId = nullptr);
  ~GitHub();

  QJsonArray releases(const Repository& repo);
  void releases(const Repository& repo,
                const std::function<void(const QJsonArray&)>& callback);

private:
  QJsonDocument request(Method method, const QString& path, const QByteArray& data,
                        bool relative);
  void request(Method method, const QString& path, const QByteArray& data,
               const std::function<void(const QJsonDocument&)>& callback,
               bool relative);

  QJsonDocument handleReply(QNetworkReply* reply);
  QNetworkReply* genReply(Method method, const QString& path, const QByteArray& data,
                          bool relative);

private:
  struct Request
  {
    Method method = Method::GET;
    QByteArray data;
    std::function<void(const QJsonDocument&)> callback;
    QTimer* timer        = nullptr;
    QNetworkReply* reply = nullptr;
  };

  QNetworkAccessManager* m_AccessManager;

  // remember the replies that are in flight and delete them in the destructor
  std::vector<QNetworkReply*> m_replies;

  void onFinished(const Request& req);
  void onError(const Request& req, QNetworkReply::NetworkError error);
  void onTimeout(const Request& req);

  void deleteReply(QNetworkReply* reply);
};