1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

refactor(core): reimplement avatar transfers

In the process of this I used some ugly hacks, to finish this in time,
they should be changed as soon as possible.
This commit is contained in:
sudden6 2018-06-27 21:32:28 +02:00
parent b647f9291e
commit e5acc6726f
No known key found for this signature in database
GPG Key ID: 279509B499E032B9
14 changed files with 150 additions and 99 deletions

View File

@ -235,8 +235,7 @@ ToxCorePtr Core::makeToxCore(const QByteArray &savedata, const ICoreSettings * c
void Core::onStarted()
{
// TODO(sudden6): this assert should hold?
//assert(QThread::currentThread() == coreThread);
assert(QThread::currentThread() == coreThread);
// One time initialization stuff
// set GUI with user and statusmsg
QString name = getUsername();

View File

@ -139,44 +139,18 @@ signals:
void disconnected();
void friendRequestReceived(const ToxPk& friendPk, const QString& message);
void friendMessageReceived(uint32_t friendId, const QString& message, bool isAction);
void friendAvatarChanged(const ToxPk& friendPk, const QPixmap& pic);
void friendAvatarData(const ToxPk& friendPk, const QByteArray& data);
void friendAvatarRemoved(const ToxPk& friendPk);
void friendAdded(uint32_t friendId, const ToxPk& friendPk);
void requestSent(const ToxPk& friendPk, const QString& message);
void friendStatusChanged(uint32_t friendId, Status status);
void friendStatusMessageChanged(uint32_t friendId, const QString& message);
void friendUsernameChanged(uint32_t friendId, const QString& username);
void friendTypingChanged(uint32_t friendId, bool isTyping);
void friendAvatarChanged(uint32_t friendId, const QPixmap& pic);
void friendAvatarRemoved(uint32_t friendId);
void friendRemoved(uint32_t friendId);
void friendLastSeenChanged(uint32_t friendId, const QDateTime& dateTime);
void emptyGroupCreated(int groupnumber);
void groupInviteReceived(const GroupInvite& inviteInfo);
void groupMessageReceived(int groupnumber, int peernumber, const QString& message, bool isAction);
void groupNamelistChanged(int groupnumber, int peernumber, uint8_t change);
void groupPeerlistChanged(int groupnumber);
void groupPeerNameChanged(int groupnumber, int peernumber, const QString& newName);
void groupTitleChanged(int groupnumber, const QString& author, const QString& title);
void groupPeerAudioPlaying(int groupnumber, int peernumber);
void failedToAddFriend(const ToxPk& friendPk, const QString& errorInfo = QString());
void usernameSet(const QString& username);
void statusMessageSet(const QString& message);
void statusSet(Status status);
void idSet(const ToxId& id);
void messageSentResult(uint32_t friendId, const QString& message, int messageId);
void groupSentFailed(int groupId);
void actionSentResult(uint32_t friendId, const QString& action, int success);
void receiptRecieved(int friedId, int receipt);
void failedToAddFriend(const ToxPk& friendPk, const QString& errorInfo = QString());
void failedToRemoveFriend(uint32_t friendId);
void failedToSetUsername(const QString& username);
void failedToSetStatusMessage(const QString& message);
void failedToSetStatus(Status status);
@ -197,10 +171,45 @@ signals:
void fileTransferBrokenUnbroken(ToxFile file, bool broken);
void fileNameChanged();
void fileSendFailed(uint32_t friendId, const QString& fname);
void saveRequest();
/**
* @deprecated prefer signals using ToxPk
*/
void fileAvatarOfferReceived(uint32_t friendId, uint32_t fileId, const QByteArray& avatarHash);
void friendMessageReceived(uint32_t friendId, const QString& message, bool isAction);
void friendAdded(uint32_t friendId, const ToxPk& friendPk);
void friendStatusChanged(uint32_t friendId, Status status);
void friendStatusMessageChanged(uint32_t friendId, const QString& message);
void friendUsernameChanged(uint32_t friendId, const QString& username);
void friendTypingChanged(uint32_t friendId, bool isTyping);
void friendAvatarChangedDeprecated(uint32_t friendId, const QPixmap& pic);
void friendRemoved(uint32_t friendId);
void friendLastSeenChanged(uint32_t friendId, const QDateTime& dateTime);
void emptyGroupCreated(int groupnumber);
void groupInviteReceived(const GroupInvite& inviteInfo);
void groupMessageReceived(int groupnumber, int peernumber, const QString& message, bool isAction);
void groupNamelistChanged(int groupnumber, int peernumber, uint8_t change);
void groupPeerlistChanged(int groupnumber);
void groupPeerNameChanged(int groupnumber, int peernumber, const QString& newName);
void groupTitleChanged(int groupnumber, const QString& author, const QString& title);
void groupPeerAudioPlaying(int groupnumber, int peernumber);
void messageSentResult(uint32_t friendId, const QString& message, int messageId);
void groupSentFailed(int groupId);
void actionSentResult(uint32_t friendId, const QString& action, int success);
void receiptRecieved(int friedId, int receipt);
void failedToRemoveFriend(uint32_t friendId);
void fileSendFailed(uint32_t friendId, const QString& fname);
private:
Core(QThread* coreThread);

View File

@ -295,33 +295,17 @@ void CoreFile::onFileReceiveCallback(Tox*, uint32_t friendId, uint32_t fileId, u
if (!filesize) {
qDebug() << QString("Received empty avatar request %1:%2").arg(friendId).arg(fileId);
// Avatars of size 0 means explicitely no avatar
emit core->friendAvatarRemoved(friendId);
// TODO(sudden6): use signal from above for that action
//core->profile.removeAvatar(friendPk);
emit core->friendAvatarRemoved(core->getFriendPublicKey(friendId));
return;
} else {
static_assert(TOX_HASH_LENGTH <= TOX_FILE_ID_LENGTH,
"TOX_HASH_LENGTH > TOX_FILE_ID_LENGTH!");
uint8_t avatarHash[TOX_FILE_ID_LENGTH];
tox_file_get_file_id(core->tox, friendId, fileId, avatarHash, nullptr);
// TODO(sudden6): fix that condition below
if (/*core->profile.getAvatarHash(friendPk)
== QByteArray((char*)avatarHash, TOX_HASH_LENGTH)*/ false) {
// If it's an avatar but we already have it cached, cancel
qDebug() << QString(
"Received avatar request %1:%2, reject, since we have it in cache.")
.arg(friendId)
.arg(fileId);
tox_file_control(core->tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr);
QByteArray avatarBytes{static_cast<const char*>(static_cast<const void*>(avatarHash)),
TOX_HASH_LENGTH};
emit core->fileAvatarOfferReceived(friendId, fileId, avatarBytes);
return;
} else {
// It's an avatar and we don't have it, autoaccept the transfer
qDebug() << QString("Received avatar request %1:%2, accept, since we don't have it "
"in cache.")
.arg(friendId)
.arg(fileId);
tox_file_control(core->tox, friendId, fileId, TOX_FILE_CONTROL_RESUME, nullptr);
}
}
} else {
const auto cleanFileName = CoreFile::getCleanFileName(filename.getQString());
@ -344,6 +328,37 @@ void CoreFile::onFileReceiveCallback(Tox*, uint32_t friendId, uint32_t fileId, u
if (kind != TOX_FILE_KIND_AVATAR)
emit core->fileReceiveRequested(file);
}
// TODO(sudden6): This whole method is a mess but needed to get stuff working for now
void CoreFile::handleAvatarOffer(uint32_t friendId, uint32_t fileId, bool accept)
{
// TODO(sudden6): evil evil evil
auto core = Core::getInstance();
if (!accept) {
// If it's an avatar but we already have it cached, cancel
qDebug() << QString(
"Received avatar request %1:%2, reject, since we have it in cache.")
.arg(friendId)
.arg(fileId);
tox_file_control(core->tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr);
return;
}
// It's an avatar and we don't have it, autoaccept the transfer
qDebug() << QString("Received avatar request %1:%2, accept, since we don't have it "
"in cache.")
.arg(friendId)
.arg(fileId);
tox_file_control(core->tox, friendId, fileId, TOX_FILE_CONTROL_RESUME, nullptr);
ToxFile file{fileId, friendId, "<avatar>", "", ToxFile::RECEIVING};
file.filesize = 0;
file.fileKind = TOX_FILE_KIND_AVATAR;
file.resumeFileId.resize(TOX_FILE_ID_LENGTH);
tox_file_get_file_id(core->tox, friendId, fileId, (uint8_t*)file.resumeFileId.data(), nullptr);
addFile(friendId, fileId, file);
}
void CoreFile::onFileControlCallback(Tox*, uint32_t friendId, uint32_t fileId,
TOX_FILE_CONTROL control, void* core)
{
@ -448,11 +463,10 @@ void CoreFile::onFileRecvChunkCallback(Tox* tox, uint32_t friendId, uint32_t fil
pic.loadFromData(file->avatarData);
if (!pic.isNull()) {
qDebug() << "Got" << file->avatarData.size() << "bytes of avatar data from" << friendId;
// TODO(sudden6): handle the action below with the signal
/*
core->profile.saveAvatar(file->avatarData,
core->getFriendPublicKey(friendId));*/
emit core->friendAvatarChanged(friendId, pic);
emit core->friendAvatarData(core->getFriendPublicKey(friendId), file->avatarData);
emit core->friendAvatarChanged(core->getFriendPublicKey(friendId), pic);
// TODO(sudden6): signal below is deprecated
emit core->friendAvatarChangedDeprecated(friendId, pic);
}
} else {
emit core->fileTransferFinished(*file);

View File

@ -39,6 +39,9 @@ class CoreFile
{
friend class Core;
public:
static void handleAvatarOffer(uint32_t friendId, uint32_t fileId, bool accept);
private:
CoreFile() = delete;

View File

@ -327,7 +327,7 @@ IProfileInfo::SetAvatarResult ProfileInfo::setAvatar(const QString &path)
return SetAvatarResult::TooLarge;
}
profile->setAvatar(bytes, core->getSelfPublicKey());
profile->setAvatar(bytes);
return SetAvatarResult::OK;
}
@ -336,5 +336,5 @@ IProfileInfo::SetAvatarResult ProfileInfo::setAvatar(const QString &path)
*/
void ProfileInfo::removeAvatar()
{
profile->removeAvatar();
profile->removeSelfAvatar();
}

View File

@ -32,6 +32,7 @@
#include "profilelocker.h"
#include "settings.h"
#include "src/core/core.h"
#include "src/core/corefile.h"
#include "src/net/avatarbroadcaster.h"
#include "src/nexus.h"
#include "src/widget/gui.h"
@ -78,19 +79,16 @@ Profile::Profile(QString name, const QString& password, bool isNewProfile, const
return;
}
const ToxId& selfId = core->getSelfId();
loadDatabase(selfId, password);
const ToxPk& selfPk = selfId.getPublicKey();
QByteArray data = loadAvatarData(selfPk);
if (data.isEmpty()) {
qDebug() << "Self avatar not found, will broadcast empty avatar to friends";
}
// save tox file when Core requests it
connect(core.get(), &Core::saveRequest, this, &Profile::onSaveToxSave);
// react to avatar changes
connect(core.get(), &Core::friendAvatarRemoved, this, &Profile::removeAvatar);
connect(core.get(), &Core::friendAvatarData, this, &Profile::saveAvatar);
connect(core.get(), &Core::fileAvatarOfferReceived, this, &Profile::onAvatarOfferReceived, Qt::ConnectionType::BlockingQueuedConnection);
const ToxId& selfId = core->getSelfId();
loadDatabase(selfId, password);
// TODO(sudden6): check if needed
//setAvatar(data, selfPk);
}
/**
@ -298,6 +296,17 @@ QString Profile::getName() const
void Profile::startCore()
{
core->start();
const ToxId& selfId = core->getSelfId();
const ToxPk& selfPk = selfId.getPublicKey();
QByteArray data = loadAvatarData(selfPk);
if (data.isEmpty()) {
qDebug() << "Self avatar not found, will broadcast empty avatar to friends";
}
// TODO(sudden6): moved here, because it crashes in the constructor
// reason: Core::getInstance() returns nullptr, because it's not yet initialized
// solution: kill Core::getInstance
setAvatar(data);
}
bool Profile::isNewProfile()
@ -317,6 +326,14 @@ void Profile::onSaveToxSave()
saveToxSave(data);
}
// TODO(sudden6): handle this better maybe?
void Profile::onAvatarOfferReceived(uint32_t friendId, uint32_t fileId, const QByteArray &avatarHash)
{
// accept if we don't have it already
const bool accept = getAvatarHash(core->getFriendPublicKey(friendId)) != avatarHash;
CoreFile::handleAvatarOffer(friendId, fileId, accept);
}
/**
* @brief Write the .tox save, encrypted if needed.
* @param data Byte array of profile save.
@ -474,26 +491,31 @@ void Profile::loadDatabase(const ToxId& id, QString password)
}
}
void Profile::setAvatar(QByteArray pic, const ToxPk& owner)
/**
* @brief Sets our own avatar
* @param pic Picture to use as avatar, if empty an Identicon will be used depending on settings
* @param owner
*/
void Profile::setAvatar(QByteArray pic)
{
QPixmap pixmap;
QByteArray avatarData;
const ToxPk& selfPk = core->getSelfPublicKey();
if (!pic.isEmpty()) {
pixmap.loadFromData(pic);
avatarData = pic;
} else {
if (Settings::getInstance().getShowIdenticons()) {
// with IDENTICON_ROWS=5 this gives a 160x160 image file
const QImage identicon = Identicon(owner.getKey()).toImage(32);
const QImage identicon = Identicon(selfPk.getKey()).toImage(32);
pixmap = QPixmap::fromImage(identicon);
} else {
pixmap.load(":/img/contact_dark.svg");
}
}
saveAvatar(avatarData, owner);
saveAvatar(selfPk, avatarData);
emit selfAvatarChanged(pixmap);
AvatarBroadcaster::setAvatar(avatarData);
@ -523,7 +545,7 @@ void Profile::onRequestSent(const ToxPk& friendPk, const QString& message)
* @param pic Picture to save.
* @param owner PK of avatar owner.
*/
void Profile::saveAvatar(QByteArray pic, const ToxPk& owner)
void Profile::saveAvatar(const ToxPk& owner, QByteArray pic)
{
if (encrypted && !pic.isEmpty()) {
pic = passkey->encrypt(pic);
@ -560,7 +582,7 @@ QByteArray Profile::getAvatarHash(const ToxPk& owner)
/**
* @brief Removes our own avatar.
*/
void Profile::removeAvatar()
void Profile::removeSelfAvatar()
{
removeAvatar(core->getSelfId().getPublicKey());
}
@ -592,7 +614,7 @@ void Profile::removeAvatar(const ToxPk& owner)
{
QFile::remove(avatarPath(owner));
if (owner == core->getSelfId().getPublicKey()) {
setAvatar({}, core->getSelfPublicKey());
setAvatar({});
}
}
@ -777,13 +799,13 @@ QString Profile::setPassword(const QString& newPassword)
Nexus::getDesktopGUI()->reloadHistory();
QByteArray avatar = loadAvatarData(core->getSelfId().getPublicKey());
saveAvatar(avatar, core->getSelfId().getPublicKey());
saveAvatar(core->getSelfId().getPublicKey(), avatar);
QVector<uint32_t> friendList = core->getFriendList();
QVectorIterator<uint32_t> i(friendList);
while (i.hasNext()) {
const ToxPk friendPublicKey = core->getFriendPublicKey(i.next());
saveAvatar(loadAvatarData(friendPublicKey), friendPublicKey);
saveAvatar(friendPublicKey, loadAvatarData(friendPublicKey));
}
return error;
}

View File

@ -56,11 +56,9 @@ public:
QPixmap loadAvatar();
QPixmap loadAvatar(const ToxPk& owner);
QByteArray loadAvatarData(const ToxPk& owner);
void setAvatar(QByteArray pic, const ToxPk& owner);
void saveAvatar(QByteArray pic, const ToxPk& owner);
void setAvatar(QByteArray pic);
QByteArray getAvatarHash(const ToxPk& owner);
void removeAvatar(const ToxPk& owner);
void removeAvatar();
void removeSelfAvatar();
bool isHistoryEnabled();
History* getHistory();
@ -88,7 +86,11 @@ public slots:
private slots:
void loadDatabase(const ToxId& id, QString password);
void saveAvatar(const ToxPk& owner, QByteArray pic);
void removeAvatar(const ToxPk& owner);
void onSaveToxSave();
// TODO(sudden6): use ToxPk instead of friendId
void onAvatarOfferReceived(uint32_t friendId, uint32_t fileId, const QByteArray& avatarHash);
private:
Profile(QString name, const QString& password, bool newProfile, const QByteArray& toxsave);

View File

@ -156,7 +156,7 @@ GroupNetCamView::GroupNetCamView(int group, QWidget* parent)
setActive();
});
connect(Core::getInstance(), &Core::friendAvatarChanged, this,
connect(Core::getInstance(), &Core::friendAvatarChangedDeprecated, this,
&GroupNetCamView::friendAvatarChanged);
selfVideoSurface->setText(Core::getInstance()->getUsername());

View File

@ -75,7 +75,7 @@ NetCamView::NetCamView(int friendId, QWidget* parent)
connections += connect(Nexus::getProfile(), &Profile::selfAvatarChanged,
[this](const QPixmap& pixmap) { selfVideoSurface->setAvatar(pixmap); });
connections += connect(Core::getInstance(), &Core::friendAvatarChanged,
connections += connect(Core::getInstance(), &Core::friendAvatarChangedDeprecated,
[this](int FriendId, const QPixmap& pixmap) {
if (this->friendId == FriendId)
videoSurface->setAvatar(pixmap);

View File

@ -158,7 +158,8 @@ ChatForm::ChatForm(Friend* chatFriend, History* history)
const Core* core = Core::getInstance();
connect(core, &Core::fileReceiveRequested, this, &ChatForm::onFileRecvRequest);
connect(core, &Core::friendAvatarChanged, this, &ChatForm::onAvatarChange);
// TODO(sudden6): update slot to new API
connect(core, &Core::friendAvatarChangedDeprecated, this, &ChatForm::onAvatarChange);
connect(core, &Core::friendAvatarRemoved, this, &ChatForm::onAvatarRemoved);
connect(core, &Core::fileSendStarted, this, &ChatForm::startFileSend);
connect(core, &Core::fileSendFailed, this, &ChatForm::onFileSendFailed);
@ -690,9 +691,9 @@ void ChatForm::dropEvent(QDropEvent* ev)
}
}
void ChatForm::onAvatarRemoved(uint32_t friendId)
void ChatForm::onAvatarRemoved(const ToxPk& friendPk)
{
if (friendId != f->getId()) {
if (friendPk != f->getPublicKey()) {
return;
}

View File

@ -73,7 +73,7 @@ public slots:
void onAvStart(uint32_t friendId, bool video);
void onAvEnd(uint32_t friendId, bool error);
void onAvatarChange(uint32_t friendId, const QPixmap& pic);
void onAvatarRemoved(uint32_t friendId);
void onAvatarRemoved(const ToxPk &friendPk);
void onFileNameChanged();
protected slots:

View File

@ -418,9 +418,9 @@ void FriendWidget::resetEventFlags()
f->setEventFlag(false);
}
void FriendWidget::onAvatarChange(uint32_t friendId, const QPixmap& pic)
void FriendWidget::onAvatarChange(const ToxPk& friendPk, const QPixmap& pic)
{
if (friendId != frnd->getId()) {
if (friendPk != frnd->getPublicKey()) {
return;
}
@ -428,9 +428,9 @@ void FriendWidget::onAvatarChange(uint32_t friendId, const QPixmap& pic)
avatar->setPixmap(pic);
}
void FriendWidget::onAvatarRemoved(uint32_t friendId)
void FriendWidget::onAvatarRemoved(const ToxPk& friendPk)
{
if (friendId != frnd->getId()) {
if (friendPk != frnd->getPublicKey()) {
return;
}

View File

@ -19,6 +19,7 @@
#define FRIENDWIDGET_H
#include "genericchatroomwidget.h"
#include "src/core/toxpk.h"
class QPixmap;
class MaskablePixmapWidget;
@ -45,8 +46,8 @@ signals:
void contextMenuCalled(QContextMenuEvent* event);
public slots:
void onAvatarChange(uint32_t friendId, const QPixmap& pic);
void onAvatarRemoved(uint32_t friendId);
void onAvatarChange(const ToxPk &friendPk, const QPixmap& pic);
void onAvatarRemoved(const ToxPk &friendPk);
void onContextMenuCalled(QContextMenuEvent* event);
protected:

View File

@ -1022,7 +1022,7 @@ void Widget::addFriend(uint32_t friendId, const ToxPk& friendPk)
QPixmap avatar = Nexus::getProfile()->loadAvatar(friendPk);
if (!avatar.isNull()) {
friendForm->onAvatarChange(friendId, avatar);
widget->onAvatarChange(friendId, avatar);
widget->onAvatarChange(friendPk, avatar);
}
FilterCriteria filter = getFilterCriteria();
@ -1284,7 +1284,7 @@ void Widget::addFriendDialog(const Friend* frnd, ContentDialog* dialog)
QPixmap avatar = Nexus::getProfile()->loadAvatar(frnd->getPublicKey());
if (!avatar.isNull()) {
friendWidget->onAvatarChange(friendId, avatar);
friendWidget->onAvatarChange(frnd->getPublicKey(), avatar);
}
}