📄 partfile.cpp
字号:
}
delete packet;
paused = true;
datarate = 0;
transferingsrc = 0;
//theApp.emuledlg->transferwnd.downloadlistctrl.UpdateItem(this);
UpdateDisplayedInfo(true);
SavePartFile();
}
void CPartFile::ResumeFile(){
if (status==PS_COMPLETE || status==PS_COMPLETING) return;
paused = false;
stopped=false;
lastsearchtime = 0;
SavePartFile();
//theApp.emuledlg->transferwnd.downloadlistctrl.UpdateItem(this);
UpdateDisplayedInfo(true);
}
CString CPartFile::getPartfileStatus(){
switch(GetStatus()){
case PS_HASHING:
case PS_WAITINGFORHASH:
return GetResString(IDS_HASHING);
case PS_COMPLETING:
return GetResString(IDS_COMPLETING);
case PS_COMPLETE:
return GetResString(IDS_COMPLETE);
case PS_PAUSED:
return GetResString(IDS_PAUSED);
case PS_ERROR:
return GetResString(IDS_ERRORLIKE);
}
if(GetTransferingSrcCount() > 0)
return GetResString(IDS_DOWNLOADING);
else
return GetResString(IDS_WAITING);
}
int CPartFile::getPartfileStatusRang(){
int tempstatus=0;
if (GetTransferingSrcCount()==0) tempstatus=1;
switch (GetStatus()) {
case PS_HASHING:
case PS_WAITINGFORHASH:
tempstatus=3;
break;
case PS_COMPLETING:
tempstatus=4;
break;
case PS_COMPLETE:
tempstatus=5;
break;
case PS_PAUSED:
tempstatus=2;
break;
case PS_ERROR:
tempstatus=6;
break;
}
return tempstatus;
}
sint32 CPartFile::getTimeRemaining(){
if (GetDatarate()==0) return -1;
return( (GetFileSize()-GetCompletedSize())/ GetDatarate());
}
void CPartFile::PreviewFile(){
if (IsArchive())
{
if ((!m_bRecoveringArchive) && (!m_bPreviewing))
CArchiveRecovery::recover(this, true);
return;
}
if (!PreviewAvailable()){
ASSERT( false );
return;
}
if (theApp.glob_prefs->IsMoviePreviewBackup()) {
m_bPreviewing = true;
CPreviewThread* pThread = (CPreviewThread*) AfxBeginThread(RUNTIME_CLASS(CPreviewThread), THREAD_PRIORITY_NORMAL,0, CREATE_SUSPENDED);
pThread->SetValues(this,theApp.glob_prefs->GetVideoPlayer());
pThread->ResumeThread();
} else {
CString strLine = this->GetFullName();
if (theApp.glob_prefs->GetVideoPlayer().Find("vlc.exe")) strLine.Replace(".met","");
char shortPath[512]; //Cax2 short path for vlc
GetShortPathName(strLine,shortPath,512);
CString path=theApp.glob_prefs->GetVideoPlayer();
int pos=path.ReverseFind('\\');
if (pos==-1) path=""; else path=path.Left(pos+1);
if (theApp.glob_prefs->GetVideoPlayer().GetLength()>0) ShellExecute(NULL, "open", theApp.glob_prefs->GetVideoPlayer() ,strLine/* shortPath*/, path, SW_SHOWNORMAL);
else ShellExecute(NULL, "open", strLine, NULL,NULL, SW_SHOWNORMAL);
}
}
bool CPartFile::PreviewAvailable(){
uint64 space;
space = 0;
space = GetFreeDiskSpaceX(theApp.glob_prefs->GetTempDir());
// Barry - Allow preview of archives of any length > 1k
if (IsArchive())
if (GetStatus() != PS_COMPLETE && GetStatus() != PS_COMPLETING && ( GetFileSize() > 1024) && (!m_bRecoveringArchive) && ((space + 100000000) > (2*GetFileSize())))
return true; else return false;
if (theApp.glob_prefs->IsMoviePreviewBackup())
return !( (GetStatus() != PS_READY && GetStatus() != PS_PAUSED)
|| m_bPreviewing || GetPartCount() < 5 || !IsMovie() || (space + 100000000) < GetFileSize()
|| ( !IsComplete(0,PARTSIZE-1) || !IsComplete(PARTSIZE*(GetPartCount()-1),GetFileSize()-1)));
else
return !((GetStatus() != PS_READY && GetStatus() != PS_PAUSED)
|| m_bPreviewing || GetPartCount() < 2 || !IsMovie() || !IsComplete(0,PARTSIZE-1));
}
void CPartFile::UpdateAvailablePartsCount(){
uint8 availablecounter = 0;
bool breakflag = false;
uint16 iPartCount = GetPartCount();
for (uint32 ixPart = 0; ixPart < iPartCount; ixPart++){
breakflag = false;
for (uint32 sl = 0; sl < SOURCESSLOTS && !breakflag; sl++){
if (!srclists[sl].IsEmpty()){
for(POSITION pos = srclists[sl].GetHeadPosition(); pos && !breakflag; ){
if (srclists[sl].GetNext(pos)->IsPartAvailable(ixPart)){
availablecounter++;
breakflag = true;
}
}
}
}
}
if (iPartCount == availablecounter && availablePartsCount < iPartCount)
lastseencomplete = CTime::GetCurrentTime();
availablePartsCount = availablecounter;
}
Packet* CPartFile::CreateSrcInfoPacket(CUpDownClient* forClient){
int sl;
bool empty=true;
for (sl=0;sl<SOURCESSLOTS;sl++) if (!srclists[sl].IsEmpty()) {empty=false;break;}
if (empty) return 0;
CMemFile data;
uint16 nCount = 0;
data.Write(m_abyFileHash,16);
data.Write(&nCount,2);
bool bNeeded;
for (sl=0;sl<SOURCESSLOTS;sl++) if (!srclists[sl].IsEmpty())
for (POSITION pos = srclists[sl].GetHeadPosition();pos != 0;srclists[sl].GetNext(pos)){
bNeeded = false;
CUpDownClient* cur_src = srclists[sl].GetAt(pos);
if (cur_src->HasLowID())
continue;
// only send source which have needed parts for this client if possible
if (forClient->reqfile == this && forClient->GetPartStatus() && cur_src->GetPartStatus()){
uint8* reqstatus = forClient->GetPartStatus();
uint8* srcstatus = cur_src->GetPartStatus();
for (int x = 0; x < GetPartCount(); x++){
if (srcstatus[x] && !reqstatus[x]){
bNeeded = true;
break;
}
}
}
if( bNeeded ){
nCount++;
uint32 dwID = cur_src->GetUserID();
uint16 nPort = cur_src->GetUserPort();
uint32 dwServerIP = cur_src->GetServerIP();
uint16 nServerPort = cur_src->GetServerPort();
data.Write(&dwID, 4);
data.Write(&nPort, 2);
data.Write(&dwServerIP, 4);
data.Write(&nServerPort, 2);
if (forClient->GetSourceExchangeVersion() > 1)
data.Write(cur_src->GetUserHash(),16);
if (nCount > 500)
break;
}
}
if (!nCount)
return 0;
data.Seek(16, 0);
data.Write(&nCount, 2);
Packet* result = new Packet(&data, OP_EMULEPROT);
result->opcode = OP_ANSWERSOURCES;
if (nCount > 28)
result->PackPacket();
theApp.emuledlg->AddDebugLogLine( false, "Send:Source User(%s) File(%s) Count(%i)", forClient->GetUserName(), GetFileName(), nCount );
return result;
}
void CPartFile::AddClientSources(CMemFile* sources, uint8 sourceexchangeversion){
if (stopped) return;
uint16 nCount;
sources->Read(&nCount,2);
theApp.emuledlg->AddDebugLogLine( false, "RCV:Sources File(%s) Count(%i)", GetFileName(), nCount );
for (int i = 0;i != nCount;i++){
uint32 dwID;
uint16 nPort;
uint32 dwServerIP;
uint16 nServerPort;
uchar m_achUserHash[16];
sources->Read(&dwID,4);
sources->Read(&nPort,2);
sources->Read(&dwServerIP,4);
sources->Read(&nServerPort,2);
if (sourceexchangeversion > 1)
sources->Read(m_achUserHash,16);
// check first if we are this source
if (theApp.serverconnect->GetClientID() < 16777216 && theApp.serverconnect->IsConnected()){
if ((theApp.serverconnect->GetClientID() == dwID) && theApp.serverconnect->GetCurrentServer()->GetIP() == dwServerIP)
continue;
}
else if (theApp.serverconnect->GetClientID() == dwID)
continue;
else if (dwID < 16777216)
continue;
if( theApp.glob_prefs->GetMaxSourcePerFile() > this->GetSourceCount() ){
CUpDownClient* newsource = new CUpDownClient(nPort,dwID,dwServerIP,nServerPort,this);
if (sourceexchangeversion > 1)
newsource->SetUserHash(m_achUserHash);
theApp.downloadqueue->CheckAndAddSource(this,newsource);
}
}
}
// making this function return a higher when more sources have the extended
// protocol will force you to ask a larger variety of people for sources
int CPartFile::GetCommonFilePenalty() {
//TODO: implement, but never return less than MINCOMMONPENALTY!
return MINCOMMONPENALTY;
}
/* Barry - Replaces BlockReceived()
Originally this only wrote to disk when a full 180k block
had been received from a client, and only asked for data in
180k blocks.
This meant that on average 90k was lost for every connection
to a client data source. That is a lot of wasted data.
To reduce the lost data, packets are now written to a buffer
and flushed to disk regularly regardless of size downloaded.
This includes compressed packets.
Data is also requested only where gaps are, not in 180k blocks.
The requests will still not exceed 180k, but may be smaller to
fill a gap.
*/
uint32 CPartFile::WriteToBuffer(uint32 transize, BYTE *data, uint32 start, uint32 end, Requested_Block_Struct *block)
{
// Increment transfered bytes counter for this file
transfered += transize;
// This is needed a few times
uint32 lenData = end - start + 1;
if( lenData > transize )
m_iGainDueToCompression += lenData-transize;
// Occasionally packets are duplicated, no point writing it twice
if (IsComplete(start, end))
{
theApp.emuledlg->AddDebugLogLine(false, "File '%s' has already been written from %ld to %ld", GetFileName(), start, end);
return 0;
}
// Create copy of data as new buffer
BYTE *buffer = new BYTE[lenData];
memcpy(buffer, data, lenData);
// Create a new buffered queue entry
PartFileBufferedData *item = new PartFileBufferedData;
item->data = buffer;
item->start = start;
item->end = end;
item->block = block;
// Add to the queue in the correct position (most likely the end)
PartFileBufferedData *queueItem;
bool added = false;
POSITION pos = m_BufferedData_list.GetTailPosition();
while (pos != NULL)
{
queueItem = m_BufferedData_list.GetPrev(pos);
if (item->end > queueItem->end)
{
added = true;
m_BufferedData_list.InsertAfter(pos, item);
break;
}
}
if (!added)
m_BufferedData_list.AddHead(item);
// Increment buffer size marker
m_nTotalBufferData += lenData;
// Mark this small section of the file as filled
FillGap(item->start, item->end);
// Update the flushed mark on the requested block
// The loop here is unfortunate but necessary to detect deleted blocks.
pos = requestedblocks_list.GetHeadPosition();
while (pos != NULL)
{
if (requestedblocks_list.GetNext(pos) == item->block)
item->block->transferred += lenData;
}
if (gaplist.IsEmpty()) FlushBuffer();
// Return the length of data written to the buffer
return lenData;
}
void CPartFile::FlushBuffer(void)
{
m_nLastBufferFlushTime = GetTickCount();
if (m_BufferedData_list.IsEmpty())
return;
uint32 partCount = GetPartCount();
bool *changedPart = new bool[partCount];
// theApp.emuledlg->AddDebugLogLine(false, "Flushing file %s - buffer size = %ld bytes (%ld queued items) transfered = %ld [time = %ld]\n", GetFileName(), m_nTotalBufferData, m_BufferedData_list.GetCount(), transfered, m_nLastBufferFlushTime);
try
{
// Remember which parts need to be checked at the end of the flush
for (int partNumber=0; (uint32)partNumber<partCount; partNumber++)
{
changedPart[partNumber] = false;
}
// Ensure file is big enough to write data to (the last item will be the furthest from the start)
PartFileBufferedData *item = m_BufferedData_list.GetTail();
if (m_hpartfile.GetLength() <= item->end)
m_hpartfile.SetLength(item->end + 1);
// Loop through queue
for (int i = m_BufferedData_list.GetCount(); i>0; i--)
{
// Get top item
item = m_BufferedData_list.GetHead();
// This is needed a few times
uint32 lenData = item->end - item->start + 1;
int curpart = item->start/PARTSIZE;
changedPart[curpart] = true;
// Go to the correct position in file and write block of data
m_hpartfile.Seek(item->start, CFile::begin);
m_hpartfile.Write(item->data, lenData);
// Remove item from queue
m_BufferedData_list.RemoveHead();
// Decrease buffer size
m_nTotalBufferData -= lenData;
// Release memory used by this item
delete [] item->data;
delete item;
}
// Flush to disk
m_hpartfile.Flush();
// Check each part of the file
uint32 partRange = (m_hpartfile.GetLength() % PARTSIZE) - 1;
for (int partNumber = partCount-1; partNumber >= 0; partNumber--)
{
if (changedPart[partNumber] == false)
{
// Any parts other than last must be full size
partRange = PARTSIZE - 1;
continue;
}
// Is this 9MB part complete
if ( IsComplete(PARTSIZE * partNumber, (PARTSIZE * (partNumber + 1)) - 1 ) )
{
// Is part corrupt
if (!HashSinglePart(partNumber))
{
theApp.emuledlg->AddLogLine(true, GetResString(IDS_ERR_PARTCORRUPT), partNumber, GetFileName());
AddGap(PARTSIZE*partNumber, (PARTSIZE*partNumber + partRange));
corrupted_list.AddTail(partNumber);
// Reduce transfered amount by corrupt amount
this->m_iLostDueToCorruption += (partRange + 1);
}
else
{
// Successfully completed part, make it available for sharing
if (status == PS_EMPTY)
{
status = PS_READY;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -