From 64079787d90035b00eee61bc0fede9488a0a8e64 Mon Sep 17 00:00:00 2001 From: yuucn Date: Sun, 9 Aug 2026 15:08:46 +0800 Subject: [PATCH] Send clipboard to friends in parallel --- .github/workflows/ci-build.yml | 47 +++++++++++++ src/AutoSendToClientThread.cpp | 121 ++++++++++++++++++--------------- src/AutoSendToClientThread.h | 2 +- 3 files changed, 114 insertions(+), 56 deletions(-) create mode 100644 .github/workflows/ci-build.yml diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml new file mode 100644 index 00000000..9a398fba --- /dev/null +++ b/.github/workflows/ci-build.yml @@ -0,0 +1,47 @@ +name: Build Ditto + +on: + push: + pull_request: + workflow_dispatch: + +jobs: + build: + name: Release x64 + runs-on: windows-2025 + + steps: + - name: Check out source + uses: actions/checkout@v4 + + - name: Locate MSBuild + id: msbuild + shell: pwsh + run: | + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + $msbuild = & $vswhere -latest -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe | Select-Object -First 1 + if (-not $msbuild) { + throw 'MSBuild was not found on the runner.' + } + "path=$msbuild" | Out-File -FilePath $env:GITHUB_OUTPUT -Append + + - name: Restore NuGet packages + run: nuget restore CP_Main_10.sln + + - name: Build + shell: pwsh + run: | + & "${{ steps.msbuild.outputs.path }}" CP_Main_10.sln /m /t:Build /p:Configuration=Release /p:Platform=x64 + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + + - name: Upload build output + uses: actions/upload-artifact@v4 + with: + name: Ditto-Release-x64 + if-no-files-found: error + path: | + Release64/Ditto.exe + Release64/ICU_Loader.dll + Release64/Addins/DittoUtil.dll diff --git a/src/AutoSendToClientThread.cpp b/src/AutoSendToClientThread.cpp index 09866e87..0b5bff4c 100644 --- a/src/AutoSendToClientThread.cpp +++ b/src/AutoSendToClientThread.cpp @@ -4,6 +4,8 @@ #include "Options.h" #include "CP_Main.h" #include "client.h" +#include +#include CAutoSendToClientThread::CAutoSendToClientThread(void) { @@ -83,15 +85,31 @@ void CAutoSendToClientThread::OnSendToClient() m_saveClips.RemoveAll(); } - SendToClient(pLocalClips); + std::vector sendThreads; + for(int nClient = 0; nClient < MAX_SEND_CLIENTS; nClient++) + { + if(CGetSetOptions::m_SendClients[nClient].bSendAll && + CGetSetOptions::m_SendClients[nClient].csIP.GetLength() > 0) + { + // Each connection can wait independently, so an offline computer does not + // delay delivery to the other configured computers. + CString clientIp = CGetSetOptions::m_SendClients[nClient].csIP; + sendThreads.emplace_back(&CAutoSendToClientThread::SendToClient, this, pLocalClips, nClient, clientIp); + } + } + + for(auto &sendThread : sendThreads) + { + sendThread.join(); + } delete pLocalClips; pLocalClips = NULL; } -bool CAutoSendToClientThread::SendToClient(CClipList *pClipList) +bool CAutoSendToClientThread::SendToClient(CClipList *pClipList, int nClient, const CString &clientIp) { - LogSendRecieveInfo("@@@@@@@@@@@@@@@ - START OF SendClientThread - @@@@@@@@@@@@@@@"); + LogSendRecieveInfo(StrF(_T("@@@@@@@@@@@@@@@ - START OF SendClientThread to %s - @@@@@@@@@@@@@@@"), clientIp)); if(pClipList == NULL) { @@ -103,62 +121,55 @@ bool CAutoSendToClientThread::SendToClient(CClipList *pClipList) LogSendRecieveInfo(StrF(_T("Start of Send ClientThread Count - %d"), lCount)); - for(int nClient = 0; nClient < MAX_SEND_CLIENTS; nClient++) + CClient client; + if(client.OpenConnection(clientIp) == FALSE) { - if(CGetSetOptions::m_SendClients[nClient].bSendAll && - CGetSetOptions::m_SendClients[nClient].csIP.GetLength() > 0) + LogSendRecieveInfo(StrF(_T("ERROR opening connection to %s"), clientIp)); + + if(CGetSetOptions::m_SendClients[nClient].bShownFirstError == FALSE) { - CClient client; - if(client.OpenConnection(CGetSetOptions::m_SendClients[nClient].csIP) == FALSE) - { - LogSendRecieveInfo(StrF(_T("ERROR opening connection to %s"), CGetSetOptions::m_SendClients[nClient].csIP)); - - if(CGetSetOptions::m_SendClients[nClient].bShownFirstError == FALSE) - { - CString cs; - cs.Format(_T("Error opening connection to %s"), CGetSetOptions::m_SendClients[nClient].csIP); - ::SendMessage(theApp.m_MainhWnd, WM_SEND_RECIEVE_ERROR, (WPARAM)cs.GetBuffer(cs.GetLength()), 0); - cs.ReleaseBuffer(); - - CGetSetOptions::m_SendClients[nClient].bShownFirstError = TRUE; - } - - continue; - } - - //We were connected successfully show an error next time we can't connect - CGetSetOptions::m_SendClients[nClient].bShownFirstError = FALSE; - - CClip* pClip; - POSITION pos; - pos = pClipList->GetHeadPosition(); - while(pos) - { - pClip = pClipList->GetNext(pos); - if(pClip == NULL) - { - ASSERT(FALSE); - LogSendRecieveInfo("Error in GetNext"); - break; - } - - LogSendRecieveInfo(StrF(_T("Sending clip to %s"), CGetSetOptions::m_SendClients[nClient].csIP)); - - if(client.SendItem(pClip, false) == FALSE) - { - CString cs; - cs.Format(_T("Error sending clip to %s"), CGetSetOptions::m_SendClients[nClient].csIP); - ::SendMessage(theApp.m_MainhWnd, WM_SEND_RECIEVE_ERROR, (WPARAM)cs.GetBuffer(cs.GetLength()), 0); - cs.ReleaseBuffer(); - break; - } - } - - client.CloseConnection(); + CString cs; + cs.Format(_T("Error opening connection to %s"), clientIp); + ::SendMessage(theApp.m_MainhWnd, WM_SEND_RECIEVE_ERROR, (WPARAM)cs.GetBuffer(cs.GetLength()), 0); + cs.ReleaseBuffer(); + + CGetSetOptions::m_SendClients[nClient].bShownFirstError = TRUE; } + + return FALSE; } - LogSendRecieveInfo("@@@@@@@@@@@@@@@ - END OF SendClientThread - @@@@@@@@@@@@@@@"); + //We were connected successfully show an error next time we can't connect + CGetSetOptions::m_SendClients[nClient].bShownFirstError = FALSE; + + CClip* pClip; + POSITION pos; + pos = pClipList->GetHeadPosition(); + while(pos) + { + pClip = pClipList->GetNext(pos); + if(pClip == NULL) + { + ASSERT(FALSE); + LogSendRecieveInfo("Error in GetNext"); + break; + } + + LogSendRecieveInfo(StrF(_T("Sending clip to %s"), clientIp)); + + if(client.SendItem(pClip, false) == FALSE) + { + CString cs; + cs.Format(_T("Error sending clip to %s"), clientIp); + ::SendMessage(theApp.m_MainhWnd, WM_SEND_RECIEVE_ERROR, (WPARAM)cs.GetBuffer(cs.GetLength()), 0); + cs.ReleaseBuffer(); + break; + } + } + + client.CloseConnection(); + + LogSendRecieveInfo(StrF(_T("@@@@@@@@@@@@@@@ - END OF SendClientThread to %s - @@@@@@@@@@@@@@@"), clientIp)); return TRUE; -} \ No newline at end of file +} diff --git a/src/AutoSendToClientThread.h b/src/AutoSendToClientThread.h index 7d4ea65a..240ab7a3 100644 --- a/src/AutoSendToClientThread.h +++ b/src/AutoSendToClientThread.h @@ -25,7 +25,7 @@ class CAutoSendToClientThread : public CEventThread virtual void OnTimeOut(void *param); void OnSendToClient(); - bool SendToClient(CClipList *pClipList); + bool SendToClient(CClipList *pClipList, int nClient, const CString &clientIp); CCriticalSection m_cs; CClipList m_saveClips;