Enigma  3.2.0
A Simple, Reliable and Efficient Encryption Tool
CheckForUpdates.hpp
Go to the documentation of this file.
1 #pragma once
2 #ifndef ENIGMA_NETWORKING_CHECK_FOR_UPDATES_H
3 #define ENIGMA_NETWORKING_CHECK_FOR_UPDATES_H
4 
5 #include <Core/Core.hpp>
6 #include <Core/Version.hpp>
7 #include <Logger/Logger.hpp>
8 
9 #include <memory>
10 
11 #pragma warning(push, 0)
13 #include <cpr/cpr.h>
15 #include <nlohmann/json.hpp>
16 #pragma warning(pop)
17 
18 
20 class CheckForUpdates final {
21  ENIGMA_STATIC_CLASS(CheckForUpdates);
22 
23  public:
25  struct Version {
26  std::uint16_t major;
27  std::uint16_t minor;
28  std::uint16_t patch;
29 
30  Version() : major(0), minor(0), patch(0) {}
31  Version(const std::string& tag_name) {
32  Parse(tag_name);
33  }
34 
35  void Parse(const std::string& tag_name) {
36  const std::vector<std::string> parts = StringUtils::Split(tag_name, '.');
37  ENIGMA_ASSERT_OR_THROW(parts.size() == 3, fmt::format("Version tag_name is malformed, expected major.minor.patch (%d.%d.%d) but received {}", tag_name));
38 
39  // Convert string parts to std::uint16_t major minor patch
40  const auto stoui16 = [](const std::string& str) -> std::uint16_t {
41  std::uint16_t i{};
42  std::stringstream oss(str);
43  oss >> i;
44  return i;
45  };
46 
47  major = stoui16(parts[0]);
48  minor = stoui16(parts[1]);
49  patch = stoui16(parts[2]);
50  }
51 
52 
53  constexpr bool operator>(const Version& other) const noexcept {
54  if (major > other.major) return true;
55  if (major < other.major) return false;
56  // At this point, major == other.major
57  if (minor > other.minor) return true;
58  if (minor < other.minor) return false;
59  // At this point, minor == other.minor
60  return patch > other.patch;
61  }
62 
63  constexpr bool operator<(const Version& other) const noexcept {
64  if (major < other.major) return true;
65  if (major > other.major) return false;
66  // At this point, major == other.major
67  if (minor < other.minor) return true;
68  if (minor > other.minor) return false;
69  // At this point, minor == other.minor
70  return patch < other.patch;
71  }
72 
73  constexpr bool operator==(const Version& other) const noexcept {
74  return major == other.major && minor == other.minor && patch == other.patch;
75  }
76 
77  friend std::ostream& operator<<(std::ostream& os, const Version& v) noexcept {
78  return os << v.major << '.' << v.minor << '.' << v.patch;
79  }
80  };
81 
84  std::string name; // "name": "Enigma Release (Windows x64, Linux x64)",
85  std::string tag_name; // version e.g 1.0.0
86  std::string created_at; //"created_at": "2021-02-06T11:41:26Z",
87  std::string published_at; //"published_at" : "2021-02-06T12:16:37Z",
88  std::string body; // "body": "Enigma first stable release for Windows x64 and Linux x64 using:\r\n- Crypto++ v8.4.0\r\n- GLFW v3.3.2\r\n- ImGui v1.79\r\n- spdlog v1.8.0\r\n- and other libraries"
89  std::string tarball_url; // "tarball_url": "https://api.github.com/repos/BaderEddineOuaich/Enigma/tarball/v1.0.0",
90  std::string zipball_url; // "zipball_url" : "https://api.github.com/repos/BaderEddineOuaich/Enigma/zipball/v1.0.0",
91  Version version; // parsed comparable version
92 
93  LatestReleaseInfo() noexcept
94  : tag_name("<unknown>"),
95  name("<unknown>"),
96  created_at("<unknown>"),
97  published_at("<unknown>"),
98  body("<unknown>"),
99  tarball_url("<unknown>"),
100  zipball_url("<unknown>"),
101  version() {}
102 
103  ~LatestReleaseInfo() noexcept = default;
104 
105  static std::unique_ptr<LatestReleaseInfo> FromJson(const nlohmann::json& obj) {
106 #define CC1(a, b) a##b
107 #define CC(a, b) CC1(a, b)
108 #define ASSIGN_IF(var, field, json_type) \
109  if (!obj[field].is_null() && CC(obj[field].is_, json_type)()) \
110  (var) = obj[field].get<decltype(var)>();
111 
112  std::unique_ptr<LatestReleaseInfo> info = std::make_unique<LatestReleaseInfo>();
113  ASSIGN_IF(info->name, "name", string);
114  ASSIGN_IF(info->tag_name, "tag_name", string);
115  ASSIGN_IF(info->created_at, "created_at", string);
116  ASSIGN_IF(info->published_at, "published_at", string);
117  ASSIGN_IF(info->body, "body", string);
118  ASSIGN_IF(info->tarball_url, "tarball_url", string);
119  ASSIGN_IF(info->zipball_url, "zipball_url", string);
120 
121  info->version.Parse(info->tag_name); // parse version by tagname
122  return info;
123 
124 #undef ASSIGN_IF
125 #undef CC1
126 #undef CC
127  }
128 
129  std::string toString() noexcept {
130  std::ostringstream oss;
131  if (!name.empty())
132  oss << "name: " << name << " ";
133  if (!tag_name.empty())
134  oss << "tag name: " << tag_name << " ";
135  if (!created_at.empty())
136  oss << "created at: " << created_at << " ";
137  if (!published_at.empty())
138  oss << "published at: " << published_at << " ";
139  if (!body.empty())
140  oss << "body: " << body << " ";
141  if (!tarball_url.empty())
142  oss << "tarball_url: " << tarball_url << " ";
143  if (!zipball_url.empty())
144  oss << "zipball_url: " << zipball_url << " ";
145  return oss.str();
146  }
147  };
148 
149  public:
151  static std::unique_ptr<LatestReleaseInfo> GetLatestReleaseInfo() {
152  try {
153  cpr::Url url = Constants::Links::ENIGMA_GITHUB_API_LATEST_RELEASE;
154  cpr::Response response = cpr::Get(url);
155  if (response.status_code == cpr::status::HTTP_OK) {
156  nlohmann::json data = nlohmann::json::parse(response.text);
157  return LatestReleaseInfo::FromJson(data);
158  } else
159  ENIGMA_WARN("Failed to get latest release info with status code {0}", response.status_code);
160  } catch (const std::exception& e) {
161  ENIGMA_WARN("Failed to get latest release info with exception {0}", e.what());
162  }
163  return nullptr;
164  }
165 };
167 
168 
169 #endif // !ENIGMA_NETWORKING_CHECK_FOR_UPDATES_H
#define ASSIGN_IF(var, field, json_type)
#define ENIGMA_WARN(...)
Definition: Logger.hpp:42
#define NS_ENIGMA_BEGIN
Enable/Disable Assertions.
Definition: Macros.hpp:13
#define NS_ENIGMA_END
Definition: Macros.hpp:14
#define ENIGMA_ASSERT_OR_THROW(x, msg)
Definition: Macros.hpp:41
cpr: cURL c++ wrapper
static std::unique_ptr< LatestReleaseInfo > GetLatestReleaseInfo()
static std::vector< StringType > Split(const StringType &str, const typename std::string::value_type delimiter)
static std::unique_ptr< LatestReleaseInfo > FromJson(const nlohmann::json &obj)
~LatestReleaseInfo() noexcept=default
Version(const std::string &tag_name)
friend std::ostream & operator<<(std::ostream &os, const Version &v) noexcept
constexpr bool operator==(const Version &other) const noexcept
void Parse(const std::string &tag_name)
constexpr bool operator<(const Version &other) const noexcept
constexpr bool operator>(const Version &other) const noexcept