#include "./tox_message_manager.hpp" #include #include #include #include #include "./msg_components.hpp" #include #include #include #include ToxMessageManager::ToxMessageManager( RegistryMessageModelI& rmm, Contact3Registry& cr, ToxContactModel2& tcm, ToxI& t, ToxEventProviderI& tep ) : _rmm(rmm), _rmm_sr(_rmm.newSubRef(this)), _cr(cr), _tcm(tcm), _t(t), _tep_sr(tep.newSubRef(this)) { _tep_sr // TODO: system messages? //.subscribe(Tox_Event::TOX_EVENT_FRIEND_CONNECTION_STATUS) //.subscribe(Tox_Event::TOX_EVENT_FRIEND_STATUS) .subscribe(Tox_Event_Type::TOX_EVENT_FRIEND_MESSAGE) .subscribe(Tox_Event_Type::TOX_EVENT_FRIEND_READ_RECEIPT) // TODO: conf // TODO: system messages? //.subscribe(Tox_Event::TOX_EVENT_GROUP_PEER_JOIN) //.subscribe(Tox_Event::TOX_EVENT_GROUP_SELF_JOIN) //.subscribe(Tox_Event::TOX_EVENT_GROUP_PEER_NAME) .subscribe(Tox_Event_Type::TOX_EVENT_GROUP_MESSAGE) .subscribe(Tox_Event_Type::TOX_EVENT_GROUP_PRIVATE_MESSAGE) ; _rmm_sr.subscribe(RegistryMessageModel_Event::send_text); } ToxMessageManager::~ToxMessageManager(void) { } bool ToxMessageManager::sendText(const Contact3 c, std::string_view message, bool action) { if (!_cr.valid(c)) { return false; } if (message.empty()) { return false; // TODO: empty messages allowed? } if (_cr.all_of(c)) { return false; // message to self? not with tox } // testing for persistent is enough if (!_cr.any_of< Contact::Components::ToxFriendPersistent, // TODO: conf Contact::Components::ToxGroupPersistent, Contact::Components::ToxGroupPeerPersistent >(c)) { return false; } auto* reg_ptr = _rmm.get(c); if (reg_ptr == nullptr) { return false; // nope } Message3Registry& reg = *reg_ptr; if (!_cr.all_of(c)) { std::cerr << "TMM error: cant get self\n"; return false; } const Contact3 c_self = _cr.get(c).self; // get current time unix epoch utc uint64_t ts = Message::getTimeMS(); // TODO: split into multiple messages here, if its too long ? auto new_msg_e = reg.create(); reg.emplace(new_msg_e, c_self); reg.emplace(new_msg_e, c); reg.emplace(new_msg_e, message); if (action) { reg.emplace(new_msg_e); } reg.emplace(new_msg_e, ts); reg.emplace(new_msg_e, ts); // reactive? // mark as read reg.emplace(new_msg_e, ts); // reactive? // if sent? reg.emplace(new_msg_e, ts); reg.emplace(new_msg_e).ts[c_self] = ts; if (_cr.any_of(c)) { const uint32_t friend_number = _cr.get(c).friend_number; auto [res, _] = _t.toxFriendSendMessage( friend_number, action ? Tox_Message_Type::TOX_MESSAGE_TYPE_ACTION : Tox_Message_Type::TOX_MESSAGE_TYPE_NORMAL, message ); if (!res.has_value()) { // set manually, so it can still be synced const uint32_t msg_id = randombytes_random(); reg.emplace(new_msg_e, msg_id); std::cerr << "TMM: failed to send friend message\n"; } else { reg.emplace(new_msg_e, res.value()); } } else if (_cr.any_of(c)) { // here we just assume friend not online (no ephemeral id) // set manually, so it can still be synced const uint32_t msg_id = randombytes_random(); reg.emplace(new_msg_e, msg_id); std::cerr << "TMM: failed to send friend message, offline and not in tox profile\n"; } else if ( _cr.any_of(c) ) { const uint32_t group_number = _cr.get(c).group_number; auto [message_id_opt, _] = _t.toxGroupSendMessage( group_number, action ? Tox_Message_Type::TOX_MESSAGE_TYPE_ACTION : Tox_Message_Type::TOX_MESSAGE_TYPE_NORMAL, message ); if (!message_id_opt.has_value()) { // set manually, so it can still be synced const uint32_t msg_id = randombytes_random(); reg.emplace(new_msg_e, msg_id); std::cerr << "TMM: failed to send group message!\n"; } else { // TODO: does group msg without msgid make sense??? reg.emplace(new_msg_e, message_id_opt.value()); // TODO: generalize? reg.emplace(new_msg_e).ts.emplace(c_self, ts); } } else if ( // non online group _cr.any_of(c) ) { // create msg_id const uint32_t msg_id = randombytes_random(); reg.emplace(new_msg_e, msg_id); // TODO: generalize? reg.emplace(new_msg_e).ts.emplace(c_self, ts); } else if ( _cr.any_of(c) ) { const auto& numbers = _cr.get(c); auto [message_id_opt, _] = _t.toxGroupSendPrivateMessage( numbers.group_number, numbers.peer_number, action ? Tox_Message_Type::TOX_MESSAGE_TYPE_ACTION : Tox_Message_Type::TOX_MESSAGE_TYPE_NORMAL, message ); if (!message_id_opt.has_value()) { // set manually, so it can still be synced const uint32_t msg_id = randombytes_random(); reg.emplace(new_msg_e, msg_id); std::cerr << "TMM: failed to send group message!\n"; } else { // TODO: does group msg without msgid make sense??? reg.emplace(new_msg_e, message_id_opt.value()); // TODO: how do we do private messages? // same as friends? //reg.emplace(new_msg_e).ts.emplace(c_self, ts); } } _rmm.throwEventConstruct(reg, new_msg_e); return true; } bool ToxMessageManager::onToxEvent(const Tox_Event_Friend_Message* e) { uint32_t friend_number = tox_event_friend_message_get_friend_number(e); Tox_Message_Type type = tox_event_friend_message_get_type(e); // get current time unix epoch utc uint64_t ts = Message::getTimeMS(); std::string_view message {reinterpret_cast(tox_event_friend_message_get_message(e)), tox_event_friend_message_get_message_length(e)}; message = message.substr(0, message.find_first_of('\0')); // trim \0 // hi zoff // TODO: low-p, extract ts from zofftrim // TODO: sanitize utf8 std::cout << "TMM friend message " << message << "\n"; const auto c = _tcm.getContactFriend(friend_number); const auto self_c = c.get().self; auto* reg_ptr = _rmm.get(c); if (reg_ptr == nullptr) { std::cerr << "TMM error: cant find reg\n"; return false; } Message3Registry& reg = *reg_ptr; auto new_msg_e = reg.create(); reg.emplace(new_msg_e, c); reg.emplace(new_msg_e, self_c); reg.emplace(new_msg_e, message); if (type == Tox_Message_Type::TOX_MESSAGE_TYPE_ACTION) { reg.emplace(new_msg_e); } reg.emplace(new_msg_e, ts); //reg.emplace(new_msg_e, 0); reg.emplace(new_msg_e, ts); // reactive? { auto& rtr = reg.emplace(new_msg_e).ts; rtr.try_emplace(self_c, ts); rtr.try_emplace(c, ts); } reg.emplace(new_msg_e); _rmm.throwEventConstruct(reg, new_msg_e); return false; // TODO: return true? } bool ToxMessageManager::onToxEvent(const Tox_Event_Friend_Read_Receipt* e) { uint32_t friend_number = tox_event_friend_read_receipt_get_friend_number(e); uint32_t msg_id = tox_event_friend_read_receipt_get_message_id(e); // get current time unix epoch utc uint64_t ts = Message::getTimeMS(); const auto c = _tcm.getContactFriend(friend_number); const auto self_c = c.get().self; auto* reg_ptr = _rmm.get(c); if (reg_ptr == nullptr) { std::cerr << "TMM error: cant find reg\n"; return false; } Message3Registry& reg = *reg_ptr; // find message by message id // TODO: keep a short list of unconfirmed msg ids // this iterates in reverse, so newest messages should be pretty front for (const auto& [m, msg_id_comp] : reg.view().each()) { if (msg_id_comp.id == msg_id) { // found it auto& rtr = reg.get_or_emplace(m); // insert but dont overwrite rtr.ts.try_emplace(c, ts); break; } } return true; } bool ToxMessageManager::onToxEvent(const Tox_Event_Group_Message* e) { const uint32_t group_number = tox_event_group_message_get_group_number(e); const uint32_t peer_number = tox_event_group_message_get_peer_id(e); const uint32_t message_id = tox_event_group_message_get_message_id(e); const Tox_Message_Type type = tox_event_group_message_get_message_type(e); const uint64_t ts = Message::getTimeMS(); auto message = std::string_view{reinterpret_cast(tox_event_group_message_get_message(e)), tox_event_group_message_get_message_length(e)}; std::cout << "TMM group message: " << message << "\n"; const auto c = _tcm.getContactGroupPeer(group_number, peer_number); const auto self_c = c.get().self; auto* reg_ptr = _rmm.get(c); //auto* reg_ptr = _rmm.get({ContactGroupPeerEphemeral{group_number, peer_number}}); if (reg_ptr == nullptr) { std::cerr << "TMM error: cant find reg\n"; return false; } Message3Registry& reg = *reg_ptr; // TODO: check for existence, hs or other syncing mechanics might have sent it already (or like, it arrived 2x or whatever) auto new_msg_e = reg.create(); { // contact // from reg.emplace(new_msg_e, c); // to reg.emplace(new_msg_e, c.get().parent); } reg.emplace(new_msg_e, message_id); reg.emplace(new_msg_e, message); if (type == Tox_Message_Type::TOX_MESSAGE_TYPE_ACTION) { reg.emplace(new_msg_e); } reg.emplace(new_msg_e, ts); //reg.emplace(new_msg_e, 0); reg.emplace(new_msg_e, ts); // reactive? reg.emplace(new_msg_e); { // by whom reg.get_or_emplace(new_msg_e).ts.emplace(self_c, ts); } { auto& rtr = reg.emplace(new_msg_e).ts; rtr.try_emplace(self_c, ts); rtr.try_emplace(c, ts); } _rmm.throwEventConstruct(reg, new_msg_e); return false; // TODO: true? } bool ToxMessageManager::onToxEvent(const Tox_Event_Group_Private_Message* e) { const uint32_t group_number = tox_event_group_private_message_get_group_number(e); const uint32_t peer_number = tox_event_group_private_message_get_peer_id(e); const Tox_Message_Type type = tox_event_group_private_message_get_message_type(e); const uint64_t ts = Message::getTimeMS(); auto message = std::string_view{reinterpret_cast(tox_event_group_private_message_get_message(e)), tox_event_group_private_message_get_message_length(e)}; std::cout << "TMM group private message: " << message << "\n"; const auto c = _tcm.getContactGroupPeer(group_number, peer_number); const auto self_c = c.get().self; auto* reg_ptr = _rmm.get(c); if (reg_ptr == nullptr) { std::cerr << "TMM error: cant find reg\n"; return false; } Message3Registry& reg = *reg_ptr; auto new_msg_e = reg.create(); { // contact // from reg.emplace(new_msg_e, c); // to reg.emplace(new_msg_e, self_c); } reg.emplace(new_msg_e, message); if (type == Tox_Message_Type::TOX_MESSAGE_TYPE_ACTION) { reg.emplace(new_msg_e); } reg.emplace(new_msg_e, ts); //reg.emplace(new_msg_e, 0); reg.emplace(new_msg_e, ts); // reactive? reg.emplace(new_msg_e); // private does not track synced by // but receive state { auto& rtr = reg.emplace(new_msg_e).ts; rtr.try_emplace(self_c, ts); rtr.try_emplace(c, ts); } _rmm.throwEventConstruct(reg, new_msg_e); return false; }