1
0
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:
tux3 2015-04-24 15:31:30 +02:00
parent e4859efe18
commit 9dedd22bb2
No known key found for this signature in database
GPG Key ID: 7E086DD661263264
9 changed files with 365 additions and 216 deletions

View File

@ -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"};

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View 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

View File

@ -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}
{
}

View File

@ -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;

View File

@ -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;