From 1df286d8a90987ad33fe3a01a7f5d4d652fa5d06 Mon Sep 17 00:00:00 2001 From: Joachim Meyer Date: Wed, 15 Oct 2014 14:15:46 +0200 Subject: [PATCH 01/12] Adding a HTTPFetcher (UNIX Socket Version coming) used by an updater for Polycode IDE. --- Core/Contents/CMakeLists.txt | 2 + Core/Contents/Include/PolyHTTPFetcher.h | 65 ++++++++ Core/Contents/Include/Polycode.h | 1 + Core/Contents/Source/PolyHTTPFetcher.cpp | 148 ++++++++++++++++++ IDE/Build/Windows2013/Polycode.rc | Bin 9330 -> 12354 bytes IDE/Build/Windows2013/resource.h | Bin 3298 -> 4422 bytes .../WindowsShared/PolycodeWinIDEView.cpp | 3 + IDE/Contents/Include/PolycodeIDEApp.h | 4 + IDE/Contents/Include/SettingsWindow.h | 21 +++ IDE/Contents/Source/PolycodeIDEApp.cpp | 32 ++++ IDE/Contents/Source/SettingsWindow.cpp | 22 +++ 11 files changed, 298 insertions(+) create mode 100644 Core/Contents/Include/PolyHTTPFetcher.h create mode 100644 Core/Contents/Source/PolyHTTPFetcher.cpp diff --git a/Core/Contents/CMakeLists.txt b/Core/Contents/CMakeLists.txt index 1b13a78c9..eaea063cb 100644 --- a/Core/Contents/CMakeLists.txt +++ b/Core/Contents/CMakeLists.txt @@ -80,6 +80,7 @@ SET(polycore_SRCS Source/PolyPeer.cpp Source/PolyClient.cpp Source/PolyServer.cpp + Source/PolyHTTPFetcher.cpp Source/PolyRay.cpp Source/PolySceneSprite.cpp Source/PolySceneEntityInstance.cpp @@ -168,6 +169,7 @@ SET(polycore_HDRS Include/PolyClient.h Include/PolyServer.h Include/PolyServerWorld.h + Include/PolyHTTPFetcher.h Include/PolyRay.h Include/PolySceneSprite.h Include/PolySceneEntityInstance.h diff --git a/Core/Contents/Include/PolyHTTPFetcher.h b/Core/Contents/Include/PolyHTTPFetcher.h new file mode 100644 index 000000000..4e5a00e79 --- /dev/null +++ b/Core/Contents/Include/PolyHTTPFetcher.h @@ -0,0 +1,65 @@ +/* +Copyright (C) 2014 by Joachim Meyer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#include "PolyPeer.h" + +#define PORT_NUMBER 80 +#define HTTP_VERSION "HTTP/1.0" +#define DEFAULT_USER_AGENT "Polycode HTTP Fetcher/1.0" +#define DEFAULT_READ_TIMEOUT 30 /* Seconds to wait before giving up + * when no data is arriving */ + +#define REQUEST_BUF_SIZE 1024 +#define HEADER_BUF_SIZE 1024 +#define DEFAULT_PAGE_BUF_SIZE 1024 * 200 /* 200K should hold most things */ + +namespace Polycode { + class HTTPFetcherEvent : public Event { + public: + HTTPFetcherEvent() { data = (char*)malloc(DEFAULT_PAGE_BUF_SIZE); memset(data, 0, DEFAULT_PAGE_BUF_SIZE); } + ~HTTPFetcherEvent(){} + + char *data; + + static const int EVENTBASE_SOCKETEVENT = 0x500; + static const int EVENT_HTTP_ERROR = EVENTBASE_SOCKETEVENT + 2; + static const int EVENT_HTTP_DATA_RECEIVED = EVENTBASE_SOCKETEVENT + 3; + }; + + class HTTPFetcher : public EventDispatcher{ + public: + HTTPFetcher(String address); + ~HTTPFetcher(); + + bool receiveHTTPData(); + + String getData(); + + private: + SOCKET s; + Address serverAddress; + String bodyReturn; + int pathIndex; + String host; + }; +} diff --git a/Core/Contents/Include/Polycode.h b/Core/Contents/Include/Polycode.h index ac5786630..7f64fd374 100755 --- a/Core/Contents/Include/Polycode.h +++ b/Core/Contents/Include/Polycode.h @@ -86,6 +86,7 @@ #include "PolyServer.h" #include "PolyServerWorld.h" #include "PolySocket.h" +#include "PolyHTTPFetcher.h" #include "PolyRay.h" #include "PolySceneSprite.h" #include "PolySceneEntityInstance.h" diff --git a/Core/Contents/Source/PolyHTTPFetcher.cpp b/Core/Contents/Source/PolyHTTPFetcher.cpp new file mode 100644 index 000000000..3da3ac2bd --- /dev/null +++ b/Core/Contents/Source/PolyHTTPFetcher.cpp @@ -0,0 +1,148 @@ +/* +Copyright (C) 2014 by Joachim Meyer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "PolyHTTPFetcher.h" +#include "PolyLogger.h" +#include "PolyTimer.h" +#include "Ws2tcpip.h" + +using namespace Polycode; + +HTTPFetcher::HTTPFetcher(String address) : EventDispatcher() { + int protocolIndex = address.find_first_of("://"); + if (protocolIndex != NULL){ + protocolIndex += strlen("://"); + pathIndex = address.find_first_of("/", protocolIndex); + + if (pathIndex != 0){ + host = address.substr(protocolIndex, pathIndex - protocolIndex); + } else { + host = address.substr(protocolIndex, address.length()); + } + } else { + pathIndex = address.find_first_of("/"); + + if (pathIndex != 0){ + host = address.substr(0, pathIndex); + } else { + host = address; + } + } + + struct sockaddr_in server; + + addrinfo *result = NULL; + addrinfo *ptr = NULL; + addrinfo hints; + + char ipstringbuffer[46]; + unsigned long ipbufferlength = 46; + + //Create a socket + if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + Logger::log("HTTP Fetcher: Could not create socket: %d\n", WSAGetLastError()); + } + + ZeroMemory(&hints, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + if (getaddrinfo(host.c_str(), address.substr(0, protocolIndex - strlen("://")).c_str(), &hints, &result) != 0) { + Logger::log("HTTP Fetcher: Address resolve error: %d\n", WSAGetLastError()); + return; + } + +#ifdef _WINDOWS + if (WSAAddressToStringA(result->ai_addr, (unsigned long)result->ai_addrlen, NULL, ipstringbuffer, &ipbufferlength) != 0) { + Logger::log("HTTP Fetcher: Address to String convert error: %d\n", WSAGetLastError()); + return; + } +#endif + + String ipString = ipstringbuffer; + ipString = ipString.substr(0, ipString.find_first_of(":")); + + server.sin_addr.s_addr = inet_addr(ipString.c_str()); + server.sin_family = AF_INET; + server.sin_port = htons(80); + + //Connect to remote server + if (connect(s, (struct sockaddr *)&server, sizeof(server)) < 0) { + Logger::log("HTTP Fetcher: connect error code: %d\n", WSAGetLastError()); + return; + } +} + +HTTPFetcher::~HTTPFetcher(){} + +bool HTTPFetcher::receiveHTTPData(){ + + //Send some data + String request; + if (pathIndex) { + request = "GET /updater.xml HTTP/1.1\r\n" + String("Host: dl.war-of-universe.com\r\n") + String("Connection: close\r\n\r\n"); //+ String("Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7"); + //request = "GET " + address.substr(pathIndex, address.length()) + " " + String(HTTP_VERSION) + "\r\nHost: " + host + "\r\nUser-Agent: " + DEFAULT_USER_AGENT + "\r\nConnection: close\r\n\r\n"; + } else { + request = "GET / " + String(HTTP_VERSION) + "\r\nHost: " + host + "\r\nUser-Agent: " + DEFAULT_USER_AGENT + "\r\nConnection: close\r\n\r\n"; + } + if (send(s, request.c_str(), strlen(request.c_str()), 0) < 0) { + Logger::log("HTTP Fetcher: Send failed %d\n", WSAGetLastError()); + return false; + } + + char server_reply[DEFAULT_PAGE_BUF_SIZE]; + unsigned long recv_size; + //Receive a reply from the server + if ((recv_size = recv(s, server_reply, 2000, 0)) == SOCKET_ERROR) { + Logger::log("HTTP Fetcher: recv failed %d\n", WSAGetLastError()); + return false; + } + + //Add a NULL terminating character to make it a proper string before printing + server_reply[recv_size] = '\0'; + + HTTPFetcherEvent *event = new HTTPFetcherEvent(); + event->data = server_reply; + char *charIndex = strstr(event->data, "HTTP/"); + int i; + if (sscanf(charIndex, "HTTP/1.1 %d", &i) != 1 || i < 200 || i>299) { + return false; + } + charIndex = strstr(event->data, "Content-Length:"); + if (charIndex == NULL) + charIndex = strstr(event->data, "Content-length:"); + if (sscanf(charIndex + strlen("content-length: "), "%d", &i) != 1) { + return false; + } + + charIndex = strstr(event->data, "\r\n\r\n") + strlen("\r\n\r\n"); + + event->data = charIndex; + bodyReturn = String(charIndex); + dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED); + return true; +} + +String HTTPFetcher::getData(){ + return this->bodyReturn; +} \ No newline at end of file diff --git a/IDE/Build/Windows2013/Polycode.rc b/IDE/Build/Windows2013/Polycode.rc index d73e4349ed9eb7946a7d6c4553a62dbeeeda39dd..7d695269434e75c5da780e9c1848838109c2d852 100644 GIT binary patch literal 12354 zcmds7e{b715ar(k_8l}87*=FS+pS-~ah=p#5*v1swnG3TOPVg5Ya6lCq`*G=w)c3x zilivnl7he;1e>xQY#%k<6A9GesK%5+W7jLg7v@bne#kIaF2hbKdPADUe}Il#Tn zPYj!PDLQQvvk$(6JiY>#rsgB)Uw}L0!!f9Si|;O|Zi7zpql4!^;S)+^wG7T7_50;G zpZ}Z3F-0WWaSL8ildeE_J>5{w>w7n=RdflYJAwU;tzBL~3lj4Kq&@`IPa`s)I~H_p zx$~W8NtYPiGJDV=v7jNW#MKM^5ZtG z8o-vH7vNdEXJY@~1?~IRFR*vAyyAZL%sgNETFOs2#!>Vlb>@iq_Y`YI=v`8C25)l) zjTTRzp)5l5b4^55=Xqki?7c*ZI!DSKN5r*`WBah+KKPfK@8NH{u=GwK_4rujzRuFM8hL2n zbOg+IxZ8uA#<)Mjy4c3&2EVqT$*J`$`UbxxU865ZM(Eu!Z=5Hj#vhSU8pF`XtW)zR zP+S0kk7NixO-)(^sERQ3!SSB?1&G?9wknc6;22x)NZWEb;^NrzxKo5=&q|&09;}ID zh`xQh9<+eHxAwRceP>n&i{#n!5c{%uZY8~s*;tU<*E7P z@ukcsWcm`KVRmr{zMR(JOMSVL0>=EztQhI}JT0drM!_C<(yxhw~icAcvIR5v#M&mq+ZnZF!iOsYgd%JrCoQBnVmzQXP|-lP|Po)4SBX}{n4AH zT{CBFL7)3}6_&U<(|x(iuebFnA@=L#s@MYlh1rI0dAWiH!4XnI>|B3cpOi(dN<|oP za7ExKKhCTkahyPVE}=ud_Wo9Z5=Fv{hOu_fqeSuNxi9`KoO>IqUAZQ>T+HUCA6S3x z`jT%Wq70*lhigmKpk!|=Iw*iuFjRs-G`;lLAM`~ zZo_M>o?Y}kqnfc4D_xy6XRj}-A@I_-Fn(p8GsflXd8-hAh?*!E;WK_6;a#jFtjj${ zFtjpvZu*PWyvyqhBN)wSRbtxaZLB`;xH5CCW=)iN6f2;se6->SdBtwt}e?9?UncMn))z!T%^ow(px#&JFdL?Qi z_X$|-$~f=wQp|e}Z}k_x zxvP_)rSD~(`5x=%6!yO;m|g8VoS)Xj_-g}$+=fU!+^+Jart3b~H;t;T!? zjZ<3_$-IJc#czeDiiB$ycaW+?9^s5qGwcG3b)DD$5Tai%~Cu)q!bvJf#6{baU zPvo7gmWdBM##4GhjyuAgRI?d-_|}`ks;l9l%@m>G&T>;c?2=QoL#>J4KkLeF(DjuTT?=;)T3Gp=LOA4N> z_Jf(6vVA3bS=mW(G3D`aN4$$!gf~^abUkkQF-apm1(q04r5T+P+{P~(es zdz5<*&AVYGy~|h06_?PHM^{zTin0=Uzi`W!oaQDzl83^>>Tc}KE*?@X`@FGQggZLV zpC)!G-c<5tcNW2>(OibkU;V-g1>cazS51D+5K*ojV9=UL98nXFtr!1h94pK39}eBu zo!4}27CgyiGR()QgUpdxi@3A9HQaIJe%T$eAXc+QOB3wl@igeItrl=MiuD6I1IqK6 zH_N^Yj7;#HH5;A@mD8$QBgD;3_fc$WdwP;=U&RG;OVWh>#?Xf2kIHLg8IrF zzeozjr@-o*!rZK?hl@rl8rt&w-W4qG|9Zl*+1YApG5wi)+FiU2d8#~AU*__8bMA?* SSi2{%a@hk6Pua)MI{pWOAGag` delta 1494 zcma)6J4_T&6uo@*Gy55KXJ%)Au&l$f3x-cXG=>-x1U85S7FbY-K_qCP!4D=76Mv1B z1@38x1+_K=L!ybDgjOOH#DYQ-Vnw4dmc;ko?hFtlT1;l%J?GwY?tM42HvY3~#Z|1% z(KOA_B;BDonxzJsA_M)6Z?Inc`_vT0sfLCaK1~nk7GuR}kbT`0r&+2+Q=_`NQ}U|_ zTQ&uIwl49`*jtgaxA5;WgRawk_RNq$UUK23Jqpc{M$CBu6V4d6Z8Fvr4HqRR*4X*E z$A=BWSHig;l>m#MFT|Y4x)qE2S!xjRu_~>=RWa_>1-|ccA?J!=-DRFz1-IK>&Tyr` z)6wH`VZ+Te%MtN-7{+5$qQ(~%<6aWp$e|n!ue=En|L!%ccuv=GTTY7jip({2?8&CS zsi$GFET6kuc96?^pYY}TUiNulcgW!k^-+e6J;TOrP?9>SgDz8+UCgFU74GW%G3@$% znD=wn8eWU@(eB2S2!0P%3bTAIhS;KaQt&P%OKb({FycgMLcx5sA`Ma(Yb#AzyiKVV zFD)vJRfTwk6F7Z>)9nsnB~g03mZPAFN1kd&nrZY6@t$O@WM zI?pf5*B+)Tbc1A&S36kb02ZZhS;Yw2r U#SUe)wbowxpa0>B`me=*08Zm`!T0v@6utA_%e?m{&k!{}(x${DXsJ@a+B6?4YmG%Qn$j<@3#AyrfMe3%4_yI0lNLT)l{sIec<)V1syeh~rcbId}oVoYhy^)`lK`pgPkEy4p>$f)O z0rhE1qzv%PJho9e13+%`o zeu<)vied^vj$p!?)KQKv>)uI>sZd9!Fr{YkDxDdMjF`bauZ%T6ucHe3{;ZD1@WpTG zC@*UG;GM&Po72%Kj(KezWpOt-cD$G<>Ubl|cF-e zI(q+%Xg~x7EXXX*N~NQ5RAm+0VuBL|yKLB3sY45NhuL^78;NGcvALd9ff#nS9o9w@5JO#I5rbUWA?em*!yA83gdDNQT1 zMhmn`A9-5hd6_q>-1ShDB=vHoX^P%A*z@#h|F}p*qe z$Dy9WK)-CMM)|-u9Jrr7wnRJjY|j~`37Vv7e0K(M=L}%x$%w-^R~hW*glE=i3{CD! z^|-I-7ksul@ih|1X{3gfRWr*C&tc2MPb)6UxRx1IEeXR;DMqopenDocs(); break; + case ID_HELP_LOOKFORUPDATES: + globalApp->checkUpdates(); + break; } break; case WM_COPYDATA: diff --git a/IDE/Contents/Include/PolycodeIDEApp.h b/IDE/Contents/Include/PolycodeIDEApp.h index af9c01d68..83b5c428d 100644 --- a/IDE/Contents/Include/PolycodeIDEApp.h +++ b/IDE/Contents/Include/PolycodeIDEApp.h @@ -72,6 +72,8 @@ class PolycodeIDEApp : public EventDispatcher { void openFile(OSFileEntry file); void stopProject(); + + void checkUpdates(); // menu commands void renameFile(); @@ -152,4 +154,6 @@ class PolycodeIDEApp : public EventDispatcher { // used in saving/closing files via popup dialog prompts std::vector tempEditorStore; + + HTTPFetcher *updater; }; diff --git a/IDE/Contents/Include/SettingsWindow.h b/IDE/Contents/Include/SettingsWindow.h index 63630988e..adf5ec7eb 100644 --- a/IDE/Contents/Include/SettingsWindow.h +++ b/IDE/Contents/Include/SettingsWindow.h @@ -51,3 +51,24 @@ class SettingsWindow : public UIWindow { UIButton *cancelButton; UIButton *okButton; }; + +class UpdateEvent : public Event { +public: + UpdateEvent(String url) { this->url = url; } + ~UpdateEvent() {} + String url; + + static const int EVENT_UPDATE_AVAILABLE = 0; +}; + +class UpdaterWindow : public UIWindow { +public: + UpdaterWindow(); + ~UpdaterWindow(); + + void handleEvent(Event *e); + void updateUI(); + + UILabel *newUpdateNot; + UIButton *openDownloadButton; +}; \ No newline at end of file diff --git a/IDE/Contents/Source/PolycodeIDEApp.cpp b/IDE/Contents/Source/PolycodeIDEApp.cpp index 90e9a5edf..ecc6b8412 100644 --- a/IDE/Contents/Source/PolycodeIDEApp.cpp +++ b/IDE/Contents/Source/PolycodeIDEApp.cpp @@ -235,6 +235,10 @@ core = new POLYCODE_CORE((PolycodeView*)view, 1100, 700,false,false, 0, 0,60, -1 applyFinalConfig(); + updater = new HTTPFetcher("http://www.polycode.org/updater.xml"); + updater->addEventListener(this, HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED); + updater->receiveHTTPData(); + core->updateAndRender(); frame->Resize(core->getXRes(), core->getYRes()); @@ -708,6 +712,28 @@ void PolycodeIDEApp::openFile(OSFileEntry file) { } } +void PolycodeIDEApp::checkUpdates(){ + int newMaj, newMin, newFix, maj, min, fix; + char newState[3], state[3]; + + Object updateObj; + updateObj.loadFromXMLString(updater->getData()); + if (updateObj.root["version"]){ + String newVersion = updateObj.root["version"]->stringVal; + String curVersion = String(POLYCODE_VERSION_STRING); + sscanf(newVersion.c_str(), "%d.%d.%d%s", &newMaj, &newMin, &newFix, &newState); + sscanf(curVersion.c_str(), "%d.%d.%d%s", &maj, &min, &fix, &state); + if (newMaj > maj || newMin > min || newFix > fix || (strstr(state, "a") != NULL && (strstr(newState, "b")!=NULL || strstr(newState, "r")!=NULL) || (strstr(state, "b")!=NULL && strstr(newState, "r")!=NULL))) { + if (updateObj.root["url"]) { + Services()->getConfig()->setStringValue("Polycode", "UpdateURL", updateObj.root["url"]->stringVal); + Services()->getConfig()->setStringValue("Polycode", "UpdateVersion", newVersion); + UpdaterWindow *update = new UpdaterWindow(); + frame->showModal(update); + } + } + } +} + void PolycodeIDEApp::handleEvent(Event *event) { if(event->getDispatcher() == frame->assetImporterWindow) { @@ -1144,6 +1170,12 @@ void PolycodeIDEApp::handleEvent(Event *event) { } } } + + if (event->getDispatcher() == updater){ + if (event->getEventCode() == HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED){ + checkUpdates(); + } + } } void PolycodeIDEApp::saveConfigFile() { diff --git a/IDE/Contents/Source/SettingsWindow.cpp b/IDE/Contents/Source/SettingsWindow.cpp index 58504e638..c4ed96589 100644 --- a/IDE/Contents/Source/SettingsWindow.cpp +++ b/IDE/Contents/Source/SettingsWindow.cpp @@ -211,3 +211,25 @@ void SettingsWindow::updateUI() { SettingsWindow::~SettingsWindow() { } + +UpdaterWindow::UpdaterWindow() : UIWindow("New Update!", 150,60) { + closeOnEscape = true; + + newUpdateNot = new UILabel("Version: "+ Services()->getConfig()->getStringValue("Polycode", "UpdateVersion"), 12); + openDownloadButton = new UIButton("Download Update", 130); + addChild(newUpdateNot); + newUpdateNot->setPosition(10, 25); + addChild(openDownloadButton); + openDownloadButton->setPosition(10, 40); + openDownloadButton->addEventListener(this, UIEvent::CLICK_EVENT); +} + +void UpdaterWindow::handleEvent(Event *e) { + if (e->getDispatcher() == openDownloadButton && e->getEventCode() == UIEvent::CLICK_EVENT) { + Services()->getCore()->openURL(Services()->getConfig()->getStringValue("Polycode","UpdateURL")); + onClose(); + } + UIWindow::handleEvent(e); +} + +UpdaterWindow::~UpdaterWindow() {} \ No newline at end of file From 5826f50db1c7167da09aadc579158df3c8241c2f Mon Sep 17 00:00:00 2001 From: Joachim Meyer Date: Wed, 15 Oct 2014 14:24:38 +0200 Subject: [PATCH 02/12] Little fix dealing with 0.8.4a_dev, originally only 0.8.4a was allowed. --- Core/Contents/Include/PolyHTTPFetcher.h | 2 +- Core/Contents/Source/PolyHTTPFetcher.cpp | 5 +++-- IDE/Contents/Source/PolycodeIDEApp.cpp | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Core/Contents/Include/PolyHTTPFetcher.h b/Core/Contents/Include/PolyHTTPFetcher.h index 4e5a00e79..52bb499fb 100644 --- a/Core/Contents/Include/PolyHTTPFetcher.h +++ b/Core/Contents/Include/PolyHTTPFetcher.h @@ -57,7 +57,7 @@ namespace Polycode { private: SOCKET s; - Address serverAddress; + String address; String bodyReturn; int pathIndex; String host; diff --git a/Core/Contents/Source/PolyHTTPFetcher.cpp b/Core/Contents/Source/PolyHTTPFetcher.cpp index 3da3ac2bd..53ea6c0af 100644 --- a/Core/Contents/Source/PolyHTTPFetcher.cpp +++ b/Core/Contents/Source/PolyHTTPFetcher.cpp @@ -28,6 +28,7 @@ THE SOFTWARE. using namespace Polycode; HTTPFetcher::HTTPFetcher(String address) : EventDispatcher() { + this->address = address; int protocolIndex = address.find_first_of("://"); if (protocolIndex != NULL){ protocolIndex += strlen("://"); @@ -100,8 +101,8 @@ bool HTTPFetcher::receiveHTTPData(){ //Send some data String request; if (pathIndex) { - request = "GET /updater.xml HTTP/1.1\r\n" + String("Host: dl.war-of-universe.com\r\n") + String("Connection: close\r\n\r\n"); //+ String("Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7"); - //request = "GET " + address.substr(pathIndex, address.length()) + " " + String(HTTP_VERSION) + "\r\nHost: " + host + "\r\nUser-Agent: " + DEFAULT_USER_AGENT + "\r\nConnection: close\r\n\r\n"; + //request = "GET /updater.xml HTTP/1.1\r\n" + String("Host: dl.war-of-universe.com\r\n") + String("Connection: close\r\n\r\n"); //+ String("Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7"); + request = "GET " + address.substr(pathIndex, address.length()) + " " + String(HTTP_VERSION) + "\r\nHost: " + host + "\r\nUser-Agent: " + DEFAULT_USER_AGENT + "\r\nConnection: close\r\n\r\n"; } else { request = "GET / " + String(HTTP_VERSION) + "\r\nHost: " + host + "\r\nUser-Agent: " + DEFAULT_USER_AGENT + "\r\nConnection: close\r\n\r\n"; } diff --git a/IDE/Contents/Source/PolycodeIDEApp.cpp b/IDE/Contents/Source/PolycodeIDEApp.cpp index ecc6b8412..db9e538dc 100644 --- a/IDE/Contents/Source/PolycodeIDEApp.cpp +++ b/IDE/Contents/Source/PolycodeIDEApp.cpp @@ -235,7 +235,7 @@ core = new POLYCODE_CORE((PolycodeView*)view, 1100, 700,false,false, 0, 0,60, -1 applyFinalConfig(); - updater = new HTTPFetcher("http://www.polycode.org/updater.xml"); + updater = new HTTPFetcher("http://127.0.0.1/updater.xml"); updater->addEventListener(this, HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED); updater->receiveHTTPData(); @@ -714,7 +714,7 @@ void PolycodeIDEApp::openFile(OSFileEntry file) { void PolycodeIDEApp::checkUpdates(){ int newMaj, newMin, newFix, maj, min, fix; - char newState[3], state[3]; + char newState[3], state[6]; Object updateObj; updateObj.loadFromXMLString(updater->getData()); From f32375a38074a5e4c5fe5c3d05333d512c5b78e6 Mon Sep 17 00:00:00 2001 From: Joachim Meyer Date: Wed, 15 Oct 2014 20:20:32 +0200 Subject: [PATCH 03/12] Add PolycodeUI Menu entry to check for updates, ported HTTPFetcher to UNIX Sockets, updater no longer uses Events, UpdaterWindow closes correctly now. --- Core/Contents/Include/PolyHTTPFetcher.h | 18 +++++- Core/Contents/Source/PolyHTTPFetcher.cpp | 81 ++++++++++++++++-------- IDE/Contents/Source/PolycodeIDEApp.cpp | 27 ++++---- IDE/Contents/Source/SettingsWindow.cpp | 4 +- 4 files changed, 84 insertions(+), 46 deletions(-) diff --git a/Core/Contents/Include/PolyHTTPFetcher.h b/Core/Contents/Include/PolyHTTPFetcher.h index 52bb499fb..5198be9d1 100644 --- a/Core/Contents/Include/PolyHTTPFetcher.h +++ b/Core/Contents/Include/PolyHTTPFetcher.h @@ -21,7 +21,21 @@ THE SOFTWARE. */ #pragma once -#include "PolyPeer.h" +#include +#ifdef _WINDOWS + #include + #include +#else + #include + #include + #include + #include + #include + #include +#endif +#include "PolyGlobals.h" +#include "PolyEvent.h" +#include "PolyEventDispatcher.h" #define PORT_NUMBER 80 #define HTTP_VERSION "HTTP/1.0" @@ -56,7 +70,7 @@ namespace Polycode { String getData(); private: - SOCKET s; + int s; String address; String bodyReturn; int pathIndex; diff --git a/Core/Contents/Source/PolyHTTPFetcher.cpp b/Core/Contents/Source/PolyHTTPFetcher.cpp index 53ea6c0af..d9cc563e1 100644 --- a/Core/Contents/Source/PolyHTTPFetcher.cpp +++ b/Core/Contents/Source/PolyHTTPFetcher.cpp @@ -22,15 +22,13 @@ THE SOFTWARE. #include "PolyHTTPFetcher.h" #include "PolyLogger.h" -#include "PolyTimer.h" -#include "Ws2tcpip.h" using namespace Polycode; HTTPFetcher::HTTPFetcher(String address) : EventDispatcher() { this->address = address; int protocolIndex = address.find_first_of("://"); - if (protocolIndex != NULL){ + if (protocolIndex != 0){ protocolIndex += strlen("://"); pathIndex = address.find_first_of("/", protocolIndex); @@ -52,32 +50,46 @@ HTTPFetcher::HTTPFetcher(String address) : EventDispatcher() { struct sockaddr_in server; addrinfo *result = NULL; - addrinfo *ptr = NULL; addrinfo hints; - char ipstringbuffer[46]; - unsigned long ipbufferlength = 46; + //Create a socket +#if PLATFORM == PLATFORM_WINDOWS + char ipstringbuffer[46]; + unsigned long ipbufferlength; - //Create a socket - if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { - Logger::log("HTTP Fetcher: Could not create socket: %d\n", WSAGetLastError()); + if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + Logger::log("HTTP Fetcher: Could not create socket: %d\n", WSAGetLastError()); +#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX + char* ipstringbuffer; + + if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + Logger::log("HTTP Fetcher: Could not create socket: %s\n", strerror(errno)); +#endif } - - ZeroMemory(&hints, sizeof(hints)); + + memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if (getaddrinfo(host.c_str(), address.substr(0, protocolIndex - strlen("://")).c_str(), &hints, &result) != 0) { +#if PLATFORM == PLATFORM_WINDOWS Logger::log("HTTP Fetcher: Address resolve error: %d\n", WSAGetLastError()); +#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX + Logger::log("HTTP Fetcher: Address resolve error: %s\n", strerror(errno)); +#endif return; } -#ifdef _WINDOWS +#if PLATFORM == PLATFORM_WINDOWS if (WSAAddressToStringA(result->ai_addr, (unsigned long)result->ai_addrlen, NULL, ipstringbuffer, &ipbufferlength) != 0) { Logger::log("HTTP Fetcher: Address to String convert error: %d\n", WSAGetLastError()); return; } +#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX + in_addr addr; + addr = ((sockaddr_in*)result->ai_addr)->sin_addr; + ipstringbuffer = inet_ntoa(addr); #endif String ipString = ipstringbuffer; @@ -89,7 +101,11 @@ HTTPFetcher::HTTPFetcher(String address) : EventDispatcher() { //Connect to remote server if (connect(s, (struct sockaddr *)&server, sizeof(server)) < 0) { - Logger::log("HTTP Fetcher: connect error code: %d\n", WSAGetLastError()); +#if PLATFORM == PLATFORM_WINDOWS + Logger::log("HTTP Fetcher: connect error code: %d\n", WSAGetLastError()); +#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX + Logger::log("HTTP Fetcher: connect error code: %s\n", strerror(errno)); +#endif return; } } @@ -97,53 +113,62 @@ HTTPFetcher::HTTPFetcher(String address) : EventDispatcher() { HTTPFetcher::~HTTPFetcher(){} bool HTTPFetcher::receiveHTTPData(){ - //Send some data String request; if (pathIndex) { - //request = "GET /updater.xml HTTP/1.1\r\n" + String("Host: dl.war-of-universe.com\r\n") + String("Connection: close\r\n\r\n"); //+ String("Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7"); request = "GET " + address.substr(pathIndex, address.length()) + " " + String(HTTP_VERSION) + "\r\nHost: " + host + "\r\nUser-Agent: " + DEFAULT_USER_AGENT + "\r\nConnection: close\r\n\r\n"; } else { request = "GET / " + String(HTTP_VERSION) + "\r\nHost: " + host + "\r\nUser-Agent: " + DEFAULT_USER_AGENT + "\r\nConnection: close\r\n\r\n"; } if (send(s, request.c_str(), strlen(request.c_str()), 0) < 0) { - Logger::log("HTTP Fetcher: Send failed %d\n", WSAGetLastError()); +#if PLATFORM == PLATFORM_WINDOWS + Logger::log("HTTP Fetcher: Send failed: %d\n", WSAGetLastError()); +#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX + Logger::log("HTTP Fetcher: Send failed: %s\n",strerror(errno)); +#endif return false; } char server_reply[DEFAULT_PAGE_BUF_SIZE]; unsigned long recv_size; //Receive a reply from the server - if ((recv_size = recv(s, server_reply, 2000, 0)) == SOCKET_ERROR) { - Logger::log("HTTP Fetcher: recv failed %d\n", WSAGetLastError()); +#if PLATFORM == PLATFORM_WINDOWS + if ((recv_size = recv(s, server_reply, DEFAULT_PAGE_BUF_SIZE, 0)) == SOCKET_ERROR) { + Logger::log("HTTP Fetcher: recv failed: %d\n", WSAGetLastError()); +#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX + if ((recv_size = recv(s, server_reply, DEFAULT_PAGE_BUF_SIZE, 0)) == -1) { + Logger::log("HTTP Fetcher: recv failed: %s\n", strerror(errno)); +#endif return false; } //Add a NULL terminating character to make it a proper string before printing server_reply[recv_size] = '\0'; - HTTPFetcherEvent *event = new HTTPFetcherEvent(); - event->data = server_reply; - char *charIndex = strstr(event->data, "HTTP/"); - int i; + HTTPFetcherEvent *event = new HTTPFetcherEvent(); + char *charIndex = strstr(server_reply, "HTTP/"); + if(charIndex == NULL){ + return false; + } + int i; if (sscanf(charIndex, "HTTP/1.1 %d", &i) != 1 || i < 200 || i>299) { return false; } - charIndex = strstr(event->data, "Content-Length:"); + charIndex = strstr(server_reply, "Content-Length:"); if (charIndex == NULL) - charIndex = strstr(event->data, "Content-length:"); + charIndex = strstr(server_reply, "Content-length:"); if (sscanf(charIndex + strlen("content-length: "), "%d", &i) != 1) { return false; } - charIndex = strstr(event->data, "\r\n\r\n") + strlen("\r\n\r\n"); + charIndex = strstr(server_reply, "\r\n\r\n") + strlen("\r\n\r\n"); - event->data = charIndex; + event->data = charIndex; bodyReturn = String(charIndex); - dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED); + dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED); return true; } String HTTPFetcher::getData(){ return this->bodyReturn; -} \ No newline at end of file +} diff --git a/IDE/Contents/Source/PolycodeIDEApp.cpp b/IDE/Contents/Source/PolycodeIDEApp.cpp index db9e538dc..8890712f0 100644 --- a/IDE/Contents/Source/PolycodeIDEApp.cpp +++ b/IDE/Contents/Source/PolycodeIDEApp.cpp @@ -216,7 +216,7 @@ core = new POLYCODE_CORE((PolycodeView*)view, 1100, 700,false,false, 0, 0,60, -1 UIMenuBarEntry *helpEntry = menuBar->addMenuBarEntry("Help"); helpEntry->addItem("API Reference", "show_api"); helpEntry->addItem("About Polycode", "show_about"); - + helpEntry->addItem("Check For Updates", "check_update"); menuBar->addEventListener(this, UIEvent::OK_EVENT); @@ -235,9 +235,8 @@ core = new POLYCODE_CORE((PolycodeView*)view, 1100, 700,false,false, 0, 0,60, -1 applyFinalConfig(); - updater = new HTTPFetcher("http://127.0.0.1/updater.xml"); - updater->addEventListener(this, HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED); - updater->receiveHTTPData(); + updater = new HTTPFetcher("http://www.polycode.org/updater.xml"); + checkUpdates(); core->updateAndRender(); frame->Resize(core->getXRes(), core->getYRes()); @@ -713,16 +712,20 @@ void PolycodeIDEApp::openFile(OSFileEntry file) { } void PolycodeIDEApp::checkUpdates(){ - int newMaj, newMin, newFix, maj, min, fix; - char newState[3], state[6]; + if(!updater->receiveHTTPData()) + return; + + int newMaj, newMin, newFix, maj, min, fix; + char *newState = (char*)malloc(2*sizeof(char)); + char *state = (char*)malloc(6*sizeof(char)); Object updateObj; updateObj.loadFromXMLString(updater->getData()); if (updateObj.root["version"]){ String newVersion = updateObj.root["version"]->stringVal; String curVersion = String(POLYCODE_VERSION_STRING); - sscanf(newVersion.c_str(), "%d.%d.%d%s", &newMaj, &newMin, &newFix, &newState); - sscanf(curVersion.c_str(), "%d.%d.%d%s", &maj, &min, &fix, &state); + sscanf(newVersion.c_str(), "%d.%d.%d%s", &newMaj, &newMin, &newFix, newState); + sscanf(curVersion.c_str(), "%d.%d.%d%s", &maj, &min, &fix, state); if (newMaj > maj || newMin > min || newFix > fix || (strstr(state, "a") != NULL && (strstr(newState, "b")!=NULL || strstr(newState, "r")!=NULL) || (strstr(state, "b")!=NULL && strstr(newState, "r")!=NULL))) { if (updateObj.root["url"]) { Services()->getConfig()->setStringValue("Polycode", "UpdateURL", updateObj.root["url"]->stringVal); @@ -827,6 +830,8 @@ void PolycodeIDEApp::handleEvent(Event *event) { openDocs(); } else if(action == "show_about") { showAbout(); + } else if(action == "check_update"){ + checkUpdates(); } else if(action == "toggle_console") { toggleConsole(); } else if(action == "settings") { @@ -1170,12 +1175,6 @@ void PolycodeIDEApp::handleEvent(Event *event) { } } } - - if (event->getDispatcher() == updater){ - if (event->getEventCode() == HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED){ - checkUpdates(); - } - } } void PolycodeIDEApp::saveConfigFile() { diff --git a/IDE/Contents/Source/SettingsWindow.cpp b/IDE/Contents/Source/SettingsWindow.cpp index c4ed96589..0c6ffaacf 100644 --- a/IDE/Contents/Source/SettingsWindow.cpp +++ b/IDE/Contents/Source/SettingsWindow.cpp @@ -227,9 +227,9 @@ UpdaterWindow::UpdaterWindow() : UIWindow("New Update!", 150,60) { void UpdaterWindow::handleEvent(Event *e) { if (e->getDispatcher() == openDownloadButton && e->getEventCode() == UIEvent::CLICK_EVENT) { Services()->getCore()->openURL(Services()->getConfig()->getStringValue("Polycode","UpdateURL")); - onClose(); + dispatchEvent(new UIEvent(), UIEvent::CLOSE_EVENT); } UIWindow::handleEvent(e); } -UpdaterWindow::~UpdaterWindow() {} \ No newline at end of file +UpdaterWindow::~UpdaterWindow() {} From 7eb58a5e41d863350a6cbf1e7ef3502a4925ef0a Mon Sep 17 00:00:00 2001 From: Joachim Meyer Date: Tue, 11 Nov 2014 19:06:24 +0100 Subject: [PATCH 04/12] Close socket savely in the destructor. --- Core/Contents/Source/PolyHTTPFetcher.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Core/Contents/Source/PolyHTTPFetcher.cpp b/Core/Contents/Source/PolyHTTPFetcher.cpp index d9cc563e1..6874e0cc1 100644 --- a/Core/Contents/Source/PolyHTTPFetcher.cpp +++ b/Core/Contents/Source/PolyHTTPFetcher.cpp @@ -110,7 +110,13 @@ HTTPFetcher::HTTPFetcher(String address) : EventDispatcher() { } } -HTTPFetcher::~HTTPFetcher(){} +HTTPFetcher::~HTTPFetcher(){ +#ifdef _WINDOWS + closesocket(s); +#else + close(s); +#endif +} bool HTTPFetcher::receiveHTTPData(){ //Send some data From 62ad1abb0e094759e1cba801585bebf9f33b2480 Mon Sep 17 00:00:00 2001 From: Joachim Meyer Date: Sat, 13 Dec 2014 14:20:23 +0100 Subject: [PATCH 05/12] Fix HTTPFetcher to not use temp chars and ints to get the connect address. --- Core/Contents/Source/PolyHTTPFetcher.cpp | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/Core/Contents/Source/PolyHTTPFetcher.cpp b/Core/Contents/Source/PolyHTTPFetcher.cpp index 6874e0cc1..7bb65bf8b 100644 --- a/Core/Contents/Source/PolyHTTPFetcher.cpp +++ b/Core/Contents/Source/PolyHTTPFetcher.cpp @@ -54,14 +54,9 @@ HTTPFetcher::HTTPFetcher(String address) : EventDispatcher() { //Create a socket #if PLATFORM == PLATFORM_WINDOWS - char ipstringbuffer[46]; - unsigned long ipbufferlength; - if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { Logger::log("HTTP Fetcher: Could not create socket: %d\n", WSAGetLastError()); #elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX - char* ipstringbuffer; - if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { Logger::log("HTTP Fetcher: Could not create socket: %s\n", strerror(errno)); #endif @@ -81,23 +76,9 @@ HTTPFetcher::HTTPFetcher(String address) : EventDispatcher() { return; } -#if PLATFORM == PLATFORM_WINDOWS - if (WSAAddressToStringA(result->ai_addr, (unsigned long)result->ai_addrlen, NULL, ipstringbuffer, &ipbufferlength) != 0) { - Logger::log("HTTP Fetcher: Address to String convert error: %d\n", WSAGetLastError()); - return; - } -#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX - in_addr addr; - addr = ((sockaddr_in*)result->ai_addr)->sin_addr; - ipstringbuffer = inet_ntoa(addr); -#endif - - String ipString = ipstringbuffer; - ipString = ipString.substr(0, ipString.find_first_of(":")); - - server.sin_addr.s_addr = inet_addr(ipString.c_str()); + server.sin_addr = ((sockaddr_in*)result->ai_addr)->sin_addr; server.sin_family = AF_INET; - server.sin_port = htons(80); + server.sin_port = ((sockaddr_in*)result->ai_addr)->sin_port; //Connect to remote server if (connect(s, (struct sockaddr *)&server, sizeof(server)) < 0) { From 2a42c0652ad7bde3772e4d6093c5802ae74a1195 Mon Sep 17 00:00:00 2001 From: Joachim Meyer Date: Sat, 13 Dec 2014 14:25:06 +0100 Subject: [PATCH 06/12] Cleanup unused "#define"s --- Core/Contents/Include/PolyHTTPFetcher.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Core/Contents/Include/PolyHTTPFetcher.h b/Core/Contents/Include/PolyHTTPFetcher.h index 5198be9d1..0e09daeef 100644 --- a/Core/Contents/Include/PolyHTTPFetcher.h +++ b/Core/Contents/Include/PolyHTTPFetcher.h @@ -37,14 +37,8 @@ THE SOFTWARE. #include "PolyEvent.h" #include "PolyEventDispatcher.h" -#define PORT_NUMBER 80 #define HTTP_VERSION "HTTP/1.0" #define DEFAULT_USER_AGENT "Polycode HTTP Fetcher/1.0" -#define DEFAULT_READ_TIMEOUT 30 /* Seconds to wait before giving up - * when no data is arriving */ - -#define REQUEST_BUF_SIZE 1024 -#define HEADER_BUF_SIZE 1024 #define DEFAULT_PAGE_BUF_SIZE 1024 * 200 /* 200K should hold most things */ namespace Polycode { From dfdfc8268a3a174672abd41b7acfb9eac13ed5b1 Mon Sep 17 00:00:00 2001 From: Joachim Meyer Date: Mon, 29 Dec 2014 12:15:57 +0100 Subject: [PATCH 07/12] Several improvements to the HTTPFetcher & Updater including using dynamically allocated buffers, threading. --- Core/Contents/Include/PolyHTTPFetcher.h | 22 +++--- Core/Contents/Source/PolyHTTPFetcher.cpp | 72 ++++++++++++------- .../WindowsShared/PolycodeWinIDEView.cpp | 2 +- IDE/Contents/Include/PolycodeIDEApp.h | 7 +- IDE/Contents/Source/PolycodeIDEApp.cpp | 49 +++++++------ 5 files changed, 89 insertions(+), 63 deletions(-) diff --git a/Core/Contents/Include/PolyHTTPFetcher.h b/Core/Contents/Include/PolyHTTPFetcher.h index 0e09daeef..be73457e3 100644 --- a/Core/Contents/Include/PolyHTTPFetcher.h +++ b/Core/Contents/Include/PolyHTTPFetcher.h @@ -34,40 +34,46 @@ THE SOFTWARE. #include #endif #include "PolyGlobals.h" -#include "PolyEvent.h" -#include "PolyEventDispatcher.h" +#include "PolyThreaded.h" #define HTTP_VERSION "HTTP/1.0" #define DEFAULT_USER_AGENT "Polycode HTTP Fetcher/1.0" #define DEFAULT_PAGE_BUF_SIZE 1024 * 200 /* 200K should hold most things */ namespace Polycode { + class HTTPFetcherEvent : public Event { public: - HTTPFetcherEvent() { data = (char*)malloc(DEFAULT_PAGE_BUF_SIZE); memset(data, 0, DEFAULT_PAGE_BUF_SIZE); } + HTTPFetcherEvent() { data = String(); } ~HTTPFetcherEvent(){} - char *data; + String data; static const int EVENTBASE_SOCKETEVENT = 0x500; static const int EVENT_HTTP_ERROR = EVENTBASE_SOCKETEVENT + 2; static const int EVENT_HTTP_DATA_RECEIVED = EVENTBASE_SOCKETEVENT + 3; }; - class HTTPFetcher : public EventDispatcher{ + class HTTPFetcher : public Threaded { public: HTTPFetcher(String address); ~HTTPFetcher(); - bool receiveHTTPData(); - String getData(); + /* + * Fetches a file given in the param + * @param pathToFile Path String to the new file to fetch from the same host. Without leading "/" + */ + void fetchFile(String pathToFile); + private: int s; String address; String bodyReturn; - int pathIndex; + String path; String host; + + void updateThread(); }; } diff --git a/Core/Contents/Source/PolyHTTPFetcher.cpp b/Core/Contents/Source/PolyHTTPFetcher.cpp index 7bb65bf8b..433785f5c 100644 --- a/Core/Contents/Source/PolyHTTPFetcher.cpp +++ b/Core/Contents/Source/PolyHTTPFetcher.cpp @@ -22,15 +22,21 @@ THE SOFTWARE. #include "PolyHTTPFetcher.h" #include "PolyLogger.h" +#include "PolyCoreServices.h" +#include "PolyCore.h" using namespace Polycode; -HTTPFetcher::HTTPFetcher(String address) : EventDispatcher() { +HTTPFetcher::HTTPFetcher(String address) : Threaded() { + core = CoreServices::getInstance()->getCore(); + eventMutex = core->getEventMutex(); + this->address = address; int protocolIndex = address.find_first_of("://"); if (protocolIndex != 0){ protocolIndex += strlen("://"); - pathIndex = address.find_first_of("/", protocolIndex); + int pathIndex = address.find_first_of("/", protocolIndex); + String path = address.substr(pathIndex+1, address.length()); if (pathIndex != 0){ host = address.substr(protocolIndex, pathIndex - protocolIndex); @@ -38,7 +44,8 @@ HTTPFetcher::HTTPFetcher(String address) : EventDispatcher() { host = address.substr(protocolIndex, address.length()); } } else { - pathIndex = address.find_first_of("/"); + int pathIndex = address.find_first_of("/"); + String path = address.substr(pathIndex+1, address.length()); if (pathIndex != 0){ host = address.substr(0, pathIndex); @@ -89,6 +96,8 @@ HTTPFetcher::HTTPFetcher(String address) : EventDispatcher() { #endif return; } + + CoreServices::getInstance()->getCore()->createThread(this); } HTTPFetcher::~HTTPFetcher(){ @@ -99,11 +108,11 @@ HTTPFetcher::~HTTPFetcher(){ #endif } -bool HTTPFetcher::receiveHTTPData(){ +void HTTPFetcher::updateThread(){ //Send some data String request; - if (pathIndex) { - request = "GET " + address.substr(pathIndex, address.length()) + " " + String(HTTP_VERSION) + "\r\nHost: " + host + "\r\nUser-Agent: " + DEFAULT_USER_AGENT + "\r\nConnection: close\r\n\r\n"; + if (path != "") { + request = "GET /" + path + " " + String(HTTP_VERSION) + "\r\nHost: " + host + "\r\nUser-Agent: " + DEFAULT_USER_AGENT + "\r\nConnection: close\r\n\r\n"; } else { request = "GET / " + String(HTTP_VERSION) + "\r\nHost: " + host + "\r\nUser-Agent: " + DEFAULT_USER_AGENT + "\r\nConnection: close\r\n\r\n"; } @@ -113,47 +122,56 @@ bool HTTPFetcher::receiveHTTPData(){ #elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX Logger::log("HTTP Fetcher: Send failed: %s\n",strerror(errno)); #endif - return false; + return; } - char server_reply[DEFAULT_PAGE_BUF_SIZE]; + HTTPFetcherEvent *event = new HTTPFetcherEvent(); + + char *server_reply = (char*)malloc(DEFAULT_PAGE_BUF_SIZE); unsigned long recv_size; - //Receive a reply from the server + do { + //Receive a reply from the server #if PLATFORM == PLATFORM_WINDOWS - if ((recv_size = recv(s, server_reply, DEFAULT_PAGE_BUF_SIZE, 0)) == SOCKET_ERROR) { - Logger::log("HTTP Fetcher: recv failed: %d\n", WSAGetLastError()); + if ((recv_size = recv(s, server_reply, DEFAULT_PAGE_BUF_SIZE, 0)) == SOCKET_ERROR) { + Logger::log("HTTP Fetcher: recv failed: %d\n", WSAGetLastError()); #elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX - if ((recv_size = recv(s, server_reply, DEFAULT_PAGE_BUF_SIZE, 0)) == -1) { - Logger::log("HTTP Fetcher: recv failed: %s\n", strerror(errno)); + if ((recv_size = recv(s, server_reply, DEFAULT_PAGE_BUF_SIZE, 0)) == -1) { + Logger::log("HTTP Fetcher: recv failed: %s\n", strerror(errno)); #endif - return false; - } + return; + } - //Add a NULL terminating character to make it a proper string before printing - server_reply[recv_size] = '\0'; + //Add a NULL terminating character to make it a proper string before using it + server_reply[recv_size] = '\0'; + event->data += String(server_reply); + } while (recv_size != 0); - HTTPFetcherEvent *event = new HTTPFetcherEvent(); - char *charIndex = strstr(server_reply, "HTTP/"); + char *charIndex = strstr(const_cast(event->data.c_str()), "HTTP/"); if(charIndex == NULL){ - return false; + return; } int i; if (sscanf(charIndex, "HTTP/1.1 %d", &i) != 1 || i < 200 || i>299) { - return false; + return; } - charIndex = strstr(server_reply, "Content-Length:"); + charIndex = strstr(const_cast(event->data.c_str()), "Content-Length:"); if (charIndex == NULL) - charIndex = strstr(server_reply, "Content-length:"); + charIndex = strstr(const_cast(event->data.c_str()), "Content-length:"); if (sscanf(charIndex + strlen("content-length: "), "%d", &i) != 1) { - return false; + return; } - charIndex = strstr(server_reply, "\r\n\r\n") + strlen("\r\n\r\n"); + charIndex = strstr(const_cast(event->data.c_str()), "\r\n\r\n") + strlen("\r\n\r\n"); event->data = charIndex; - bodyReturn = String(charIndex); + bodyReturn = event->data; dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED); - return true; + killThread(); +} + +void HTTPFetcher::fetchFile(String pathToFile){ + path = pathToFile; + CoreServices::getInstance()->getCore()->createThread(this); } String HTTPFetcher::getData(){ diff --git a/IDE/Build/WindowsShared/PolycodeWinIDEView.cpp b/IDE/Build/WindowsShared/PolycodeWinIDEView.cpp index 96bf5bcc7..e92f2d4a1 100644 --- a/IDE/Build/WindowsShared/PolycodeWinIDEView.cpp +++ b/IDE/Build/WindowsShared/PolycodeWinIDEView.cpp @@ -155,7 +155,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) globalApp->openDocs(); break; case ID_HELP_LOOKFORUPDATES: - globalApp->checkUpdates(); + globalApp->updater->fetchFile("updater.xml"); break; } break; diff --git a/IDE/Contents/Include/PolycodeIDEApp.h b/IDE/Contents/Include/PolycodeIDEApp.h index 83b5c428d..b774149a1 100644 --- a/IDE/Contents/Include/PolycodeIDEApp.h +++ b/IDE/Contents/Include/PolycodeIDEApp.h @@ -73,7 +73,7 @@ class PolycodeIDEApp : public EventDispatcher { void stopProject(); - void checkUpdates(); + void checkUpdates(const String updateFile); // menu commands void renameFile(); @@ -122,7 +122,8 @@ class PolycodeIDEApp : public EventDispatcher { const static int EVENT_SHOW_MENU = 1; Core *core; - + HTTPFetcher *updater; + void saveFiles(std::vector editors); void closeFiles(std::vector editors, String saveMsg=""); bool filesHaveChanges(std::vector editors); @@ -154,6 +155,4 @@ class PolycodeIDEApp : public EventDispatcher { // used in saving/closing files via popup dialog prompts std::vector tempEditorStore; - - HTTPFetcher *updater; }; diff --git a/IDE/Contents/Source/PolycodeIDEApp.cpp b/IDE/Contents/Source/PolycodeIDEApp.cpp index 8890712f0..249a8532d 100644 --- a/IDE/Contents/Source/PolycodeIDEApp.cpp +++ b/IDE/Contents/Source/PolycodeIDEApp.cpp @@ -236,7 +236,7 @@ core = new POLYCODE_CORE((PolycodeView*)view, 1100, 700,false,false, 0, 0,60, -1 applyFinalConfig(); updater = new HTTPFetcher("http://www.polycode.org/updater.xml"); - checkUpdates(); + updater->addEventListener(this, HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED); core->updateAndRender(); frame->Resize(core->getXRes(), core->getYRes()); @@ -711,27 +711,26 @@ void PolycodeIDEApp::openFile(OSFileEntry file) { } } -void PolycodeIDEApp::checkUpdates(){ - if(!updater->receiveHTTPData()) - return; - - int newMaj, newMin, newFix, maj, min, fix; - char *newState = (char*)malloc(2*sizeof(char)); - char *state = (char*)malloc(6*sizeof(char)); - - Object updateObj; - updateObj.loadFromXMLString(updater->getData()); - if (updateObj.root["version"]){ - String newVersion = updateObj.root["version"]->stringVal; - String curVersion = String(POLYCODE_VERSION_STRING); - sscanf(newVersion.c_str(), "%d.%d.%d%s", &newMaj, &newMin, &newFix, newState); - sscanf(curVersion.c_str(), "%d.%d.%d%s", &maj, &min, &fix, state); - if (newMaj > maj || newMin > min || newFix > fix || (strstr(state, "a") != NULL && (strstr(newState, "b")!=NULL || strstr(newState, "r")!=NULL) || (strstr(state, "b")!=NULL && strstr(newState, "r")!=NULL))) { - if (updateObj.root["url"]) { - Services()->getConfig()->setStringValue("Polycode", "UpdateURL", updateObj.root["url"]->stringVal); - Services()->getConfig()->setStringValue("Polycode", "UpdateVersion", newVersion); - UpdaterWindow *update = new UpdaterWindow(); - frame->showModal(update); +void PolycodeIDEApp::checkUpdates(const String updateFile){ + if (updateFile != ""){ + int newMaj, newMin, newFix, maj, min, fix; + char *newState = (char*)malloc(2 * sizeof(char)); + char *state = (char*)malloc(6 * sizeof(char)); + + Object updateObj; + updateObj.loadFromXMLString(updater->getData()); + if (updateObj.root["version"]){ + String newVersion = updateObj.root["version"]->stringVal; + String curVersion = String(POLYCODE_VERSION_STRING); + sscanf(newVersion.c_str(), "%d.%d.%d%s", &newMaj, &newMin, &newFix, newState); + sscanf(curVersion.c_str(), "%d.%d.%d%s", &maj, &min, &fix, state); + if (newMaj > maj || newMin > min || newFix > fix || (strstr(state, "a") != NULL && (strstr(newState, "b") != NULL || strstr(newState, "r") != NULL) || (strstr(state, "b") != NULL && strstr(newState, "r") != NULL))) { + if (updateObj.root["url"]) { + Services()->getConfig()->setStringValue("Polycode", "UpdateURL", updateObj.root["url"]->stringVal); + Services()->getConfig()->setStringValue("Polycode", "UpdateVersion", newVersion); + UpdaterWindow *update = new UpdaterWindow(); + frame->showModal(update); + } } } } @@ -831,7 +830,7 @@ void PolycodeIDEApp::handleEvent(Event *event) { } else if(action == "show_about") { showAbout(); } else if(action == "check_update"){ - checkUpdates(); + updater->fetchFile("updater.xml"); } else if(action == "toggle_console") { toggleConsole(); } else if(action == "settings") { @@ -1175,6 +1174,10 @@ void PolycodeIDEApp::handleEvent(Event *event) { } } } + + if (event->getEventCode() == HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED){ + checkUpdates(((HTTPFetcherEvent*)event)->data); + } } void PolycodeIDEApp::saveConfigFile() { From d8dff267069069e4ba7fc0bf4e0d76832d711afd Mon Sep 17 00:00:00 2001 From: Joachim Meyer Date: Mon, 29 Dec 2014 14:14:09 +0100 Subject: [PATCH 08/12] Some more fixes, making it more flexible and stable, fixes Unix not finding close(). --- Core/Contents/Include/PolyHTTPFetcher.h | 17 ++--- Core/Contents/Source/PolyHTTPFetcher.cpp | 95 ++++++++++++++++-------- 2 files changed, 71 insertions(+), 41 deletions(-) diff --git a/Core/Contents/Include/PolyHTTPFetcher.h b/Core/Contents/Include/PolyHTTPFetcher.h index be73457e3..961937904 100644 --- a/Core/Contents/Include/PolyHTTPFetcher.h +++ b/Core/Contents/Include/PolyHTTPFetcher.h @@ -22,21 +22,11 @@ THE SOFTWARE. #pragma once #include -#ifdef _WINDOWS - #include - #include -#else - #include - #include - #include - #include - #include - #include -#endif + #include "PolyGlobals.h" #include "PolyThreaded.h" -#define HTTP_VERSION "HTTP/1.0" +#define HTTP_VERSION "HTTP/1.1" #define DEFAULT_USER_AGENT "Polycode HTTP Fetcher/1.0" #define DEFAULT_PAGE_BUF_SIZE 1024 * 200 /* 200K should hold most things */ @@ -48,6 +38,7 @@ namespace Polycode { ~HTTPFetcherEvent(){} String data; + int errorCode; static const int EVENTBASE_SOCKETEVENT = 0x500; static const int EVENT_HTTP_ERROR = EVENTBASE_SOCKETEVENT + 2; @@ -73,7 +64,9 @@ namespace Polycode { String bodyReturn; String path; String host; + String protocol; + void createSocket(); void updateThread(); }; } diff --git a/Core/Contents/Source/PolyHTTPFetcher.cpp b/Core/Contents/Source/PolyHTTPFetcher.cpp index 433785f5c..cd07ef1e8 100644 --- a/Core/Contents/Source/PolyHTTPFetcher.cpp +++ b/Core/Contents/Source/PolyHTTPFetcher.cpp @@ -20,6 +20,19 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#ifdef _WINDOWS +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#endif + #include "PolyHTTPFetcher.h" #include "PolyLogger.h" #include "PolyCoreServices.h" @@ -35,8 +48,9 @@ HTTPFetcher::HTTPFetcher(String address) : Threaded() { int protocolIndex = address.find_first_of("://"); if (protocolIndex != 0){ protocolIndex += strlen("://"); + protocol = address.substr(0, protocolIndex - strlen("://")); int pathIndex = address.find_first_of("/", protocolIndex); - String path = address.substr(pathIndex+1, address.length()); + path = address.substr(pathIndex+1, address.length()); if (pathIndex != 0){ host = address.substr(protocolIndex, pathIndex - protocolIndex); @@ -45,7 +59,7 @@ HTTPFetcher::HTTPFetcher(String address) : Threaded() { } } else { int pathIndex = address.find_first_of("/"); - String path = address.substr(pathIndex+1, address.length()); + path = address.substr(pathIndex+1, address.length()); if (pathIndex != 0){ host = address.substr(0, pathIndex); @@ -54,35 +68,50 @@ HTTPFetcher::HTTPFetcher(String address) : Threaded() { } } + createSocket(); + + threadRunning = true; + CoreServices::getInstance()->getCore()->createThread(this); +} + +HTTPFetcher::~HTTPFetcher(){ +#ifdef _WINDOWS + closesocket(s); +#else + close(s); +#endif +} + +void HTTPFetcher::createSocket(){ struct sockaddr_in server; - + addrinfo *result = NULL; addrinfo hints; - //Create a socket + //Create a socket #if PLATFORM == PLATFORM_WINDOWS - if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { - Logger::log("HTTP Fetcher: Could not create socket: %d\n", WSAGetLastError()); + if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + Logger::log("HTTP Fetcher: Could not create socket: %d\n", WSAGetLastError()); #elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX - if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - Logger::log("HTTP Fetcher: Could not create socket: %s\n", strerror(errno)); + if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + Logger::log("HTTP Fetcher: Could not create socket: %s\n", strerror(errno)); #endif } - memset(&hints, 0, sizeof(hints)); + memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; - - if (getaddrinfo(host.c_str(), address.substr(0, protocolIndex - strlen("://")).c_str(), &hints, &result) != 0) { + + if (getaddrinfo(host.c_str(), protocol.c_str(), &hints, &result) != 0) { #if PLATFORM == PLATFORM_WINDOWS Logger::log("HTTP Fetcher: Address resolve error: %d\n", WSAGetLastError()); #elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX - Logger::log("HTTP Fetcher: Address resolve error: %s\n", strerror(errno)); + Logger::log("HTTP Fetcher: Address resolve error: %s\n", strerror(errno)); #endif return; } - + server.sin_addr = ((sockaddr_in*)result->ai_addr)->sin_addr; server.sin_family = AF_INET; server.sin_port = ((sockaddr_in*)result->ai_addr)->sin_port; @@ -90,22 +119,12 @@ HTTPFetcher::HTTPFetcher(String address) : Threaded() { //Connect to remote server if (connect(s, (struct sockaddr *)&server, sizeof(server)) < 0) { #if PLATFORM == PLATFORM_WINDOWS - Logger::log("HTTP Fetcher: connect error code: %d\n", WSAGetLastError()); + Logger::log("HTTP Fetcher: connect error code: %d\n", WSAGetLastError()); #elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX - Logger::log("HTTP Fetcher: connect error code: %s\n", strerror(errno)); + Logger::log("HTTP Fetcher: connect error code: %s\n", strerror(errno)); #endif return; } - - CoreServices::getInstance()->getCore()->createThread(this); -} - -HTTPFetcher::~HTTPFetcher(){ -#ifdef _WINDOWS - closesocket(s); -#else - close(s); -#endif } void HTTPFetcher::updateThread(){ @@ -116,17 +135,22 @@ void HTTPFetcher::updateThread(){ } else { request = "GET / " + String(HTTP_VERSION) + "\r\nHost: " + host + "\r\nUser-Agent: " + DEFAULT_USER_AGENT + "\r\nConnection: close\r\n\r\n"; } + + HTTPFetcherEvent *event = new HTTPFetcherEvent(); + if (send(s, request.c_str(), strlen(request.c_str()), 0) < 0) { #if PLATFORM == PLATFORM_WINDOWS Logger::log("HTTP Fetcher: Send failed: %d\n", WSAGetLastError()); + event->errorCode = WSAGetLastError(); #elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX Logger::log("HTTP Fetcher: Send failed: %s\n",strerror(errno)); + event->errorCode = strerror(errno); #endif + createSocket(); + dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_ERROR); return; } - HTTPFetcherEvent *event = new HTTPFetcherEvent(); - char *server_reply = (char*)malloc(DEFAULT_PAGE_BUF_SIZE); unsigned long recv_size; do { @@ -134,10 +158,14 @@ void HTTPFetcher::updateThread(){ #if PLATFORM == PLATFORM_WINDOWS if ((recv_size = recv(s, server_reply, DEFAULT_PAGE_BUF_SIZE, 0)) == SOCKET_ERROR) { Logger::log("HTTP Fetcher: recv failed: %d\n", WSAGetLastError()); + event->errorCode = WSAGetLastError(); #elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX if ((recv_size = recv(s, server_reply, DEFAULT_PAGE_BUF_SIZE, 0)) == -1) { Logger::log("HTTP Fetcher: recv failed: %s\n", strerror(errno)); + event->errorCode = strerror(errno); #endif + dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_ERROR); + killThread(); return; } @@ -146,18 +174,26 @@ void HTTPFetcher::updateThread(){ event->data += String(server_reply); } while (recv_size != 0); + if (event->data == ""){ + createSocket(); + return; + } + char *charIndex = strstr(const_cast(event->data.c_str()), "HTTP/"); if(charIndex == NULL){ - return; + killThread(); + return; } int i; - if (sscanf(charIndex, "HTTP/1.1 %d", &i) != 1 || i < 200 || i>299) { + if (sscanf(charIndex + strlen("HTTP/1.1"), "%d", &i) != 1 || i < 200 || i>299) { + killThread(); return; } charIndex = strstr(const_cast(event->data.c_str()), "Content-Length:"); if (charIndex == NULL) charIndex = strstr(const_cast(event->data.c_str()), "Content-length:"); if (sscanf(charIndex + strlen("content-length: "), "%d", &i) != 1) { + killThread(); return; } @@ -171,6 +207,7 @@ void HTTPFetcher::updateThread(){ void HTTPFetcher::fetchFile(String pathToFile){ path = pathToFile; + threadRunning = true; CoreServices::getInstance()->getCore()->createThread(this); } From d5502d7ef12fd9a23a6bf157a96a2f6515cdf267 Mon Sep 17 00:00:00 2001 From: Joachim Meyer Date: Mon, 29 Dec 2014 22:29:24 +0100 Subject: [PATCH 09/12] Smaller chunks downloaded per time in the HTTPFetcher recv loop, making it binary file compatible by no longer using Strings but dynamically re-, allocated char buffers. --- Core/Contents/Include/PolyHTTPFetcher.h | 10 ++++--- Core/Contents/Source/PolyHTTPFetcher.cpp | 38 +++++++++++++++--------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/Core/Contents/Include/PolyHTTPFetcher.h b/Core/Contents/Include/PolyHTTPFetcher.h index 961937904..ea44d07a5 100644 --- a/Core/Contents/Include/PolyHTTPFetcher.h +++ b/Core/Contents/Include/PolyHTTPFetcher.h @@ -28,17 +28,19 @@ THE SOFTWARE. #define HTTP_VERSION "HTTP/1.1" #define DEFAULT_USER_AGENT "Polycode HTTP Fetcher/1.0" -#define DEFAULT_PAGE_BUF_SIZE 1024 * 200 /* 200K should hold most things */ +#define DEFAULT_PAGE_BUF_SIZE 2048 namespace Polycode { class HTTPFetcherEvent : public Event { public: - HTTPFetcherEvent() { data = String(); } + HTTPFetcherEvent() { contentSize = 0; errorCode = 0; data = NULL; } ~HTTPFetcherEvent(){} - String data; + char* data; int errorCode; + + unsigned long contentSize; static const int EVENTBASE_SOCKETEVENT = 0x500; static const int EVENT_HTTP_ERROR = EVENTBASE_SOCKETEVENT + 2; @@ -66,7 +68,7 @@ namespace Polycode { String host; String protocol; - void createSocket(); + bool createSocket(); void updateThread(); }; } diff --git a/Core/Contents/Source/PolyHTTPFetcher.cpp b/Core/Contents/Source/PolyHTTPFetcher.cpp index cd07ef1e8..6b0d13a20 100644 --- a/Core/Contents/Source/PolyHTTPFetcher.cpp +++ b/Core/Contents/Source/PolyHTTPFetcher.cpp @@ -68,7 +68,8 @@ HTTPFetcher::HTTPFetcher(String address) : Threaded() { } } - createSocket(); + if (!createSocket()) + return; threadRunning = true; CoreServices::getInstance()->getCore()->createThread(this); @@ -82,7 +83,7 @@ HTTPFetcher::~HTTPFetcher(){ #endif } -void HTTPFetcher::createSocket(){ +bool HTTPFetcher::createSocket(){ struct sockaddr_in server; addrinfo *result = NULL; @@ -96,6 +97,7 @@ void HTTPFetcher::createSocket(){ if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { Logger::log("HTTP Fetcher: Could not create socket: %s\n", strerror(errno)); #endif + return false; } memset(&hints, 0, sizeof(hints)); @@ -109,7 +111,7 @@ void HTTPFetcher::createSocket(){ #elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX Logger::log("HTTP Fetcher: Address resolve error: %s\n", strerror(errno)); #endif - return; + return false; } server.sin_addr = ((sockaddr_in*)result->ai_addr)->sin_addr; @@ -123,8 +125,9 @@ void HTTPFetcher::createSocket(){ #elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX Logger::log("HTTP Fetcher: connect error code: %s\n", strerror(errno)); #endif - return; + return false; } + return true; } void HTTPFetcher::updateThread(){ @@ -152,15 +155,16 @@ void HTTPFetcher::updateThread(){ } char *server_reply = (char*)malloc(DEFAULT_PAGE_BUF_SIZE); - unsigned long recv_size; + char *rec = server_reply; + unsigned long recv_size = 0, totalRec = 0; do { //Receive a reply from the server #if PLATFORM == PLATFORM_WINDOWS - if ((recv_size = recv(s, server_reply, DEFAULT_PAGE_BUF_SIZE, 0)) == SOCKET_ERROR) { + if ((recv_size = recv(s, rec, DEFAULT_PAGE_BUF_SIZE, 0)) == SOCKET_ERROR) { Logger::log("HTTP Fetcher: recv failed: %d\n", WSAGetLastError()); event->errorCode = WSAGetLastError(); #elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX - if ((recv_size = recv(s, server_reply, DEFAULT_PAGE_BUF_SIZE, 0)) == -1) { + if ((recv_size = recv(s, rec, DEFAULT_PAGE_BUF_SIZE, 0)) == -1) { Logger::log("HTTP Fetcher: recv failed: %s\n", strerror(errno)); event->errorCode = strerror(errno); #endif @@ -169,17 +173,21 @@ void HTTPFetcher::updateThread(){ return; } - //Add a NULL terminating character to make it a proper string before using it - server_reply[recv_size] = '\0'; - event->data += String(server_reply); + + totalRec += recv_size; + server_reply = (char*)realloc(server_reply, totalRec + DEFAULT_PAGE_BUF_SIZE); + rec = server_reply+totalRec; } while (recv_size != 0); + server_reply[totalRec] = '\0'; + event->data = server_reply; + if (event->data == ""){ createSocket(); return; } - char *charIndex = strstr(const_cast(event->data.c_str()), "HTTP/"); + char *charIndex = strstr(event->data, "HTTP/"); if(charIndex == NULL){ killThread(); return; @@ -189,15 +197,17 @@ void HTTPFetcher::updateThread(){ killThread(); return; } - charIndex = strstr(const_cast(event->data.c_str()), "Content-Length:"); + charIndex = strstr(event->data, "Content-Length:"); if (charIndex == NULL) - charIndex = strstr(const_cast(event->data.c_str()), "Content-length:"); + charIndex = strstr(event->data, "Content-length:"); if (sscanf(charIndex + strlen("content-length: "), "%d", &i) != 1) { killThread(); return; } - charIndex = strstr(const_cast(event->data.c_str()), "\r\n\r\n") + strlen("\r\n\r\n"); + event->contentSize = min(i, totalRec); + + charIndex = strstr(event->data, "\r\n\r\n") + strlen("\r\n\r\n"); event->data = charIndex; bodyReturn = event->data; From 94a60b006959013eee40aaec3efd570672d8b66c Mon Sep 17 00:00:00 2001 From: Joachim Meyer Date: Sat, 14 Mar 2015 14:43:46 +0100 Subject: [PATCH 10/12] Fix Windows to return the real ThreadID for getThreadID(). --- Core/Contents/Source/PolyWinCore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Contents/Source/PolyWinCore.cpp b/Core/Contents/Source/PolyWinCore.cpp index 85713dda0..66a65b1ef 100644 --- a/Core/Contents/Source/PolyWinCore.cpp +++ b/Core/Contents/Source/PolyWinCore.cpp @@ -50,7 +50,7 @@ PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = NULL; using namespace Polycode; long getThreadID() { - return 0; + return GetCurrentThreadId(); } extern Win32Core *core; From 2e65e1bc07dc9e84b0a9baefbda08aeb5f1a9239 Mon Sep 17 00:00:00 2001 From: Joachim Meyer Date: Sun, 15 Mar 2015 18:16:48 +0100 Subject: [PATCH 11/12] Added flag that HTTPFetcher would download and directly save the requested data to a file. Using this for the Updater to directly download the new version into the IDE's directory. --- Core/Contents/Include/PolyHTTPFetcher.h | 14 ++-- Core/Contents/Source/PolyHTTPFetcher.cpp | 88 +++++++++++++++++++++--- IDE/Contents/Include/PolycodeFrame.h | 1 + IDE/Contents/Include/PolycodeIDEApp.h | 8 ++- IDE/Contents/Include/SettingsWindow.h | 9 +-- IDE/Contents/Source/PolycodeIDEApp.cpp | 17 +++-- IDE/Contents/Source/SettingsWindow.cpp | 18 +++-- 7 files changed, 125 insertions(+), 30 deletions(-) diff --git a/Core/Contents/Include/PolyHTTPFetcher.h b/Core/Contents/Include/PolyHTTPFetcher.h index ea44d07a5..8de2c596f 100644 --- a/Core/Contents/Include/PolyHTTPFetcher.h +++ b/Core/Contents/Include/PolyHTTPFetcher.h @@ -34,14 +34,15 @@ namespace Polycode { class HTTPFetcherEvent : public Event { public: - HTTPFetcherEvent() { contentSize = 0; errorCode = 0; data = NULL; } + HTTPFetcherEvent() { contentSize = 0; errorCode = 0; data = NULL; storedInFile = false; } ~HTTPFetcherEvent(){} char* data; int errorCode; + bool storedInFile; unsigned long contentSize; - + static const int EVENTBASE_SOCKETEVENT = 0x500; static const int EVENT_HTTP_ERROR = EVENTBASE_SOCKETEVENT + 2; static const int EVENT_HTTP_DATA_RECEIVED = EVENTBASE_SOCKETEVENT + 3; @@ -49,7 +50,7 @@ namespace Polycode { class HTTPFetcher : public Threaded { public: - HTTPFetcher(String address); + HTTPFetcher(String address, bool saveToPath = false, String savePath = ""); ~HTTPFetcher(); String getData(); @@ -58,7 +59,11 @@ namespace Polycode { * Fetches a file given in the param * @param pathToFile Path String to the new file to fetch from the same host. Without leading "/" */ - void fetchFile(String pathToFile); + void fetchFile(String pathToFile, bool saveToPath = false, String savePath = ""); + + static const int HTTPFETCHER_ERROR_WRONG_SIZE = 0x10F00; + + bool storeInFile; private: int s; @@ -67,6 +72,7 @@ namespace Polycode { String path; String host; String protocol; + String savePath; bool createSocket(); void updateThread(); diff --git a/Core/Contents/Source/PolyHTTPFetcher.cpp b/Core/Contents/Source/PolyHTTPFetcher.cpp index 6b0d13a20..2947cf854 100644 --- a/Core/Contents/Source/PolyHTTPFetcher.cpp +++ b/Core/Contents/Source/PolyHTTPFetcher.cpp @@ -40,10 +40,13 @@ THE SOFTWARE. using namespace Polycode; -HTTPFetcher::HTTPFetcher(String address) : Threaded() { +HTTPFetcher::HTTPFetcher(String address, bool saveToPath, String savePath) : Threaded() { core = CoreServices::getInstance()->getCore(); eventMutex = core->getEventMutex(); + storeInFile = saveToPath; + this->savePath = savePath; + this->address = address; int protocolIndex = address.find_first_of("://"); if (protocolIndex != 0){ @@ -131,6 +134,16 @@ bool HTTPFetcher::createSocket(){ } void HTTPFetcher::updateThread(){ + int protocolIndex = path.find_first_of("://"); + if (protocolIndex != 0){ + protocolIndex += strlen("://"); + protocol = path.substr(0, protocolIndex - strlen("://")); + int pathIndex = path.find_first_of("/", protocolIndex); + path = path.substr(pathIndex + 1, path.length()); + } else if (path.find_first_of("/") == 0) { + path = path.substr(1, path.length()); + } + //Send some data String request; if (path != "") { @@ -154,13 +167,13 @@ void HTTPFetcher::updateThread(){ return; } - char *server_reply = (char*)malloc(DEFAULT_PAGE_BUF_SIZE); + char *server_reply = (char*)malloc(1); char *rec = server_reply; unsigned long recv_size = 0, totalRec = 0; do { //Receive a reply from the server #if PLATFORM == PLATFORM_WINDOWS - if ((recv_size = recv(s, rec, DEFAULT_PAGE_BUF_SIZE, 0)) == SOCKET_ERROR) { + if ((recv_size = recv(s, rec, 1, 0)) == SOCKET_ERROR) { Logger::log("HTTP Fetcher: recv failed: %d\n", WSAGetLastError()); event->errorCode = WSAGetLastError(); #elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX @@ -175,14 +188,14 @@ void HTTPFetcher::updateThread(){ totalRec += recv_size; - server_reply = (char*)realloc(server_reply, totalRec + DEFAULT_PAGE_BUF_SIZE); - rec = server_reply+totalRec; - } while (recv_size != 0); + server_reply = (char*)realloc(server_reply, totalRec + 1); + rec = server_reply + totalRec; + } while (recv_size != 0 && strstr(server_reply, "\r\n\r\n") == NULL); server_reply[totalRec] = '\0'; event->data = server_reply; - if (event->data == ""){ + if (strlen(event->data) == 0){ createSocket(); return; } @@ -194,6 +207,8 @@ void HTTPFetcher::updateThread(){ } int i; if (sscanf(charIndex + strlen("HTTP/1.1"), "%d", &i) != 1 || i < 200 || i>299) { + event->errorCode = i; + dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_ERROR); killThread(); return; } @@ -201,22 +216,73 @@ void HTTPFetcher::updateThread(){ if (charIndex == NULL) charIndex = strstr(event->data, "Content-length:"); if (sscanf(charIndex + strlen("content-length: "), "%d", &i) != 1) { + dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_ERROR); killThread(); return; } - event->contentSize = min(i, totalRec); + FILE* tempFile; + if (storeInFile){ + tempFile = fopen(savePath.c_str(), "wb"); + } + + free(server_reply); + server_reply = (char*)malloc(DEFAULT_PAGE_BUF_SIZE); + rec = server_reply; + recv_size = 0, totalRec = 0; + + do { + //Receive a reply from the server +#if PLATFORM == PLATFORM_WINDOWS + if ((recv_size = recv(s, rec, DEFAULT_PAGE_BUF_SIZE, 0)) == SOCKET_ERROR) { + Logger::log("HTTP Fetcher: recv failed: %d\n", WSAGetLastError()); + event->errorCode = WSAGetLastError(); +#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX + if ((recv_size = recv(s, rec, DEFAULT_PAGE_BUF_SIZE, 0)) == -1) { + Logger::log("HTTP Fetcher: recv failed: %s\n", strerror(errno)); + event->errorCode = strerror(errno); +#endif + dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_ERROR); + killThread(); + return; + } + + + totalRec += recv_size; + if (!storeInFile){ + server_reply = (char*)realloc(server_reply, totalRec + DEFAULT_PAGE_BUF_SIZE); + rec = server_reply + totalRec; + } else { + server_reply[recv_size] = '\0'; + fwrite(server_reply, 1, recv_size, tempFile); + } + } while (recv_size !=0 && totalRec < i); - charIndex = strstr(event->data, "\r\n\r\n") + strlen("\r\n\r\n"); + if (totalRec > i){ + event->errorCode = HTTPFetcher::HTTPFETCHER_ERROR_WRONG_SIZE; + dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_ERROR); + killThread(); + return; + } + if (storeInFile){ + event->storedInFile = true; + event->data = (char*)malloc(sizeof(char)*(savePath.length() + 1)); + strcpy(event->data, savePath.c_str()); + fclose(tempFile); + } else { + event->data = server_reply; + } - event->data = charIndex; + event->contentSize = totalRec; bodyReturn = event->data; dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED); killThread(); } -void HTTPFetcher::fetchFile(String pathToFile){ +void HTTPFetcher::fetchFile(String pathToFile, bool saveToPath, String savePath){ path = pathToFile; + this->savePath = savePath; + this->storeInFile = saveToPath; threadRunning = true; CoreServices::getInstance()->getCore()->createThread(this); } diff --git a/IDE/Contents/Include/PolycodeFrame.h b/IDE/Contents/Include/PolycodeFrame.h index 1618ff991..3a4073075 100644 --- a/IDE/Contents/Include/PolycodeFrame.h +++ b/IDE/Contents/Include/PolycodeFrame.h @@ -19,6 +19,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#pragma once #include "PolycodeUI.h" #include "Polycode.h" diff --git a/IDE/Contents/Include/PolycodeIDEApp.h b/IDE/Contents/Include/PolycodeIDEApp.h index b774149a1..6e53f927d 100644 --- a/IDE/Contents/Include/PolycodeIDEApp.h +++ b/IDE/Contents/Include/PolycodeIDEApp.h @@ -20,6 +20,8 @@ THE SOFTWARE. */ +#pragma once + #if defined(__APPLE__) && defined(__MACH__) #import "PolycodeView.h" #elif defined(_WINDOWS) @@ -73,8 +75,6 @@ class PolycodeIDEApp : public EventDispatcher { void stopProject(); - void checkUpdates(const String updateFile); - // menu commands void renameFile(); void removeFile(); @@ -130,6 +130,8 @@ class PolycodeIDEApp : public EventDispatcher { protected: + void checkUpdates(const String updateFile); + bool quittingApp; bool runNextFrame; @@ -143,6 +145,8 @@ class PolycodeIDEApp : public EventDispatcher { PolycodeRemoteDebugger *debugger; UIMenuBar *menuBar; + + UpdaterWindow *updaterWindow; private: diff --git a/IDE/Contents/Include/SettingsWindow.h b/IDE/Contents/Include/SettingsWindow.h index adf5ec7eb..70de8b0d2 100644 --- a/IDE/Contents/Include/SettingsWindow.h +++ b/IDE/Contents/Include/SettingsWindow.h @@ -54,11 +54,12 @@ class SettingsWindow : public UIWindow { class UpdateEvent : public Event { public: - UpdateEvent(String url) { this->url = url; } + UpdateEvent() { this->url = ""; } ~UpdateEvent() {} String url; - static const int EVENT_UPDATE_AVAILABLE = 0; + static const int EVENT_UPDATE_AVAILABLE = 0x500+10; + static const int EVENT_UPDATE_DOWNLOADED = 0x500+11; }; class UpdaterWindow : public UIWindow { @@ -67,8 +68,8 @@ class UpdaterWindow : public UIWindow { ~UpdaterWindow(); void handleEvent(Event *e); - void updateUI(); + void openUpdate(String pathToUpdate); - UILabel *newUpdateNot; + UIMultilineLabel *updateNot; UIButton *openDownloadButton; }; \ No newline at end of file diff --git a/IDE/Contents/Source/PolycodeIDEApp.cpp b/IDE/Contents/Source/PolycodeIDEApp.cpp index 249a8532d..c710f1c37 100644 --- a/IDE/Contents/Source/PolycodeIDEApp.cpp +++ b/IDE/Contents/Source/PolycodeIDEApp.cpp @@ -728,8 +728,9 @@ void PolycodeIDEApp::checkUpdates(const String updateFile){ if (updateObj.root["url"]) { Services()->getConfig()->setStringValue("Polycode", "UpdateURL", updateObj.root["url"]->stringVal); Services()->getConfig()->setStringValue("Polycode", "UpdateVersion", newVersion); - UpdaterWindow *update = new UpdaterWindow(); - frame->showModal(update); + updaterWindow = new UpdaterWindow(); + updaterWindow->addEventListener(this, UIEvent::OK_EVENT); + frame->showModal(updaterWindow); } } } @@ -1175,8 +1176,16 @@ void PolycodeIDEApp::handleEvent(Event *event) { } } - if (event->getEventCode() == HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED){ - checkUpdates(((HTTPFetcherEvent*)event)->data); + if (event->getDispatcher() == updater){ + if (event->getEventCode() == HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED){ + HTTPFetcherEvent* e = (HTTPFetcherEvent*)event; + if (e->storedInFile){ + updaterWindow->openUpdate(e->data); + frame->showModal(updaterWindow); + } else { + checkUpdates(e->data); + } + } } } diff --git a/IDE/Contents/Source/SettingsWindow.cpp b/IDE/Contents/Source/SettingsWindow.cpp index 0c6ffaacf..6f07b70c9 100644 --- a/IDE/Contents/Source/SettingsWindow.cpp +++ b/IDE/Contents/Source/SettingsWindow.cpp @@ -16,6 +16,7 @@ THE SOFTWARE. */ +#include "PolycodeIDEApp.h" #include "SettingsWindow.h" #include "PolycodeFrame.h" #include "PolycodeTextEditor.h" @@ -23,6 +24,7 @@ extern PolycodeFrame *globalFrame; extern UIGlobalMenu *globalMenu; extern SyntaxHighlightTheme *globalSyntaxTheme; +extern PolycodeIDEApp *globalApp; SettingsWindow::SettingsWindow() : UIWindow(L"Settings", SETTINGS_WINDOW_WIDTH, SETTINGS_WINDOW_HEIGHT) { @@ -215,10 +217,11 @@ SettingsWindow::~SettingsWindow() { UpdaterWindow::UpdaterWindow() : UIWindow("New Update!", 150,60) { closeOnEscape = true; - newUpdateNot = new UILabel("Version: "+ Services()->getConfig()->getStringValue("Polycode", "UpdateVersion"), 12); + updateNot = new UIMultilineLabel("Version: "+ Services()->getConfig()->getStringValue("Polycode", "UpdateVersion"), 12,2); + addChild(updateNot); + updateNot->setPosition(10, 25); + openDownloadButton = new UIButton("Download Update", 130); - addChild(newUpdateNot); - newUpdateNot->setPosition(10, 25); addChild(openDownloadButton); openDownloadButton->setPosition(10, 40); openDownloadButton->addEventListener(this, UIEvent::CLICK_EVENT); @@ -226,10 +229,15 @@ UpdaterWindow::UpdaterWindow() : UIWindow("New Update!", 150,60) { void UpdaterWindow::handleEvent(Event *e) { if (e->getDispatcher() == openDownloadButton && e->getEventCode() == UIEvent::CLICK_EVENT) { - Services()->getCore()->openURL(Services()->getConfig()->getStringValue("Polycode","UpdateURL")); - dispatchEvent(new UIEvent(), UIEvent::CLOSE_EVENT); + globalApp->updater->fetchFile(Services()->getConfig()->getStringValue("Polycode", "UpdateURL"), true, "PolycodeUpdate" + Services()->getConfig()->getStringValue("Polycode", "UpdateVersion") + ".zip"); + dispatchEvent(new UIEvent(), UIEvent::CLOSE_EVENT); } UIWindow::handleEvent(e); } +void UpdaterWindow::openUpdate(String pathToUpdate){ + updateNot->setText("Downloaded Update into\nyour Polycode Directory:\n"+pathToUpdate); + removeChild(openDownloadButton); +} + UpdaterWindow::~UpdaterWindow() {} From 12882b18623cd82bad685a1363d083f61eec5a35 Mon Sep 17 00:00:00 2001 From: Joachim Meyer Date: Thu, 2 Apr 2015 16:32:19 +0200 Subject: [PATCH 12/12] Add some documentation to the HTTPFetcher. Remove unused UpdateEvent class from SettingsWindow.h. If no savePath is given it will save the fetched file to the same path as it is on the server if saving is turned on. --- Core/Contents/Include/PolyHTTPFetcher.h | 17 +++++++++++++++++ Core/Contents/Source/PolyHTTPFetcher.cpp | 2 ++ IDE/Contents/Include/SettingsWindow.h | 10 ---------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Core/Contents/Include/PolyHTTPFetcher.h b/Core/Contents/Include/PolyHTTPFetcher.h index 8de2c596f..0d4e67eb6 100644 --- a/Core/Contents/Include/PolyHTTPFetcher.h +++ b/Core/Contents/Include/PolyHTTPFetcher.h @@ -37,10 +37,14 @@ namespace Polycode { HTTPFetcherEvent() { contentSize = 0; errorCode = 0; data = NULL; storedInFile = false; } ~HTTPFetcherEvent(){} + //If storedInFile: data is the file path, else: data contains all the fetched data char* data; + //Error code: contains either the errno / WSAError code or the HTTP error code or the HTTPFetcher error code int errorCode; + //Has the data been saved to a file or is it shipped with this event? bool storedInFile; + //Size of the HTTP reply unsigned long contentSize; static const int EVENTBASE_SOCKETEVENT = 0x500; @@ -48,8 +52,18 @@ namespace Polycode { static const int EVENT_HTTP_DATA_RECEIVED = EVENTBASE_SOCKETEVENT + 3; }; + /** + * A utility to download a file from the WWW through HTTP. It is threaded (and therefor non blocking). + * If you want to use the data you might add an EventListener for the HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED event code. + */ class HTTPFetcher : public Threaded { public: + /* + * Connects to a host and fetches a file given in the param + * @param address Full path including the hostname (Domain or IP) and protocol (http://) aswell as the path to the file on the server + * @param saveToPath true if you want the file to be directly saved, false if you just want the data as char array + * @param savePath Path String where the file should be saved to + */ HTTPFetcher(String address, bool saveToPath = false, String savePath = ""); ~HTTPFetcher(); @@ -58,9 +72,12 @@ namespace Polycode { /* * Fetches a file given in the param * @param pathToFile Path String to the new file to fetch from the same host. Without leading "/" + * @param saveToPath true if you want the file to be directly saved, false if you just want the data as char array + * @param savePath Path String where the file should be saved to */ void fetchFile(String pathToFile, bool saveToPath = false, String savePath = ""); + //The received data is more or less than the HTTP header told us it should be static const int HTTPFETCHER_ERROR_WRONG_SIZE = 0x10F00; bool storeInFile; diff --git a/Core/Contents/Source/PolyHTTPFetcher.cpp b/Core/Contents/Source/PolyHTTPFetcher.cpp index 2947cf854..c521d757e 100644 --- a/Core/Contents/Source/PolyHTTPFetcher.cpp +++ b/Core/Contents/Source/PolyHTTPFetcher.cpp @@ -223,6 +223,8 @@ void HTTPFetcher::updateThread(){ FILE* tempFile; if (storeInFile){ + if (savePath == "") + savePath = path; tempFile = fopen(savePath.c_str(), "wb"); } diff --git a/IDE/Contents/Include/SettingsWindow.h b/IDE/Contents/Include/SettingsWindow.h index 70de8b0d2..9cc286445 100644 --- a/IDE/Contents/Include/SettingsWindow.h +++ b/IDE/Contents/Include/SettingsWindow.h @@ -52,16 +52,6 @@ class SettingsWindow : public UIWindow { UIButton *okButton; }; -class UpdateEvent : public Event { -public: - UpdateEvent() { this->url = ""; } - ~UpdateEvent() {} - String url; - - static const int EVENT_UPDATE_AVAILABLE = 0x500+10; - static const int EVENT_UPDATE_DOWNLOADED = 0x500+11; -}; - class UpdaterWindow : public UIWindow { public: UpdaterWindow();