📄 downloading.cpp
字号:
/*
This file is part of KCeasy (http://www.kceasy.com)
Copyright (C) 2002-2004 Markus Kern <mkern@kceasy.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
//---------------------------------------------------------------------------
#pragma hdrstop
#include "Downloading.h"
#include "GiftCommand.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
namespace KCeasyEngine {
// initial number of max sources. 0 is unlimited.
static const int INITIAL_MAX_SOURCES = 20;
// if there was no data transfer for this time look for new sources
static const int KEEP_ALIVE_TIMEOUT = 1000 * 60 * 10;
// class TDlSource
// public
unsigned int TDlSource::GetTimeLeft()
{
if(Throughput.GetBps() == 0)
return 0;
return (Size - Transmitted) / Throughput.GetBps();
}
// private
TDlSource::TDlSource()
: State(New),
Start(0),
Size(0),
Transmitted(0)
{
User = new TUser();
}
TDlSource::~TDlSource()
{
delete User;
}
// private
bool TDlSource::SetStateStr(const string& StateStr)
{
if(StateStr == "Waiting") State = Waiting;
else if(StateStr == "Paused") State = Paused;
else if(StateStr == "Queued (Remotely)") State = QueuedRemote;
else if(StateStr == "Queued") State = QueuedLocal;
else if(StateStr == "Active") State = Active;
else if(StateStr == "Complete") State = Complete;
else if(StateStr == "Cancelled (Remotely)") State = Cancelled;
else if(StateStr == "Timed out") State = Timeout;
else {
State = Unused;
return false;
}
return true;
}
// class TDownload
// private
TDownload::TDownload(TEngine* ParentEngine, const THashSet* NHashes)
: Engine(ParentEngine),
Hashes(NULL),
GiftId(0),
MaxSources(INITIAL_MAX_SOURCES),
SourcesSearch(NULL),
State(New),
FileSize(0),
Transmitted(0),
Cancelling(false)
{
Hashes = new THashSet(NHashes);
// set active on creation
LastActiveTime = ::GetTickCount();
}
TDownload::~TDownload()
{
delete Hashes;
ClearSources();
}
void TDownload::ClearSources()
{
LockSources();
while(!Sources.empty()) {
delete Sources.front();
Sources.pop_front();
}
ReleaseSources();
}
bool TDownload::ProcessAddDownload(TGiftCommand* Cmd)
{
if(Cmd->Name != "ADDDOWNLOAD")
return false;
Engine->LockDownloads();
// update download
GiftId = string_to_int(Cmd->Value);
SaveFileName = Cmd->GetNode("file").Value;
FileSize = string_to_int(Cmd->GetNode("size").Value);
Transmitted = string_to_int(Cmd->GetNode("transmit").Value);
// set mime type if not already set from search result in AddSource
if(MimeType == "")
MimeType = Cmd->GetNode("mime").Value;
// HACK: get network from random source
if(Cmd->NodeExists("SOURCE"))
Network = ProtocolFromUrl(Cmd->GetNode("SOURCE").GetNode("url").Value);
// notify UI if this download wasn't created by us
if(State == New) {
// always make state queued at first
State = TDownload::Queued;
Engine->ReleaseDownloads();
Engine->SendCallback(CbcNewDownload,(void*)this);
Engine->LockDownloads();
}
// always make state queued at first if not paused
State = (Cmd->GetNode("state").Value == "Paused") ? Paused : Queued;
// set active on creation
LastActiveTime = ::GetTickCount();
// set current file path
string SavePath = Cmd->GetNode("path").Value;
if(SavePath != "") {
if (Engine->IsUsingLocalGift())
SavePath = UnixToWindowsPath(SavePath);
// decide where to save it
if(IncomingPath == "")
IncomingPath = SavePath;
else if (IncomingPath != SavePath)
CompletedPath = SavePath;
}
// erase all previous sources and add the reported ones
LockSources();
ClearSources();
for(TGiftCommand::Iterator itr=Cmd->Nodes.begin();itr!=Cmd->Nodes.end();++itr) {
if((*itr).Name == "SOURCE") {
TDlSource* DlSource = new TDlSource();
DlSource->SourceId = (*itr).GetNode("url").Value;
DlSource->GetUser()->SetId((*itr).GetNode("user").Value);
DlSource->Network = ProtocolFromUrl(DlSource->SourceId);
DlSource->Start = string_to_int((*itr).GetNode("start").Value);
DlSource->Size = string_to_int((*itr).GetNode("total").Value);
DlSource->Transmitted = string_to_int((*itr).GetNode("transmit").Value);
DlSource->SetStateStr((*itr).GetNode("statusgrl").Value);
DlSource->ProtoState = (*itr).GetNode("status").Value;
Sources.push_back(DlSource);
ReleaseSources();
Engine->ReleaseDownloads();
// notify UI
Engine->SendCallback(CbcDownloadAddSource,(void*)this,(void*)DlSource);
Engine->LockDownloads();
LockSources();
}
}
ReleaseSources();
Engine->ReleaseDownloads();
return true;
}
bool TDownload::ProcessDelDownload(TGiftCommand* Cmd)
{
if(Cmd->Name != "DELDOWNLOAD" || string_to_int(Cmd->Value) != GiftId)
return false;
Engine->LockDownloads();
// update state
switch(State) {
case Completed: {
// add file to shares if we have a path
if(GetCompletedPath() != "") {
TSharedFile* File = new TSharedFile();
*File->Hashes = *GetHashes();
File->FileName = FileFromPath(GetCompletedPath());
File->FileDir = DirFromPath(GetCompletedPath());
File->FileSize = GetFileSize();
File->MimeType = GetMimeType();
File->FileType = FileTypeFromMime(File->MimeType);
File->MetaData = GetMetaData();
Engine->GetShares()->AddFile(File);
delete File;
}
break;
}
case Cancelled:
case Failed: {
break;
}
default: {
// we should never get here
if(GetTransmitted() == GetFileSize())
State = Completed;
else
State = Cancelled;
break;
}
}
GiftId = 0; // giFT reuses old IDs so drop it
LastActiveTime = 0;
if(SourcesSearch) {
SourcesSearch->Cancel();
SourcesSearch->SetUData(NULL);
SourcesSearch = NULL; // will be freed in TSearch::ProcessItem later
}
Engine->ReleaseDownloads();
// notify UI
Engine->SendCallback(CbcDownloadUpdate,(void*)this);
return true;
}
bool TDownload::ProcessChgDownload(TGiftCommand* Cmd)
{
if(Cmd->Name != "CHGDOWNLOAD" || string_to_int(Cmd->Value) != GiftId)
return false;
if(State == Cancelled || State == Completed || State == Failed)
return false;
Engine->LockDownloads();
// update sources
int TimeElapsed = string_to_int(Cmd->GetNode("elapsed").Value);
LockSources();
Throughput.Reset();
for(TGiftCommand::Iterator itr=Cmd->Nodes.begin();itr!=Cmd->Nodes.end();++itr) {
if((*itr).Name == "SOURCE") {
// find matching source
string SourceId = (*itr).GetNode("url").Value;
TDownload::TSourceIterator sitr = Sources.begin();
while(sitr != Sources.end() && (*sitr)->SourceId != SourceId)
++sitr;
if(sitr == Sources.end())
continue;
// update source
(*sitr)->Start = string_to_int((*itr).GetNode("start").Value);
(*sitr)->Size = string_to_int((*itr).GetNode("total").Value);
// throughput
if((*sitr)->Transmitted == 0 || string_to_int((*itr).GetNode("transmit").Value) == 0)
(*sitr)->Throughput.Reset();
else /* if (TimeElapsed > 100) */ // require at least 100 msec sampling time to prevent outliners
(*sitr)->Throughput.AddSample(string_to_int((*itr).GetNode("transmit").Value)-(*sitr)->Transmitted,TimeElapsed);
Throughput.SetBps(Throughput.GetBps() + (*sitr)->Throughput.GetBps());
(*sitr)->Transmitted = string_to_int((*itr).GetNode("transmit").Value);
(*sitr)->SetStateStr((*itr).GetNode("statusgrl").Value);
(*sitr)->ProtoState = (*itr).GetNode("status").Value;
}
}
ReleaseSources();
Transmitted = string_to_int(Cmd->GetNode("transmit").Value);
// set current file path
string SavePath = Cmd->GetNode("path").Value;
if(SavePath != "") {
if (Engine->IsUsingLocalGift())
SavePath = UnixToWindowsPath(SavePath);
// decide where to save it
if(IncomingPath == "")
IncomingPath = SavePath;
else if (IncomingPath != SavePath)
CompletedPath = SavePath;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -