Skip to content

Commit

Permalink
Retrieve Participant List and real JID lookup of participants
Browse files Browse the repository at this point in the history
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 21, 2017
1 parent f4035e2 commit 7359480
Show file tree
Hide file tree
Showing 9 changed files with 262 additions and 16 deletions.
106 changes: 102 additions & 4 deletions Limber/MIXMockServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
#include <Swiften/Elements/DiscoItems.h>
#include <Swiften/Elements/MIXJoin.h>
#include <Swiften/Elements/MIXLeave.h>
#include <Swiften/Elements/MIXParticipant.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 @@ -147,7 +151,20 @@ 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 All @@ -165,7 +182,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 @@ -179,6 +196,8 @@ class Server {
rosterUpdatePayload->addItem(itemPayload);
session->sendElement(IQ::createRequest(IQ::Set, iq->getFrom(), iq->getID(), rosterUpdatePayload));

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

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

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

removeParticipantFromNode(*channelJID, iq->getFrom().toBare());
} else {
SWIFT_LOG(debug) << "Initial roster not requested by client." <<std::endl;
}
Expand All @@ -219,12 +240,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 @@ -240,6 +290,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));
if (j != jidMap_.end()) {
itemPayload->setID(j->second);
} else {
SWIFT_LOG(debug) << "Participant" << participant << "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 @@ -253,6 +345,12 @@ class Server {

using RosterMap = std::map<JID, std::shared_ptr<XMPPRosterImpl>>;
RosterMap rosterMap_;

using JIDMap = std::map<JID, JID>;
JIDMap jidMap_;

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
67 changes: 63 additions & 4 deletions Swiften/Examples/MIXListAndJoin/MIXListAndJoin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Elements/ErrorPayload.h>
#include <Swiften/Elements/MIXParticipant.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 +42,66 @@ 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 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;
}
}

// 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 +111,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
22 changes: 22 additions & 0 deletions Swiften/MIX/MIX.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
#include <Swiften/Base/API.h>
#include <Swiften/JID/JID.h>
#include <Swiften/Elements/Form.h>
#include <Swiften/Elements/Message.h>
#include <Swiften/Elements/PubSub.h>
#include <Swiften/Elements/PubSubItem.h>
#include <Swiften/Elements/PubSubItems.h>
#include <Swiften/Elements/MIXUpdateSubscription.h>
#include <Swiften/Elements/MIXUserPreference.h>
#include <Swiften/Elements/ErrorPayload.h>
Expand Down Expand Up @@ -52,9 +56,27 @@ namespace Swift {
*/
virtual void updatePreferences(Form::ref form) = 0;

/**
* Sends a message to channel with given body.
*/
virtual void sendMessage(const std::string &body) = 0;

/**
* Look up real JIDs from proxy JIDs in JIDVisible or JIDMaybeVisible Rooms.
*/
virtual void lookupJID(const std::unordered_set<std::string>& proxyJIDs) = 0;

/**
* Retrieves the list of participants of the channel.
*/
virtual void requestParticipantList() = 0;

public:
boost::signals2::signal<void (MIXUpdateSubscription::ref /* updateResponse */, ErrorPayload::ref /* updateError */)> onSubscriptionUpdateResponse;
boost::signals2::signal<void (Form::ref /* preferencesForm */, ErrorPayload::ref /* failedConfiguration */)> onPreferencesFormResponse;
boost::signals2::signal<void (MIXUserPreference::ref /* userPreferenceResponse */, ErrorPayload::ref /* failedUpdate */)> onPreferencesUpdateResponse;
boost::signals2::signal<void (Message::ref /*message*/)> onMessageReceived;
boost::signals2::signal<void (std::shared_ptr<PubSub> /* responsePubSub */, ErrorPayload::ref /* lookupError */)> onLookupResponse;
boost::signals2::signal<void (std::shared_ptr<PubSub> /* responsePubSub */, ErrorPayload::ref /* lookupError */)> onParticipantResponse;
};
}
55 changes: 54 additions & 1 deletion Swiften/MIX/MIXImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

namespace Swift {

MIXImpl::MIXImpl(const JID& ownJID, const JID& channelJID, IQRouter* iqRouter) : ownJID_(ownJID), channelJID_(channelJID), iqRouter_(iqRouter) {
MIXImpl::MIXImpl(const JID& ownJID, const JID& channelJID, IQRouter* iqRouter, StanzaChannel* stanzaChannel) : ownJID_(ownJID), channelJID_(channelJID), iqRouter_(iqRouter), stanzaChannel_(stanzaChannel) {

}

Expand Down Expand Up @@ -60,4 +60,57 @@ void MIXImpl::updatePreferences(Form::ref form) {
request->send();
}

void MIXImpl::sendMessage(const std::string &body) {
auto message = std::make_shared<Message>();
message->setTo(channelJID_);
message->setType(Message::Groupchat);
message->setBody(body);
message->setID(idGenerator.generateID());
stanzaChannel_->sendMessage(message);
}

void MIXImpl::handleIncomingMessage(Message::ref message) {
if (message) {
onMessageReceived(message);
}
}

void MIXImpl::lookupJID(const std::unordered_set<std::string>& proxyJIDs) {
auto itemsPayload = std::make_shared<PubSubItems>();
itemsPayload->setNode(MIX::JIDMapNode);

for (auto proxyJID : proxyJIDs) {
auto item = std::make_shared<PubSubItem>();
item->setID(std::string(proxyJID));
itemsPayload->addItem(item);
}

auto pubSubPayload = std::make_shared<PubSub>();
pubSubPayload->setPayload(itemsPayload);

auto request = std::make_shared<GenericRequest<PubSub>>(IQ::Get, channelJID_, pubSubPayload, iqRouter_);
request->onResponse.connect(boost::bind(&MIXImpl::handleJIDLookupResponse, this, _1, _2));
request->send();
}

void MIXImpl::handleJIDLookupResponse(std::shared_ptr<PubSub> payload, ErrorPayload::ref error) {
onLookupResponse(payload, error);
}

void MIXImpl::requestParticipantList() {
auto itemsPayload = std::make_shared<PubSubItems>();
itemsPayload->setNode(MIX::ParticipantsNode);

auto pubSubPayload = std::make_shared<PubSub>();
pubSubPayload->setPayload(itemsPayload);

auto request = std::make_shared<GenericRequest<PubSub>>(IQ::Get, channelJID_, pubSubPayload, iqRouter_);
request->onResponse.connect(boost::bind(&MIXImpl::handleParticipantList, this, _1, _2));
request->send();
}

void MIXImpl::handleParticipantList(std::shared_ptr<PubSub> payload, ErrorPayload::ref error) {
onParticipantResponse(payload, error);
}

}
Loading

0 comments on commit 7359480

Please sign in to comment.