Skip to content

Commit

Permalink
Retrieve Participant List, Send Message to Channel and Real JID looku…
Browse files Browse the repository at this point in the history
…p of participants proxy JID

Adds sending message to channel and server forwarding message to participants and reflecting back message to originator.
Adds JID lookup request by client and corresponding response by MIX Mock Server.
Adds requesting participant list by client and response from mock server.

License:
This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details.

Change-Id: I53091a13422598f200134ac08cc3095cd140b792
  • Loading branch information
tarun018 committed Aug 22, 2017
1 parent 24a3bd0 commit 51c7c18
Show file tree
Hide file tree
Showing 9 changed files with 323 additions and 16 deletions.
156 changes: 152 additions & 4 deletions Limber/MIXMockServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,16 @@

#include <Swiften/Base/IDGenerator.h>
#include <Swiften/Elements/IQ.h>
#include <Swiften/Elements/Message.h>
#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Elements/DiscoItems.h>
#include <Swiften/Elements/MIXJoin.h>
#include <Swiften/Elements/MIXLeave.h>
#include <Swiften/Elements/MIXParticipant.h>
#include <Swiften/Elements/MIXPayload.h>
#include <Swiften/Elements/PubSub.h>
#include <Swiften/Elements/PubSubItem.h>
#include <Swiften/Elements/PubSubItems.h>
#include <Swiften/Elements/RosterPayload.h>
#include <Swiften/Elements/RosterItemPayload.h>
#include <Swiften/Elements/Stanza.h>
Expand Down Expand Up @@ -95,6 +101,12 @@ class Server {
}
stanza->setFrom(session->getRemoteJID());

auto message = std::dynamic_pointer_cast<Message>(stanza);
if (message) {
handleMessageReceived(message);
return;
}

auto iq = std::dynamic_pointer_cast<IQ>(stanza);
if (!iq) {
return;
Expand All @@ -112,6 +124,46 @@ class Server {
}
}

void handleMessageReceived(Message::ref message) {
SWIFT_LOG(debug) << "Message Received" << std::endl;
auto channelJID = message->getTo();
auto sender = message->getFrom();
SWIFT_LOG(debug) << "Channel " << channelJID << std::endl;
SWIFT_LOG(debug) << "Sender " << sender << std::endl;

SWIFT_LOG_ASSERT(mixChannelRegistry_->hasMIXChannel(channelJID), warning);
auto i = participantMap_.find(channelJID);
if (i != participantMap_.end()) {
auto participants = i->second;

auto forwardMessage = std::make_shared<Message>();
forwardMessage->setFrom(channelJID);
forwardMessage->setType(Message::Groupchat);
forwardMessage->setBody(message->getBody());
forwardMessage->setID(idGenerator_.generateID());

auto mixPayload = std::make_shared<MIXPayload>();
auto j = jidMap_.find(sender.toBare());
if (j != jidMap_.end()) {
mixPayload->setJID(j->second);
}

forwardMessage->addPayload(mixPayload);

for (auto participant : participants) {
if (participant != sender.toString()) {
SWIFT_LOG(debug) << "Forwarding to " << participant << std::endl;
forwardMessage->setTo(JID(participant));
serverFromClientSessions_[0]->sendElement(forwardMessage);
}
}

mixPayload->setSubmissionID(message->getID());
forwardMessage->setTo(sender);
serverFromClientSessions_[0]->sendElement(forwardMessage);
}
}

