⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 engine.cpp

📁 Last change: 2008-02-03 This is the source code of KCeasy。
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
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 + -