platform/shared/common/RhodesApp.cpp in rhodes-2.0.3 vs platform/shared/common/RhodesApp.cpp in rhodes-2.1.0
- old
+ new
@@ -1,81 +1,76 @@
#include "RhodesApp.h"
#include "common/RhoMutexLock.h"
#include "common/IRhoClassFactory.h"
#include "common/RhoConf.h"
#include "common/RhoFilePath.h"
+#include "common/RhoAppAdapter.h"
#include "net/INetRequest.h"
-#include "net/HttpServer.h"
-#include "ruby/ext/rho/rhoruby.h"
-//#include <math.h>
#include "sync/ClientRegister.h"
#include "sync/SyncThread.h"
-#include "net/AsyncHttp.h"
-#include "unzip/unzip.h"
#include "net/URI.h"
+
+#include "net/HttpServer.h"
+#include "ruby/ext/rho/rhoruby.h"
+#include "net/AsyncHttp.h"
#include "rubyext/WebView.h"
+#include "rubyext/GeoLocation.h"
#ifdef OS_WINCE
#include <winsock.h>
#endif
-//#include "shttpd/src/shttpd.h"
-//#include "shttpd/src/std_includes.h"
using rho::net::HttpHeader;
using rho::net::HttpHeaderList;
using rho::net::CHttpServer;
extern "C" {
-void rho_sync_create();
-void rho_sync_destroy();
-void rho_sync_doSyncAllSources(int show_status_popup);
void rho_map_location(char* query);
void rho_appmanager_load( void* httpContext, const char* szQuery);
void rho_db_init_attr_manager();
+void rho_sys_app_exit();
}
namespace rho {
namespace common{
IMPLEMENT_LOGCLASS(CRhodesApp,"RhodesApp");
-CRhodesApp* CRhodesApp::m_pInstance = 0;
/*static*/ CRhodesApp* CRhodesApp::Create(const String& strRootPath)
{
if ( m_pInstance != null)
- return m_pInstance;
+ return (CRhodesApp*)m_pInstance;
m_pInstance = new CRhodesApp(strRootPath);
- return m_pInstance;
+ return (CRhodesApp*)m_pInstance;
}
/*static*/void CRhodesApp::Destroy()
{
if ( m_pInstance )
delete m_pInstance;
m_pInstance = 0;
}
-CRhodesApp::CRhodesApp(const String& strRootPath) : CRhoThread(createClassFactory())
+CRhodesApp::CRhodesApp(const String& strRootPath) : CRhodesAppBase(strRootPath)
{
- m_strRhoRootPath = strRootPath;
m_bExit = false;
+ m_bDeactivationMode = false;
- m_ptrFactory = createClassFactory();
+ m_ptrFactory = rho_impl_createClassFactory();
m_NetRequest = m_ptrFactory->createNetRequest();
- m_oGeoLocation.init(m_ptrFactory);
#if defined( OS_WINCE ) || defined (OS_WINDOWS)
//initializing winsock
WSADATA WsaData;
int result = WSAStartup(MAKEWORD(2,2),&WsaData);
#endif
- //rho_logconf_Init(m_strRhoRootPath.c_str());
initAppUrls();
- //start(epNormal);
+
+ initHttpServer();
getSplashScreen().init();
}
void CRhodesApp::startApp()
@@ -84,34 +79,43 @@
}
void CRhodesApp::run()
{
LOG(INFO) + "Starting RhodesApp main routine...";
- initHttpServer();
RhoRubyStart();
+ rubyext::CGeoLocation::Create(m_ptrFactory);
+
rho_db_init_attr_manager();
LOG(INFO) + "Starting sync engine...";
- rho_sync_create();
+ sync::CSyncThread::Create(rho_impl_createClassFactory());
LOG(INFO) + "RhoRubyInitApp...";
RhoRubyInitApp();
- LOG(INFO) + "activate app";
- rho_ruby_activateApp();
+ //LOG(INFO) + "activate app";
+ //rho_ruby_activateApp();
getSplashScreen().hide();
LOG(INFO) + "navigate to first start url";
navigateToUrl(getFirstStartUrl());
- m_httpServer->run();
+ //rho_clientregister_create("iphone_client");
+
+ while (!m_bExit) {
+ m_httpServer->run();
+ if (m_bExit)
+ break;
+ wait(-1);
+ }
LOG(INFO) + "RhodesApp thread shutdown";
+ rubyext::CGeoLocation::Destroy();
RhoRubyStop();
- rho_sync_destroy();
+ sync::CSyncThread::Destroy();
}
CRhodesApp::~CRhodesApp(void)
{
stopApp();
@@ -125,66 +129,133 @@
void CRhodesApp::stopApp()
{
if (!m_bExit)
{
m_bExit = true;
- m_httpServer->stop();
+ m_httpServer->stop();
+ stopWait();
stop(2000);
}
net::CAsyncHttp::Destroy();
}
-class CRhoCallbackCall : public common::CRhoThread
+template <typename T>
+class CRhoCallInThread : public common::CRhoThread
{
- common::CAutoPtr<common::IRhoClassFactory> m_ptrFactory;
- String m_strCallback, m_strBody;
public:
- CRhoCallbackCall(const String& strCallback, const String& strBody, common::IRhoClassFactory* factory) : CRhoThread(factory),
- m_ptrFactory(factory), m_strCallback(strCallback), m_strBody(strBody)
- { start(epNormal); }
+ CRhoCallInThread(T* cb)
+ :CRhoThread(rho_impl_createClassFactory()), m_cb(cb)
+ {
+ start(epNormal);
+ }
private:
virtual void run()
{
- common::CAutoPtr<net::INetRequest> pNetRequest = m_ptrFactory->createNetRequest();
- common::CAutoPtr<net::INetResponse> presp = pNetRequest->pushData( m_strCallback, m_strBody, null );
+ m_cb->run(*this);
delete this;
}
+
+private:
+ common::CAutoPtr<T> m_cb;
};
+template <typename T>
+void rho_rhodesapp_call_in_thread(T *cb)
+{
+ new CRhoCallInThread<T>(cb);
+}
+
+class CRhoCallbackCall
+{
+ common::CAutoPtr<common::IRhoClassFactory> m_ptrFactory;
+ String m_strCallback, m_strBody;
+public:
+ CRhoCallbackCall(const String& strCallback, const String& strBody, common::IRhoClassFactory* factory)
+ :m_ptrFactory(factory), m_strCallback(strCallback), m_strBody(strBody)
+ {}
+
+ void run(common::CRhoThread &)
+ {
+ common::CAutoPtr<net::INetRequest> pNetRequest = m_ptrFactory->createNetRequest();
+ common::CAutoPtr<net::INetResponse> presp = pNetRequest->pushData( m_strCallback, m_strBody, null );
+ }
+};
+
void CRhodesApp::runCallbackInThread(const String& strCallback, const String& strBody)
{
- new CRhoCallbackCall(strCallback, strBody, createClassFactory() );
+ rho_rhodesapp_call_in_thread(new CRhoCallbackCall(strCallback, strBody, rho_impl_createClassFactory() ) );
}
static void callback_activateapp(void *arg, String const &strQuery)
{
rho_ruby_activateApp();
String strMsg;
rho_http_sendresponse(arg, strMsg.c_str());
}
+static void callback_deactivateapp(void *arg, String const &strQuery)
+{
+ rho_ruby_deactivateApp();
+ String strMsg;
+ rho_http_sendresponse(arg, strMsg.c_str());
+}
+
static void callback_loadserversources(void *arg, String const &strQuery)
{
- rho_ruby_loadserversources(strQuery.c_str());
+ RhoAppAdapter.loadServerSources(strQuery);
String strMsg;
rho_http_sendresponse(arg, strMsg.c_str());
}
+class CRhoActivateApp
+{
+ String m_strUrl;
+public:
+ CRhoActivateApp(const String& strUrl) :m_strUrl(strUrl) {}
+ void run(common::CRhoThread &thisThread)
+ {
+ while (!rho_is_local_server_started())
+ thisThread.wait(1);
+ common::CAutoPtr<common::IRhoClassFactory> factory = rho_impl_createClassFactory();
+ common::CAutoPtr<net::INetRequest> pNetRequest = factory->createNetRequest();
+ NetResponse(resp, pNetRequest->pullData( m_strUrl, null ) );
+ if ( !resp.isOK() )
+ LOG(ERROR) + "activate app failed. Code: " + resp.getRespCode() + "; Error body: " + resp.getCharData();
+ }
+};
+
void CRhodesApp::callAppActiveCallback(boolean bActive)
{
- m_httpServer->pause(!bActive);
+ LOG(INFO) + "callAppActiveCallback";
if (bActive)
{
+ this->stopWait();
+
String strUrl = m_strHomeUrl + "/system/activateapp";
+ // Activation callback need to be runned in separate thread
+ // Otherwise UI thread will be blocked. This can cause deadlock if user defined
+ // activate callback contains code which need to hold UI thread for execute
+ rho_rhodesapp_call_in_thread( new CRhoActivateApp( strUrl ) );
+ }
+ else
+ {
+ // Deactivation callback must be called in place (not in separate thread!)
+ // This is because system can kill application at any time after this callback finished
+ // So to guarantee user code is executed on deactivation, we must not exit from this function
+ // until application finish executing of user-defined deactivation callback.
+ // However, blocking UI thread can cause problem with API refering to UI (such as WebView.navigate etc)
+ // To fix this problem, new mode 'deactivation' introduced. When this mode active, no UI operations allowed.
+ // All such operation will throw exception in ruby code when calling in 'deactivate' mode.
+ m_bDeactivationMode = true;
+ String strUrl = m_strHomeUrl + "/system/deactivateapp";
NetResponse(resp,getNet().pullData( strUrl, null ));
if ( !resp.isOK() )
- LOG(ERROR) + "activate app failed. Code: " + resp.getRespCode() + "; Error body: " + resp.getCharData();
-
- LOG(INFO) + "navigate to first start url";
- navigateToUrl(getFirstStartUrl());
+ LOG(ERROR) + "deactivate app failed. Code: " + resp.getRespCode() + "; Error body: " + resp.getCharData();
+ m_httpServer->stop();
+ m_bDeactivationMode = false;
}
}
void CRhodesApp::callCameraCallback(String strCallbackUrl, const String& strImagePath,
const String& strError, boolean bCancel )
@@ -202,10 +273,28 @@
strBody += "&rho_callback=1";
NetRequest( getNet().pushData( strCallbackUrl, strBody, null ) );
}
+void CRhodesApp::callSignatureCallback(String strCallbackUrl, const String& strSignaturePath,
+ const String& strError, boolean bCancel )
+ {
+ strCallbackUrl = canonicalizeRhoUrl(strCallbackUrl);
+ String strBody;
+ if ( bCancel || strError.length() > 0 )
+ {
+ if ( bCancel )
+ strBody = "status=cancel&message=User canceled operation.";
+ else
+ strBody = "status=error&message=" + strError;
+ }else
+ strBody = "status=ok&signature_uri=db%2Fdb-files%2F" + strSignaturePath;
+
+ strBody += "&rho_callback=1";
+ NetRequest( getNet().pushData( strCallbackUrl, strBody, null ) );
+ }
+
void CRhodesApp::callDateTimeCallback(String strCallbackUrl, long lDateTime, const char* szData, int bCancel )
{
strCallbackUrl = canonicalizeRhoUrl(strCallbackUrl);
String strBody;
if ( bCancel )
@@ -318,10 +407,11 @@
m_httpServer->register_uri("/system/map", callback_map);
m_httpServer->register_uri("/system/shared", callback_shared);
m_httpServer->register_uri("/AppManager/loader/load", callback_AppManager_load);
m_httpServer->register_uri("/system/getrhomessage", callback_getrhomessage);
m_httpServer->register_uri("/system/activateapp", callback_activateapp);
+ m_httpServer->register_uri("/system/deactivateapp", callback_deactivateapp);
m_httpServer->register_uri("/system/loadserversources", callback_loadserversources);
}
const char* CRhodesApp::getFreeListeningPort()
{
@@ -421,29 +511,20 @@
return m_strListeningPorts.c_str();
}
void CRhodesApp::initAppUrls()
{
+ CRhodesAppBase::initAppUrls();
m_currentTabIndex = 0;
m_strHomeUrl = "http://localhost:";
m_strHomeUrl += getFreeListeningPort();
- m_strBlobsDirPath = getRhoRootPath() + "db/db-files";
- m_strDBDirPath = getRhoRootPath() + "db";
m_strLoadingPagePath = "file://" + getRhoRootPath() + "apps/app/loading.html";
m_strLoadingPngPath = getRhoRootPath() + "apps/app/loading.png";
}
-String CRhodesApp::resolveDBFilesPath(const String& strFilePath)
-{
- if ( String_startsWith(strFilePath, getRhoRootPath()) )
- return strFilePath;
-
- return CFilePath::join(getRhoRootPath(), strFilePath);
-}
-
void CRhodesApp::keepLastVisitedUrl(String strUrl)
{
//LOG(INFO) + "Current URL: " + strUrl;
m_currentUrls[m_currentTabIndex] = canonicalizeRhoUrl(strUrl);
@@ -542,30 +623,22 @@
//rho::String strAppUrl = getAppBackUrl();
if ( m_strAppBackUrlOrig.length() > 0 )
loadUrl(m_strAppBackUrlOrig);
else if ( strcasecmp(getCurrentUrl().c_str(),getStartUrl().c_str()) != 0 )
+ {
+#ifdef OS_MACOSX
+ if (RHOCONF().getBool("jqtouch_mode"))
+ {
+ rho_webview_execute_js("window.Rho.jqt.goBack()", 0);
+ return;
+ }
+#endif
rho_webview_navigate_back();
+ }
}
-String CRhodesApp::canonicalizeRhoUrl(const String& strUrl)
-{
- if (strUrl.length() == 0 )
- return m_strHomeUrl;
-
- if ( strncmp("http://", strUrl.c_str(), 7 ) == 0 ||
- strncmp("https://", strUrl.c_str(), 8 ) == 0 ||
- strncmp("javascript:", strUrl.c_str(), 11 ) == 0 ||
- strncmp("mailto:", strUrl.c_str(), 7) == 0 ||
- strncmp("tel:", strUrl.c_str(), 4) == 0 ||
- strncmp("wtai:", strUrl.c_str(), 5) == 0
- )
- return strUrl;
-
- return CFilePath::join(m_strHomeUrl,strUrl);
-}
-
boolean CRhodesApp::sendLog()
{
String strDevicePin = rho::sync::CClientRegister::getInstance() ? rho::sync::CClientRegister::getInstance()->getDevicePin() : "";
String strClientID = rho::sync::CSyncThread::getSyncEngine().readClientID();
@@ -600,11 +673,10 @@
for (int i = 0; i < (int)m_arCallbackObjects.size(); i++)
{
if ( m_arCallbackObjects.elementAt(i) == 0 )
nIndex = i;
}
-// rho_ruby_holdValue(valObject);
if ( nIndex == -1 )
{
m_arCallbackObjects.addElement(pCallbackObject);
nIndex = m_arCallbackObjects.size()-1;
}else
@@ -647,13 +719,11 @@
synchronized(m_mxPushCallback)
{
if ( m_strPushCallback.length() == 0 )
return false;
- String strBody = "status=ok&message=";
- net::URI::urlEncode(strData, strBody);
- strBody += "&rho_callback=1";
+ String strBody = strData + "&rho_callback=1";
if ( m_strPushCallbackParams.length() > 0 )
strBody += "&" + m_strPushCallbackParams;
common::CAutoPtr<net::INetRequest> pNetRequest = m_ptrFactory->createNetRequest();
NetResponse(resp,pNetRequest->pushData( m_strPushCallback, strBody, null ));
@@ -664,11 +734,11 @@
const char* szData = resp.getCharData();
return !(szData && strcmp(szData,"rho_push") == 0);
}
}
- return true;
+ return false;
}
void CRhodesApp::setScreenRotationNotification(String strUrl, String strParams)
{
synchronized(m_mxScreenRotationCallback)
@@ -708,11 +778,16 @@
boolean callback = false;
if (String_startsWith(url, "callback:") )
{
callback = true;
url = url.substr(9);
+ }else if ( strcasecmp(url.c_str(), "exit")==0 || strcasecmp(url.c_str(), "close") == 0 )
+ {
+ rho_sys_app_exit();
+ return;
}
+
url = canonicalizeRhoUrl(url);
if (callback)
{
common::CAutoPtr<net::INetRequest> pNetRequest = m_ptrFactory->createNetRequest();
NetResponse(resp, pNetRequest->pushData( url, "rho_callback=1", null ));
@@ -720,15 +795,23 @@
}
else
navigateToUrl(url);
}
+boolean CRhodesApp::isLocalServerStarted()
+{
+ if (!m_httpServer)
+ return false;
+ return m_httpServer->started();
+}
+
} //namespace common
} //namespace rho
extern "C" {
+using namespace rho::common;
unsigned long rho_rhodesapp_GetCallbackObject(int nIndex)
{
return RHODESAPP().getCallbackObject(nIndex);
}
@@ -880,10 +963,16 @@
const char* strError, int bCancel )
{
RHODESAPP().callCameraCallback(strCallbackUrl, strImagePath, strError, bCancel != 0);
}
+void rho_rhodesapp_callSignatureCallback(const char* strCallbackUrl, const char* strSignaturePath,
+ const char* strError, int bCancel )
+{
+ RHODESAPP().callSignatureCallback(strCallbackUrl, strSignaturePath, strError, bCancel != 0);
+}
+
void rho_rhodesapp_callDateTimeCallback(const char* strCallbackUrl, long lDateTime, const char* szData, int bCancel )
{
RHODESAPP().callDateTimeCallback(strCallbackUrl, lDateTime, szData, bCancel != 0);
}
@@ -892,11 +981,12 @@
RHODESAPP().callPopupCallback(strCallbackUrl, id, title);
}
void rho_rhodesapp_callAppActiveCallback(int nActive)
{
- RHODESAPP().callAppActiveCallback(nActive!=0);
+ if ( rho::common::CRhodesApp::getInstance() )
+ RHODESAPP().callAppActiveCallback(nActive!=0);
}
void rho_rhodesapp_setViewMenu(unsigned long valMenu)
{
RHODESAPP().getAppMenu().setAppMenu(valMenu);
@@ -1013,57 +1103,49 @@
return out;
}
void rho_net_request(const char *url)
{
- rho::common::CAutoPtr<rho::common::IRhoClassFactory> factory = rho::common::createClassFactory();
+ rho::common::CAutoPtr<rho::common::IRhoClassFactory> factory = rho_impl_createClassFactory();
rho::common::CAutoPtr<rho::net::INetRequest> request = factory->createNetRequest();
request->pullData(url, null);
}
-int rho_unzip_file(const char* szZipPath)
+void rho_rhodesapp_load_url(const char *url)
{
-#ifdef UNICODE
- rho::StringW strZipPathW;
- rho::common::convertToStringW(szZipPath, strZipPathW);
- HZIP hz = OpenZipFile(strZipPathW.c_str(), "");
- if ( !hz )
- return 0;
+ RHODESAPP().loadUrl(url);
+}
- // Set base for unziping
- SetUnzipBaseDir(hz, rho::common::convertToStringW(RHODESAPP().getDBDirPath()).c_str() );
-#else
- HZIP hz = OpenZipFile(szZipPath, "");
- if ( !hz )
+int rho_rhodesapp_check_mode()
+{
+ if (RHODESAPP().deactivationMode())
+ {
+ LOG(ERROR) + "Operation is not allowed in 'deactivation' mode";
return 0;
+ }
+ return 1;
+}
- // Set base for unziping
- SetUnzipBaseDir(hz, RHODESAPP().getDBDirPath().c_str() );
-#endif
+int rho_is_local_server_started()
+{
+ return RHODESAPP().isLocalServerStarted();
+}
- ZIPENTRY ze;
- ZRESULT res = 0;
- // Get info about the zip
- // -1 gives overall information about the zipfile
- res = GetZipItem(hz,-1,&ze);
- int numitems = ze.index;
-
- // Iterate through items and unzip them
- for (int zi = 0; zi<numitems; zi++)
- {
- // fetch individual details, e.g. the item's name.
- res = GetZipItem(hz,zi,&ze);
- if ( res == ZR_OK )
- res = UnzipItem(hz, zi, ze.name);
- }
-
- CloseZip(hz);
-
- return res == ZR_OK ? 1 : 0;
+#if defined(OS_ANDROID) && defined(RHO_LOG_ENABLED)
+int rho_log(const char *fmt, ...)
+{
+ va_list vl;
+ va_start(vl, fmt);
+ int ret = __android_log_vprint(ANDROID_LOG_INFO, "RhoLog", fmt, vl);
+ va_end(vl);
+ return ret;
}
-void rho_rhodesapp_load_url(const char *url)
+unsigned long long rho_cur_time()
{
- RHODESAPP().loadUrl(url);
+ timeval tv;
+ gettimeofday(&tv, NULL);
+ return ((unsigned long long)tv.tv_sec)*1000000 + tv.tv_usec;
}
+#endif
} //extern "C"