[Tizen] Http thread implementation.

+ Move and scale
This commit is contained in:
Sergey Pisarchik 2014-04-27 20:10:48 +03:00 committed by Alex Zolotarev
parent 308503449a
commit b2b9e6e40a
9 changed files with 513 additions and 48 deletions

View file

@ -0,0 +1,283 @@
#include "http_thread_tizen.hpp"
#include"../base/logging.hpp"
#include "platform.hpp"
#include "http_thread_callback.hpp"
#include "tizen_string_utils.hpp"
#include <FBaseColIEnumerator.h>
using namespace std;
using namespace Tizen::Net::Http;
using Tizen::Base::String;
using Tizen::Base::LongLong;
using Tizen::Base::ByteBuffer;
using Tizen::Base::Collection::IEnumerator;
HttpThread::HttpThread(std::string const & url,
downloader::IHttpThreadCallback & callback,
int64_t beg,
int64_t end,
int64_t size,
string const & pb)
: m_callback(callback),
m_begRange(beg), m_endRange(end),
m_downloadedBytes(0), m_expectedSize(size),
m_url(url), m_pb(pb),
m_pTransaction(null)
{
result r = E_SUCCESS;
String * pProxyAddr = null;
String hostAddr(m_url.c_str());
HttpHeader * header = NULL;
LOG(LDEBUG, ("Creating HttpSession", m_url));
m_pSession = new HttpSession();
r = m_pSession->Construct(NET_HTTP_SESSION_MODE_NORMAL, pProxyAddr, hostAddr, header);
if (r != E_SUCCESS)
{
LOG(LERROR, ("HttpSession Construction error:", r));
return;
}
// Open a new HttpTransaction.
m_pTransaction = m_pSession->OpenTransactionN();
if ((r = GetLastResult()) != E_SUCCESS)
{
LOG(LERROR, ("OpenTransactionN", GetLastResult()));
return;
}
m_pTransaction->AddHttpTransactionListener(*this);
m_pTransaction->SetHttpProgressListener(*this);
HttpRequest* pRequest = m_pTransaction->GetRequest();
pRequest->SetUri(m_url.c_str());
HttpHeader* pHeader = pRequest->GetHeader();
// use Range header only if we don't download whole file from start
if (!(m_begRange == 0 && m_endRange < 0))
{
if (m_endRange > 0)
{
LOG(LDEBUG, (m_url, "downloading range [", m_begRange, ",", m_endRange, "]"));
String range("bytes=");
range.Append(m_begRange);
range.Append('-');
range.Append(m_endRange);
pHeader->AddField(L"Range", range);
}
else
{
LOG(LDEBUG, (m_url, "resuming download from position", m_begRange));
String range("bytes=");
range.Append(m_begRange);
range.Append('-');
pHeader->AddField("Range", range);
}
}
// set user-agent with unique client id only for mapswithme requests
if (m_url.find("mapswithme.com") != string::npos)
{
static string const uid = GetPlatform().UniqueClientId();
pHeader->AddField("User-Agent", uid.c_str());
}
if (m_pb.empty())
{
pRequest->SetMethod(NET_HTTP_METHOD_GET);
}
else
{
pRequest->SetMethod(NET_HTTP_METHOD_POST);
pHeader->AddField("Content-Type", "application/json");
long long sz = m_pb.size();
String lenght;
lenght.Append(sz);
pHeader->AddField("Content-Length", lenght);
ByteBuffer body;
body.Construct((const byte *)m_pb.c_str(), 0, sz, sz);
pRequest->WriteBody(body);
}
LOG(LDEBUG, ("Connecting to", m_url, "[", m_begRange, ",", m_endRange, "]", "size=", m_expectedSize));
r = m_pTransaction->Submit();
}
HttpThread::~HttpThread()
{
m_pTransaction->RemoveHttpTransactionListener(*this);
m_pSession->CloseTransaction(*m_pTransaction);
delete m_pTransaction;
delete m_pSession;
}
void HttpThread::OnTransactionHeaderCompleted (HttpSession &httpSession,
HttpTransaction &httpTransaction,
int headerLen, bool bAuthRequired)
{
result r = E_SUCCESS;
HttpResponse* pResponse = httpTransaction.GetResponse();
if ((r = GetLastResult()) != E_SUCCESS)
{
LOG(LWARNING, ("httpTransaction.GetResponse error", r));
return;
}
int const httpStatusCode = pResponse->GetHttpStatusCode();
// When we didn't ask for chunks, code should be 200
// When we asked for a chunk, code should be 206
bool const isChunk = !(m_begRange == 0 && m_endRange < 0);
if ((isChunk && httpStatusCode != 206) || (!isChunk && httpStatusCode != 200))
{
LOG(LWARNING, ("Http request to", m_url, " aborted with HTTP code", httpStatusCode));
r = httpSession.CancelTransaction(httpTransaction);
r = httpSession.CloseTransaction(httpTransaction);
LOG(LDEBUG, ("CloseTransaction result", r));
return;
}
else if (m_expectedSize > 0)
{
bool bGoodSize = false;
// try to get content length from Content-Range header first
HttpHeader * pHeader = pResponse->GetHeader();
LOG(LDEBUG, ("Header:", FromTizenString(*pHeader->GetRawHeaderN())));
IEnumerator * pValues = pHeader->GetFieldValuesN("Content-Range");
if (GetLastResult() == E_SUCCESS)
{
bGoodSize = true;
pValues->MoveNext(); // strange, but works
String const * pString = dynamic_cast<String const *>(pValues->GetCurrent());
if (pString->GetLength())
{
int lastInd;
pString->LastIndexOf ('/', pString->GetLength()-1, lastInd);
long long value = -1;
String tail;
pString->SubString(lastInd + 1, tail);
LOG(LDEBUG, ("tail value:",FromTizenString(tail)));
LongLong::Parse(tail, value);
if (value != m_expectedSize)
{
LOG(LWARNING, ("Http request to", m_url,
"aborted - invalid Content-Range:", value, " expected:" ,m_expectedSize ));
r = httpSession.CancelTransaction(httpTransaction);
r = httpSession.CloseTransaction(httpTransaction);
LOG(LDEBUG, ("CloseTransaction result", r));
}
}
}
else
{
pValues = pHeader->GetFieldValuesN("Content-Length");
if (GetLastResult() == E_SUCCESS)
{
bGoodSize = true;
pValues->MoveNext(); // strange, but works
String const * pString = dynamic_cast<String const *>(pValues->GetCurrent());
if (pString)
{
long long value = -1;
LongLong::Parse(*pString, value);
if (value != m_expectedSize)
{
LOG(LWARNING, ("Http request to", m_url,
"aborted - invalid Content-Length:", value, " expected:" ,m_expectedSize ));
r = httpSession.CancelTransaction(httpTransaction);
r = httpSession.CloseTransaction(httpTransaction);
LOG(LDEBUG, ("CloseTransaction result", r));
}
}
}
}
if (!bGoodSize)
{
LOG(LWARNING, ("Http request to", m_url,
"aborted, server didn't send any valid file size"));
r = httpSession.CancelTransaction(httpTransaction);
r = httpSession.CloseTransaction(httpTransaction);
LOG(LDEBUG, ("CloseTransaction result", r));
}
}
}
void HttpThread::OnHttpDownloadInProgress (HttpSession &/*httpSession*/,
Tizen::Net::Http::HttpTransaction &httpTransaction,
long long currentLength,
long long totalLength)
{
HttpResponse* pResponse = httpTransaction.GetResponse();
if (pResponse->GetHttpStatusCode() == HTTP_STATUS_OK
|| pResponse->GetHttpStatusCode() == HTTP_STATUS_PARTIAL_CONTENT)
{
ByteBuffer* pBuffer = null;
pBuffer = pResponse->ReadBodyN();
int chunkSize = pBuffer->GetLimit();
m_downloadedBytes += chunkSize;
m_callback.OnWrite(m_begRange + m_downloadedBytes - chunkSize, pBuffer->GetPointer(), chunkSize);
delete pBuffer;
}
else
LOG(LERROR, ("OnHttpDownloadInProgress ERROR", FromTizenString(pResponse->GetStatusText())));
}
void HttpThread::OnTransactionCompleted (HttpSession &/*httpSession*/,
HttpTransaction & httpTransaction)
{
HttpResponse* pResponse = httpTransaction.GetResponse();
if (pResponse->GetHttpStatusCode() == HTTP_STATUS_OK
|| pResponse->GetHttpStatusCode() == HTTP_STATUS_PARTIAL_CONTENT)
{
m_callback.OnFinish(200, m_begRange, m_endRange);
}
else
{
LOG(LWARNING, ("Download has finished with status code:", pResponse->GetHttpStatusCode(),
" and text:", FromTizenString(pResponse->GetStatusText() )));
m_callback.OnFinish(-100, m_begRange, m_endRange);
}
}
void HttpThread::OnTransactionAborted (HttpSession &/*httpSession*/,
HttpTransaction &/*httpTransaction*/,
result r)
{
LOG(LINFO, ("OnTransactionAborted result:", r));
m_callback.OnFinish(-100, m_begRange, m_endRange);
}
void HttpThread::OnTransactionCertVerificationRequiredN (HttpSession &/*httpSession*/,
HttpTransaction &/*httpTransaction*/,
String */*pCert*/)
{
LOG(LERROR, ("OnTransactionCertVerificationRequiredN"));
}
void HttpThread::OnTransactionReadyToRead (HttpSession &/*httpSession*/,
HttpTransaction &/*httpTransaction*/,
int /*availableBodyLen*/)
{
}
void HttpThread::OnTransactionReadyToWrite (HttpSession &/*httpSession*/,
HttpTransaction &/*httpTransaction*/,
int /*recommendedChunkSize*/)
{
}
void HttpThread::OnHttpUploadInProgress (Tizen::Net::Http::HttpSession &/*httpSession*/,
Tizen::Net::Http::HttpTransaction &/*httpTransaction*/,
long long /*currentLength*/,
long long /*totalLength*/)
{
}