void handleElementReceivedForAccount(IQ::ref iq, std::shared_ptr<ServerFromClientSession> session) {
if(iq->getPayload<RosterPayload>()) {
handleRosterRequest(iq, session);
Expand All @@ -134,7 +186,19 @@ class Server {
}

void handleElementReceivedForMIXChannel(IQ::ref iq, std::shared_ptr<ServerFromClientSession> session) {
if (iq->getPayload<DiscoItems>()->getNode() == "mix") {
if (auto pubSubPayload = iq->getPayload<PubSub>()) {
SWIFT_LOG(debug) << "Query: PubSub" << std::endl;
auto channelJID = iq->getTo();
SWIFT_LOG_ASSERT(mixChannelRegistry_->hasMIXChannel(channelJID), warning);
auto itemsPayload = std::dynamic_pointer_cast<PubSubItems>(pubSubPayload->getPayload());
if (itemsPayload->getNode() == MIX::ParticipantsNode) {
SWIFT_LOG(debug) << "Query: Participant List for " << channelJID << std::endl;
session->sendElement(IQ::createResult(iq->getFrom(), iq->getTo(), iq->getID(), getParticipantsOfChannel(channelJID)));
} else if (itemsPayload->getNode() == MIX::JIDMapNode) {
SWIFT_LOG(debug) << "Query: Lookup Participants from " << channelJID << std::endl;
session->sendElement(IQ::createResult(iq->getFrom(), iq->getTo(), iq->getID(), getRealJIDResponse(pubSubPayload)));
}
} else if (iq->getPayload<DiscoItems>()->getNode() == "mix") {
SWIFT_LOG(debug) << "Query: Channel Nodes Supported" << std::endl;
auto responsePayload = std::make_shared<DiscoItems>();
responsePayload->addItem(DiscoItems::Item(MIX::ParticipantsNode, JID(iq->getTo())));
Expand Down Expand Up @@ -166,7 +230,7 @@ class Server {
SWIFT_LOG(debug) << "Request: Channel Join - " << *channelJID << std::endl;
if (mixChannelRegistry_->hasMIXChannel(*channelJID)) {

auto responsePayload = createJoinResult(incomingJoinPayload->getSubscriptions());
auto responsePayload = createJoinResult(*channelJID, iq->getFrom().toBare(), incomingJoinPayload->getSubscriptions());
session->sendElement(IQ::createResult(iq->getFrom(), iq->getTo(), iq->getID(), responsePayload));

auto i = rosterMap_.find(iq->getFrom().toBare());
Expand All @@ -180,6 +244,8 @@ class Server {
rosterUpdatePayload->addItem(itemPayload);
session->sendElement(IQ::createRequest(IQ::Set, iq->getFrom(), iq->getID(), rosterUpdatePayload));

updateParticipantNode(*channelJID, iq->getFrom());

} else {
SWIFT_LOG(debug) << "Initial roster not requested by client." <<std::endl;
}
Expand Down Expand Up @@ -209,6 +275,8 @@ class Server {
rosterUpdatePayload->addItem(itemPayload);

session->sendElement(IQ::createRequest(IQ::Set, iq->getFrom(), iq->getID(), rosterUpdatePayload));

removeParticipantFromNode(*channelJID, iq->getFrom());
} else {
SWIFT_LOG(debug) << "Initial roster not requested by client." <<std::endl;
}
Expand All @@ -220,12 +288,41 @@ class Server {
}
}

MIXJoin::ref createJoinResult(const std::unordered_set<std::string>& nodes) {
void updateParticipantNode(const JID& channelJID, const JID& participantJID) {
auto i = participantMap_.find(channelJID);
if (i != participantMap_.end()) {
(i->second).insert(participantJID);
} else {
std::unordered_set<std::string> participants;
participants.insert(participantJID);
participantMap_.insert(std::make_pair(channelJID, participants));
}
}

void removeParticipantFromNode(const JID& channelJID, const JID& participantJID) {
auto i = participantMap_.find(channelJID);
if (i != participantMap_.end()) {
(i->second).erase(participantJID);
}
}

MIXJoin::ref createJoinResult(const JID& channelJID, const JID& participantJID, const std::unordered_set<std::string>& nodes) {
auto joinResultPayload = std::make_shared<MIXJoin>();
for (auto node : nodes) {
joinResultPayload->addSubscription(node);
}
joinResultPayload->setJID(JID("123456#coven@example.com"));
auto i = jidMap_.find(participantJID);
auto proxyJID = idGenerator_.generateID();

if (i != jidMap_.end()) {
proxyJID = i->second;
} else {
proxyJID += ("#"+channelJID.toString());
jidMap_.insert(std::make_pair(participantJID, proxyJID));
}

joinResultPayload->setJID(JID(proxyJID));

return joinResultPayload;
}

Expand All @@ -241,6 +338,48 @@ class Server {
return rosterPayload;
}

std::shared_ptr<PubSub> getParticipantsOfChannel(const JID& channelJID) {
auto pubSubPayload = std::make_shared<PubSub>();
auto pubSubItems = std::make_shared<PubSubItems>();
pubSubItems->setNode(MIX::ParticipantsNode);
auto i = participantMap_.find(channelJID);
if (i != participantMap_.end()) {
auto participants = i->second;
for (auto participant : participants) {

auto itemPayload = std::make_shared<PubSubItem>();
auto mixParticipant = std::make_shared<MIXParticipant>();
auto j = jidMap_.find(JID(participant).toBare());
if (j != jidMap_.end()) {
itemPayload->setID(j->second);
} else {
SWIFT_LOG(debug) << "Participant" << JID(participant).toBare() << "not found in JIDMap." << std::endl;
}
itemPayload->addData(mixParticipant);
pubSubItems->addItem(itemPayload);
}
} else {
SWIFT_LOG(debug) << "Channel" << channelJID << "not found in ParticipantMap." << std::endl;
}
pubSubPayload->setPayload(pubSubItems);
return pubSubPayload;
}

std::shared_ptr<PubSub> getRealJIDResponse(std::shared_ptr<PubSub> payload) {
auto itemsPayload = std::dynamic_pointer_cast<PubSubItems>(payload->getPayload());
for (auto item : itemsPayload->getItems()) {
for( auto iter = jidMap_.begin(), iend = jidMap_.end(); iter != iend; ++iter ) {
if (iter->second == item->getID()) {
auto mixParticipant = std::make_shared<MIXParticipant>();
mixParticipant->setJID(iter->first);
item->addData(mixParticipant);
break;
}
}
}
return payload;
}

private:
IDGenerator idGenerator_;
PlatformXMLParserFactory xmlParserFactory_;
Expand All @@ -252,8 +391,17 @@ class Server {
FullPayloadParserFactoryCollection payloadParserFactories_;
FullPayloadSerializerCollection payloadSerializers_;

// Maps JID of participant to its roster object.
using RosterMap = std::map<JID, std::shared_ptr<XMPPRosterImpl>>;
RosterMap rosterMap_;

// Maps JID of participant to its proxy JID.
using JIDMap = std::map<JID, JID>;
JIDMap jidMap_;

// Maps channel JID to its participants.
using ParticipantMap = std::map<JID, std::unordered_set<std::string>>;
ParticipantMap participantMap_;
};

int main() {
Expand Down
2 changes: 1 addition & 1 deletion Swiften/Client/Client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Client::Client(const JID& jid, const SafeString& password, NetworkFactories* net
directedPresenceSender = new DirectedPresenceSender(stanzaChannelPresenceSender);
discoManager = new ClientDiscoManager(getIQRouter(), directedPresenceSender, networkFactories->getCryptoProvider());

mixRegistry = std::make_unique<MIXRegistry>(getJID(), getIQRouter(), getRoster());
mixRegistry = std::make_unique<MIXRegistry>(getJID(), getIQRouter(), getRoster(), getStanzaChannel());

mucRegistry = new MUCRegistry();
mucManager = new MUCManager(getStanzaChannel(), getIQRouter(), directedPresenceSender, mucRegistry);
Expand Down
86 changes: 82 additions & 4 deletions Swiften/Examples/MIXListAndJoin/MIXListAndJoin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@

#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Elements/ErrorPayload.h>
#include <Swiften/Elements/Message.h>
#include <Swiften/Elements/MIXParticipant.h>
#include <Swiften/Elements/MIXPayload.h>
#include <Swiften/Elements/PubSub.h>
#include <Swiften/Elements/PubSubItems.h>
#include <Swiften/Client/Client.h>
#include <Swiften/Client/ClientOptions.h>
#include <Swiften/Client/ClientXMLTracer.h>
Expand Down Expand Up @@ -40,8 +44,82 @@ static MIXImpl::ref mix;
static JID mixChannelJID;
static JID mixServiceDomain;
static std::unordered_set<std::string> supportedNodes;
static std::unordered_set<std::string> participants;
static MIXRegistry* mixRegistry_;

static void handleMessageReceived(Message::ref message) {
if (auto mixPayload = message->getPayload<MIXPayload>()) {
if (mixPayload->getSubmissionID()) {
SWIFT_LOG(debug) << "Ignoring the replicated message" << std::endl;
return;
} else if (message->getFrom().toBare() == mixChannelJID) {
std::cout << "[ " << mixChannelJID << " ] " << message->getFrom().getResource() << ": " << message->getBody().get_value_or("") << std::endl;
}
}
}

static void handleLookupResponse(std::shared_ptr<PubSub> payload, ErrorPayload::ref error) {
if (error) {
return;
}

std::cout << "Lookup of participant in channel " << mixChannelJID << std::endl;
int participantCount = 0;
auto itemsPayload = std::dynamic_pointer_cast<PubSubItems>(payload->getPayload());
SWIFT_LOG_ASSERT(itemsPayload->getNode() == MIX::JIDMapNode, warning);

auto items = itemsPayload->getItems();

for(auto item : items) {
SWIFT_LOG_ASSERT(item->getData().size() == static_cast<int>(1), warning);
participantCount++;
auto mixParticipant = std::dynamic_pointer_cast<MIXParticipant>(item->getData()[0]);
if (auto realJID = mixParticipant->getJID()) {
std::cout << "\t" << participantCount << ". " << item->getID() << " - " << *realJID << std::endl;
}
}

std::cout << std::endl;

// Sending message to channel
mix->sendMessage("Hello, I am here! " + client->getJID().getNode());

// Leave channel.
// Commented to test the sync between different clients of same user.
// mixRegistry_->leaveChannel(mixChannelJID);
}

static void handleParticipantsReceived(std::shared_ptr<PubSub> payload, ErrorPayload::ref error) {
if (error) {
return;
}

std::cout << "Participants of channel " << mixChannelJID << std::endl;
int participantCount = 0;
auto itemsPayload = std::dynamic_pointer_cast<PubSubItems>(payload->getPayload());
SWIFT_LOG_ASSERT(itemsPayload->getNode() == MIX::ParticipantsNode, warning);

auto items = itemsPayload->getItems();

for(auto item : items) {
SWIFT_LOG_ASSERT(item->getData().size() == static_cast<int>(1), warning);
participantCount++;
auto mixParticipant = std::dynamic_pointer_cast<MIXParticipant>(item->getData()[0]);
std::cout << "\t" << participantCount << ". " << item->getID() << std::endl;
participants.insert(item->getID());
}

if (participantCount == 0) {
std::cout << "No participants already joined." << std::endl;
}

std::cout << std::endl;

//Perform JID lookups.
mix->onLookupResponse.connect(&handleLookupResponse);
mix->lookupJID(participants);
}

static void handleChannelJoined(const JID& jid) {
// Successfully joined the channel.
assert(mixRegistry_);
Expand All @@ -51,14 +129,13 @@ static void handleChannelJoined(const JID& jid) {

//trying to rejoin the same channel joined. Should not send the iq request. Will print a warning.
mixRegistry_->joinChannel(mixChannelJID, supportedNodes);
std::cout << std::endl;

mix = mixRegistry_->getMIXInstance(jid);

mix->onParticipantResponse.connect(&handleParticipantsReceived);
// Can perform other functions with MIXImpl object: mix.
mix->requestParticipantList();

// Finally leave channel.
// This is commented to check the sync between different users using different clients(resources) to connect.
//mixRegistry_->leaveChannel(mixChannelJID);
}

static void handleChannelJoinFailed(ErrorPayload::ref /*error*/) {
Expand Down Expand Up @@ -181,6 +258,7 @@ int main(int argc, char* argv[]) {

client->onConnected.connect(&handleConnected);
client->onDisconnected.connect(&handleDisconnected);
client->onMessageReceived.connect(&handleMessageReceived);

std::cout << "Connecting..." << std::flush;
client->connect(options);
Expand Down
Loading

0 comments on commit 51c7c18

Please sign in to comment.