The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

225 lines
8.0KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. #pragma once
  19. #include "jucer_LicenseState.h"
  20. #include "jucer_LicenseQueryThread.h"
  21. //==============================================================================
  22. class LicenseController : private Timer
  23. {
  24. public:
  25. LicenseController()
  26. {
  27. checkLicense();
  28. }
  29. //==============================================================================
  30. static LicenseState getGPLState()
  31. {
  32. return { LicenseState::Type::gpl, projucerMajorVersion, {}, {} };
  33. }
  34. LicenseState getCurrentState() const noexcept
  35. {
  36. return state;
  37. }
  38. void setState (const LicenseState& newState)
  39. {
  40. if (state != newState)
  41. {
  42. state = newState;
  43. licenseStateToSettings (state, getGlobalProperties());
  44. stateListeners.call ([] (LicenseStateListener& l) { l.licenseStateChanged(); });
  45. }
  46. }
  47. void resetState()
  48. {
  49. setState ({});
  50. }
  51. void signIn (const String& email, const String& password,
  52. std::function<void (const String&)> completionCallback)
  53. {
  54. licenseQueryThread.doSignIn (email, password,
  55. [this, completionCallback] (LicenseQueryThread::ErrorMessageAndType error,
  56. LicenseState newState)
  57. {
  58. completionCallback (error.first);
  59. setState (newState);
  60. });
  61. }
  62. void cancelSignIn()
  63. {
  64. licenseQueryThread.cancelRunningJobs();
  65. }
  66. //==============================================================================
  67. struct LicenseStateListener
  68. {
  69. virtual ~LicenseStateListener() = default;
  70. virtual void licenseStateChanged() = 0;
  71. };
  72. void addListener (LicenseStateListener* listenerToAdd)
  73. {
  74. stateListeners.add (listenerToAdd);
  75. }
  76. void removeListener (LicenseStateListener* listenerToRemove)
  77. {
  78. stateListeners.remove (listenerToRemove);
  79. }
  80. private:
  81. //==============================================================================
  82. static const char* getLicenseStateValue (LicenseState::Type type)
  83. {
  84. switch (type)
  85. {
  86. case LicenseState::Type::gpl: return "GPL";
  87. case LicenseState::Type::personal: return "personal";
  88. case LicenseState::Type::educational: return "edu";
  89. case LicenseState::Type::indie: return "indie";
  90. case LicenseState::Type::pro: return "pro";
  91. case LicenseState::Type::none:
  92. default: break;
  93. }
  94. return nullptr;
  95. }
  96. static LicenseState::Type getLicenseTypeFromValue (const String& d)
  97. {
  98. if (d == getLicenseStateValue (LicenseState::Type::gpl)) return LicenseState::Type::gpl;
  99. if (d == getLicenseStateValue (LicenseState::Type::personal)) return LicenseState::Type::personal;
  100. if (d == getLicenseStateValue (LicenseState::Type::educational)) return LicenseState::Type::educational;
  101. if (d == getLicenseStateValue (LicenseState::Type::indie)) return LicenseState::Type::indie;
  102. if (d == getLicenseStateValue (LicenseState::Type::pro)) return LicenseState::Type::pro;
  103. return LicenseState::Type::none;
  104. }
  105. static LicenseState licenseStateFromSettings (PropertiesFile& props)
  106. {
  107. if (auto licenseXml = props.getXmlValue ("license"))
  108. {
  109. // this is here for backwards compatibility with old-style settings files using XML text elements
  110. if (licenseXml->getChildElementAllSubText ("type", {}).isNotEmpty())
  111. {
  112. auto stateFromOldSettings = [&licenseXml]() -> LicenseState
  113. {
  114. return { getLicenseTypeFromValue (licenseXml->getChildElementAllSubText ("type", {})),
  115. licenseXml->getChildElementAllSubText ("version", "-1").getIntValue(),
  116. licenseXml->getChildElementAllSubText ("username", {}),
  117. licenseXml->getChildElementAllSubText ("authToken", {}) };
  118. }();
  119. licenseStateToSettings (stateFromOldSettings, props);
  120. return stateFromOldSettings;
  121. }
  122. return { getLicenseTypeFromValue (licenseXml->getStringAttribute ("type", {})),
  123. licenseXml->getIntAttribute ("version", -1),
  124. licenseXml->getStringAttribute ("username", {}),
  125. licenseXml->getStringAttribute ("authToken", {}) };
  126. }
  127. return {};
  128. }
  129. static void licenseStateToSettings (const LicenseState& state, PropertiesFile& props)
  130. {
  131. props.removeValue ("license");
  132. if (state.isSignedIn())
  133. {
  134. XmlElement licenseXml ("license");
  135. if (auto* typeString = getLicenseStateValue (state.type))
  136. licenseXml.setAttribute ("type", typeString);
  137. licenseXml.setAttribute ("version", state.version);
  138. licenseXml.setAttribute ("username", state.username);
  139. licenseXml.setAttribute ("authToken", state.authToken);
  140. props.setValue ("license", &licenseXml);
  141. }
  142. props.saveIfNeeded();
  143. }
  144. //==============================================================================
  145. void checkLicense()
  146. {
  147. if (state.authToken.isNotEmpty() && ! state.isGPL())
  148. {
  149. auto completionCallback = [this] (LicenseQueryThread::ErrorMessageAndType error,
  150. LicenseState updatedState)
  151. {
  152. if (error == LicenseQueryThread::ErrorMessageAndType())
  153. {
  154. setState (updatedState);
  155. }
  156. else if ((error.second == LicenseQueryThread::ErrorType::busy
  157. || error.second == LicenseQueryThread::ErrorType::cancelled
  158. || error.second == LicenseQueryThread::ErrorType::connectionError)
  159. && ! hasRetriedLicenseCheck)
  160. {
  161. hasRetriedLicenseCheck = true;
  162. startTimer (10000);
  163. }
  164. };
  165. licenseQueryThread.checkLicenseValidity (state, std::move (completionCallback));
  166. }
  167. }
  168. void timerCallback() override
  169. {
  170. stopTimer();
  171. checkLicense();
  172. }
  173. //==============================================================================
  174. #if JUCER_ENABLE_GPL_MODE
  175. LicenseState state = getGPLState();
  176. #else
  177. LicenseState state = licenseStateFromSettings (getGlobalProperties());
  178. #endif
  179. ListenerList<LicenseStateListener> stateListeners;
  180. LicenseQueryThread licenseQueryThread;
  181. bool hasRetriedLicenseCheck = false;
  182. //==============================================================================
  183. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LicenseController)
  184. };