View file

@ -0,0 +1,77 @@
#pragma once
#include "../../std/target_os.hpp"
#include "../../std/noncopyable.hpp"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wignored-qualifiers"
#include <FNet.h>
#pragma clang diagnostic pop
namespace downloader
{
class IHttpThreadCallback;
}
using namespace Tizen::Net::Http;
class HttpThread
: public Tizen::Net::Http::IHttpTransactionEventListener
, public Tizen::Net::Http::IHttpProgressEventListener
, noncopyable
{
public:
HttpThread(std::string const & url,
downloader::IHttpThreadCallback & callback,
int64_t beg, int64_t end,
int64_t size,
std::string const & pb);
~HttpThread();
bool OnStart(void);
///
///Tizen::Net::Http::IHttpTransactionEventListener
///
virtual void OnTransactionAborted (HttpSession &httpSession,
HttpTransaction &httpTransaction,
result r);
virtual void OnTransactionCertVerificationRequiredN (HttpSession &httpSession,
HttpTransaction &httpTransaction,
Tizen::Base::String *pCert);
virtual void OnTransactionCompleted (HttpSession &httpSession,
HttpTransaction &httpTransaction);
virtual void OnTransactionHeaderCompleted (HttpSession &httpSession,
HttpTransaction &httpTransaction,
int headerLen, bool bAuthRequired);
virtual void OnTransactionReadyToRead (HttpSession &httpSession,
HttpTransaction &httpTransaction,
int availableBodyLen);
virtual void OnTransactionReadyToWrite (HttpSession &httpSession,
HttpTransaction &httpTransaction,
int recommendedChunkSize);
///
///Tizen::Net::Http::IHttpProgressEventListener
///
virtual void OnHttpDownloadInProgress (HttpSession &httpSession,
HttpTransaction &httpTransaction,
long long currentLength,
long long totalLength);
virtual void OnHttpUploadInProgress (HttpSession &httpSession,
HttpTransaction &httpTransaction,
long long currentLength,
long long totalLength);
private:
downloader::IHttpThreadCallback & m_callback;
int64_t m_begRange;
int64_t m_endRange;
int64_t m_downloadedBytes;
int64_t m_expectedSize;
std::string const m_url;
std::string const & m_pb;
HttpSession * m_pSession;
HttpTransaction* m_pTransaction;
};

