#include "baseapp.h"
#include "data_download.h"
#include "data_downloads.h"
#include "resmgr/resmgr.h"
#include "client_lib/client_interface.h"
namespace KBEngine{
DataDownload::DataDownload(PyObjectPtr objptr,
const std::string & descr, int16 id):
objptr_(objptr),
descr_(descr),
id_(id),
pDataDownloads_(NULL),
sentStart_(false),
totalBytes_(0),
totalSentBytes_(0),
remainSent_(0),
currSent_(0),
stream_(NULL),
entityID_(0),
error_(false)
{
}
DataDownload::~DataDownload()
{
SAFE_RELEASE_ARRAY(stream_);
Proxy* proxy = static_cast<Proxy*>(Baseapp::getSingleton().findEntity(entityID_));
if(proxy)
{
proxy->onStreamComplete(id_, totalBytes_ > 0 ? totalSentBytes_ == totalBytes_ : false);
}
}
bool DataDownload::send(const Network::MessageHandler& msgHandler, Network::Bundle* pBundle)
{
Proxy* proxy = static_cast<Proxy*>(Baseapp::getSingleton().findEntity(entityID_));
if(proxy && proxy->clientEntityCall())
{
proxy->sendToClient(msgHandler, pBundle);
}
else
{
Network::Bundle::reclaimPoolObject(pBundle);
return false;
}
return true;
}
thread::TPTask::TPTaskState DataDownload::presentMainThread()
{
if(error_)
{
ERROR_MSG(fmt::format("DataDownload::presentMainThread: proxy({}), downloadID({}), type({}), thread error.\n",
entityID(), id(), (int)type()));
return thread::TPTask::TPTASK_STATE_COMPLETED;
}
uint32 datasize = GAME_PACKET_MAX_SIZE_TCP - sizeof(int16) - sizeof(uint32);
if ((remainSent_ > 0 && currSent_ < remainSent_) || totalBytes_ == 0)
{
Network::Bundle* pBundle = Network::Bundle::createPoolObject(OBJECTPOOL_POINT);
if(!sentStart_)
{
pBundle->newMessage(ClientInterface::onStreamDataStarted);
(*pBundle) << this->id();
(*pBundle) << totalBytes_;
(*pBundle) << descr_;
(*pBundle) << type();
sentStart_ = true;
if(!send(ClientInterface::onStreamDataStarted, pBundle))
{
DEBUG_MSG(fmt::format("DataDownload::presentMainThread: proxy({}), downloadID({}), type({}), thread exit.\n",
entityID(), id(), (int)type()));
return thread::TPTask::TPTASK_STATE_COMPLETED;
}
return thread::TPTask::TPTASK_STATE_CONTINUE_MAINTHREAD;
}
pBundle->newMessage(ClientInterface::onStreamDataRecv);
(*pBundle) << id();
if(remainSent_ - currSent_ > datasize)
{
(*pBundle) << datasize;
(*pBundle).append(getOutStream() + currSent_, datasize);
currSent_ += datasize;
totalSentBytes_ += datasize;
if(!send(ClientInterface::onStreamDataRecv, pBundle))
{
DEBUG_MSG(fmt::format("DataDownload::presentMainThread: proxy({}), downloadID({}), type({}), thread exit.\n",
entityID(), id(), (int)type()));
error_ = true;
return thread::TPTask::TPTASK_STATE_COMPLETED;
}
}
else
{
datasize = remainSent_ - currSent_;
(*pBundle) << datasize;
(*pBundle).append(getOutStream() + currSent_, datasize);
if(!send(ClientInterface::onStreamDataRecv, pBundle))
{
DEBUG_MSG(fmt::format("DataDownload::presentMainThread: proxy({}), downloadID({}), type({}), thread exit.\n",
entityID(), id(), (int)type()));
error_ = true;
return thread::TPTask::TPTASK_STATE_COMPLETED;
}
totalSentBytes_ += datasize;
currSent_ = remainSent_;
}
}
if(totalSentBytes_ == totalBytes_)
{
DEBUG_MSG(fmt::format("DataDownload::presentMainThread: proxy({0}), downloadID({1}), type({6}), sentBytes={5},{2}/{3} ({4:.2f}%).\n",
entityID(), id(), totalSentBytes_, this->totalBytes(), 100.0f, datasize, (int)type()));
pDataDownloads_->onDownloadCompleted(this);
Network::Bundle* pBundle = Network::Bundle::createPoolObject(OBJECTPOOL_POINT);
pBundle->newMessage(ClientInterface::onStreamDataCompleted);
(*pBundle) << this->id();
send(ClientInterface::onStreamDataCompleted, pBundle);
return thread::TPTask::TPTASK_STATE_COMPLETED;
}
DEBUG_MSG(fmt::format("DataDownload::presentMainThread: proxy({0}), downloadID({1}), type({6}), sentBytes={5},{2}/{3} ({4:.2f}%).\n",
entityID(), id(), totalSentBytes_, this->totalBytes(),
(((float)totalSentBytes_ / (float)this->totalBytes()) * 100.0f), datasize, type()));
if(currSent_ == remainSent_)
{
DEBUG_MSG(fmt::format("DataDownload::presentMainThread: proxy({}), downloadID({}), type({}), thread-continue.\n",
entityID(), id(), (int)type()));
return thread::TPTask::TPTASK_STATE_CONTINUE_CHILDTHREAD;
}
return thread::TPTask::TPTASK_STATE_CONTINUE_MAINTHREAD;
}
StringDataDownload::StringDataDownload(PyObjectPtr objptr,
const std::string & descr, int16 id):
DataDownload(objptr, descr, id)
{
PyObject* pyobj = PyUnicode_AsUTF8String(objptr.get());
if(pyobj == NULL)
{
SCRIPT_ERROR_CHECK();
error_ = true;
}
else
{
totalBytes_ = (uint32)PyBytes_GET_SIZE(pyobj);
stream_ = new char[totalBytes_ + 1];
memcpy(getOutStream(), PyBytes_AS_STRING(pyobj), totalBytes_);
Py_DECREF(pyobj);
}
}
StringDataDownload::~StringDataDownload()
{
}
bool StringDataDownload::process()
{
return false;
}
char* StringDataDownload::getOutStream()
{
remainSent_ = totalBytes_ - totalSentBytes_;
if(remainSent_ > 65535)
remainSent_ = 65535;
currSent_ = 0;
return stream_ + totalSentBytes_;
}
int8 StringDataDownload::type()
{
return static_cast<int8>(DataDownloadFactory::DATA_DOWNLOAD_STREAM_STRING);
}
FileDataDownload::FileDataDownload(PyObjectPtr objptr,
const std::string & descr, int16 id):
DataDownload(objptr, descr, id)
{
path_ = PyUnicode_AsUTF8AndSize(objptr.get(), NULL);
stream_ = new char[65537];
}
FileDataDownload::~FileDataDownload()
{
}
bool FileDataDownload::process()
{
ResourceObjectPtr fptr = Resmgr::getSingleton().openResource(path_.c_str(), "rb");
if(fptr == NULL || !fptr->valid())
{
ERROR_MSG(fmt::format("FileDataDownload::process(): can't open {}.\n",
Resmgr::getSingleton().matchRes(path_).c_str()));
error_ = true;
return false;
}
FileObject* f = static_cast<FileObject*>(fptr.get());
if(totalBytes_ == 0)
{
f->seek(0, SEEK_END);
totalBytes_ = f->tell();
}
f->seek(totalSentBytes_, SEEK_SET);
remainSent_ = f->read(stream_, 65535);
currSent_ = 0;
if(remainSent_ == 0)
remainSent_ = totalBytes_ - totalSentBytes_;
return false;
}
int8 FileDataDownload::type()
{
return static_cast<int8>(DataDownloadFactory::DATA_DOWNLOAD_STREAM_FILE);
}
}