diff --git a/src/ringdht/ringaccount.cpp b/src/ringdht/ringaccount.cpp index 6bccd925de94b858b231df44a1c20c420b10aac9..90dcd65bbb6e33ebf03bccdcc6d687cb29e02083 100644 --- a/src/ringdht/ringaccount.cpp +++ b/src/ringdht/ringaccount.cpp @@ -1532,9 +1532,8 @@ RingAccount::doRegister_() } // Listen for incoming calls - auto ringDeviceId = identity_.first->getPublicKey().getId().toString(); - callKey_ = dht::InfoHash::get("callto:"+ringDeviceId); - RING_DBG("Listening on callto:%s : %s", ringDeviceId.c_str(), callKey_.toString().c_str()); + callKey_ = dht::InfoHash::get("callto:"+ringDeviceId_); + RING_DBG("Listening on callto:%s : %s", ringDeviceId_.c_str(), callKey_.toString().c_str()); dht_.listen<dht::IceCandidates>( callKey_, [shared] (dht::IceCandidates&& msg) { @@ -1623,9 +1622,10 @@ RingAccount::doRegister_() } ); + auto inboxDeviceKey = dht::InfoHash::get("inbox:"+ringDeviceId_); dht_.listen<dht::ImMessage>( - inboxKey, - [shared, inboxKey](dht::ImMessage&& v) { + inboxDeviceKey, + [shared, inboxDeviceKey](dht::ImMessage&& v) { auto& this_ = *shared.get(); auto res = this_.treatedMessages_.insert(v.id); if (!res.second) @@ -1638,7 +1638,7 @@ RingAccount::doRegister_() utf8_make_valid(v.msg)}}; shared->onTextMessage(from, payloads); RING_DBG("Sending message confirmation %" PRIu64, v.id); - this_.dht_.putEncrypted(inboxKey, + this_.dht_.putEncrypted(inboxDeviceKey, v.from, dht::ImMessage(v.id, std::string(), now)); return true; @@ -2123,20 +2123,40 @@ RingAccount::sendTextMessage(const std::string& to, const std::map<std::string, messageEngine_.onMessageSent(token, false); return; } + if (payloads.size() != 1) { + // Multi-part message + // TODO: not supported yet + RING_ERR("Multi-part im is not supported yet by RingAccount"); + messageEngine_.onMessageSent(token, false); + return; + } + std::weak_ptr<RingAccount> wshared = std::static_pointer_cast<RingAccount>(shared_from_this()); auto toUri = parseRingUri(to); auto toH = dht::InfoHash(toUri); auto now = system_clock::to_time_t(system_clock::now()); + auto treatedDevices_ = std::make_shared<std::set<dht::InfoHash>>(); + + struct PendingConfirmation { + bool replied {false}; + std::map<dht::InfoHash, std::future<size_t>> listenTokens {}; + }; + auto confirm = std::make_shared<PendingConfirmation>(); + + // Find listening Ring devices for this account + dht_.get<DeviceAnnouncement>(toH, [=](DeviceAnnouncement&& dev) { + if (dev.from != toH) + return true; + if (not treatedDevices_->emplace(dev.dev).second) + return true; - // Single-part message - if (payloads.size() == 1) { auto e = sentMessages_.emplace(token, PendingMessage {}); - e.first->second.to = toH; + e.first->second.to = dev.dev; - auto h = dht::InfoHash::get("inbox:"+toUri); - std::weak_ptr<RingAccount> wshared = std::static_pointer_cast<RingAccount>(shared_from_this()); + auto h = dht::InfoHash::get("inbox:"+dev.dev.toString()); + RING_DBG("Found device to send message %s -> %s", dev.dev.toString().c_str(), h.toString().c_str()); - dht_.listen<dht::ImMessage>(h, [wshared,token](dht::ImMessage&& msg) { + auto list_token = dht_.listen<dht::ImMessage>(h, [h,wshared,token,confirm](dht::ImMessage&& msg) { if (auto this_ = wshared.lock()) { // check expected message confirmation if (msg.id != token) @@ -2165,27 +2185,29 @@ RingAccount::sendTextMessage(const std::string& to, const std::map<std::string, this_->saveTreatedMessages(); // report message as confirmed received + for (auto& t : confirm->listenTokens) + this_->dht_.cancelListen(t.first, t.second.get()); + confirm->listenTokens.clear(); + confirm->replied = true; this_->messageEngine_.onMessageSent(token, true); } return false; }); + confirm->listenTokens.emplace(h, std::move(list_token)); dht_.putEncrypted(h, - toH, + dev.dev, dht::ImMessage(token, std::string(payloads.begin()->second), now), - [wshared,token](bool ok) { + [wshared,token,confirm,h](bool ok) { if (auto this_ = wshared.lock()) { - if (not ok) - this_->messageEngine_.onMessageSent(token, false); + if (not ok) { + confirm->listenTokens.erase(h); + if (confirm->listenTokens.empty() and not confirm->replied) + this_->messageEngine_.onMessageSent(token, false); + } } }); - return; - } - - // Multi-part message - // TODO: not supported yet - RING_ERR("Multi-part im is not supported yet by RingAccount"); - messageEngine_.onMessageSent(token, false); + }); } } // namespace ring