View file

@ -41,10 +41,12 @@ INCLUDEPATH += $$ROOT_DIR/3party/jansson/src
SOURCES += platform_android.cpp \
pthread_video_timer.cpp
} else:tizen* {
HEADERS += tizen_string_utils.hpp
HEADERS += tizen_string_utils.hpp \
http_thread_tizen.hpp
SOURCES += platform_tizen.cpp \
tizen_string_utils.cpp \
pthread_video_timer.cpp
pthread_video_timer.cpp \
http_thread_tizen.cpp \
}
macx-*|iphone* {

View file

@ -1,23 +1,22 @@
#include "platform.hpp"
#include <FAppApp.h>
#include "../../tizen/inc/FIo.hpp"
#include "constants.hpp"
#include "platform_unix_impl.hpp"
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "../base/logging.hpp"
#include "../coding/file_reader.hpp"
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "constants.hpp"
#include "platform_unix_impl.hpp"
#include "tizen_string_utils.hpp"
#include "http_thread_tizen.hpp"
#include <FAppApp.h>
#include "../../tizen/inc/FIo.hpp"
Platform::Platform()
{
@ -121,13 +120,14 @@ HttpThread * CreateNativeHttpThread(string const & url,
int64_t size,
string const & pb)
{
// todo;
return 0;
HttpThread * pRes = new HttpThread(url, cb, beg, end, size, pb);
return pRes;
}
void DeleteNativeHttpThread(HttpThread * request)
{
// todo;
delete request;
}
}

View file

@ -2,20 +2,23 @@
#include <FUi.h>
#include <FUiITouchEventListener.h>
#include "../../../std/vector.hpp"
class MapsWithMeApp;
class MapsWithMeForm
: public Tizen::Ui::Controls::Form
: public Tizen::Ui::Controls::Form
, public Tizen::Ui::ITouchEventListener
, public Tizen::Ui::IActionEventListener
{
public:
MapsWithMeForm(MapsWithMeApp* pApp);
virtual ~MapsWithMeForm(void);
virtual result OnDraw(void);
bool Initialize(void);
virtual result OnInitializing(void);
// virtual void OnTouchCanceled (const Tizen::Ui::Control &source, const Tizen::Graphics::Point &currentPosition, const Tizen::Ui::TouchEventInfo &touchInfo)
virtual void OnTouchFocusIn (const Tizen::Ui::Control &source,
const Tizen::Graphics::Point &currentPosition,
const Tizen::Ui::TouchEventInfo &touchInfo);
@ -31,6 +34,9 @@ public:
virtual void OnTouchReleased (const Tizen::Ui::Control &source,
const Tizen::Graphics::Point &currentPosition,
const Tizen::Ui::TouchEventInfo &touchInfo);
virtual void OnActionPerformed(const Tizen::Ui::Control& source, int actionId);
private:
std::vector<std::pair<double, double> > m_prev_pts;
MapsWithMeApp* m_pApp;
};

View file

@ -1,24 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Manifest xmlns="http://schemas.tizen.org/2012/12/manifest">
<Id>3BMaQARPoL</Id>
<Version>1.0.0</Version>
<Type>C++App</Type>
<Requirements>
<Feature Name="http://tizen.org/feature/platform.native.api.version">2.2</Feature>
</Requirements>
<Apps>
<ApiVersion>2.2</ApiVersion>
<Privileges></Privileges>
<UiApp Name="MapsWithMe" Main="True" MenuIconVisible="True">
<UiScalability CoordinateSystem="Logical" BaseScreenSize="Normal" LogicalCoordinate="720"></UiScalability>
<UiTheme SystemTheme="White"></UiTheme>
<DisplayNames>
<DisplayName Locale="eng-GB">MapsWithMe</DisplayName>
</DisplayNames>
<Icons>
<Icon Section="MainMenu" >mainmenu.png</Icon>
</Icons>
</UiApp>
</Apps>
<Id>3BMaQARPoL</Id>
<Version>1.0.0</Version>
<Type>C++App</Type>
<Requirements>
<Feature Name="http://tizen.org/feature/platform.native.api.version">2.2</Feature>
</Requirements>
<Apps>
<ApiVersion>2.2</ApiVersion>
<Privileges>
<Privilege>http://tizen.org/privilege/http</Privilege>
<Privilege>http://tizen.org/privilege/download</Privilege>
</Privileges>
<UiApp LaunchingHistoryVisible="True" Main="True" MenuIconVisible="True" Name="MapsWithMe">
<UiScalability BaseScreenSize="Normal" CoordinateSystem="Logical" LogicalCoordinate="720"/>
<UiTheme SystemTheme="White"/>
<DisplayNames>
<DisplayName Locale="eng-GB">MapsWithMe</DisplayName>
</DisplayNames>
<Icons>
<Icon Section="MainMenu">mainmenu.png</Icon>
</Icons>
<LaunchConditions/>
</UiApp>
</Apps>
</Manifest>

View file

@ -35,7 +35,7 @@ bool MapsWithMeApp::OnAppInitializing(AppRegistry& appRegistry)
MapsWithMeForm * pForm = new MapsWithMeForm(this);
TryReturn(pForm != null, false, "The memory is insufficient.");
pForm->Construct(Tizen::Ui::Controls::FORM_STYLE_NORMAL);
pForm->Initialize();
pMapsWithMeFrame->AddControl(pForm);
pForm->AddTouchEventListener(*pForm);

View file

@ -2,6 +2,19 @@
#include "MapsWithMeApp.h"
#include "Framework.hpp"
#include "../../../map/framework.hpp"
#include "../../../gui/controller.hpp"
#include <FUi.h>
#include <FBase.h>
#include <FMedia.h>
#include <FGraphics.h>
using namespace Tizen::Ui;
using namespace Tizen::Ui::Controls;
using namespace Tizen::Graphics;
using namespace Tizen::Media;
using namespace Tizen::Base;
using namespace Tizen::Base::Collection;
using namespace Tizen::Base::Utility;
MapsWithMeForm::MapsWithMeForm(MapsWithMeApp* pApp)
: m_pApp(pApp)
@ -13,34 +26,117 @@ MapsWithMeForm::~MapsWithMeForm(void)
{
}
bool MapsWithMeForm::Initialize(void)
{
LOG(LDEBUG, ("MapsWithMeForm::Initialize"));
Construct(Tizen::Ui::Controls::FORM_STYLE_NORMAL);
return true;
}
result MapsWithMeForm::OnInitializing(void)
{
LOG(LDEBUG, ("MapsWithMeForm::OnInitializing"));
return E_SUCCESS;
}
void MapsWithMeForm::OnActionPerformed(const Tizen::Ui::Control& source, int actionId)
{
}
result MapsWithMeForm::OnDraw(void)
{
return m_pApp->Draw();
}
namespace detail
{
std::vector<std::pair<double, double> > GetTouchedPoints()
{
std::vector<std::pair<double, double> > res;
IListT<TouchEventInfo *> * pList = TouchEventManager::GetInstance()->GetTouchInfoListN();
if (pList)
{
int count = pList->GetCount();
for (int i = 0; i < count; ++i)
{
TouchEventInfo * pTouchInfo;
pList->GetAt(i, pTouchInfo);
Point pt = pTouchInfo->GetCurrentPosition();
res.push_back(std::make_pair(pt.x, pt.y));
}
pList->RemoveAll();
delete pList;
}
return res;
}
}
void MapsWithMeForm::OnTouchPressed(const Tizen::Ui::Control& source,
const Tizen::Graphics::Point& currentPosition,
const Tizen::Ui::TouchEventInfo& touchInfo)
{
LOG(LINFO, ("OnTouchPressed"));
std::vector<std::pair<double, double> > pts = detail::GetTouchedPoints();
::Framework * pFramework = tizen::Framework::GetInstance();
pFramework->StartDrag(DragEvent(currentPosition.x, currentPosition.y));
if (!pFramework->GetGuiController()->OnTapStarted(m2::PointD(pts[0].first, pts[0].second)))
{
if (pts.size() == 1)
pFramework->StartDrag(DragEvent(pts[0].first, pts[0].second));
else if (pts.size() > 1)
pFramework->StartScale(ScaleEvent(pts[0].first, pts[0].second, pts[1].first, pts[1].second));
}
std::swap(m_prev_pts, pts);
}
void MapsWithMeForm::OnTouchMoved(const Tizen::Ui::Control& source,
const Tizen::Graphics::Point& currentPosition,
const Tizen::Ui::TouchEventInfo& touchInfo)
{
std::vector<std::pair<double, double> > pts = detail::GetTouchedPoints();
::Framework * pFramework = tizen::Framework::GetInstance();
pFramework->DoDrag(DragEvent(currentPosition.x, currentPosition.y));
if (!pFramework->GetGuiController()->OnTapMoved(m2::PointD(pts[0].first, pts[0].second)))
{
if (pts.size() == 1)
pFramework->DoDrag(DragEvent(pts[0].first, pts[0].second));
else if (pts.size() > 1)
{
if (m_prev_pts.size() > 1)
{
pFramework->DoScale(ScaleEvent(pts[0].first, pts[0].second, pts[1].first, pts[1].second));
}
else if (!m_prev_pts.empty())
{
pFramework->StopDrag(DragEvent(m_prev_pts[0].first, m_prev_pts[0].second));
pFramework->StartScale(ScaleEvent(pts[0].first, pts[0].second, pts[1].first, pts[1].second));
}
}
}
std::swap(m_prev_pts, pts);
}
void MapsWithMeForm::OnTouchReleased(const Tizen::Ui::Control& source,
const Tizen::Graphics::Point& currentPosition,
const Tizen::Ui::TouchEventInfo& touchInfo)
{
std::vector<std::pair<double, double> > pts = detail::GetTouchedPoints();
::Framework * pFramework = tizen::Framework::GetInstance();
pFramework->StopDrag(DragEvent(currentPosition.x, currentPosition.y));
//using prev_pts because pts contains not all points
if (!m_prev_pts.empty())
{
if (!pFramework->GetGuiController()->OnTapEnded(m2::PointD(m_prev_pts[0].first, m_prev_pts[0].second)))
{
if (m_prev_pts.size() == 1)
pFramework->StopDrag(DragEvent(m_prev_pts[0].first, m_prev_pts[0].second));
else if (m_prev_pts.size() > 1)
pFramework->StopScale(ScaleEvent(m_prev_pts[0].first, m_prev_pts[0].second, m_prev_pts[1].first, m_prev_pts[1].second));
}
m_prev_pts.clear();
}
}
void MapsWithMeForm::OnTouchFocusIn(const Tizen::Ui::Control& source,
@ -54,6 +150,3 @@ void MapsWithMeForm::OnTouchFocusOut(const Tizen::Ui::Control& source,
const Tizen::Ui::TouchEventInfo& touchInfo)
{
}

View file

@ -277,6 +277,7 @@ QMAKE_LINK_SHLIB = $${QMAKE_CXX}
QMAKE_CFLAGS += -g -Wall -c --sysroot="/Users/Sergey/tizen-sdk/platforms/tizen2.2/rootstraps/tizen-emulator-2.2.native"
QMAKE_CFLAGS += -I"/Users/Sergey/tizen-sdk/platforms/tizen2.2/rootstraps/tizen-emulator-2.2.native/usr/include"
QMAKE_CFLAGS += -I"/Users/Sergey/tizen-sdk/platforms/tizen2.2/rootstraps/tizen-emulator-2.2.native/usr/include/osp"
QMAKE_CFLAGS += -I"/Users/Sergey/tizen-sdk/platforms/tizen2.2/rootstraps/tizen-emulator-2.2.native/usr/include/libxml2"
# TODO: fix paths
QMAKE_CFLAGS_RELEASE += -O3