📄 engine.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.
*/
//---------------------------------------------------------------------------
//#define NETWORK_LOGGING
//#define CALLBACK_LOGGING
//---------------------------------------------------------------------------
#include <windows.h>
#if defined(NETWORK_LOGGING) || defined(CALLBACK_LOGGING)
# include <stdio.h>
#endif
#pragma hdrstop
#include "Engine.h"
#include "StringSocket.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
namespace KCeasyEngine {
static const int LOCAL_CONNECT_RETRY_COUNT = 20;
static const int LOCAL_CONNECT_RETRY_DELAY = 100; // ms
static const unsigned int TIMER_FUNC_INTERVAL = 1000*2;
static const unsigned int AUTO_SEARCH_DELAY = 30; // in TIMER_FUNC_INTERVAL units
static const unsigned int MAX_AUTO_SEARCHES = 2;
// global thread functions
DWORD WINAPI g_SocketThreadFunc(void* data)
{
((TEngine*)data)->SocketThreadFunc();
return 0;
}
// class TEngine
TEngine::TEngine(const char* NClientName, const char* NClientVersion)
: ClientName(NClientName),
ClientVersion(NClientVersion),
CallbackWindow(NULL),
SocketThreadHandle(NULL),
State(Offline),
NextGiftId(MinGiftId),
Debug(false),
GiftLauncher(NULL),
UsingLocalGift(false),
GiftHost(""),
GiftPort(0),
Shares(NULL),
Networks(NULL),
ConnectTime(0),
DisconnectTime(0),
AutoSearchCountdown(0)
{
GiftLauncher = new TGiftLauncher();
}
TEngine::~TEngine()
{
ExitSocketThread = true;
if(WaitForSingleObject(SocketThreadHandle,1000) == WAIT_TIMEOUT)
TerminateThread(SocketThreadHandle,0);
Reset();
delete GiftLauncher;
}
void TEngine::Init()
{
GiftLauncher->Init();
}
bool TEngine::TurnOnline()
{
DWORD ThreadID;
if(!IsOffline())
return true;
if(!GiftLauncher->IsInstalled())
return false;
Reset(); // bring us in well defined state
GiftHost = "Localhost";
GiftPort = 1213;
UsingLocalGift = true;
ConnectTime = 0;
DisconnectTime = 0;
SetState(Connecting, true);
Shares = new TShares(this);
Networks = new TNetworks(this);
ExitSocketThread = false;
SocketThreadHandle = CreateThread(NULL,4096,g_SocketThreadFunc,(void*)this,0,&ThreadID);
return true;
}
void TEngine::TurnOnline(const string& Host, unsigned short Port)
{
DWORD ThreadID;
if(!IsOffline())
return;
Reset(); // bring us in well defined state
GiftHost = Host;
GiftPort = Port;
UsingLocalGift = false;
ConnectTime = 0;
DisconnectTime = 0;
SetState(Connecting, true);
Shares = new TShares(this);
Networks = new TNetworks(this);
ExitSocketThread = false;
SocketThreadHandle = CreateThread(NULL,4096,g_SocketThreadFunc,(void*)this,0,&ThreadID);
}
void TEngine::TurnOffline()
{
if(IsOffline() || IsDisconnecting())
return;
SetState(Disconnecting, true);
if(IsUsingLocalGift())
QueueCommand(new TGiftCommand("QUIT"));
else
QueueCommand(new TGiftCommand("DETACH"));
}
unsigned int TEngine::GetUptime()
{
if (ConnectTime == 0)
return 0;
if (DisconnectTime == 0)
return (::GetTickCount() / 1000 - ConnectTime);
else
return (DisconnectTime - ConnectTime);
}
// FIXME: threading!
list<string> TEngine::GetBannedWords()
{
return BannedWordsList;
}
void TEngine::SetBannedWords(const list<string>& Words)
{
// make lower case copy
BannedWordsList.clear();
for(list<string>::const_iterator itr = Words.begin();itr != Words.end(); ++itr)
BannedWordsList.push_front(string_trim(string_tolower(*itr)));
}
list<string> TEngine::GetBannedExtensions()
{
return BannedExtensionsList;
}
void TEngine::SetBannedExtensions(const list<string>& Extensions)
{
// make lower case copy without leading dots
BannedExtensionsList.clear();
for(list<string>::const_iterator itr = Extensions.begin();itr != Extensions.end(); ++itr) {
string Ext = string_trim(string_tolower(*itr));
if(Ext[0] == '.')
Ext = Ext.substr(1);
BannedExtensionsList.push_front(Ext);
}
}
// searching
TSearch* TEngine::NewSearch(const string& Query, TSearchRealm Realm,
const string& Network, const TMetaData& MetaData,
bool BanWords, bool BanExtensions, bool Intern)
{
if(!IsOnline())
return NULL;
TSearch* Search = new TSearch(this, Query, Realm, Network, MetaData, BanWords, BanExtensions, Intern);
LockSearches();
Searches.push_back(Search);
ReleaseSearches();
if(!Search->IsInternal())
SendCallback(CbcNewSearch,(void*)Search);
return Search;
}
TSearch* TEngine::NewSearch(const THashSet* Hashes, const string& Network, bool Intern)
{
if(Hashes->Size() == 0)
return NULL;
// TODO: search for all hashes once giFT supports it
return NewSearch(Hashes->GetFirstHash()->GetGiftHash(), SRSource, Network, TMetaData(), false, false, Intern);
}
bool TEngine::RemoveSearch(TSearch* Search)
{
if(!IsOnline())
return false;
Search->Cancel();
LockSearches();
TSearchIterator itr = Searches.begin();
for(;*itr != Search;++itr)
if(itr == Searches.end()) {
ReleaseSearches();
return false;
}
ReleaseSearches();
// notify UI
if(!Search->IsInternal())
SendCallback(CbcSearchRemoved,(void*)(*itr));
LockSearches();
delete *itr;
Searches.erase(itr);
ReleaseSearches();
return true;
}
int TEngine::GetActiveSearchesCount(const string& Network)
{
if(!IsOnline())
return 0;
int Count = 0;
LockSearches();
for(TSearchIterator itr = Searches.begin();itr != Searches.end();++itr) {
if((*itr)->GetState() == TSearch::Searching &&
(Network == "" || Network == (*itr)->GetNetwork() || (*itr)->GetNetwork() == ""))
{
Count++;
}
}
ReleaseSearches();
return Count;
}
int TEngine::GetActiveHashSearchesCount(const string& Network)
{
if(!IsOnline())
return 0;
int Count = 0;
LockSearches();
for(TSearchIterator itr = Searches.begin();itr != Searches.end();++itr) {
if((*itr)->GetState() == TSearch::Searching && (*itr)->GetRealm() == SRSource &&
(Network == "" || Network == (*itr)->GetNetwork() || (*itr)->GetNetwork() == ""))
{
Count++;
}
}
ReleaseSearches();
return Count;
}
// downloading
TDownload* TEngine::NewDownload(const TSearchResult* SearchResult, const string& SaveFileName)
{
if(!IsOnline())
return NULL;
LockDownloads();
// are we already downloading this file?
// always create a new download if hashes is empty (network without hashes)
if (SearchResult->GetHashes()->Size() != 0) {
TDownloadIterator itr = Downloads.begin();
while(itr != Downloads.end() && *(*itr)->GetHashes() != *SearchResult->GetHashes())
++itr;
if(itr != Downloads.end() &&
((*itr)->GetState() != TDownload::Completed &&
(*itr)->GetState() != TDownload::Failed &&
(*itr)->GetState() != TDownload::Cancelled))
{
ReleaseDownloads();
return *itr;
}
}
// create new download
TDownload* Download = new TDownload(this, SearchResult->GetHashes());
Downloads.push_back(Download);
Download->FileSize = SearchResult->FileSize;
Download->Network = SearchResult->Network;
if(SaveFileName != "")
Download->SaveFileName = SanitizePath(SaveFileName);
else
Download->SaveFileName = SanitizePath(SearchResult->FileName);
Download->State = TDownload::Registering;
ReleaseDownloads();
// notify UI
SendCallback(CbcNewDownload,(void*)Download);
// add first source
Download->AddSource(SearchResult);
// if we have free auto search slots do a source search now
if(GetActiveHashSearchesCount() < MAX_AUTO_SEARCHES)
Download->FindMoreSources();
return Download;
}
TDownload* TEngine::NewDownload(const THashSet* Hashes, const string& Network, const string& SaveFileName)
{
if(!IsOnline())
return NULL;
if(Network == "" || SanitizePath(SaveFileName) == "")
return NULL;
// look up hash for this network
GetNetworks()->Lock();
THashSet* NewHashes = new THashSet();
TNetwork* Net = GetNetworks()->GetNetwork(Network);
if(Net) {
for(THashSet::Iterator itr = Hashes->Begin(); itr != Hashes->End(); ++itr) {
if(Net->GetAlgos()->GetAlgo((*itr)->GetName()) != NULL) {
NewHashes->AddHash(new THash(*itr));
break;
}
}
}
GetNetworks()->Release();
if(NewHashes->Size() == 0) {
delete NewHashes;
return NULL;
}
LockDownloads();
// are we already downloading this file?
TDownloadIterator itr = Downloads.begin();
while(itr != Downloads.end() && !(*itr)->GetHashes()->Equals(NewHashes))
++itr;
if(itr != Downloads.end() &&
((*itr)->GetState() != TDownload::Completed &&
(*itr)->GetState() != TDownload::Failed &&
(*itr)->GetState() != TDownload::Cancelled))
{
ReleaseDownloads();
delete NewHashes;
return *itr;
}
// create new download
TDownload* Download = new TDownload(this, NewHashes);
Downloads.push_back(Download);
Download->FileSize = 0;
Download->Network = Network;
Download->SaveFileName = SanitizePath(SaveFileName);
Download->State = TDownload::Registering;
ReleaseDownloads();
// notify UI
SendCallback(CbcNewDownload,(void*)Download);
// start searching sources
Download->FindMoreSources();
return Download;
}
bool TEngine::RemoveDownload(TDownload* Download)
{
if(!IsOnline())
return false;
if(Download->GetState() == TDownload::Queued ||
Download->GetState() == TDownload::Paused ||
Download->GetState() == TDownload::Downloading)
{
Download->Cancel();
}
LockDownloads();
TDownloadIterator itr = Downloads.begin();
for(;*itr != Download;++itr)
if(itr == Downloads.end()) {
ReleaseDownloads();
return false;
}
// cancel source search, if any
if(Download->SourcesSearch)
RemoveSearch(Download->SourcesSearch);
ReleaseDownloads();
// notify UI
SendCallback(CbcDownloadRemoved,(void*)(*itr));
LockDownloads();
delete *itr;
Downloads.erase(itr);
ReleaseDownloads();
return true;
}
TDownload* TEngine::GetDownloadByHashes(const THashSet* Hashes)
{
LockDownloads();
for(TDownloadIterator itr=Downloads.begin(); itr != Downloads.end(); ++itr) {
if(*(*itr)->GetHashes() == *Hashes) {
ReleaseDownloads();
return (*itr);
}
}
ReleaseDownloads();
return NULL;
}
// uploading
bool TEngine::RemoveUpload(TUpload* Upload)
{
if(!IsOnline())
return false;
if(Upload->GetState() == TUpload::Queued ||
Upload->GetState() == TUpload::Uploading)
{
Upload->Cancel();
}
LockUploads();
TUploadIterator itr = Uploads.begin();
for(;*itr != Upload;++itr)
if(itr == Uploads.end()) {
ReleaseUploads();
return false;
}
ReleaseUploads();
// notify UI
SendCallback(CbcUploadRemoved,(void*)(*itr));
LockUploads();
delete *itr;
Uploads.erase(itr);
ReleaseUploads();
return true;
}
TUpload* TEngine::GetUploadByHashes(const THashSet* Hashes)
{
LockUploads();
for(TUploadIterator itr=Uploads.begin(); itr != Uploads.end(); ++itr) {
if(*(*itr)->GetHashes() == *Hashes) {
ReleaseUploads();
return (*itr);
}
}
ReleaseUploads();
return NULL;
}
// private
void TEngine::Reset()
{
OutQueueCritSec.Enter();
while(!OutQueue.empty()) {
delete OutQueue.front();
OutQueue.pop();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -