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

📄 engine.cpp

📁 Last change: 2008-02-03 This is the source code of KCeasy。
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    OutQueueCritSec.Leave();

    LockSearches();
    while(!Searches.empty()) {
        delete Searches.front();
        Searches.pop_front();
    }
    ReleaseSearches();

    LockDownloads();
    while(!Downloads.empty()) {
        delete Downloads.front();
        Downloads.pop_front();
    }
    ReleaseDownloads();

    LockUploads();
    while(!Uploads.empty()) {
        delete Uploads.front();
        Uploads.pop_front();
    }
    ReleaseUploads();

    delete Shares; Shares = NULL;
    delete Networks; Networks = NULL;

    SetState(Offline);
    UsingLocalGift = false;
    NextGiftId = MinGiftId;
    GiftHost = "";
    GiftPort = 0;
    GiftLog = "";
}

void TEngine::SocketThreadFunc()
{
    TGiftCommand* Cmd;
    TStringSocket Socket;
    char* Data = new char[1024];
    int DataLen = 0;
    int DataSize = 1024;

    // connect to daemon
    if(!Socket.Connect(GiftHost.c_str(),GiftPort)) {
        if(!IsUsingLocalGift()) {
            SendCallback(CbcNetworkError,(void*)&Socket.GetErrorString());
            SetState(ConnectFailed, true);
            Reset();
            return;
        }
        SetState(LaunchingGift, true);

        // if there is a lingering daemon from a previous session kill it
        if(GiftLauncher->IsRunning())
            GiftLauncher->Kill();

        if(!GiftLauncher->Launch()) {
            SetState(LaunchFailed, true, true); // gift closed connection unexpectedly
            Reset();
            return;
        }
        SetState(LaunchSucceeded, true);
        SetState(Connecting, true);
        for(int i=0;!Socket.Connect(GiftHost.c_str(),GiftPort);++i) {
            if(i >= LOCAL_CONNECT_RETRY_COUNT) {
                // we started giFT but can't connect, kill it
                GiftLauncher->Kill();
                SendCallback(CbcNetworkError,(void*)&Socket.GetErrorString());
                SetState(LaunchFailed, true);
                Reset();
                return;
            }
            Sleep(LOCAL_CONNECT_RETRY_DELAY);
        }
    }

    Cmd = new TGiftCommand("ATTACH");
    Cmd->AddNode(TGiftCommand("client",ClientName.c_str()));
    Cmd->AddNode(TGiftCommand("version",ClientVersion.c_str()));
    QueueCommand(Cmd);

    unsigned int TimerFuncNextRaise = ::GetTickCount() + TIMER_FUNC_INTERVAL;
    AutoSearchCountdown = 0;

    while(!ExitSocketThread) {
        if(Socket.WaitForData(10)) {
            char* Buf;

            if((Buf = Socket.Receive()) == NULL)
                break;

/*
    FILE* fp = fopen("part_network.log","ab");
    fprintf(fp,"%s",Buf);
    fclose(fp);
*/
            int AddLen = strlen(Buf);

            // resize Data buffer if necessary
            if(DataSize < DataLen + AddLen + 1) {
                char* OldData = Data;
                while(DataSize < DataLen + AddLen + 1)
                    DataSize *= 2;
                Data = new char[DataSize];
                memcpy(Data, OldData, DataLen + 1);
                delete[] OldData;
            }

            // data data just read
            memcpy(Data + DataLen,Buf,AddLen+1);
            Buf = Data + DataLen;
            DataLen += AddLen;

            while(((Buf = strchr(Buf,';')) != NULL) && !ExitSocketThread) {
                if(Buf[-1] == '\\') {
                    Buf++;
                    continue;
                }

                Buf++; // move past ';'
                int PacketLen = Buf - Data;

#ifdef NETWORK_LOGGING
                FILE* fp = fopen("network.log","ab");
                fprintf(fp,"\n\n*** (PacketLen: %d) ***\n",PacketLen);
                fwrite(Data,PacketLen,1,fp);
                fclose(fp);
#endif
                Cmd = new TGiftCommand();
                Cmd->Parse(Data);

                if(Debug)
                    SendCallback(CbcDebug,(void*)1,(void*)&Cmd->Print());
                if(!IsDisconnecting())
                    DispatchCommand(Cmd);

                delete Cmd;

                // remove processed data
                DataLen -= PacketLen;
                memmove(Data,Buf,DataLen+1); // also copy \0
                Buf = Data;
            }
        }
        // anything to send?
        if(!OutQueue.empty()) {
            OutQueueCritSec.Enter();
            Cmd = OutQueue.front();
            OutQueue.pop();
            OutQueueCritSec.Leave();

            if(Debug)
                SendCallback(CbcDebug,(void*)0,(void*)&Cmd->Print());
#ifdef NETWORK_LOGGING
            FILE* fp = fopen("network.log","ab");
            fwrite(Cmd->Print().c_str(),Cmd->Print().length(),1,fp);
            fclose(fp);
#endif
            if(!Socket.Send(Cmd->Print().c_str())) {
                SendCallback(CbcNetworkError,(void*)&Socket.GetErrorString());
                break;
            }

            // End thread if this was a QUIT or DETACH.
            if(Cmd->Name == "QUIT" || Cmd->Name == "DETACH") {
                Socket.Shutdown();
                ExitSocketThread = true;
            }

            delete Cmd;
        }
        // run timer func?
        if(GetTickCount() > TimerFuncNextRaise) {
            TimerFunc();
            TimerFuncNextRaise = GetTickCount() + TIMER_FUNC_INTERVAL;
        }

        // check for log output from giFT
        if(UsingLocalGift)
            ReadGiftLog();
    }
    Socket.Disconnect();
    delete[] Data;

//    GetLauncher()->CloseStdoutHandle();

    DisconnectTime = ::GetTickCount() / 1000;

    if(ExitSocketThread)
        SetState(Offline, true);
    else
        SetState(Offline, true, true); // gift closed connection unexpectedly

    // kceasy may have started a reconnect... this is so messy
    if(IsOffline())
        Reset();
}

