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.

270 lines
7.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #ifndef JUCER_AUTOUPDATER_H_INCLUDED
  18. #define JUCER_AUTOUPDATER_H_INCLUDED
  19. //==============================================================================
  20. class LatestVersionChecker : private Thread,
  21. private Timer
  22. {
  23. public:
  24. LatestVersionChecker() : Thread ("Updater"),
  25. hasAttemptedToReadWebsite (false)
  26. {
  27. startTimer (2000);
  28. }
  29. ~LatestVersionChecker()
  30. {
  31. stopThread (20000);
  32. }
  33. static URL getLatestVersionURL()
  34. {
  35. return URL ("http://www.juce.com/juce/updates/updatelist.php");
  36. }
  37. void checkForNewVersion()
  38. {
  39. hasAttemptedToReadWebsite = true;
  40. {
  41. const ScopedPointer<InputStream> in (getLatestVersionURL().createInputStream (false));
  42. if (in == nullptr || threadShouldExit())
  43. return; // can't connect: fail silently.
  44. jsonReply = JSON::parse (in->readEntireStreamAsString());
  45. }
  46. if (threadShouldExit())
  47. return;
  48. if (jsonReply.isArray() || jsonReply.isObject())
  49. startTimer (100);
  50. }
  51. void downloadNewVersion (URL url)
  52. {
  53. const ScopedPointer<InputStream> in (getLatestVersionURL().createInputStream (false));
  54. if (in == nullptr || threadShouldExit())
  55. return; // can't connect: fail silently.
  56. jsonReply = JSON::parse (in->readEntireStreamAsString());
  57. }
  58. void processResult (var reply)
  59. {
  60. DBG (JSON::toString (reply));
  61. if (reply.isArray())
  62. {
  63. askUserAboutNewVersion (VersionInfo (reply[0]));
  64. }
  65. else if (reply.isObject())
  66. {
  67. // In the far-distant future, this may be contacting a defunct
  68. // URL, so hopefully the website will contain a helpful message
  69. // for the user..
  70. String message = reply.getProperty ("message", var()).toString();
  71. if (message.isNotEmpty())
  72. {
  73. AlertWindow::showMessageBox (AlertWindow::WarningIcon,
  74. TRANS("JUCE Updater"),
  75. message);
  76. }
  77. }
  78. }
  79. struct VersionInfo
  80. {
  81. VersionInfo (var v)
  82. {
  83. version = v.getProperty ("version", var()).toString().trim();
  84. url = v.getProperty (
  85. #if JUCE_MAC
  86. "url_osx",
  87. #elif JUCE_WINDOWS
  88. "url_win",
  89. #elif JUCE_LINUX
  90. "url_linux",
  91. #endif
  92. var()).toString();
  93. }
  94. String version;
  95. URL url;
  96. };
  97. void askUserAboutNewVersion (const VersionInfo& info)
  98. {
  99. if (info.version != SystemStats::getJUCEVersion()
  100. && info.version.containsChar ('.')
  101. && info.version.length() > 2)
  102. {
  103. DBG (info.version);
  104. DBG (info.url.toString (true));
  105. if (isRunningFromZipFolder())
  106. {
  107. JUCE_COMPILER_WARNING("todo")
  108. // startDownload (info.url);
  109. }
  110. else
  111. {
  112. JUCE_COMPILER_WARNING("todo")
  113. // startDownload (info.url);
  114. }
  115. }
  116. }
  117. void startDownload (URL url)
  118. {
  119. jassert (! isThreadRunning());
  120. newVersionToDownload = url;
  121. startThread (3);
  122. }
  123. bool isRunningFromZipFolder() const
  124. {
  125. File appParentFolder (File::getSpecialLocation (File::currentApplicationFile));
  126. return appParentFolder.getChildFile ("modules").isDirectory()
  127. && appParentFolder.getChildFile ("extras").isDirectory()
  128. && appParentFolder.getChildFile ("examples").isDirectory()
  129. && ! appParentFolder.getChildFile (".git").isDirectory();
  130. }
  131. private:
  132. void timerCallback() override
  133. {
  134. stopTimer();
  135. if (hasAttemptedToReadWebsite)
  136. processResult (jsonReply);
  137. else
  138. startThread (3);
  139. }
  140. void run() override
  141. {
  142. if (newVersionToDownload.isEmpty())
  143. checkForNewVersion();
  144. else
  145. downloadNewVersion (newVersionToDownload);
  146. }
  147. var jsonReply;
  148. bool hasAttemptedToReadWebsite;
  149. URL newVersionToDownload;
  150. //==============================================================================
  151. class DownloadNewVersionThread : public ThreadWithProgressWindow
  152. {
  153. public:
  154. DownloadNewVersionThread (URL u)
  155. : ThreadWithProgressWindow ("Downloading New Version", true, true),
  156. result (Result::ok()),
  157. url (u)
  158. {
  159. }
  160. static void update (URL u)
  161. {
  162. DownloadNewVersionThread d (u);
  163. if (d.runThread())
  164. {
  165. if (d.result.failed())
  166. {
  167. AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
  168. "Installation Failed",
  169. d.result.getErrorMessage());
  170. }
  171. else
  172. {
  173. JUCE_COMPILER_WARNING("todo")
  174. }
  175. }
  176. }
  177. void run() override
  178. {
  179. MemoryBlock zipData;
  180. result = download (zipData);
  181. if (result.wasOk() && ! threadShouldExit())
  182. result = unzip (zipData);
  183. }
  184. Result download (MemoryBlock& dest)
  185. {
  186. setStatusMessage ("Downloading...");
  187. const ScopedPointer<InputStream> in (url.createInputStream (false, nullptr, nullptr, String::empty, 10000));
  188. if (in != nullptr && in->readIntoMemoryBlock (dest))
  189. return Result::ok();
  190. return Result::fail ("Failed to download from: " + url.toString (false));
  191. }
  192. Result unzip (const MemoryBlock& data)
  193. {
  194. setStatusMessage ("Installing...");
  195. MemoryInputStream input (data, false);
  196. ZipFile zip (input);
  197. if (zip.getNumEntries() == 0)
  198. return Result::fail ("The downloaded file wasn't a valid JUCE file!");
  199. // if (! m.getFolder().deleteRecursively())
  200. // return Result::fail ("Couldn't delete the existing folder:\n" + m.getFolder().getFullPathName());
  201. //
  202. // return zip.uncompressTo (m.getFolder().getParentDirectory(), true);
  203. }
  204. Result result;
  205. URL url;
  206. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DownloadNewVersionThread)
  207. };
  208. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LatestVersionChecker)
  209. };
  210. #endif // JUCER_AUTOUPDATER_H_INCLUDED