mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Port file transfers to the new API
Parallel, extremely large, and other edge case transfers have not been tested, but the common path should work well.
This commit is contained in:
parent
e4859efe18
commit
9dedd22bb2
|
@ -77,6 +77,7 @@ FileTransferWidget::FileTransferWidget(QWidget *parent, ToxFile file)
|
|||
connect(Core::getInstance(), &Core::fileTransferCancelled, this, &FileTransferWidget::onFileTransferCancelled);
|
||||
connect(Core::getInstance(), &Core::fileTransferPaused, this, &FileTransferWidget::onFileTransferPaused);
|
||||
connect(Core::getInstance(), &Core::fileTransferFinished, this, &FileTransferWidget::onFileTransferFinished);
|
||||
connect(Core::getInstance(), &Core::fileTransferRemotePausedUnpaused, this, &FileTransferWidget::fileTransferRemotePausedUnpaused);
|
||||
|
||||
setupButtons();
|
||||
|
||||
|
@ -222,7 +223,10 @@ void FileTransferWidget::onFileTransferInfo(ToxFile file)
|
|||
// ETA, speed
|
||||
qreal deltaSecs = dt / 1000.0;
|
||||
|
||||
qint64 deltaBytes = qMax(file.bytesSent - lastBytesSent, qint64(0));
|
||||
// (can't use ::abs or ::max on unsigned types substraction, they'd just overflow)
|
||||
quint64 deltaBytes = file.bytesSent > lastBytesSent
|
||||
? file.bytesSent - lastBytesSent
|
||||
: lastBytesSent - file.bytesSent;
|
||||
qreal bytesPerSec = static_cast<int>(static_cast<qreal>(deltaBytes) / deltaSecs);
|
||||
|
||||
// calculate mean
|
||||
|
@ -306,6 +310,26 @@ void FileTransferWidget::onFileTransferPaused(ToxFile file)
|
|||
setupButtons();
|
||||
}
|
||||
|
||||
void FileTransferWidget::onFileTransferResumed(ToxFile file)
|
||||
{
|
||||
if(fileInfo != file)
|
||||
return;
|
||||
|
||||
fileInfo = file;
|
||||
|
||||
ui->etaLabel->setText("");
|
||||
ui->progressLabel->setText(tr("Resuming...", "file transfer widget"));
|
||||
|
||||
// reset mean
|
||||
meanIndex = 0;
|
||||
for(size_t i=0; i<TRANSFER_ROLLING_AVG_COUNT; ++i)
|
||||
meanData[i] = 0.0;
|
||||
|
||||
setBackgroundColor(Style::getColor(Style::LightGrey), false);
|
||||
|
||||
setupButtons();
|
||||
}
|
||||
|
||||
void FileTransferWidget::onFileTransferFinished(ToxFile file)
|
||||
{
|
||||
if(fileInfo != file)
|
||||
|
@ -333,6 +357,14 @@ void FileTransferWidget::onFileTransferFinished(ToxFile file)
|
|||
disconnect(Core::getInstance(), 0, this, 0);
|
||||
}
|
||||
|
||||
void FileTransferWidget::fileTransferRemotePausedUnpaused(ToxFile file, bool paused)
|
||||
{
|
||||
if (paused)
|
||||
onFileTransferPaused(file);
|
||||
else
|
||||
onFileTransferResumed(file);
|
||||
}
|
||||
|
||||
QString FileTransferWidget::getHumanReadableSize(qint64 size)
|
||||
{
|
||||
static const char* suffix[] = {"B","kiB","MiB","GiB","TiB"};
|
||||
|
|
|
@ -45,7 +45,9 @@ protected slots:
|
|||
void onFileTransferAccepted(ToxFile file);
|
||||
void onFileTransferCancelled(ToxFile file);
|
||||
void onFileTransferPaused(ToxFile file);
|
||||
void onFileTransferResumed(ToxFile file);
|
||||
void onFileTransferFinished(ToxFile file);
|
||||
void fileTransferRemotePausedUnpaused(ToxFile file, bool paused);
|
||||
|
||||
protected:
|
||||
QString getHumanReadableSize(qint64 size);
|
||||
|
@ -69,7 +71,7 @@ private:
|
|||
Ui::FileTransferWidget *ui;
|
||||
ToxFile fileInfo;
|
||||
QTime lastTick;
|
||||
qint64 lastBytesSent = 0;
|
||||
quint64 lastBytesSent = 0;
|
||||
QVariantAnimation* backgroundColorAnimation = nullptr;
|
||||
QVariantAnimation* buttonColorAnimation = nullptr;
|
||||
QColor backgroundColor;
|
||||
|
|
|
@ -45,8 +45,6 @@
|
|||
|
||||
const QString Core::CONFIG_FILE_NAME = "data";
|
||||
const QString Core::TOX_EXT = ".tox";
|
||||
QList<ToxFile> Core::fileSendQueue;
|
||||
QList<ToxFile> Core::fileRecvQueue;
|
||||
QHash<int, ToxGroupCall> Core::groupCalls;
|
||||
QThread* Core::coreThread{nullptr};
|
||||
|
||||
|
@ -69,7 +67,6 @@ Core::Core(Camera* cam, QThread *CoreThread, QString loadPath) :
|
|||
toxTimer = new QTimer(this);
|
||||
toxTimer->setSingleShot(true);
|
||||
connect(toxTimer, &QTimer::timeout, this, &Core::process);
|
||||
//connect(fileTimer, &QTimer::timeout, this, &Core::fileHeartbeat);
|
||||
connect(&Settings::getInstance(), &Settings::dhtServerListChanged, this, &Core::process);
|
||||
|
||||
for (int i=0; i<TOXAV_MAX_CALLS;i++)
|
||||
|
@ -486,6 +483,7 @@ void Core::onConnectionStatusChanged(Tox*/* tox*/, uint32_t friendId, TOX_CONNEC
|
|||
{
|
||||
static_cast<Core*>(core)->checkLastOnline(friendId);
|
||||
|
||||
/** TODO: Review file sending breaking/resuming
|
||||
for (ToxFile& f : fileSendQueue)
|
||||
{
|
||||
if (f.friendId == friendId && f.status == ToxFile::TRANSMITTING)
|
||||
|
@ -502,9 +500,11 @@ void Core::onConnectionStatusChanged(Tox*/* tox*/, uint32_t friendId, TOX_CONNEC
|
|||
emit static_cast<Core*>(core)->fileTransferBrokenUnbroken(f, true);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
for (ToxFile& f : fileRecvQueue)
|
||||
{
|
||||
if (f.friendId == friendId && f.status == ToxFile::BROKEN)
|
||||
|
@ -514,6 +514,7 @@ void Core::onConnectionStatusChanged(Tox*/* tox*/, uint32_t friendId, TOX_CONNEC
|
|||
emit static_cast<Core*>(core)->fileTransferBrokenUnbroken(f, false);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -680,186 +681,37 @@ void Core::changeGroupTitle(int groupId, const QString& title)
|
|||
|
||||
void Core::sendFile(uint32_t friendId, QString Filename, QString FilePath, long long filesize)
|
||||
{
|
||||
QMutexLocker mlocker(&fileSendMutex);
|
||||
|
||||
QByteArray fileName = Filename.toUtf8();
|
||||
uint32_t fileNum = tox_file_send(tox, friendId, TOX_FILE_KIND_DATA, filesize, nullptr,
|
||||
(uint8_t*)fileName.data(), fileName.size(), nullptr);
|
||||
if (fileNum == UINT32_MAX)
|
||||
{
|
||||
qWarning() << "Core::sendFile: Can't create the Tox file sender";
|
||||
emit fileSendFailed(friendId, Filename);
|
||||
return;
|
||||
}
|
||||
qDebug() << QString("Core::sendFile: Created file sender %1 with friend %2").arg(fileNum).arg(friendId);
|
||||
|
||||
ToxFile file{fileNum, friendId, fileName, FilePath, ToxFile::SENDING};
|
||||
file.filesize = filesize;
|
||||
if (!file.open(false))
|
||||
{
|
||||
qWarning() << QString("Core::sendFile: Can't open file, error: %1").arg(file.file->errorString());
|
||||
}
|
||||
fileSendQueue.append(file);
|
||||
|
||||
emit fileSendStarted(fileSendQueue.last());
|
||||
CoreFile::sendFile(this, friendId, Filename, FilePath, filesize);
|
||||
}
|
||||
|
||||
void Core::pauseResumeFileSend(uint32_t friendId, uint32_t fileNum)
|
||||
{
|
||||
ToxFile* file{nullptr};
|
||||
for (ToxFile& f : fileSendQueue)
|
||||
{
|
||||
if (f.fileNum == fileNum && f.friendId == friendId)
|
||||
{
|
||||
file = &f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!file)
|
||||
{
|
||||
qWarning("Core::pauseResumeFileSend: No such file in queue");
|
||||
return;
|
||||
}
|
||||
if (file->status == ToxFile::TRANSMITTING)
|
||||
{
|
||||
file->status = ToxFile::PAUSED;
|
||||
emit fileTransferPaused(*file);
|
||||
tox_file_control(tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_PAUSE, nullptr);
|
||||
}
|
||||
else if (file->status == ToxFile::PAUSED)
|
||||
{
|
||||
file->status = ToxFile::TRANSMITTING;
|
||||
emit fileTransferAccepted(*file);
|
||||
tox_file_control(tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_RESUME, nullptr);
|
||||
}
|
||||
else
|
||||
qWarning() << "Core::pauseResumeFileSend: File is stopped";
|
||||
CoreFile::pauseResumeFileSend(this, friendId, fileNum);
|
||||
}
|
||||
|
||||
void Core::pauseResumeFileRecv(uint32_t friendId, uint32_t fileNum)
|
||||
{
|
||||
ToxFile* file{nullptr};
|
||||
for (ToxFile& f : fileRecvQueue)
|
||||
{
|
||||
if (f.fileNum == fileNum && f.friendId == friendId)
|
||||
{
|
||||
file = &f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!file)
|
||||
{
|
||||
qWarning("Core::cancelFileRecv: No such file in queue");
|
||||
return;
|
||||
}
|
||||
if (file->status == ToxFile::TRANSMITTING)
|
||||
{
|
||||
file->status = ToxFile::PAUSED;
|
||||
emit fileTransferPaused(*file);
|
||||
tox_file_control(tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_PAUSE, nullptr);
|
||||
}
|
||||
else if (file->status == ToxFile::PAUSED)
|
||||
{
|
||||
file->status = ToxFile::TRANSMITTING;
|
||||
emit fileTransferAccepted(*file);
|
||||
tox_file_control(tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_RESUME, nullptr);
|
||||
}
|
||||
else
|
||||
qWarning() << "Core::pauseResumeFileRecv: File is stopped or broken";
|
||||
CoreFile::pauseResumeFileRecv(this, friendId, fileNum);
|
||||
}
|
||||
|
||||
void Core::cancelFileSend(uint32_t friendId, uint32_t fileNum)
|
||||
{
|
||||
ToxFile* file{nullptr};
|
||||
for (ToxFile& f : fileSendQueue)
|
||||
{
|
||||
if (f.fileNum == fileNum && f.friendId == friendId)
|
||||
{
|
||||
file = &f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!file)
|
||||
{
|
||||
qWarning("Core::cancelFileSend: No such file in queue");
|
||||
return;
|
||||
}
|
||||
file->status = ToxFile::STOPPED;
|
||||
emit fileTransferCancelled(*file);
|
||||
tox_file_control(tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
while (file->sendTimer) QThread::msleep(1); // Wait until sendAllFileData returns before deleting
|
||||
removeFileFromQueue(true, friendId, fileNum);
|
||||
CoreFile::cancelFileSend(this, friendId, fileNum);
|
||||
}
|
||||
|
||||
void Core::cancelFileRecv(uint32_t friendId, uint32_t fileNum)
|
||||
{
|
||||
ToxFile* file{nullptr};
|
||||
for (ToxFile& f : fileRecvQueue)
|
||||
{
|
||||
if (f.fileNum == fileNum && f.friendId == friendId)
|
||||
{
|
||||
file = &f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!file)
|
||||
{
|
||||
qWarning("Core::cancelFileRecv: No such file in queue");
|
||||
return;
|
||||
}
|
||||
file->status = ToxFile::STOPPED;
|
||||
emit fileTransferCancelled(*file);
|
||||
tox_file_control(tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
removeFileFromQueue(true, friendId, fileNum);
|
||||
CoreFile::cancelFileRecv(this, friendId, fileNum);
|
||||
}
|
||||
|
||||
void Core::rejectFileRecvRequest(uint32_t friendId, uint32_t fileNum)
|
||||
{
|
||||
ToxFile* file{nullptr};
|
||||
for (ToxFile& f : fileRecvQueue)
|
||||
{
|
||||
if (f.fileNum == fileNum && f.friendId == friendId)
|
||||
{
|
||||
file = &f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!file)
|
||||
{
|
||||
qWarning("Core::rejectFileRecvRequest: No such file in queue");
|
||||
return;
|
||||
}
|
||||
file->status = ToxFile::STOPPED;
|
||||
emit fileTransferCancelled(*file);
|
||||
tox_file_control(tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
removeFileFromQueue(false, friendId, fileNum);
|
||||
CoreFile::rejectFileRecvRequest(this, friendId, fileNum);
|
||||
}
|
||||
|
||||
void Core::acceptFileRecvRequest(uint32_t friendId, uint32_t fileNum, QString path)
|
||||
{
|
||||
ToxFile* file{nullptr};
|
||||
for (ToxFile& f : fileRecvQueue)
|
||||
{
|
||||
if (f.fileNum == fileNum && f.friendId == friendId)
|
||||
{
|
||||
file = &f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!file)
|
||||
{
|
||||
qWarning("Core::acceptFileRecvRequest: No such file in queue");
|
||||
return;
|
||||
}
|
||||
file->setFilePath(path);
|
||||
if (!file->open(true))
|
||||
{
|
||||
qWarning() << "Core::acceptFileRecvRequest: Unable to open file";
|
||||
return;
|
||||
}
|
||||
file->status = ToxFile::TRANSMITTING;
|
||||
emit fileTransferAccepted(*file);
|
||||
tox_file_control(tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_RESUME, nullptr);
|
||||
CoreFile::acceptFileRecvRequest(this, friendId, fileNum, path);
|
||||
}
|
||||
|
||||
void Core::removeFriend(uint32_t friendId, bool fake)
|
||||
|
@ -1269,43 +1121,6 @@ void Core::quitGroupChat(int groupId) const
|
|||
tox_del_groupchat(tox, groupId);
|
||||
}
|
||||
|
||||
void Core::removeFileFromQueue(bool sendQueue, uint32_t friendId, uint32_t fileId)
|
||||
{
|
||||
bool found = false;
|
||||
if (sendQueue)
|
||||
{
|
||||
for (int i=0; i<fileSendQueue.size();)
|
||||
{
|
||||
if (fileSendQueue[i].friendId == friendId && fileSendQueue[i].fileNum == fileId)
|
||||
{
|
||||
found = true;
|
||||
fileSendQueue[i].file->close();
|
||||
delete fileSendQueue[i].file;
|
||||
fileSendQueue.removeAt(i);
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i=0; i<fileRecvQueue.size();)
|
||||
{
|
||||
if (fileRecvQueue[i].friendId == friendId && fileRecvQueue[i].fileNum == fileId)
|
||||
{
|
||||
found = true;
|
||||
fileRecvQueue[i].file->close();
|
||||
delete fileRecvQueue[i].file;
|
||||
fileRecvQueue.removeAt(i);
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
qWarning() << "Core::removeFileFromQueue: No such file in queue";
|
||||
}
|
||||
|
||||
void Core::groupInviteFriend(uint32_t friendId, int groupId)
|
||||
{
|
||||
tox_invite_friend(tox, friendId, groupId);
|
||||
|
|
|
@ -278,8 +278,6 @@ private:
|
|||
void make_tox(QByteArray savedata);
|
||||
void loadFriends();
|
||||
|
||||
static void removeFileFromQueue(bool sendQueue, uint32_t friendId, uint32_t fileId);
|
||||
|
||||
void checkLastOnline(uint32_t friendId);
|
||||
|
||||
void deadifyTox();
|
||||
|
@ -292,13 +290,12 @@ private:
|
|||
QString loadPath; // meaningless after start() is called
|
||||
QList<DhtServer> dhtServerList;
|
||||
int dhtServerId;
|
||||
static QList<ToxFile> fileSendQueue, fileRecvQueue;
|
||||
static ToxCall calls[TOXAV_MAX_CALLS];
|
||||
#ifdef QTOX_FILTER_AUDIO
|
||||
static AudioFilterer * filterer[TOXAV_MAX_CALLS];
|
||||
#endif
|
||||
static QHash<int, ToxGroupCall> groupCalls; // Maps group IDs to ToxGroupCalls
|
||||
QMutex fileSendMutex, messageSendMutex;
|
||||
QMutex messageSendMutex;
|
||||
bool ready;
|
||||
|
||||
TOX_PASS_KEY* pwsaltedkeys[PasswordType::ptCounter] = {nullptr}; // use the pw's hash as the "pw"
|
||||
|
@ -319,6 +316,7 @@ private:
|
|||
static QThread *coreThread;
|
||||
|
||||
friend class Audio; ///< Audio can access our calls directly to reduce latency
|
||||
friend class CoreFile; ///< CoreFile can access tox* and emit our signals
|
||||
};
|
||||
|
||||
#endif // CORE_HPP
|
||||
|
|
|
@ -1,26 +1,298 @@
|
|||
#include "core.h"
|
||||
#include "corefile.h"
|
||||
#include "corestructs.h"
|
||||
#include "src/misc/cstring.h"
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QThread>
|
||||
#include <memory>
|
||||
|
||||
QMutex CoreFile::fileSendMutex;
|
||||
QHash<uint64_t, ToxFile> CoreFile::fileMap;
|
||||
using namespace std;
|
||||
|
||||
void CoreFile::sendFile(Core* core, uint32_t friendId, QString Filename, QString FilePath, long long filesize)
|
||||
{
|
||||
QMutexLocker mlocker(&fileSendMutex);
|
||||
|
||||
QByteArray fileName = Filename.toUtf8();
|
||||
uint32_t fileNum = tox_file_send(core->tox, friendId, TOX_FILE_KIND_DATA, filesize, nullptr,
|
||||
(uint8_t*)fileName.data(), fileName.size(), nullptr);
|
||||
if (fileNum == UINT32_MAX)
|
||||
{
|
||||
qWarning() << "CoreFile::sendFile: Can't create the Tox file sender";
|
||||
emit core->fileSendFailed(friendId, Filename);
|
||||
return;
|
||||
}
|
||||
qDebug() << QString("CoreFile::sendFile: Created file sender %1 with friend %2").arg(fileNum).arg(friendId);
|
||||
|
||||
ToxFile file{fileNum, friendId, fileName, FilePath, ToxFile::SENDING};
|
||||
file.filesize = filesize;
|
||||
if (!file.open(false))
|
||||
{
|
||||
qWarning() << QString("CoreFile::sendFile: Can't open file, error: %1").arg(file.file->errorString());
|
||||
}
|
||||
addFile(friendId, fileNum, file);
|
||||
|
||||
emit core->fileSendStarted(file);
|
||||
}
|
||||
|
||||
void CoreFile::pauseResumeFileSend(Core* core, uint32_t friendId, uint32_t fileId)
|
||||
{
|
||||
ToxFile* file = findFile(friendId, fileId);
|
||||
if (!file)
|
||||
{
|
||||
qWarning("CoreFile::pauseResumeFileSend: No such file in queue");
|
||||
return;
|
||||
}
|
||||
if (file->status == ToxFile::TRANSMITTING)
|
||||
{
|
||||
file->status = ToxFile::PAUSED;
|
||||
emit core->fileTransferPaused(*file);
|
||||
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_PAUSE, nullptr);
|
||||
}
|
||||
else if (file->status == ToxFile::PAUSED)
|
||||
{
|
||||
file->status = ToxFile::TRANSMITTING;
|
||||
emit core->fileTransferAccepted(*file);
|
||||
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_RESUME, nullptr);
|
||||
}
|
||||
else
|
||||
qWarning() << "CoreFile::pauseResumeFileSend: File is stopped";
|
||||
}
|
||||
|
||||
void CoreFile::pauseResumeFileRecv(Core* core, uint32_t friendId, uint32_t fileId)
|
||||
{
|
||||
ToxFile* file = findFile(friendId, fileId);
|
||||
if (!file)
|
||||
{
|
||||
qWarning("CoreFile::cancelFileRecv: No such file in queue");
|
||||
return;
|
||||
}
|
||||
if (file->status == ToxFile::TRANSMITTING)
|
||||
{
|
||||
file->status = ToxFile::PAUSED;
|
||||
emit core->fileTransferPaused(*file);
|
||||
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_PAUSE, nullptr);
|
||||
}
|
||||
else if (file->status == ToxFile::PAUSED)
|
||||
{
|
||||
file->status = ToxFile::TRANSMITTING;
|
||||
emit core->fileTransferAccepted(*file);
|
||||
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_RESUME, nullptr);
|
||||
}
|
||||
else
|
||||
qWarning() << "CoreFile::pauseResumeFileRecv: File is stopped or broken";
|
||||
}
|
||||
|
||||
void CoreFile::cancelFileSend(Core* core, uint32_t friendId, uint32_t fileId)
|
||||
{
|
||||
ToxFile* file = findFile(friendId, fileId);
|
||||
if (!file)
|
||||
{
|
||||
qWarning("CoreFile::cancelFileSend: No such file in queue");
|
||||
return;
|
||||
}
|
||||
file->status = ToxFile::STOPPED;
|
||||
emit core->fileTransferCancelled(*file);
|
||||
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
while (file->sendTimer) QThread::msleep(1); // Wait until sendAllFileData returns before deleting
|
||||
removeFile(friendId, fileId);
|
||||
}
|
||||
|
||||
void CoreFile::cancelFileRecv(Core* core, uint32_t friendId, uint32_t fileId)
|
||||
{
|
||||
ToxFile* file = findFile(friendId, fileId);
|
||||
if (!file)
|
||||
{
|
||||
qWarning("CoreFile::cancelFileRecv: No such file in queue");
|
||||
return;
|
||||
}
|
||||
file->status = ToxFile::STOPPED;
|
||||
emit core->fileTransferCancelled(*file);
|
||||
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
removeFile(friendId, fileId);
|
||||
}
|
||||
|
||||
void CoreFile::rejectFileRecvRequest(Core* core, uint32_t friendId, uint32_t fileId)
|
||||
{
|
||||
ToxFile* file = findFile(friendId, fileId);
|
||||
if (!file)
|
||||
{
|
||||
qWarning("CoreFile::rejectFileRecvRequest: No such file in queue");
|
||||
return;
|
||||
}
|
||||
file->status = ToxFile::STOPPED;
|
||||
emit core->fileTransferCancelled(*file);
|
||||
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
removeFile(friendId, fileId);
|
||||
}
|
||||
|
||||
void CoreFile::acceptFileRecvRequest(Core* core, uint32_t friendId, uint32_t fileId, QString path)
|
||||
{
|
||||
ToxFile* file = findFile(friendId, fileId);
|
||||
if (!file)
|
||||
{
|
||||
qWarning("CoreFile::acceptFileRecvRequest: No such file in queue");
|
||||
return;
|
||||
}
|
||||
file->setFilePath(path);
|
||||
if (!file->open(true))
|
||||
{
|
||||
qWarning() << "CoreFile::acceptFileRecvRequest: Unable to open file";
|
||||
return;
|
||||
}
|
||||
file->status = ToxFile::TRANSMITTING;
|
||||
emit core->fileTransferAccepted(*file);
|
||||
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_RESUME, nullptr);
|
||||
}
|
||||
|
||||
ToxFile* CoreFile::findFile(uint32_t friendId, uint32_t fileId)
|
||||
{
|
||||
uint64_t key = ((uint64_t)friendId<<32) + (uint64_t)fileId;
|
||||
if (!fileMap.contains(key))
|
||||
{
|
||||
qWarning() << "CoreFile::addFile: File transfer with ID "<<friendId<<':'<<fileId<<" doesn't exist";
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
return &fileMap[key];
|
||||
}
|
||||
|
||||
void CoreFile::addFile(uint32_t friendId, uint32_t fileId, const ToxFile& file)
|
||||
{
|
||||
uint64_t key = ((uint64_t)friendId<<32) + (uint64_t)fileId;
|
||||
if (fileMap.contains(key))
|
||||
qWarning() << "CoreFile::addFile: Overwriting existing file transfer with same ID "<<friendId<<':'<<fileId;
|
||||
fileMap.insert(key, file);
|
||||
}
|
||||
|
||||
void CoreFile::removeFile(uint32_t friendId, uint32_t fileId)
|
||||
{
|
||||
uint64_t key = ((uint64_t)friendId<<32) + (uint64_t)fileId;
|
||||
if (!fileMap.remove(key))
|
||||
qWarning() << "CoreFile::removeFile: No such file in queue";
|
||||
}
|
||||
|
||||
void CoreFile::onFileReceiveCallback(Tox*, uint32_t friendId, uint32_t fileId, uint32_t kind,
|
||||
uint64_t filesize, const uint8_t *fname, size_t fnameLen, void *core)
|
||||
{
|
||||
qDebug() << QString("Core: Received file request %1:%2").arg(friendId).arg(fileId);
|
||||
qDebug() << QString("CoreFile: Received file request %1:%2 kind %3")
|
||||
.arg(friendId).arg(fileId).arg(kind);
|
||||
|
||||
ToxFile file{fileId, friendId,
|
||||
CString::toString(fname,fnameLen).toUtf8(), "", ToxFile::RECEIVING};
|
||||
file.filesize = filesize;
|
||||
file.fileKind = kind;
|
||||
addFile(friendId, fileId, file);
|
||||
if (kind == TOX_FILE_KIND_DATA)
|
||||
emit static_cast<Core*>(core)->fileReceiveRequested(file);
|
||||
}
|
||||
void CoreFile::onFileControlCallback(Tox* tox, uint32_t friendnumber, uint32_t filenumber,
|
||||
void CoreFile::onFileControlCallback(Tox*, uint32_t friendId, uint32_t fileId,
|
||||
TOX_FILE_CONTROL control, void *core)
|
||||
{
|
||||
qDebug() << "File control "<<control<<" for file "<<friendnumber<<':'<<filenumber;
|
||||
ToxFile* file = findFile(friendId, fileId);
|
||||
if (!file)
|
||||
{
|
||||
qWarning("CoreFile::onFileControlCallback: No such file in queue");
|
||||
return;
|
||||
}
|
||||
|
||||
void CoreFile::onFileDataCallback(Tox *tox, uint32_t friendnumber, uint32_t filenumber,
|
||||
if (control == TOX_FILE_CONTROL_CANCEL)
|
||||
{
|
||||
qDebug() << "CoreFile::onFileControlCallback: Received cancel for file "<<friendId<<":"<<fileId;
|
||||
emit static_cast<Core*>(core)->fileTransferCancelled(*file);
|
||||
removeFile(friendId, fileId);
|
||||
}
|
||||
else if (control == TOX_FILE_CONTROL_PAUSE)
|
||||
{
|
||||
qDebug() << "CoreFile::onFileControlCallback: Received pause for file "<<friendId<<":"<<fileId;
|
||||
file->status = ToxFile::PAUSED;
|
||||
emit static_cast<Core*>(core)->fileTransferRemotePausedUnpaused(*file, true);
|
||||
}
|
||||
else if (control == TOX_FILE_CONTROL_RESUME)
|
||||
{
|
||||
qDebug() << "CoreFile::onFileControlCallback: Received pause for file "<<friendId<<":"<<fileId;
|
||||
file->status = ToxFile::TRANSMITTING;
|
||||
emit static_cast<Core*>(core)->fileTransferRemotePausedUnpaused(*file, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "Unhandled file control "<<control<<" for file "<<friendId<<':'<<fileId;
|
||||
}
|
||||
}
|
||||
|
||||
void CoreFile::onFileDataCallback(Tox *tox, uint32_t friendId, uint32_t fileId,
|
||||
uint64_t pos, size_t length, void* core)
|
||||
{
|
||||
qDebug() << "File data req of "<<length<<" at "<<pos<<" for file "<<friendnumber<<':'<<filenumber;
|
||||
//qDebug() << "File data req of "<<length<<" at "<<pos<<" for file "<<friendId<<':'<<fileId;
|
||||
|
||||
ToxFile* file = findFile(friendId, fileId);
|
||||
if (!file)
|
||||
{
|
||||
qWarning("CoreFile::onFileDataCallback: No such file in queue");
|
||||
return;
|
||||
}
|
||||
|
||||
// If we reached EOF, ack and cleanup the transfer
|
||||
if (!length)
|
||||
{
|
||||
qDebug("CoreFile::onFileDataCallback: File sending completed");
|
||||
emit static_cast<Core*>(core)->fileTransferFinished(*file);
|
||||
removeFile(friendId, fileId);
|
||||
return;
|
||||
}
|
||||
|
||||
unique_ptr<uint8_t[]> data(new uint8_t[length]);
|
||||
|
||||
file->file->seek(pos);
|
||||
int64_t nread = file->file->read((char*)data.get(), length);
|
||||
if (nread <= 0)
|
||||
{
|
||||
qWarning("CoreFile::onFileDataCallback: Failed to read from file");
|
||||
emit static_cast<Core*>(core)->fileTransferCancelled(*file);
|
||||
tox_file_send_chunk(tox, friendId, fileId, pos, nullptr, 0, nullptr);
|
||||
removeFile(friendId, fileId);
|
||||
return;
|
||||
}
|
||||
file->bytesSent += length;
|
||||
|
||||
if (!tox_file_send_chunk(tox, friendId, fileId, pos, data.get(), nread, nullptr))
|
||||
{
|
||||
qWarning("CoreFile::onFileDataCallback: Failed to send data chunk");
|
||||
return;
|
||||
}
|
||||
emit static_cast<Core*>(core)->fileTransferInfo(*file);
|
||||
}
|
||||
|
||||
void CoreFile::onFileRecvChunkCallback(Tox *tox, uint32_t friendId, uint32_t fileId, uint64_t position,
|
||||
const uint8_t *data, size_t length, void *core)
|
||||
{
|
||||
qDebug() << QString("Core: Received file chunk for request %1:%2").arg(friendId).arg(fileId);
|
||||
//qDebug() << QString("CoreFile: Received file chunk for request %1:%2").arg(friendId).arg(fileId);
|
||||
|
||||
ToxFile* file = findFile(friendId, fileId);
|
||||
if (!file)
|
||||
{
|
||||
qWarning("CoreFile::onFileRecvChunkCallback: No such file in queue");
|
||||
tox_file_control(tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (file->bytesSent != position)
|
||||
{
|
||||
/// TODO: Allow ooo receiving for non-stream transfers, with very careful checking
|
||||
qWarning("CoreFile::onFileRecvChunkCallback: Received a chunk out-of-order, aborting transfer");
|
||||
emit static_cast<Core*>(core)->fileTransferCancelled(*file);
|
||||
tox_file_control(tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
removeFile(friendId, fileId);
|
||||
return;
|
||||
}
|
||||
file->bytesSent += length;
|
||||
file->file->write((char*)data,length);
|
||||
//qDebug() << QString("CoreFile::onFileRecvChunkCallback: received %1/%2 bytes").arg(file->bytesSent).arg(file->filesize);
|
||||
|
||||
if (file->bytesSent == file->filesize)
|
||||
emit static_cast<Core*>(core)->fileTransferFinished(*file);
|
||||
else
|
||||
emit static_cast<Core*>(core)->fileTransferInfo(*file);
|
||||
}
|
||||
|
|
|
@ -3,26 +3,53 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <tox/tox.h>
|
||||
|
||||
#include "corestructs.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QMutex>
|
||||
#include <QHash>
|
||||
|
||||
struct Tox;
|
||||
class Core;
|
||||
|
||||
/// Implements Core's file transfer callbacks
|
||||
/// Avoids polluting core.h with private internal callbacks
|
||||
class CoreFile
|
||||
{
|
||||
friend class Core;
|
||||
|
||||
private:
|
||||
CoreFile()=delete;
|
||||
|
||||
public:
|
||||
private:
|
||||
static void sendFile(Core *core, uint32_t friendId, QString Filename, QString FilePath, long long filesize);
|
||||
static void pauseResumeFileSend(Core* core, uint32_t friendId, uint32_t fileId);
|
||||
static void pauseResumeFileRecv(Core* core, uint32_t friendId, uint32_t fileId);
|
||||
static void cancelFileSend(Core* core, uint32_t friendId, uint32_t fileId);
|
||||
static void cancelFileRecv(Core* core, uint32_t friendId, uint32_t fileId);
|
||||
static void rejectFileRecvRequest(Core* core, uint32_t friendId, uint32_t fileId);
|
||||
static void acceptFileRecvRequest(Core* core, uint32_t friendId, uint32_t fileId, QString path);
|
||||
static ToxFile *findFile(uint32_t friendId, uint32_t fileId);
|
||||
static void addFile(uint32_t friendId, uint32_t fileId, const ToxFile& file);
|
||||
static void removeFile(uint32_t friendId, uint32_t fileId);
|
||||
|
||||
private:
|
||||
static void onFileReceiveCallback(Tox*, uint32_t friendnumber, uint32_t fileId, uint32_t kind,
|
||||
uint64_t filesize, const uint8_t *fname, size_t fnameLen, void *core);
|
||||
static void onFileControlCallback(Tox *tox, uint32_t friendnumber, uint32_t filenumber,
|
||||
static void onFileControlCallback(Tox *tox, uint32_t friendId, uint32_t fileId,
|
||||
TOX_FILE_CONTROL control, void *core);
|
||||
static void onFileDataCallback(Tox *tox, uint32_t friendnumber, uint32_t filenumber,
|
||||
static void onFileDataCallback(Tox *tox, uint32_t friendId, uint32_t fileId,
|
||||
uint64_t pos, size_t length, void *core);
|
||||
static void onFileRecvChunkCallback(Tox *tox, uint32_t friendId, uint32_t fileId, uint64_t position,
|
||||
const uint8_t *data, size_t length, void *core);
|
||||
|
||||
private:
|
||||
static QMutex fileSendMutex;
|
||||
static QHash<uint64_t, ToxFile> fileMap;
|
||||
/// TODO: Replace the two queues by a hash map uint64_t -> unique_ptr<ToxFile>
|
||||
};
|
||||
|
||||
#endif // COREFILE_H
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
#define TOX_HEX_ID_LENGTH 2*TOX_ADDRESS_SIZE
|
||||
|
||||
ToxFile::ToxFile(uint32_t FileNum, uint32_t FriendId, QByteArray FileName, QString FilePath, FileDirection Direction)
|
||||
: fileNum(FileNum), friendId(FriendId), fileName{FileName}, filePath{FilePath}, file{new QFile(filePath)},
|
||||
bytesSent{0}, filesize{0}, status{STOPPED}, direction{Direction}, sendTimer{nullptr}
|
||||
: fileKind{TOX_FILE_KIND_DATA}, fileNum(FileNum), friendId(FriendId), fileName{FileName},
|
||||
filePath{FilePath}, file{new QFile(filePath)}, bytesSent{0}, filesize{0},
|
||||
status{STOPPED}, direction{Direction}, sendTimer{nullptr}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -67,13 +67,14 @@ struct ToxFile
|
|||
void setFilePath(QString path);
|
||||
bool open(bool write);
|
||||
|
||||
uint8_t fileKind; ///< Data file (default) or avatar
|
||||
uint32_t fileNum;
|
||||
uint32_t friendId;
|
||||
QByteArray fileName;
|
||||
QString filePath;
|
||||
QFile* file;
|
||||
qint64 bytesSent;
|
||||
qint64 filesize;
|
||||
quint64 bytesSent;
|
||||
quint64 filesize;
|
||||
FileStatus status;
|
||||
FileDirection direction;
|
||||
QTimer* sendTimer;
|
||||
|
|
|
@ -134,6 +134,7 @@ bool IPC::isCurrentOwner()
|
|||
{
|
||||
if (globalMemory.lock())
|
||||
{
|
||||
/// TODO: Segfault on exit on "mov rdx,QWORD PTR [rax]" w/ rax=0.
|
||||
bool isOwner = ((*(uint64_t*)globalMemory.data()) == globalId);
|
||||
globalMemory.unlock();
|
||||
return isOwner;
|
||||
|
|
Loading…
Reference in New Issue
Block a user