continue transfer object refactor, re-enabling avatar receiving
Some checks failed
ContinuousDelivery / linux-ubuntu (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android-23]) (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android-23]) (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android-23]) (push) Has been cancelled
ContinuousDelivery / windows (push) Has been cancelled
ContinuousDelivery / windows-asan (push) Has been cancelled
ContinuousDelivery / dumpsyms (push) Has been cancelled
ContinuousDelivery / release (push) Has been cancelled
ContinuousIntegration / linux (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android-23]) (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android-23]) (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android-23]) (push) Has been cancelled
ContinuousIntegration / macos (push) Has been cancelled
ContinuousIntegration / windows (push) Has been cancelled

This commit is contained in:
Green Sky 2025-05-04 19:11:28 +02:00
parent 7021e092b1
commit 2654cd1b19
No known key found for this signature in database
GPG Key ID: DBE05085D874AB4A
12 changed files with 390 additions and 69 deletions

@ -1 +1 @@
Subproject commit 99d9633ff109321e78cf2817d3b8631d364a2483
Subproject commit a5508ff6f3443ca5ca22ef0d7d91ac0f9319230f

@ -1 +1 @@
Subproject commit 2a3828b30d7ec5fb9e7c8a8a82d1be66e040ea74
Subproject commit c8e3e9374360fa241ccebd070e1d70abf6ba665b

@ -1 +1 @@
Subproject commit 738e1a2071b95000bbed64e2262261cfbdc7dbab
Subproject commit 889761f538eda8feb7ee0ea224c98e6ea05f6246

@ -1 +1 @@
Subproject commit 4e75bd64aedf6c252456da0ca7c30a414f0fcaaf
Subproject commit 7e12cdfb232a412f6052102fb9d8d3ceb04db4f4

View File

@ -30,6 +30,9 @@ target_sources(tomato PUBLIC
./main_screen.hpp
./main_screen.cpp
./backends/std_fs.hpp
./backends/std_fs.cpp
./tox_client.hpp
./tox_client.cpp
./auto_dirty.hpp

107
src/backends/std_fs.cpp Normal file
View File

@ -0,0 +1,107 @@
#include "./std_fs.hpp"
#include <solanaceae/object_store/meta_components.hpp>
#include <solanaceae/object_store/meta_components_file.hpp>
#include <solanaceae/file/file2_std.hpp>
#include <iostream>
namespace Backends {
STDFS::STDFS(
ObjectStore2& os
) : _os(os) {
}
STDFS::~STDFS(void) {
}
ObjectHandle STDFS::newObject(ByteSpan id, bool throw_construct) {
ObjectHandle o{_os.registry(), _os.registry().create()};
o.emplace<ObjComp::Ephemeral::BackendMeta>(this); // ?
o.emplace<ObjComp::Ephemeral::BackendFile2>(this);
o.emplace<ObjComp::ID>(std::vector<uint8_t>{id});
//o.emplace<ObjComp::Ephemeral::FilePath>(object_file_path.generic_u8string());
if (throw_construct) {
_os.throwEventConstruct(o);
}
return o;
}
bool STDFS::attach(Object ov) {
auto o = _os.objectHandle(ov);
if (!static_cast<bool>(o)) {
return false;
}
if (o.any_of<
ObjComp::Ephemeral::BackendMeta,
ObjComp::Ephemeral::BackendFile2
>()) {
return false;
}
o.emplace<ObjComp::Ephemeral::BackendMeta>(this); // ?
o.emplace<ObjComp::Ephemeral::BackendFile2>(this);
return true;
}
std::unique_ptr<File2I> STDFS::file2(Object ov, FILE2_FLAGS flags) {
if (flags & FILE2_RAW) {
std::cerr << "STDFS error: does not support raw modes\n";
return nullptr;
}
if (flags == FILE2_NONE) {
std::cerr << "STDFS error: no file mode set\n";
assert(false);
return nullptr;
}
ObjectHandle o{_os.registry(), ov};
if (!static_cast<bool>(o)) {
return nullptr;
}
// will this do if we go and support enc?
// use ObjComp::Ephemeral::FilePath instead??
if (!o.all_of<ObjComp::F::SingleInfoLocal>()) {
std::cerr << "STDFS error: no SingleInfoLocal\n";
return nullptr;
}
const auto& file_path = o.get<ObjComp::F::SingleInfoLocal>().file_path;
if (file_path.empty()) {
std::cerr << "STDFS error: SingleInfoLocal path empty\n";
return nullptr;
}
std::unique_ptr<File2I> res;
if ((flags & FILE2_WRITE) != 0 && (flags & FILE2_READ) != 0) {
res = std::make_unique<File2RWFile>(file_path);
} else if (flags & FILE2_READ) {
res = std::make_unique<File2RFile>(file_path);
} else if ((flags & FILE2_WRITE) && o.all_of<ObjComp::File::SingleInfo>()) {
// HACK: use info and presize the file AND truncate
// TODO: actually support streaming :P
res = std::make_unique<File2RWFile>(file_path, o.get<ObjComp::File::SingleInfo>().file_size, true);
} else if (flags & FILE2_WRITE) {
res = std::make_unique<File2WFile>(file_path);
}
if (!res || !res->isGood()) {
std::cerr << "STDFS error: failed constructing file '" << file_path << "'\n";
return nullptr;
}
return res;
}
} // Backends

24
src/backends/std_fs.hpp Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <solanaceae/object_store/object_store.hpp>
namespace Backends {
struct STDFS : public StorageBackendIMeta, public StorageBackendIFile2 {
ObjectStore2& _os;
STDFS(
ObjectStore2& os
);
~STDFS(void);
ObjectHandle newObject(ByteSpan id, bool throw_construct = true) override;
// TODO: interface?
bool attach(Object ov);
std::unique_ptr<File2I> file2(Object o, FILE2_FLAGS flags) override;
};
} // Backends

View File

@ -55,9 +55,9 @@ MainScreen::MainScreen(const SimpleConfigModel& conf_, SDL_Renderer* renderer_,
#endif
theme(theme_),
mmil(rmm),
tam(/*rmm, */ os, cs, conf),
tam(os, cs, conf, tcm),
sdlrtu(renderer_),
tal(cs),
tal(cs, os),
contact_tc(tal, sdlrtu),
mil(),
msg_tc(mil, sdlrtu),

View File

@ -8,6 +8,9 @@
#include <solanaceae/contact/contact_store_i.hpp>
#include <solanaceae/contact/components.hpp>
#include <solanaceae/tox_contacts/components.hpp>
#include <solanaceae/object_store/object_store.hpp>
#include <solanaceae/object_store/meta_components_file.hpp>
#include <solanaceae/file/file2.hpp>
#include <entt/entity/registry.hpp>
@ -18,7 +21,82 @@
#include <cassert>
#include <vector>
ToxAvatarLoader::ToxAvatarLoader(ContactStore4I& cs) : _cs(cs) {
ByteSpanWithOwnership ToxAvatarLoader::loadDataFromObj(Contact4 cv) {
auto c = _cs.contactHandle(cv);
auto o = _os.objectHandle(c.get<Contact::Components::AvatarObj>().obj);
if (!static_cast<bool>(o)) {
std::cerr << "TAL error: avatar object set, but invalid\n";
return ByteSpan{};
}
if (!o.all_of<ObjComp::F::TagLocalHaveAll>()) {
return ByteSpan{}; // we dont have all data
}
if (!o.all_of<ObjComp::Ephemeral::BackendFile2, ObjComp::F::SingleInfo>()) {
std::cerr << "TAL error: object missing file backend/file info (?)\n";
return ByteSpan{};
}
// TODO: handle collections
const auto file_size = o.get<ObjComp::F::SingleInfo>().file_size;
if (file_size > 2*1024*1024) {
std::cerr << "TAL error: image file too large (" << file_size << " > 2MiB)\n";
return ByteSpan{};
}
auto* file_backend = o.get<ObjComp::Ephemeral::BackendFile2>().ptr;
if (file_backend == nullptr) {
std::cerr << "TAL error: object backend nullptr\n";
return ByteSpan{};
}
auto file2 = file_backend->file2(o, StorageBackendIFile2::FILE2_READ);
if (!file2 || !file2->isGood() || !file2->can_read) {
std::cerr << "TAL error: creating file2 from object via backendI\n";
return ByteSpan{};
}
auto read_data = file2->read(file_size, 0);
if (read_data.ptr == nullptr) {
std::cerr << "TAL error: reading from file2 returned nullptr\n";
return ByteSpan{};
}
if (read_data.size != file_size) {
std::cerr << "TAL error: reading from file2 size missmatch, should be " << file_size << ", is " << read_data.size << "\n";
return ByteSpan{};
}
return read_data;
}
ByteSpanWithOwnership ToxAvatarLoader::loadData(Contact4 cv) {
auto c = _cs.contactHandle(cv);
if (c.all_of<Contact::Components::AvatarFile>()) {
// TODO: factor out
const auto& a_f = c.get<Contact::Components::AvatarFile>();
std::vector<uint8_t> tmp_buffer;
std::ifstream file(a_f.file_path, std::ios::binary);
if (file.is_open()) {
tmp_buffer = std::vector<uint8_t>{};
while (file.good()) {
auto ch = file.get();
if (ch == EOF) {
break;
} else {
tmp_buffer.push_back(ch);
}
}
}
return tmp_buffer;
} else { // obj assumed
return loadDataFromObj(cv);
}
}
ToxAvatarLoader::ToxAvatarLoader(ContactStore4I& cs, ObjectStore2& os) : _cs(cs), _os(os) {
_image_loaders.push_back(std::make_unique<ImageLoaderSDLBMP>());
_image_loaders.push_back(std::make_unique<ImageLoaderQOI>());
_image_loaders.push_back(std::make_unique<ImageLoaderWebP>());
@ -142,24 +220,13 @@ TextureLoaderResult ToxAvatarLoader::load(TextureUploaderI& tu, Contact4 c) {
return {new_entry};
}
if (cr.all_of<Contact::Components::AvatarFile>(c)) {
const auto& a_f = cr.get<Contact::Components::AvatarFile>(c);
std::ifstream file(a_f.file_path, std::ios::binary);
if (file.is_open()) {
std::vector<uint8_t> tmp_buffer;
while (file.good()) {
auto ch = file.get();
if (ch == EOF) {
break;
} else {
tmp_buffer.push_back(ch);
}
}
if (cr.any_of<Contact::Components::AvatarFile, Contact::Components::AvatarObj>(c)) {
const auto tmp_buffer = loadData(c);
if (!tmp_buffer.empty()) {
// try all loaders after another
for (auto& il : _image_loaders) {
auto res = il->loadFromMemoryRGBA(tmp_buffer.data(), tmp_buffer.size());
auto res = il->loadFromMemoryRGBA(tmp_buffer.ptr, tmp_buffer.size);
if (res.frames.empty() || res.height == 0 || res.width == 0) {
continue;
}
@ -176,7 +243,11 @@ TextureLoaderResult ToxAvatarLoader::load(TextureUploaderI& tu, Contact4 c) {
new_entry.width = res.width;
new_entry.height = res.height;
std::cout << "TAL: loaded image file " << a_f.file_path << "\n";
if (cr.all_of<Contact::Components::AvatarFile>(c)) {
std::cout << "TAL: loaded image file " << cr.get<Contact::Components::AvatarFile>(c).file_path << "\n";
} else {
std::cout << "TAL: loaded image object " << entt::to_integral(cr.get<Contact::Components::AvatarObj>(c).obj) << "\n";
}
return {new_entry};
}

View File

@ -1,6 +1,9 @@
#pragma once
#include <solanaceae/contact/fwd.hpp>
#include <solanaceae/object_store/fwd.hpp>
#include <solanaceae/file/file2.hpp>
#include "./image_loader.hpp"
#include "./texture_cache.hpp"
@ -9,11 +12,15 @@
class ToxAvatarLoader {
ContactStore4I& _cs;
ObjectStore2& _os;
std::vector<std::unique_ptr<ImageLoaderI>> _image_loaders;
ByteSpanWithOwnership loadDataFromObj(Contact4 cv);
ByteSpanWithOwnership loadData(Contact4 cv);
public:
ToxAvatarLoader(ContactStore4I& cr);
ToxAvatarLoader(ContactStore4I& cs, ObjectStore2& os);
TextureLoaderResult load(TextureUploaderI& tu, Contact4 c);
};

View File

@ -1,6 +1,6 @@
#include "./tox_avatar_manager.hpp"
// TODO: this whole thing needs a rewrite and is currently disabled
// TODO: this whole thing needs a rewrite, seperating tcs and rng uid os
#include <solanaceae/util/config_model.hpp>
@ -33,11 +33,13 @@ namespace Components {
ToxAvatarManager::ToxAvatarManager(
ObjectStore2& os,
ContactStore4I& cs,
ConfigModelI& conf
) : _os(os), _os_sr(_os.newSubRef(this)), _cs(cs), _conf(conf) {
ConfigModelI& conf,
ToxContactModel2& tcm
) : _os(os), _os_sr(_os.newSubRef(this)), _cs(cs), _conf(conf), _tcm(tcm), _sb_tcs(os) {
_os_sr
.subscribe(ObjectStore_Event::object_construct)
.subscribe(ObjectStore_Event::object_update)
.subscribe(ObjectStore_Event::object_destroy)
;
if (!_conf.has_string("ToxAvatarManager", "save_path")) {
@ -45,20 +47,21 @@ ToxAvatarManager::ToxAvatarManager(
_conf.set("ToxAvatarManager", "save_path", std::string_view{"tmp_avatar_dir"});
}
//_conf.set("TransferAutoAccept", "autoaccept_limit", int64_t(50l*1024l*1024l)); // sane default
const std::string_view avatar_save_path {_conf.get_string("ToxAvatarManager", "save_path").value()};
// make sure it exists
std::filesystem::create_directories(avatar_save_path);
// TODO: instead listen for new contacts, and attach
{ // scan tox contacts for cached avatars
// old sts says pubkey.png
_cs.registry().view<Contact::Components::ToxFriendPersistent>().each([this](auto c, const Contact::Components::ToxFriendPersistent& tox_pers) {
// try
addAvatarFileToContact(c, tox_pers.key);
});
_cs.registry().view<Contact::Components::ToxGroupPersistent>().each([this](auto c, const Contact::Components::ToxGroupPersistent& tox_pers) {
// try
addAvatarFileToContact(c, tox_pers.chat_id);
});
@ -88,30 +91,70 @@ void ToxAvatarManager::iterate(void) {
std::string ToxAvatarManager::getAvatarPath(const ToxKey& key) const {
const std::string_view avatar_save_path {_conf.get_string("ToxAvatarManager", "save_path").value()};
const auto pub_key_string = bin2hex({key.data.cbegin(), key.data.cend()});
const auto file_path = std::filesystem::path(avatar_save_path) / (pub_key_string + ".png");
const auto file_path = std::filesystem::path(avatar_save_path) / getAvatarFileName(key);
return file_path.generic_u8string();
}
std::string ToxAvatarManager::getAvatarFileName(const ToxKey& key) const {
const auto pub_key_string = bin2hex({key.data.cbegin(), key.data.cend()});
return pub_key_string + ".png"; // TODO: remove png?
}
void ToxAvatarManager::addAvatarFileToContact(const Contact4 c, const ToxKey& key) {
const auto file_path = getAvatarPath(key);
if (std::filesystem::is_regular_file(file_path)) {
// avatar file png file exists
_cs.registry().emplace_or_replace<Contact::Components::AvatarFile>(c, file_path);
_cs.registry().emplace_or_replace<Contact::Components::TagAvatarInvalidate>(c);
_cs.throwEventUpdate(c);
if (!std::filesystem::is_regular_file(file_path)) {
return;
}
//std::cout << "TAM: found '" << file_path << "'\n";
// TODO: use guid instead
auto o = _sb_tcs.newObject(ByteSpan{key.data}, false);
o.emplace_or_replace<ObjComp::F::SingleInfoLocal>(file_path);
o.emplace_or_replace<ObjComp::F::TagLocalHaveAll>();
// for file size
o.emplace_or_replace<ObjComp::F::SingleInfo>(
getAvatarFileName(key),
std::filesystem::file_size(file_path)
);
_os.throwEventConstruct(o);
// avatar file "png" exists
//_cs.registry().emplace_or_replace<Contact::Components::AvatarFile>(c, file_path);
_cs.registry().emplace_or_replace<Contact::Components::AvatarObj>(c, o);
_cs.registry().emplace_or_replace<Contact::Components::TagAvatarInvalidate>(c);
_cs.throwEventUpdate(c);
}
void ToxAvatarManager::clearAvatarFromContact(const Contact4 c) {
auto& cr = _cs.registry();
if (cr.all_of<Contact::Components::AvatarFile>(c)) {
std::filesystem::remove(cr.get<Contact::Components::AvatarFile>(c).file_path);
cr.remove<Contact::Components::AvatarFile>(c);
if (cr.any_of<Contact::Components::AvatarFile, Contact::Components::AvatarObj>(c)) {
if (cr.all_of<Contact::Components::AvatarFile>(c)) {
std::filesystem::remove(cr.get<Contact::Components::AvatarFile>(c).file_path);
} else if (cr.all_of<Contact::Components::AvatarObj>(c)) {
auto o = _os.objectHandle(cr.get<Contact::Components::AvatarObj>(c).obj);
if (o) {
if (o.all_of<ObjComp::F::SingleInfoLocal>()) {
std::filesystem::remove(o.get<ObjComp::F::SingleInfoLocal>().file_path);
}
// TODO: make destruction more ergonomic
//_sb_tcs.destroy() ??
_os.throwEventDestroy(o);
o.destroy();
}
}
cr.remove<
Contact::Components::AvatarFile,
Contact::Components::AvatarObj
>(c);
cr.emplace_or_replace<Contact::Components::TagAvatarInvalidate>(c);
_cs.throwEventUpdate(c);
std::cout << "TAM: cleared avatar from " << entt::to_integral(c) << "\n";
}
}
@ -131,13 +174,12 @@ void ToxAvatarManager::checkObj(ObjectHandle o) {
return;
}
// TODO: non tox code path?
if (!o.all_of<
ObjComp::Tox::TagIncomming,
//ObjComp::Ephemeral::Backend,
ObjComp::F::SingleInfo,
ObjComp::Tox::FileKind
// TODO: mesage? how do we know where a file is from??
//Message::Components::ContactFrom // should always be there, just making sure
ObjComp::Tox::FileKind,
ObjComp::Ephemeral::ToxContact
>()) {
return;
}
@ -159,10 +201,14 @@ void ToxAvatarManager::checkObj(ObjectHandle o) {
return; // too large
}
#if 0 // TODO: make avatars work again !!!!!
auto contact = o.get<ObjComp::Ephemeral::ToxContact>().c;
if (!static_cast<bool>(contact)) {
std::cerr << "TAM error: failed to attribute object to contact\n";
}
// TCS-2.2.10
if (file_info.file_name.empty() || file_info.file_size == 0) {
std::cout << "TAM: no filename or filesize, deleting avatar\n";
// reset
clearAvatarFromContact(contact);
// TODO: cancel
@ -175,30 +221,38 @@ void ToxAvatarManager::checkObj(ObjectHandle o) {
return;
}
std::string file_path;
if (_cr.all_of<Contact::Components::ToxFriendPersistent>(contact)) {
file_path = getAvatarPath(_cr.get<Contact::Components::ToxFriendPersistent>(contact).key);
} else if (_cr.all_of<Contact::Components::ToxGroupPersistent>(contact)) {
file_path = getAvatarPath(_cr.get<Contact::Components::ToxGroupPersistent>(contact).chat_id);
} else {
std::cerr << "TAM error: cant get toxkey for contact\n";
// TODO: mark handled?
return;
}
if (o.all_of<ObjComp::F::TagLocalHaveAll>()) {
std::cout << "TAM: full avatar received\n";
if (_cr.all_of<Contact::Components::ToxFriendPersistent>(contact)) {
addAvatarFileToContact(contact, _cr.get<Contact::Components::ToxFriendPersistent>(contact).key);
} else if (_cr.all_of<Contact::Components::ToxGroupPersistent>(contact)) {
addAvatarFileToContact(contact, _cr.get<Contact::Components::ToxGroupPersistent>(contact).chat_id);
} else {
std::cerr << "TAM error: cant get toxkey for contact\n";
}
// old code no longer works, we already have the object (right here lol)
contact.emplace_or_replace<Contact::Components::AvatarObj>(o);
contact.emplace_or_replace<Contact::Components::TagAvatarInvalidate>();
o.emplace_or_replace<Components::TagAvatarImageHandled>();
} else {
} else if (!o.all_of<
ObjComp::Ephemeral::BackendMeta, // hmm
ObjComp::Ephemeral::BackendFile2,
ObjComp::Ephemeral::BackendAtomic // to be safe
>()) {
std::string file_path;
if (contact.all_of<Contact::Components::ToxFriendPersistent>()) {
file_path = getAvatarPath(contact.get<Contact::Components::ToxFriendPersistent>().key);
} else if (contact.all_of<Contact::Components::ToxGroupPersistent>()) {
file_path = getAvatarPath(contact.get<Contact::Components::ToxGroupPersistent>().chat_id);
} else {
std::cerr << "TAM error: cant get toxkey for contact\n";
// TODO: mark handled?
return;
}
// already has avatar, delete old (TODO: or check hash)
if (contact.all_of<Contact::Components::AvatarObj>()) {
clearAvatarFromContact(contact);
}
// crude
// TODO: queue/async instead
// check file id for existing hash
if (std::filesystem::is_regular_file(file_path)) {
//const auto& supposed_file_hash = h.get<Message::Components::Transfer::FileID>().id;
@ -209,12 +263,18 @@ void ToxAvatarManager::checkObj(ObjectHandle o) {
std::filesystem::remove(file_path); // hack, hard replace existing file
}
std::cout << "TAM: accepted avatar ft\n";
if (!_sb_tcs.attach(o)) {
std::cerr << "TAM error: failed to attach backend??\n";
return;
}
// if not already on disk
_accept_queue.push_back(AcceptEntry{o, file_path});
o.emplace_or_replace<ObjComp::F::SingleInfoLocal>(file_path);
// ... do we do anything here?
// like set "accepted" tag comp or something
std::cout << "TAM: accepted avatar ft\n";
}
#endif
}
bool ToxAvatarManager::onEvent(const ObjectStore::Events::ObjectConstruct& e) {
@ -227,3 +287,42 @@ bool ToxAvatarManager::onEvent(const ObjectStore::Events::ObjectUpdate& e) {
return false;
}
bool ToxAvatarManager::onEvent(const ObjectStore::Events::ObjectDestory& e) {
// TODO: avatar contact comp instead?
// TODO: generic contact comp? (hard, very usecase dep)
#if 0
if (!e.e.all_of<ObjComp::Ephemeral::File::Sender>()) {
// cant be reasonable be attributed to a contact
return false;
}
// TODO: remove obj from contact
#endif
if (!e.e.all_of<ObjComp::Ephemeral::ToxContact>()) {
// cant be reasonable be attributed to a contact
return false;
}
auto c = e.e.get<ObjComp::Ephemeral::ToxContact>().c;
if (!static_cast<bool>(c)) {
// meh
return false;
}
if (!c.all_of<Contact::Components::AvatarObj>()) {
// funny
return false;
}
if (c.get<Contact::Components::AvatarObj>().obj != e.e) {
// maybe got replace?
// TODO: make error and do proper cleanup
return false;
}
c.remove<Contact::Components::AvatarObj>();
c.emplace_or_replace<Contact::Components::TagAvatarInvalidate>();
// TODO: throw contact update!!!
return false;
}

View File

@ -2,6 +2,9 @@
#include <solanaceae/object_store/object_store.hpp>
#include <solanaceae/contact/fwd.hpp>
#include <solanaceae/tox_contacts/tox_contact_model2.hpp>
#include "./backends/std_fs.hpp"
#include <string>
#include <vector>
@ -17,6 +20,9 @@ class ToxAvatarManager : public ObjectStoreEventI {
ObjectStore2::SubscriptionReference _os_sr;
ContactStore4I& _cs;
ConfigModelI& _conf;
ToxContactModel2& _tcm;
Backends::STDFS _sb_tcs;
struct AcceptEntry {
ObjectHandle m;
@ -28,7 +34,8 @@ class ToxAvatarManager : public ObjectStoreEventI {
ToxAvatarManager(
ObjectStore2& os,
ContactStore4I& cs,
ConfigModelI& conf
ConfigModelI& conf,
ToxContactModel2& tcm
);
void iterate(void);
@ -36,12 +43,15 @@ class ToxAvatarManager : public ObjectStoreEventI {
protected:
// TODO: become backend and work in objects instead
std::string getAvatarPath(const ToxKey& key) const;
std::string getAvatarFileName(const ToxKey& key) const;
void addAvatarFileToContact(const Contact4 c, const ToxKey& key);
void clearAvatarFromContact(const Contact4 c);
void checkObj(ObjectHandle o);
protected: // os
// on new obj, check for ToxTransferFriend and emplace own contact tracker
bool onEvent(const ObjectStore::Events::ObjectConstruct& e) override;
bool onEvent(const ObjectStore::Events::ObjectUpdate& e) override;
bool onEvent(const ObjectStore::Events::ObjectDestory& e) override;
};