2019-11-01 20:00:28 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2017-2018 Adubbz
|
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2019-10-18 03:59:34 +00:00
|
|
|
#include "install/http_nsp.hpp"
|
|
|
|
|
|
|
|
#include <switch.h>
|
|
|
|
#include <threads.h>
|
|
|
|
#include "data/buffered_placeholder_writer.hpp"
|
|
|
|
#include "util/title_util.hpp"
|
2019-10-22 22:14:37 +00:00
|
|
|
#include "util/error.hpp"
|
|
|
|
#include "util/debug.h"
|
2019-10-26 05:58:32 +00:00
|
|
|
#include "util/util.hpp"
|
2019-12-20 00:09:36 +00:00
|
|
|
#include "util/lang.hpp"
|
2019-12-19 02:36:38 +00:00
|
|
|
#include "ui/instPage.hpp"
|
2019-10-18 03:59:34 +00:00
|
|
|
|
|
|
|
namespace tin::install::nsp
|
|
|
|
{
|
2019-12-13 16:46:23 +00:00
|
|
|
bool stopThreadsHttpNsp;
|
2019-12-13 16:04:42 +00:00
|
|
|
|
2019-10-18 03:59:34 +00:00
|
|
|
HTTPNSP::HTTPNSP(std::string url) :
|
|
|
|
m_download(url)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
struct StreamFuncArgs
|
|
|
|
{
|
|
|
|
tin::network::HTTPDownload* download;
|
|
|
|
tin::data::BufferedPlaceholderWriter* bufferedPlaceholderWriter;
|
|
|
|
u64 pfs0Offset;
|
|
|
|
u64 ncaSize;
|
|
|
|
};
|
|
|
|
|
|
|
|
int CurlStreamFunc(void* in)
|
|
|
|
{
|
|
|
|
StreamFuncArgs* args = reinterpret_cast<StreamFuncArgs*>(in);
|
|
|
|
|
|
|
|
auto streamFunc = [&](u8* streamBuf, size_t streamBufSize) -> size_t
|
|
|
|
{
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
if (args->bufferedPlaceholderWriter->CanAppendData(streamBufSize))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
args->bufferedPlaceholderWriter->AppendData(streamBuf, streamBufSize);
|
|
|
|
return streamBufSize;
|
|
|
|
};
|
|
|
|
|
2019-12-13 16:46:23 +00:00
|
|
|
if (args->download->StreamDataRange(args->pfs0Offset, args->ncaSize, streamFunc) == 1) stopThreadsHttpNsp = true;
|
2019-10-18 03:59:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int PlaceholderWriteFunc(void* in)
|
|
|
|
{
|
|
|
|
StreamFuncArgs* args = reinterpret_cast<StreamFuncArgs*>(in);
|
|
|
|
|
2019-12-13 16:46:23 +00:00
|
|
|
while (!args->bufferedPlaceholderWriter->IsPlaceholderComplete() && !stopThreadsHttpNsp)
|
2019-10-18 03:59:34 +00:00
|
|
|
{
|
|
|
|
if (args->bufferedPlaceholderWriter->CanWriteSegmentToPlaceholder())
|
|
|
|
args->bufferedPlaceholderWriter->WriteSegmentToPlaceholder();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-03 18:18:42 +00:00
|
|
|
void HTTPNSP::StreamToPlaceholder(std::shared_ptr<nx::ncm::ContentStorage>& contentStorage, NcmContentId placeholderId)
|
2019-10-18 03:59:34 +00:00
|
|
|
{
|
|
|
|
const PFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(placeholderId);
|
|
|
|
std::string ncaFileName = this->GetFileEntryName(fileEntry);
|
|
|
|
|
2019-11-30 17:12:59 +00:00
|
|
|
LOG_DEBUG("Retrieving %s\n", ncaFileName.c_str());
|
2019-10-18 03:59:34 +00:00
|
|
|
size_t ncaSize = fileEntry->fileSize;
|
|
|
|
|
2019-11-03 18:18:42 +00:00
|
|
|
tin::data::BufferedPlaceholderWriter bufferedPlaceholderWriter(contentStorage, placeholderId, ncaSize);
|
2019-10-18 03:59:34 +00:00
|
|
|
StreamFuncArgs args;
|
|
|
|
args.download = &m_download;
|
|
|
|
args.bufferedPlaceholderWriter = &bufferedPlaceholderWriter;
|
|
|
|
args.pfs0Offset = this->GetDataOffset() + fileEntry->dataOffset;
|
|
|
|
args.ncaSize = ncaSize;
|
|
|
|
thrd_t curlThread;
|
|
|
|
thrd_t writeThread;
|
|
|
|
|
2019-12-13 16:46:23 +00:00
|
|
|
stopThreadsHttpNsp = false;
|
2019-10-18 03:59:34 +00:00
|
|
|
thrd_create(&curlThread, CurlStreamFunc, &args);
|
|
|
|
thrd_create(&writeThread, PlaceholderWriteFunc, &args);
|
2019-11-03 18:18:42 +00:00
|
|
|
|
|
|
|
u64 freq = armGetSystemTickFreq();
|
2019-10-18 03:59:34 +00:00
|
|
|
u64 startTime = armGetSystemTick();
|
|
|
|
size_t startSizeBuffered = 0;
|
|
|
|
double speed = 0.0;
|
|
|
|
|
2019-12-19 02:36:38 +00:00
|
|
|
inst::ui::instPage::setInstBarPerc(0);
|
2019-12-13 16:46:23 +00:00
|
|
|
while (!bufferedPlaceholderWriter.IsBufferDataComplete() && !stopThreadsHttpNsp)
|
2019-10-18 03:59:34 +00:00
|
|
|
{
|
|
|
|
u64 newTime = armGetSystemTick();
|
|
|
|
|
2019-11-06 00:45:31 +00:00
|
|
|
if (newTime - startTime >= freq * 0.5)
|
2019-10-18 03:59:34 +00:00
|
|
|
{
|
|
|
|
size_t newSizeBuffered = bufferedPlaceholderWriter.GetSizeBuffered();
|
|
|
|
double mbBuffered = (newSizeBuffered / 1000000.0) - (startSizeBuffered / 1000000.0);
|
|
|
|
double duration = ((double)(newTime - startTime) / (double)freq);
|
|
|
|
speed = mbBuffered / duration;
|
|
|
|
|
|
|
|
startTime = newTime;
|
|
|
|
startSizeBuffered = newSizeBuffered;
|
|
|
|
|
2019-11-04 01:07:38 +00:00
|
|
|
int downloadProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeBuffered() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
2019-10-18 03:59:34 +00:00
|
|
|
|
2019-12-20 00:09:36 +00:00
|
|
|
inst::ui::instPage::setInstInfoText("inst.info_page.downloading"_lang + inst::util::formatUrlString(ncaFileName) + "inst.info_page.at"_lang + std::to_string(speed).substr(0, std::to_string(speed).size()-4) + "MB/s");
|
2019-12-19 02:36:38 +00:00
|
|
|
inst::ui::instPage::setInstBarPerc((double)downloadProgress);
|
2019-11-04 01:07:38 +00:00
|
|
|
}
|
2019-10-18 03:59:34 +00:00
|
|
|
}
|
2019-12-19 02:36:38 +00:00
|
|
|
inst::ui::instPage::setInstBarPerc(100);
|
2019-10-18 03:59:34 +00:00
|
|
|
|
2019-12-20 00:09:36 +00:00
|
|
|
inst::ui::instPage::setInstInfoText("inst.info_page.top_info0"_lang + ncaFileName + "...");
|
2019-12-19 02:36:38 +00:00
|
|
|
inst::ui::instPage::setInstBarPerc(0);
|
2019-12-13 16:46:23 +00:00
|
|
|
while (!bufferedPlaceholderWriter.IsPlaceholderComplete() && !stopThreadsHttpNsp)
|
2019-10-18 03:59:34 +00:00
|
|
|
{
|
|
|
|
int installProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
|
|
|
|
2019-12-19 02:36:38 +00:00
|
|
|
inst::ui::instPage::setInstBarPerc((double)installProgress);
|
2019-10-18 03:59:34 +00:00
|
|
|
}
|
2019-12-19 02:36:38 +00:00
|
|
|
inst::ui::instPage::setInstBarPerc(100);
|
2019-11-03 18:18:42 +00:00
|
|
|
|
2019-10-18 03:59:34 +00:00
|
|
|
thrd_join(curlThread, NULL);
|
|
|
|
thrd_join(writeThread, NULL);
|
2019-12-20 00:09:36 +00:00
|
|
|
if (stopThreadsHttpNsp) THROW_FORMAT(("inst.net.transfer_interput"_lang).c_str());
|
2019-10-18 03:59:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void HTTPNSP::BufferData(void* buf, off_t offset, size_t size)
|
|
|
|
{
|
|
|
|
m_download.BufferDataRange(buf, offset, size, nullptr);
|
|
|
|
}
|
2019-11-03 18:18:42 +00:00
|
|
|
}
|