diff options
-rw-r--r-- | include/erebos/message.h | 3 | ||||
-rw-r--r-- | include/erebos/network.h | 1 | ||||
-rw-r--r-- | src/main.cpp | 50 | ||||
-rw-r--r-- | src/message.cpp | 30 | ||||
-rw-r--r-- | src/network.cpp | 14 | ||||
-rw-r--r-- | test/message.test | 45 |
6 files changed, 116 insertions, 27 deletions
diff --git a/include/erebos/message.h b/include/erebos/message.h index 497b536..011007a 100644 --- a/include/erebos/message.h +++ b/include/erebos/message.h @@ -12,6 +12,7 @@ namespace erebos { using std::unique_ptr; +class Contact; class Identity; class DirectMessage @@ -94,6 +95,8 @@ public: DirectMessageThread thread(const Identity &); + DirectMessage send(const Identity &, const std::string &); + DirectMessage send(const Contact &, const std::string &); DirectMessage send(const Peer &, const std::string &); private: diff --git a/include/erebos/network.h b/include/erebos/network.h index 66edfa4..6a3112a 100644 --- a/include/erebos/network.h +++ b/include/erebos/network.h @@ -34,6 +34,7 @@ public: template<class S> S & svc(); class PeerList & peerList() const; + optional<erebos::Peer> peer(const Identity &) const; void addPeer(const string & node) const; void addPeer(const string & node, const string & service) const; diff --git a/src/main.cpp b/src/main.cpp index f33bcc4..cc02b55 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -104,6 +104,22 @@ TestPeer & getPeer(const Peer & peer) throw invalid_argument("peer not found"); } +Contact getContact(const string & id) +{ + auto cmp = [](const Contact & x, const Contact & y) { + return x.data() < y.data(); + }; + for (const auto & c : h->behavior().lens<SharedState>().lens<Set<Contact>>().get().view(cmp)) { + if (string(c.leastRoot()) == id) { + return c; + } + } + + ostringstream ss; + ss << "contact '" << id << "' not found"; + throw invalid_argument(ss.str().c_str()); +} + struct Command { string name; @@ -505,22 +521,16 @@ void contactSetName(const vector<string> & args) auto id = args.at(0); auto name = args.at(1); - auto cmp = [](const Contact & x, const Contact & y) { - return x.data() < y.data(); - }; - for (const auto & c : h->behavior().lens<SharedState>().lens<Set<Contact>>().get().view(cmp)) { - if (string(c.leastRoot()) == id) { - auto nh = h->update([&] (const Stored<LocalState> & loc) { - auto st = loc.ref().storage(); - auto cc = c.customName(st, name); - auto contacts = loc->shared<Set<Contact>>(); - return st.store(loc->shared<Set<Contact>>(contacts.add(st, cc))); - }); - if (nh) - *h = *nh; - break; - } - } + auto c = getContact(id); + auto nh = h->update([&] (const Stored<LocalState> & loc) { + auto st = loc.ref().storage(); + auto cc = c.customName(st, name); + auto contacts = loc->shared<Set<Contact>>(); + return st.store(loc->shared<Set<Contact>>(contacts.add(st, cc))); + }); + if (nh) + *h = *nh; + printLine("contact-set-name-done"); } @@ -531,6 +541,13 @@ void dmSendPeer(const vector<string> & args) args.at(1)); } +void dmSendContact(const vector<string> & args) +{ + server->svc<DirectMessageService>().send( + getContact(args.at(0)), + args.at(1)); +} + vector<Command> commands = { { "store", store }, { "stored-generation", storedGeneration }, @@ -556,6 +573,7 @@ vector<Command> commands = { { "contact-list", contactList }, { "contact-set-name", contactSetName }, { "dm-send-peer", dmSendPeer }, + { "dm-send-contact", dmSendContact }, }; } diff --git a/src/message.cpp b/src/message.cpp index dd4f9d5..ff8e05b 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -1,5 +1,6 @@ #include "message.h" +#include <erebos/contact.h> #include <erebos/network.h> using namespace erebos; @@ -246,26 +247,37 @@ DirectMessageThread DirectMessageService::thread(const Identity & peer) return DirectMessageThread::Priv::getThreadLocked(peer.finalOwner()); } -DirectMessage DirectMessageService::send(const Peer & peer, const string & text) +DirectMessage DirectMessageService::send(const Identity & to, const string & text) { - auto pid = peer.identity(); - if (!pid) - throw std::runtime_error("Peer without known identity"); - auto powner = pid->finalOwner(); - scoped_lock lock(threadLock); auto msg = server.localHead().ref().storage().store(DirectMessageData { - .prev = DirectMessageThread::Priv::getThreadLocked(powner).p->head, + .prev = DirectMessageThread::Priv::getThreadLocked(to).p->head, .from = server.identity().finalOwner(), .time = ZonedTime::now(), .text = text, }); - DirectMessageThread::Priv::updateThreadLocked(powner, { msg }); - peer.send(myUUID, msg.ref()); + DirectMessageThread::Priv::updateThreadLocked(to, { msg }); + + if (auto peer = server.peer(to)) + peer->send(myUUID, msg.ref()); return DirectMessage(new DirectMessage::Priv { .data = msg, }); } + +DirectMessage DirectMessageService::send(const Contact & to, const string & text) +{ + if (auto id = to.identity()) + return send(*id, text); + throw std::runtime_error("contact without erebos identity"); +} + +DirectMessage DirectMessageService::send(const Peer & to, const string & text) +{ + if (auto id = to.identity()) + return send(id->finalOwner(), text); + throw std::runtime_error("peer without known identity"); +} diff --git a/src/network.cpp b/src/network.cpp index 1eb33d0..929908a 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -73,6 +73,20 @@ PeerList & Server::peerList() const return p->plist; } +optional<Peer> Server::peer(const Identity & identity) const +{ + scoped_lock lock(p->dataMutex); + + for (auto & peer : p->peers) { + const auto & pid = peer->identity; + if (holds_alternative<Identity>(pid)) + if (std::get<Identity>(pid).finalOwner().sameAs(identity)) + return peer->lpeer; + } + + return nullopt; +} + void Server::addPeer(const string & node) const { return addPeer(node, to_string(Priv::discoveryPort)); diff --git a/test/message.test b/test/message.test index 9567611..3f108d3 100644 --- a/test/message.test +++ b/test/message.test @@ -14,16 +14,57 @@ test DirectMessage: /peer ([0-9]+) addr ${p1.node.ip} 29665/ capture peer2_1 /peer $peer2_1 id Device1 Owner1/ + # Send messages to peers + for i in [1..2]: send "dm-send-peer $peer1_2 hello$i" to p1 expect /dm-received from Owner1 text hello$i/ from p2 for i in [1..2]: - send "dm-send-peer $peer1_2 hello$i" to p2 + send "dm-send-peer $peer2_1 hello$i" to p2 expect /dm-received from Owner2 text hello$i/ from p1 for i in [3..4]: send "dm-send-peer $peer1_2 hello$i" to p1 expect /dm-received from Owner1 text hello$i/ from p2 - send "dm-send-peer $peer1_2 hello$i" to p2 + send "dm-send-peer $peer2_1 hello$i" to p2 + expect /dm-received from Owner2 text hello$i/ from p1 + + # Create contacts + + local: + send "contact-request $peer1_2" to p1 + expect /contact-request $peer2_1 ([0-9]*)/ from p2 capture code2 + expect /contact-response $peer1_2 ([0-9]*)/ from p1 capture code1 + guard (code1 == code2) + + send "contact-accept $peer1_2" to p1 + send "contact-accept $peer2_1" to p2 + expect /contact-request-done $peer2_1/ from p2 + expect /contact-response-done $peer1_2/ from p1 + + send "contact-list" to p1 + expect from p1: + /contact-list-item ([a-z0-9#]+) Owner2 Owner2/ capture c1_2 + /contact-list-(.*)/ capture done1_1 + + send "contact-list" to p2 + expect from p2: + /contact-list-item ([a-z0-9#]+) Owner1 Owner1/ capture c2_1 + /contact-list-(.*)/ capture done1_2 + + # Send messages to contacts + + for i in [1..2]: + send "dm-send-contact $c1_2 hello$i" to p1 + expect /dm-received from Owner1 text hello$i/ from p2 + + for i in [1..2]: + send "dm-send-contact $c2_1 hello$i" to p2 + expect /dm-received from Owner2 text hello$i/ from p1 + + for i in [3..4]: + send "dm-send-contact $c1_2 hello$i" to p1 + expect /dm-received from Owner1 text hello$i/ from p2 + send "dm-send-contact $c2_1 hello$i" to p2 expect /dm-received from Owner2 text hello$i/ from p1 |