// called periodically every couple seconds by the engine thread
void TEngine::TimerFunc()
{
    // update network stats periodically
    Networks->UpdateIfNecessary();

    // keep downloads alive
    if (AutoSearchCountdown > 0)
        AutoSearchCountdown--;
    LockDownloads();

    TDownloadIterator itr = Downloads.begin();
    while(itr != Downloads.end() && AutoSearchCountdown <= 0 &&
          GetActiveHashSearchesCount() < MAX_AUTO_SEARCHES)
    {
        // oh well...
//        ReleaseDownloads();
        if((*itr)->KeepAlive())
            AutoSearchCountdown = AUTO_SEARCH_DELAY; // wait x seconds before next search
//        LockDownloads();
        ++itr;
    }
    ReleaseDownloads();

    // commit search results to UI
    LockSearches();
    for(TSearchIterator itr = Searches.begin(); itr != Searches.end(); ++itr) {
//        ReleaseSearches();
        if((*itr)->GetState() == TSearch::Searching)
            (*itr)->CommitCachedResults();
//        LockSearches();
    }
    ReleaseSearches();
}

bool TEngine::ReadGiftLog()
{
    char buf[2048];
    DWORD BytesAvail;
    DWORD BytesRead;
    int pos;

    // check if there is new data
    if(!PeekNamedPipe(GiftLauncher->GetStdoutHandle(),NULL,0,NULL,&BytesAvail,NULL))
        return false;

    if(BytesAvail == 0)
        return false;

    if(BytesAvail > 2047)
        BytesAvail = 2047;

    // read new data
    if(!ReadFile(GiftLauncher->GetStdoutHandle(),buf,BytesAvail,&BytesRead,NULL))
        return false;

    if(BytesRead == 0)
        return false;

    // note: we must read from the pipe even if we don't need the data or giFT will block
    if(!GiftLogging)
        return false;

    // add new data to string
    buf[BytesRead] = 0;
    GiftLog += buf;

    // if all entire lines to application
    if((pos = GiftLog.rfind('\n')) == -1)
        return false;

    string Rest = GiftLog.substr(pos+1);
    GiftLog.resize(pos+1);

    SendCallback(CbcGiftLog,(void*)&GiftLog,NULL);

    GiftLog = Rest;
    return true;
}


void TEngine::QueueCommand(TGiftCommand* Cmd)
{
    OutQueueCritSec.Enter();
    OutQueue.push(Cmd);
    OutQueueCritSec.Leave();
}

