diff --git a/src/apps/haikudepot/HaikuDepotConstants.h b/src/apps/haikudepot/HaikuDepotConstants.h new file mode 100644 index 0000000000..7ca466b908 --- /dev/null +++ b/src/apps/haikudepot/HaikuDepotConstants.h @@ -0,0 +1,22 @@ +/* + * Copyright 2018, Andrew Lindesay . + * All rights reserved. Distributed under the terms of the MIT License. + */ + + +enum { + MSG_MAIN_WINDOW_CLOSED = 'mwcl', + MSG_PACKAGE_SELECTED = 'pkgs', + MSG_PACKAGE_WORKER_BUSY = 'pkwb', + MSG_PACKAGE_WORKER_IDLE = 'pkwi', + MSG_ADD_VISIBLE_PACKAGES = 'avpk', + MSG_UPDATE_SELECTED_PACKAGE = 'uspk', + MSG_CLIENT_TOO_OLD = 'oldc', +}; + + +#define HD_ERROR_BASE (B_ERRORS_END + 1) +#define HD_NETWORK_INACCESSIBLE (HD_ERROR_BASE + 1) +#define HD_CLIENT_TOO_OLD (HD_ERROR_BASE + 2) +#define HD_ERR_NOT_MODIFIED (HD_ERROR_BASE + 3) +#define HD_ERR_NO_DATA (HD_ERROR_BASE + 4) \ No newline at end of file diff --git a/src/apps/haikudepot/Jamfile b/src/apps/haikudepot/Jamfile index 02a988d599..72c968b781 100644 --- a/src/apps/haikudepot/Jamfile +++ b/src/apps/haikudepot/Jamfile @@ -101,6 +101,7 @@ Application HaikuDepot : # network + server AbstractServerProcess.cpp AbstractSingleFileServerProcess.cpp + ServerHelper.cpp ServerSettings.cpp WebAppInterface.cpp PkgDataUpdateProcess.cpp diff --git a/src/apps/haikudepot/server/AbstractServerProcess.cpp b/src/apps/haikudepot/server/AbstractServerProcess.cpp index c78614f035..3187476515 100644 --- a/src/apps/haikudepot/server/AbstractServerProcess.cpp +++ b/src/apps/haikudepot/server/AbstractServerProcess.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #include "AbstractServerProcess.h" @@ -17,7 +17,9 @@ #include +#include "HaikuDepotConstants.h" #include "Logger.h" +#include "ServerHelper.h" #include "ServerSettings.h" #include "StandardMetaDataJsonEventListener.h" #include "StorageUtils.h" @@ -27,8 +29,6 @@ #define MAX_REDIRECTS 3 #define MAX_FAILURES 2 -#define HTTP_STATUS_FOUND 302 -#define HTTP_STATUS_NOT_MODIFIED 304 // 30 seconds #define TIMEOUT_MICROSECONDS 3e+7 @@ -405,10 +405,13 @@ AbstractServerProcess::DownloadToLocalFile(const BPath& targetFilePath, fprintf(stdout, "[%s] did complete streaming data [%" B_PRIdSSIZE " bytes]\n", Name(), listener.ContentLength()); return B_OK; - } else if (statusCode == HTTP_STATUS_NOT_MODIFIED) { + } else if (statusCode == B_HTTP_STATUS_NOT_MODIFIED) { fprintf(stdout, "[%s] remote data has not changed since [%s]\n", Name(), ifModifiedSinceHeader.String()); - return APP_ERR_NOT_MODIFIED; + return HD_ERR_NOT_MODIFIED; + } else if (statusCode == B_HTTP_STATUS_PRECONDITION_FAILED) { + ServerHelper::NotifyClientTooOld(responseHeaders); + return HD_CLIENT_TOO_OLD; } else if (BHttpRequest::IsRedirectionStatusCode(statusCode)) { if (location.Length() != 0) { BUrl redirectUrl(result.Url(), location); @@ -477,5 +480,5 @@ AbstractServerProcess::MoveDamagedFileAside(const BPath& currentFilePath) bool AbstractServerProcess::IsSuccess(status_t e) { - return e == B_OK || e == APP_ERR_NOT_MODIFIED; + return e == B_OK || e == HD_ERR_NOT_MODIFIED; } diff --git a/src/apps/haikudepot/server/AbstractServerProcess.h b/src/apps/haikudepot/server/AbstractServerProcess.h index f8288b13e3..11e7cf5602 100644 --- a/src/apps/haikudepot/server/AbstractServerProcess.h +++ b/src/apps/haikudepot/server/AbstractServerProcess.h @@ -1,5 +1,5 @@ /* - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -15,10 +15,6 @@ #include "Stoppable.h" -#define APP_ERR_NOT_MODIFIED (B_APP_ERROR_BASE + 452) -#define APP_ERR_NO_DATA (B_APP_ERROR_BASE + 453) - - typedef enum process_options { SERVER_PROCESS_NO_NETWORKING = 1 << 0, SERVER_PROCESS_PREFER_CACHE = 1 << 1, @@ -87,10 +83,8 @@ protected: const BPath& targetFilePath, const BUrl& url); - status_t DeleteLocalFile(const BPath& currentFilePath); - - status_t MoveDamagedFileAside( - const BPath& currentFilePath); + status_t DeleteLocalFile(const BPath& filePath); + status_t MoveDamagedFileAside(const BPath& filePath); bool HasOption(uint32 flag); bool ShouldAttemptNetworkDownload( diff --git a/src/apps/haikudepot/server/AbstractSingleFileServerProcess.cpp b/src/apps/haikudepot/server/AbstractSingleFileServerProcess.cpp index 39df0eba90..2a852fa58f 100644 --- a/src/apps/haikudepot/server/AbstractSingleFileServerProcess.cpp +++ b/src/apps/haikudepot/server/AbstractSingleFileServerProcess.cpp @@ -1,9 +1,10 @@ /* - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #include "AbstractSingleFileServerProcess.h" +#include "HaikuDepotConstants.h" #include "Logger.h" #include "ServerSettings.h" #include "StorageUtils.h" @@ -49,18 +50,17 @@ AbstractSingleFileServerProcess::RunInternal() ServerSettings::CreateFullUrl(urlPathComponent)); } - if (IsSuccess(result) || result == APP_ERR_NOT_MODIFIED) { + if (IsSuccess(result)) { status_t hasDataResult = StorageUtils::ExistsObject( localPath, &hasData, NULL, &size); hasData = hasData && size > 0; if (hasDataResult == B_OK && !hasData) - result = APP_ERR_NO_DATA; + result = HD_ERR_NO_DATA; } - if (IsSuccess(result) || result == APP_ERR_NOT_MODIFIED) { - + if (IsSuccess(result)) { if (Logger::IsInfoEnabled()) printf("[%s] did fetch data\n", Name()); diff --git a/src/apps/haikudepot/server/BulkLoadStateMachine.cpp b/src/apps/haikudepot/server/BulkLoadStateMachine.cpp index e7a5a5b1e0..c88964816b 100644 --- a/src/apps/haikudepot/server/BulkLoadStateMachine.cpp +++ b/src/apps/haikudepot/server/BulkLoadStateMachine.cpp @@ -1,18 +1,17 @@ /* - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #include "BulkLoadStateMachine.h" #include -#include -#include #include "Logger.h" #include "PkgDataUpdateProcess.h" #include "RepositoryDataUpdateProcess.h" #include "ServerIconExportUpdateProcess.h" #include "ServerSettings.h" +#include "ServerHelper.h" BulkLoadStateMachine::BulkLoadStateMachine(Model* model) @@ -186,9 +185,17 @@ BulkLoadStateMachine::Start() if (!IsRunning()) { fBulkLoadContext = new BulkLoadContext(); - if (ServerSettings::ForceNoNetwork() || !HasNetwork()) + if (ServerSettings::IsClientTooOld()) { + printf("bulk load proceeding without network communications " + "because the client is too old\n"); fBulkLoadContext->AddProcessOption( SERVER_PROCESS_NO_NETWORKING); + } + + if (!ServerHelper::IsNetworkAvailable()) { + fBulkLoadContext->AddProcessOption( + SERVER_PROCESS_NO_NETWORKING); + } if (ServerSettings::PreferCache()) fBulkLoadContext->AddProcessOption(SERVER_PROCESS_PREFER_CACHE); @@ -348,22 +355,4 @@ BulkLoadStateMachine::InitiateBulkPopulatePackagesForAllDepots() if (0 == fBulkLoadContext->CountPkgProcesses()) ContextPoll(); -} - - -bool -BulkLoadStateMachine::HasNetwork() -{ - BNetworkRoster& roster = BNetworkRoster::Default(); - BNetworkInterface interface; - uint32 cookie = 0; - while (roster.GetNextInterface(&cookie, interface) == B_OK) { - uint32 flags = interface.Flags(); - if ((flags & IFF_LOOPBACK) == 0 - && (flags & (IFF_UP | IFF_LINK)) == (IFF_UP | IFF_LINK)) { - return true; - } - } - - return false; -} +} \ No newline at end of file diff --git a/src/apps/haikudepot/server/BulkLoadStateMachine.h b/src/apps/haikudepot/server/BulkLoadStateMachine.h index 0fb8f15085..b1063e5d6d 100644 --- a/src/apps/haikudepot/server/BulkLoadStateMachine.h +++ b/src/apps/haikudepot/server/BulkLoadStateMachine.h @@ -1,5 +1,5 @@ /* - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef BULK_LOAD_STATE_MACHINE_H @@ -31,7 +31,6 @@ private: void ContextPoll(); void SetContextState(bulk_load_state state); void StopAllProcesses(); - bool HasNetwork(); bool CanTransitionTo( bulk_load_state targetState); diff --git a/src/apps/haikudepot/server/ServerHelper.cpp b/src/apps/haikudepot/server/ServerHelper.cpp new file mode 100644 index 0000000000..d9033292b7 --- /dev/null +++ b/src/apps/haikudepot/server/ServerHelper.cpp @@ -0,0 +1,92 @@ +/* + * Copyright 2017-2018, Andrew Lindesay . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "ServerHelper.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "HaikuDepotConstants.h" +#include "ServerSettings.h" + + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "ServerHelper" +#define KEY_MSG_MINIMUM_VERSION "minimumVersion" +#define KEY_HEADER_MINIMUM_VERSION "X-Desktop-Application-Minimum-Version" + + +void +ServerHelper::NotifyClientTooOld(const BHttpHeaders& responseHeaders) +{ + if (!ServerSettings::IsClientTooOld()) { + ServerSettings::SetClientTooOld(); + + const char* minimumVersionC = responseHeaders[KEY_HEADER_MINIMUM_VERSION]; + BMessage message(MSG_CLIENT_TOO_OLD); + + if (minimumVersionC != NULL && strlen(minimumVersionC) != 0) { + message.AddString(KEY_MSG_MINIMUM_VERSION, minimumVersionC); + } + + be_app->PostMessage(&message); + } +} + + +void +ServerHelper::AlertClientTooOld(BMessage* message) +{ + BString minimumVersion; + BString alertText; + + if (message->FindString(KEY_MSG_MINIMUM_VERSION, &minimumVersion) != B_OK) + minimumVersion = "???"; + + alertText.SetToFormat( + B_TRANSLATE("This application is too old to communicate with the " + " HaikuDepot server system. Obtain a newer version of HaikuDepot " + " by updating your Haiku system. The minimum version of " + " HaikuDepot required is \"%s\"."), minimumVersion.String()); + + BAlert* alert = new BAlert( + B_TRANSLATE("client_version_too_old"), + alertText, + B_TRANSLATE("OK")); + + alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); + alert->Go(); +} + + +bool +ServerHelper::IsNetworkAvailable() +{ + return !ServerSettings::ForceNoNetwork() && IsPlatformNetworkAvailable(); +} + + +bool +ServerHelper::IsPlatformNetworkAvailable() +{ + BNetworkRoster& roster = BNetworkRoster::Default(); + BNetworkInterface interface; + uint32 cookie = 0; + while (roster.GetNextInterface(&cookie, interface) == B_OK) { + uint32 flags = interface.Flags(); + if ((flags & IFF_LOOPBACK) == 0 + && (flags & (IFF_UP | IFF_LINK)) == (IFF_UP | IFF_LINK)) { + return true; + } + } + + return false; +} diff --git a/src/apps/haikudepot/server/ServerHelper.h b/src/apps/haikudepot/server/ServerHelper.h new file mode 100644 index 0000000000..b526cf8845 --- /dev/null +++ b/src/apps/haikudepot/server/ServerHelper.h @@ -0,0 +1,24 @@ +/* + * Copyright 2017-2018, Andrew Lindesay . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#ifndef SERVER_HELPER_H +#define SERVER_HELPER_H + +#include +#include + + +class ServerHelper { +public: + static bool IsNetworkAvailable(); + static bool IsPlatformNetworkAvailable(); + + static void NotifyClientTooOld( + const BHttpHeaders& responseHeaders + ); + static void AlertClientTooOld(BMessage* message); +}; + +#endif // SERVER_HELPER_H diff --git a/src/apps/haikudepot/server/ServerIconExportUpdateProcess.cpp b/src/apps/haikudepot/server/ServerIconExportUpdateProcess.cpp index 5d434c9a35..521e355d20 100644 --- a/src/apps/haikudepot/server/ServerIconExportUpdateProcess.cpp +++ b/src/apps/haikudepot/server/ServerIconExportUpdateProcess.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -14,6 +14,7 @@ #include #include +#include "HaikuDepotConstants.h" #include "Logger.h" #include "ServerSettings.h" #include "StorageUtils.h" @@ -71,7 +72,7 @@ ServerIconExportUpdateProcess::RunInternal() status_t hasDataResult = HasLocalData(&hasData); if (IsSuccess(hasDataResult) && !hasData) - result = APP_ERR_NO_DATA; + result = HD_ERR_NO_DATA; } } @@ -150,10 +151,7 @@ ServerIconExportUpdateProcess::DownloadAndUnpack() result = Download(tarGzFilePath); - if (result != APP_ERR_NOT_MODIFIED) { - if (result != B_OK) - return result; - + if (result == B_OK) { printf("delete any existing stored data\n"); StorageUtils::RemoveDirectoryContents(fLocalStorageDirectoryPath); @@ -185,9 +183,9 @@ ServerIconExportUpdateProcess::DownloadAndUnpack() } delete tarGzFile; - } - printf("did complete fetching icons\n"); + printf("did complete fetching icons\n"); + } return result; } @@ -226,4 +224,7 @@ ServerIconExportUpdateProcess::Download(BPath& tarGzFilePath) { return DownloadToLocalFileAtomically(tarGzFilePath, ServerSettings::CreateFullUrl("/__pkgicon/all.tar.gz")); -} \ No newline at end of file +} + + + diff --git a/src/apps/haikudepot/server/ServerSettings.cpp b/src/apps/haikudepot/server/ServerSettings.cpp index 043fee4b48..7a24a887d2 100644 --- a/src/apps/haikudepot/server/ServerSettings.cpp +++ b/src/apps/haikudepot/server/ServerSettings.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -10,6 +10,9 @@ #include #include +#include +#include +#include #include #include @@ -24,6 +27,8 @@ pthread_once_t ServerSettings::sUserAgentInitOnce = PTHREAD_ONCE_INIT; bool ServerSettings::sPreferCache = false; bool ServerSettings::sDropCache = false; bool ServerSettings::sForceNoNetwork = false; +bool ServerSettings::sClientTooOld = false; +BLocker ServerSettings::sLock; status_t @@ -152,4 +157,20 @@ void ServerSettings::SetForceNoNetwork(bool value) { sForceNoNetwork = value; +} + + +bool +ServerSettings::IsClientTooOld() +{ + BAutolock locker(&sLock); + return sClientTooOld; +} + + +void +ServerSettings::SetClientTooOld() +{ + BAutolock locker(&sLock); + sClientTooOld = true; } \ No newline at end of file diff --git a/src/apps/haikudepot/server/ServerSettings.h b/src/apps/haikudepot/server/ServerSettings.h index 63fe40ec57..51f6073d4b 100644 --- a/src/apps/haikudepot/server/ServerSettings.h +++ b/src/apps/haikudepot/server/ServerSettings.h @@ -1,5 +1,5 @@ /* - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -26,17 +27,21 @@ public: static void SetDropCache(bool value); static bool ForceNoNetwork(); static void SetForceNoNetwork(bool value); + static bool IsClientTooOld(); + static void SetClientTooOld(); private: static void _InitUserAgent(); static const BString _GetUserAgentVersionString(); + static BLocker sLock; static BUrl sBaseUrl; static BString sUserAgent; static pthread_once_t sUserAgentInitOnce; static bool sPreferCache; static bool sDropCache; static bool sForceNoNetwork; + static bool sClientTooOld; }; #endif // SERVER_SETTINGS_H diff --git a/src/apps/haikudepot/server/WebAppInterface.cpp b/src/apps/haikudepot/server/WebAppInterface.cpp index c3e02ede50..b4e7c0ec09 100644 --- a/src/apps/haikudepot/server/WebAppInterface.cpp +++ b/src/apps/haikudepot/server/WebAppInterface.cpp @@ -23,10 +23,12 @@ #include #include "AutoLocker.h" +#include "HaikuDepotConstants.h" #include "List.h" #include "Logger.h" #include "PackageInfo.h" #include "ServerSettings.h" +#include "ServerHelper.h" #define BASEURL_DEFAULT "https://depot.haiku-os.org" @@ -560,6 +562,12 @@ status_t WebAppInterface::_SendJsonRequest(const char* domain, BString jsonString, uint32 flags, BMessage& reply) const { + if (!ServerHelper::IsNetworkAvailable()) + return HD_NETWORK_INACCESSIBLE; + + if (!ServerSettings::IsClientTooOld()) + return HD_CLIENT_TOO_OLD; + if (Logger::IsTraceEnabled()) printf("_SendJsonRequest(%s)\n", jsonString.String()); @@ -602,9 +610,19 @@ WebAppInterface::_SendJsonRequest(const char* domain, BString jsonString, request.Result()); int32 statusCode = result.StatusCode(); - if (statusCode != 200) { - printf("Response code: %" B_PRId32 "\n", statusCode); - return B_ERROR; + + switch (statusCode) { + case B_HTTP_STATUS_OK: + break; + + case B_HTTP_STATUS_PRECONDITION_FAILED: + ServerHelper::NotifyClientTooOld(result.Headers()); + return HD_CLIENT_TOO_OLD; + + default: + printf("json-rpc request to endpoint [.../%s] failed with http " + "status [%" B_PRId32 "]\n", domain, statusCode); + return B_ERROR; } jsonString.SetTo(static_cast(replyData.Buffer()), diff --git a/src/apps/haikudepot/ui/App.cpp b/src/apps/haikudepot/ui/App.cpp index e7ede8a8f4..af3543d509 100644 --- a/src/apps/haikudepot/ui/App.cpp +++ b/src/apps/haikudepot/ui/App.cpp @@ -1,6 +1,6 @@ /* * Copyright 2013, Stephan Aßmus . - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -24,6 +24,7 @@ #include "FeaturedPackagesView.h" #include "Logger.h" #include "MainWindow.h" +#include "ServerHelper.h" #include "ServerSettings.h" #include "ScreenshotWindow.h" @@ -103,6 +104,10 @@ App::MessageReceived(BMessage* message) break; } + case MSG_CLIENT_TOO_OLD: + ServerHelper::AlertClientTooOld(message); + break; + default: BApplication::MessageReceived(message); break; @@ -149,7 +154,7 @@ app_print_help() fprintf(stdout, "'-v' : allows for the verbosity level to be set.\n"); fprintf(stdout, "'-u' : allows for the haiku depot server url to be\n"); fprintf(stdout, " configured.\n"); - fprintf(stdout, "'--nonetworking' : prevents network access.**\n"); + fprintf(stdout, "'--nonetworking' : prevents network access.\n"); fprintf(stdout, "'--prefercache' : prefer to get data from cache rather\n"); fprintf(stdout, " then obtain data from the network.**\n"); fprintf(stdout, "'--dropcache' : drop cached data before performing\n"); diff --git a/src/apps/haikudepot/ui/MainWindow.h b/src/apps/haikudepot/ui/MainWindow.h index 152b46c1c3..2fda08e70b 100644 --- a/src/apps/haikudepot/ui/MainWindow.h +++ b/src/apps/haikudepot/ui/MainWindow.h @@ -2,7 +2,7 @@ * Copyright 2013-2014, Stephan Aßmus . * Copyright 2013, Rene Gollent . * Copyright 2017, Julian Harnath . - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef MAIN_WINDOW_H @@ -15,6 +15,7 @@ #include "PackageAction.h" #include "PackageActionHandler.h" #include "PackageInfoListener.h" +#include "HaikuDepotConstants.h" class BCardLayout; @@ -30,16 +31,6 @@ class ScreenshotWindow; class WorkStatusView; -enum { - MSG_MAIN_WINDOW_CLOSED = 'mwcl', - MSG_PACKAGE_SELECTED = 'pkgs', - MSG_PACKAGE_WORKER_BUSY = 'pkwb', - MSG_PACKAGE_WORKER_IDLE = 'pkwi', - MSG_ADD_VISIBLE_PACKAGES = 'avpk', - MSG_UPDATE_SELECTED_PACKAGE = 'uspk', -}; - - class MainWindow : public BWindow, private PackageInfoListener, private PackageActionHandler { public: