#include "./sha1_ngcft1.hpp" #include #include #include #include #include #include "./ft1_sha1_info.hpp" #include "./hash_utils.hpp" #include namespace Components { using FT1InfoSHA1 = FT1InfoSHA1; struct FT1InfoSHA1Data { std::vector data; }; struct FT1InfoSHA1Hash { std::vector hash; }; } // Components SHA1_NGCFT1::SHA1_NGCFT1( Contact3Registry& cr, RegistryMessageModel& rmm, NGCFT1& nft, ToxContactModel2& tcm ) : _cr(cr), _rmm(rmm), _nft(nft), _tcm(tcm) { _nft.subscribe(this, NGCFT1_Event::recv_request); _nft.subscribe(this, NGCFT1_Event::recv_init); _nft.subscribe(this, NGCFT1_Event::recv_data); _nft.subscribe(this, NGCFT1_Event::send_data); //_rmm.subscribe(this, RegistryMessageModel_Event::message_construct); //_rmm.subscribe(this, RegistryMessageModel_Event::message_updated); //_rmm.subscribe(this, RegistryMessageModel_Event::message_destroy); _rmm.subscribe(this, RegistryMessageModel_Event::send_file_path); } bool SHA1_NGCFT1::onEvent(const Events::NGCFT1_recv_request& e) { // only interested in sha1 if (e.file_kind != NGCFT1_file_kind::HASH_SHA1_INFO && e.file_kind != NGCFT1_file_kind::HASH_SHA1_CHUNK) { return false; } //std::cout << "SHA1_NGCFT1: FT1_REQUEST fk:" << int(e.file_kind) << " [" << bin2hex({e.file_id, e.file_id+e.file_id_size}) << "]\n"; if (e.file_kind == NGCFT1_file_kind::HASH_SHA1_INFO) { if (e.file_id_size != 20) { // error return false; } SHA1Digest info_hash{e.file_id, e.file_id_size}; if (!_info_to_message.count(info_hash)) { // we dont know about this return false; } auto msg = _info_to_message.at(info_hash); assert(msg.all_of()); // assume we have the info, send init _nft.NGC_FT1_send_init_private( e.group_number, e.peer_number, static_cast(e.file_kind), e.file_id, e.file_id_size, msg.get().data.size(), nullptr ); } return false; } bool SHA1_NGCFT1::onEvent(const Events::NGCFT1_recv_init& e) { // only interested in sha1 if (e.file_kind != NGCFT1_file_kind::HASH_SHA1_INFO && e.file_kind != NGCFT1_file_kind::HASH_SHA1_CHUNK) { return false; } return false; } bool SHA1_NGCFT1::onEvent(const Events::NGCFT1_recv_data& e) { return false; } bool SHA1_NGCFT1::onEvent(const Events::NGCFT1_send_data& e) { return false; } bool SHA1_NGCFT1::sendFilePath(const Contact3 c, std::string_view file_name, std::string_view file_path) { if ( // TODO: add support of offline queuing !_cr.all_of(c) ) { return false; } std::cout << "SHA1_NGCFT1: got sendFilePath()\n"; auto* reg_ptr = _rmm.get(c); if (reg_ptr == nullptr) { return false; } // TODO: rw auto file_impl = std::make_unique(file_path); if (!file_impl->isGood()) { std::cerr << "SHA1_NGCFT1 error: failed opening file '" << file_path << "'!\n"; return true; } // get current time unix epoch utc uint64_t ts = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); // 1. build info by hashing all chunks FT1InfoSHA1 sha1_info; // build info sha1_info.file_name = file_name; sha1_info.file_size = file_impl->_file_size; { // build chunks // HACK: load file fully // TODO: the speed is truly horrid const auto file_data = file_impl->read(0, file_impl->_file_size); size_t i = 0; for (; i + sha1_info.chunk_size < file_data.size(); i += sha1_info.chunk_size) { sha1_info.chunks.push_back(hash_sha1(file_data.data()+i, sha1_info.chunk_size)); } if (i < file_data.size()) { sha1_info.chunks.push_back(hash_sha1(file_data.data()+i, file_data.size()-i)); } } // 2. hash info std::vector sha1_info_data; std::vector sha1_info_hash; std::cout << "SHA1_NGCFT1 info is: \n" << sha1_info; sha1_info_data = sha1_info.toBuffer(); std::cout << "SHA1_NGCFT1 sha1_info size: " << sha1_info_data.size() << "\n"; sha1_info_hash = hash_sha1(sha1_info_data.data(), sha1_info_data.size()); std::cout << "SHA1_NGCFT1 sha1_info_hash: " << bin2hex(sha1_info_hash) << "\n"; const auto c_self = _cr.get(c).self; if (!_cr.valid(c_self)) { std::cerr << "SHA1_NGCFT1 error: failed to get self!\n"; return true; } const auto e = reg_ptr->create(); reg_ptr->emplace(e, c); reg_ptr->emplace(e, c_self); reg_ptr->emplace(e, ts); // reactive? reg_ptr->emplace(e); reg_ptr->emplace(e); reg_ptr->emplace(e, sha1_info); reg_ptr->emplace(e, sha1_info_data); // keep around? or file? reg_ptr->emplace(e, sha1_info_hash); _info_to_message[sha1_info_hash] = {*reg_ptr, e}; //reg_ptr->emplace(e, file_kind); // file id would be sha1_info hash or something //reg_ptr->emplace(e, file_id); { // file info auto& file_info = reg_ptr->emplace(e); file_info.file_list.emplace_back() = {std::string{file_name}, file_impl->_file_size}; file_info.total_size = file_impl->_file_size; reg_ptr->emplace(e, std::vector{std::string{file_path}}); } reg_ptr->emplace(e); // TODO: determine if this is true //reg_ptr->emplace(e); // TODO: ft1 specific comp reg_ptr->emplace(e, std::move(file_impl)); #if 0 const auto friend_number = _cr.get(c).friend_number; const auto&& [transfer_id, err] = _t.toxFileSend(friend_number, file_kind, file_impl->_file_size, file_id, file_name); if (err == TOX_ERR_FILE_SEND_OK) { reg_ptr->emplace(e, friend_number, transfer_id.value()); // TODO: add tag signifying init sent status? toxFriendLookupAdd({*reg_ptr, e}); } // else queue? #endif _rmm.throwEventConstruct(*reg_ptr, e); return true; }