void TEngine::DispatchCommand(TGiftCommand* Cmd)
{
    if(Cmd->Name == "ATTACH") {
        ConnectTime = ::GetTickCount() / 1000;
        SetState(Online, true);
        Networks->Update();
        return;
    } else if(Cmd->Name == "STATS") {
        Networks->ProcessStats(Cmd);
        return;
    } else if(Cmd->Name == "ITEM") {
        unsigned int GiftId = string_to_int(Cmd->Value);

        // is this a shares update?
        if(GiftId == Shares->FilesGiftId) {
            Shares->ProcessItem(Cmd);
            return;
        }
        // not a shares update, find corresponding search
        LockSearches();
        TSearchIterator sitr = Searches.begin();
        while(sitr != Searches.end() && (*sitr)->GiftId != GiftId)
            ++sitr;
        ReleaseSearches();

        if(sitr != Searches.end() && (*sitr)->State == TSearch::Searching)
            (*sitr)->ProcessItem(Cmd);

        return;
    } else if(Cmd->Name == "ADDDOWNLOAD") {
        // find corresponding download
        THashSet* Hashes = new THashSet();
        Hashes->AddGiftHash(Cmd->GetNode("hash").Value);
        LockDownloads();
        TDownloadIterator ditr = Downloads.begin();
        while(ditr != Downloads.end() && (*(*ditr)->GetHashes() != *Hashes || (*ditr)->State != TDownload::Registering))
            ++ditr;
        bool NewDownload = (ditr == Downloads.end());
        // new download after ATTACH
        if(NewDownload)
            ditr = Downloads.insert(Downloads.end(),new TDownload(this, Hashes));
        ReleaseDownloads();
        (*ditr)->ProcessAddDownload(Cmd);
        delete Hashes;

        return;
    } else if(Cmd->Name == "DELDOWNLOAD") {
        // find corresponding download
        unsigned int GiftId = string_to_int(Cmd->Value);
        LockDownloads();
        TDownloadIterator ditr = Downloads.begin();
        while(ditr != Downloads.end() && (*ditr)->GiftId != GiftId)
            ++ditr;
        ReleaseDownloads();

        if(ditr != Downloads.end())
            (*ditr)->ProcessDelDownload(Cmd);

        return;
    } else if(Cmd->Name == "CHGDOWNLOAD") {
        // find corresponding download
        unsigned int GiftId = string_to_int(Cmd->Value);
        LockDownloads();
        TDownloadIterator ditr = Downloads.begin();
        while(ditr != Downloads.end() && (*ditr)->GiftId != GiftId)
            ++ditr;
        ReleaseDownloads();

        if(ditr != Downloads.end())
            (*ditr)->ProcessChgDownload(Cmd);

        return;
    } else if(Cmd->Name == "ADDSOURCE") {
        // find download
        unsigned int GiftId = string_to_int(Cmd->Value);
        LockDownloads();
        TDownloadIterator ditr = Downloads.begin();
        while(ditr != Downloads.end() && (*ditr)->GiftId != GiftId)
            ++ditr;
         ReleaseDownloads();

        if(ditr != Downloads.end())
            (*ditr)->ProcessAddSource(Cmd);

        return;
    } else if(Cmd->Name == "DELSOURCE") {
        // find download
        unsigned int GiftId = string_to_int(Cmd->Value);
        LockDownloads();
        TDownloadIterator ditr = Downloads.begin();
        while(ditr != Downloads.end() && (*ditr)->GiftId != GiftId)
            ++ditr;
        ReleaseDownloads();

        if(ditr != Downloads.end())
            (*ditr)->ProcessDelSource(Cmd);

        return;
    } else if(Cmd->Name == "ADDUPLOAD") {
        // new download
        LockUploads();
        TUpload* Upload = new TUpload(this);
        Uploads.push_back(Upload);
        ReleaseUploads();

        Upload->ProcessAddUpload(Cmd);

        return;
    } else if(Cmd->Name == "DELUPLOAD") {
        // find corresponding upload
        unsigned int GiftId = string_to_int(Cmd->Value);
        LockUploads();
        TUploadIterator uitr = Uploads.begin();
        while(uitr != Uploads.end() && (*uitr)->GiftId != GiftId)
            ++uitr;
        ReleaseUploads();

        if(uitr != Uploads.end())
            (*uitr)->ProcessDelUpload(Cmd);

        return;
    } else if(Cmd->Name == "CHGUPLOAD") {
        // find corresponding upload
        unsigned int GiftId = string_to_int(Cmd->Value);
        LockUploads();
        TUploadIterator uitr = Uploads.begin();
        while(uitr != Uploads.end() && (*uitr)->GiftId != GiftId)
            ++uitr;
        ReleaseUploads();

        if(uitr != Uploads.end())
            (*uitr)->ProcessChgUpload(Cmd);

        return;
    } else if(Cmd->Name == "SHARE") {
        Shares->ProcessShare(Cmd);
        return;
    }
}

void TEngine::SetState(TState NState, bool NotifyUI, bool GiftCrashed)
{
    State = NState;
    if(NotifyUI)
        SendCallback(CbcStateChange, (void*)State, (void*)((int)GiftCrashed));
}

bool TEngine::SendCallback(TCallbackCode Code, void* Param1, void* Param2)
{
    if(!CallbackWindow)
        return false;
    TCallbackInfo CbInfo(Code,Param1,Param2);

#ifdef CALLBACK_LOGGING
    FILE* fp = fopen("callback.log","ab");
    fprintf(fp,"SendCallback(type = \"%d\", Param1 = 0x%08X, Param2 = 0x%08X)\r\n\tConnectState = %d\r\n",(int)Code,Param1,Param2,(int)ConnectState);
    fclose(fp);
#endif

    // using SendMessage makes windows switch to CallbackWindow's thread
    // and block this thread till the handler has executed
    SendMessage(CallbackWindow,WM_ENGINE_CALLBACK,(WPARAM)&CbInfo,(LPARAM)NULL);

#ifdef CALLBACK_LOGGING
    fp = fopen("callback.log","ab");
    fprintf(fp,"\treturned\r\n");
    fclose(fp);
#endif

    return true;
}

unsigned int TEngine::GetNextGiftId()
{
    NextGiftId++;

    if(NextGiftId >= MaxGiftId)
        NextGiftId = MinGiftId;

    return NextGiftId;
}

} // namespace KCeasyEngine


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -