Get pending messages from a Chat - chat

I am developing a chat using quickblox but I am having some problems when I open a new chat. Suddenly I received all the messages that others users sends to me when I was desconnected. The problem is that when I start a chat with user A, I receive the chats from users B, C, D.. in user A chat room.
I have find the way to only show the A users. But the problem is that the server has already sent to me the "disconnected" messages, so when I start a chat to B I do not receive any text because the message that the user B sent to me has been delivered (and ommitted) while I was chating with user A.
How can I do to receive the pending messages (kind of history) or to just retreive the message of the chat I am logged in?
A piece of my code:
// Create Connection.
Connection.DEBUG_ENABLED = true;
config = new ConnectionConfiguration(CHAT_SERVER);
connection = new XMPPConnection(config);
try {
connection.connect();
connection.login(chatLogin, password);
// Create Chat Manager.
chatManager = connection.getChatManager();
// Create Chat.
chat = chatManager.createChat(friendLogin, null);
// // Set listener for outcoming messages.
// chatManager.addChatListener(chatManagerListener);
// Accept only messages from
String from_messages = Integer.toString(receiver_chat_id);
PacketFilter filter = new AndFilter(new PacketTypeFilter(Message.class),
new FromContainsFilter(from_messages+"-3758#chat.quickblox.com"));
// Collect these messages
PacketCollector collector = connection.createPacketCollector(filter);
Packet packet = collector.pollResult();
PacketListener myListener = new PacketListener() {
public void processPacket(Packet packet) {
if (packet instanceof Message) {
Message msg = (Message) packet;
if(msg!=null){
// Process message
System.out.println("Rebem missatge: " +msg.getBody());
}
}
}
};
// Register the listener.
connection.addPacketListener(myListener, filter);
// Set listener for detect Receiver Status
if (connection.isConnected()){
roster = connection.getRoster();
roster.addRosterListener(new RosterListener() {
public void entriesDeleted(Collection<String> addresses) {}
public void entriesUpdated(Collection<String> addresses) {}
public void presenceChanged(Presence presence) {}
public void entriesAdded(Collection<String> arg0) {}
});
}

Make a arraylist and store the receiving offline messages into that array-list. you could add a code in your processPacket(Packet packet) function to add incoming messages to the array-list. or you could use Multimaps(Google Guava) to store all the incoming messages with the key. and when you open the activity that displays the messages from the certain person you could match the name of that person with the key(stored in multimap) and displays the message of that certain person. And the better option is to store all the incomming and outgoing message chat with the certain person so that you could show all the previous chat then you open up the activity.

Related

Google pubsub listener not receiving all the messages

I'm using Google Cloud Storage for storing objects, with the bucket associated to a topic and subscription id. The flow is such that a Java application requests for the upload link(s), and upload object(s) using those upload link(s). I also have a pubsub listener implemented in Java, which receives the upload notification message, and does something on every successful upload. This is the snippet that handles the event listening.
public void eventListener() {
MessageReceiver messageReceiver = (message, consumer) -> {
final Map<String, Object> uploadMetaDataMap = getUploadDataMap(message);
LOGGER.info("Upload event detected => {} ", uploadMetaDataMap);
// do something
consumer.ack();
};
Subscriber subscriber = null;
Subscriber finalSubscriber = subscriber;
/* To ensure that any messages already being handled by receiveMessage run to completion */
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
finalSubscriber.stopAsync().awaitTerminated();
}
});
try {
subscriber = Subscriber.newBuilder(subscription, messageReceiver)
.setCredentialsProvider(FixedCredentialsProvider.create(creds)).build();
subscriber.addListener(new Subscriber.Listener() {
#Override
public void failed(Subscriber.State from, Throwable failure) {
// Handle failure. This is called when the Subscriber encountered a fatal error and is shutting down.
LOGGER.error(String.valueOf(failure));
}
}, MoreExecutors.directExecutor());
subscriber.startAsync().awaitRunning();
subscriber.awaitTerminated();
} finally {
if (subscriber != null) {
subscriber.stopAsync().awaitTerminated();
}
}
}
I'm storing the objects in this format => bucket/uuid/objectName.extension and on every successful upload, LOGGER.info("Upload event detected => {} ", uploadMetaDataMap); logs messages like this
2020-08-03 16:12:14,686 [Gax-1] INFO listener.AsynchronousPull - Upload event detected => {size=85, uuid=6dff9a20-3995-4f28-93e9-79e6c3cf613d, bucket=bucketName}
The issue I'm facing now is, not all the successful upload events send out notification message. I can see the folder structure created in the GCS with the respective object inside it, but notification related to that upload is nowhere to be found in the logs printed by pubsub listener. It's been bothering me for a while now, and could really use some help with this.

UWP DatagramsSocket doesn't not fire MessageReceived

I'm working on a UWP application which should communicate via TCP/UDP to a remote device. My issue is that the UWP app successfully sends UDP messages to the remote device, but does not receive the replies.
Here follows the code extracted from the app (simplified):
async Task TestUdpIP()
{
// Writer to the DatagramSocket
DataWriter writer;
using (var udpClient = new DatagramSocket())
{
try
{
// UDP Socket binding
udpClient.MessageReceived += UdpClient_MessageReceived;
var controllerName = new Windows.Networking.HostName(controllerIpAddress.ToString());
await udpClient.BindEndpointAsync(controllerName, controllerIpPort.ToString());
var remoteHostName = new Windows.Networking.HostName(hostIpAddres.ToString());
await udpClient.ConnectAsync(remoteHostName, remoteHostPort.ToString());
// Create a message to send
string message = "Some message";
// Reset the counter of messages received back from the remote robot
messagesReceived = 0;
// Send the message
writer = new DataWriter(udpClient.OutputStream);
writer.WriteString(message);
await writer.StoreAsync();
// Wait for robot status messages
await Task.Delay(5000);
}
catch
{
}
}
}
void UdpClient_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
{
// Just increment the number of messages received
messagesReceived++;
}
However the UdpClient_MessageReceived handler does not fire. I'm sure that UDP messages are correctly sent from the UWP app and that the remote device replies back as shown in the following screenshot from Wireshark (the test has been taken on the same PC where the UWP app is running)
.
(IP Address, Port) details are shown in the following list to better explain the picture above
UWP application: (192.168.1.108, 19000) to send and receive.
Remote device: (192.168.1.152, 15999) to receive and (192.168.1.152, 54697) to send
Note: this is a similar question, where the answer says that for whatever reason the DatagramSocket should fire some messages before being able to receive. In my example a message is sent out however the message received handler does not fire anyway.
Note: The UWP app has been granted the internet (client) and the internet (client and server) capabilities
Note: I've tried also this (more readable) approach to bind the inbound/outbound datagram socket on the UWP app obtaining the same results:
// UDP Socket binding
var controllerName = new HostName(controllerIpAddress.ToString());
var remoteHostName = new HostName(hostIpAddres.ToString());
EndpointPair endpointpar = new EndpointPair(controllerName,
controllerIpPort.ToString(),
remoteHostName,
remoteHostPort.ToString());
udpClient.MessageReceived += UdpClient_MessageReceived;
await udpClient.ConnectAsync(endpointpar);
Where is the issue? Many thanks!
Please try to also add the Private Networks (Client & Server) capability in your app's manifest.
On other hand, you can try the Official DatagramSocket sample to see whether the both devices can communicate with each other.
After some experimenting, I came out with the idea of using two different DatagramSocket instances: one to send out UDP messages, and one to listen for incoming messages. With this code, I've been able to send UDP messages to the remote device (as before) and also I've been able to receive UDP messages from the remote device.
async Task TestUdpIP_DifferentPorts()
{
// Writer to the DatagramSocket
DataWriter writer;
// Inbound and outbound DatagramSocket
DatagramSocket udpListener = new DatagramSocket();
DatagramSocket udpSender = new DatagramSocket();
try
{
// String containing the serializaed message
string serializedMessage = "Some message";
var controllerName = new HostName(controllerIpAddress.ToString());
var remoteHostName = new HostName(hostIpAddres.ToString());
// Bind listener
udpListener.MessageReceived += UdpClient_MessageReceived;
await udpListener.BindEndpointAsync(controllerName, controllerIpPort.ToString());
// Connect sender
await udpSender.ConnectAsync(remoteHostName, remoteHostPort.ToString());
// Reset the counter of messages received back from the remote robot
messagesReceived = 0;
// Send the message
writer = new DataWriter(udpSender.OutputStream);
writer.WriteString(JsonConvert.SerializeObject(message));
await writer.StoreAsync();
// Wait for robot status messages
await Task.Delay(1000);
}
catch (Exception ex)
{
// Some exception handling
}
udpSender.Dispose();
udpListener.Dispose();
}
void UdpClient_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
{
// Just increment the number of messages received
messagesReceived++;
}
With this approach only the IP port (or service name) of the inbound listener needs to be specified. The framework will choose the next available outbound IP port.
Note: If I understand well the DatagramSocket.ConnectAsync(EndpointPair) documentation, the same DatagramSocket instance can be used to send and listen for incoming message, so I could not figure out the need for two different instances. From the documentation:
This ConnectAsync(EndPointPair) method on a DatagramSocket is used to define the local and remote endpoint where datagrams will be sent when using the OutputStream property. This method also restricts remote IP addresses of packets that will be accepted to the remote hostname in the endpointPair parameter. Only incoming packets that match the remote endpoint in the endpointPair parameter will trigger the MessageReceived event on the DatagramSocket.

How to know who received a message in a MUC room

For my thesis, I am using Smack to log a XMPP network that uses the MUC module.
Another software is currently sending IoT sensor data into different MUC rooms.
I'd like to know for every message sent into a MUC room, which users were in that room at the time of the message. Is this possible? I could use a messageListener to every muc room, however the listener only receives a message as an argument. Therefore I could not know who is logged into the room inside the listener method.
you can get all muc message in StanzaListener in xmpp. Please follow few steps to done this
Step 1. Declare as a global variables
ChatManagerListener chatListener;
Chat chat;
StanzaListener packetListener;
Step 2. Use this code in oncreate or in fragment
Note: Make sure you have connected with chat server.
packetListener = new StanzaListener() {
#Override
public void processPacket(Stanza packet) throws SmackException.NotConnectedException, InterruptedException {
if (packet instanceof Message) {
final Message message = (Message) packet;
}
}
};
XMPP.getInstance().getConnection(acitiviy)).addAsyncStanzaListener(stanzaListener, null);
ServiceDiscoveryManager sdm = ServiceDiscoveryManager
.getInstanceFor(XMPP.getInstance().getConnection(acitiviy)));
sdm.addFeature("jabber.org/protocol/si");
sdm.addFeature("http://jabber.org/protocol/si");
sdm.addFeature("http://jabber.org/protocol/disco#info");
sdm.addFeature("jabber:iq:privacy");
Step 3. Methods for one to one chat purposer
void sendMessage(String message) {
if (chat != null) {
try {
chat.sendMessage(message);
Message msg = new Message();
msg.setTo(JidCreate.bareFrom(jid));
msg.setFrom(XMPP.getInstance().getConnection(acitiviy)
.getUser());
ChatStateExtension ext = new ChatStateExtension(
ChatState.paused);
msg.addExtension(ext);
lastComposing = System.currentTimeMillis();
chat.sendMessage(msg);
} catch (SmackException.NotConnectedException e) {
} catch (Exception e) {
}
}
}
Step 4. On destroy
XMPP.getInstance().getConnection(acitiviy)).removeAsyncStanzaListener(stanzaListener);
Hope this will help you and if you want more information take a look from here. Thankyou
Nothing prervents you from calling Multi UserCaht.getParticipants() from within the listener. But be warned: If your goal is to determine the other receivers of receivers, then this approach is fragile. I also suggest to think about using PubSub instead of MUC for your IoT use case.

Duplicate message received in XMPP Multi User Conference Room

When device1 is sending the message to the conference room "del#conference.jabber.org"
the message is dispalyed in the chat list as well as a duplicated message is also displayed that is being send by the conference room "del#conference.jabber.org". I'm stuck, why i'm getting duplicate message.
public void setConnection(XMPPConnection connection) {
this.connection = connection;
if (connection != null) {
PacketFilter filter = new MessageTypeFilter(Message.Type.groupchat);
connection.addPacketListener(new PacketListener() {
#Override
public void processPacket(Packet packet) {
Message message = (Message) packet;
if (message.getBody() != null) {
String fromName = StringUtils.parseBareAddress(message.getFrom());
String[] parts = fromName.split("#");
String from = parts[0].trim();
messages.add(from + ":");
messages.add(message.getBody());
// Add the incoming message to the list view
mHandler.post(new Runnable() {
public void run() {
setListAdapter();
}
});
}
}
}, filter);
}
}
The send message is on button click, which is as follows
Button send = (Button) this.findViewById(R.id.sendBtn);
send.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Message mg = muc.createMessage();
String text = textMessage.getText().toString();
mg.setBody(text);
Log.i("XMPPChatDemoActivity ", "Sending text ");
if (connection != null) {
connection.sendPacket(mg);
messages.add("Me :");
messages.add(text);
setListAdapter();
}
textMessage.setText("");
}
});
and this is what i have written to connect the conference room
muc = new MultiUserChat(connection, "del#conference.jabber.org");
muc.join("alias name","password");
output what i'm getting when sending message
me: hello
del: hello
what i want i no duplicate message when i send the message i.e
me: hello
When you're in a MUC room you receive copies of all the messages, including your own.
http://xmpp.org/extensions/xep-0045.html#message - "and reflect the message out to the full JID of each occupant."
So for MUCs (not for direct messages) you will get a duplicate if you log both on send and on receive (assuming you have sufficient access to post, etc.). Your options are, largely, either to not log it on send (which is the option most clients go for) or to attempt to do smart message matching to detect when you receive your own message and elide it. The former option ensures that everyone sees a consistent view of message ordering, which some people find very useful.
Maybe your chat server sent your message to you also?
So you add one message manually in onClickListener and then the same message received from server.
I think, it will be right not to add messages from onClickListener - add only those that server sends.

android GCM Receive Messages from Multiple devices

i am building a chat application with the help of GoogleCloudMessaging(GCM).i am able to send and receive messages. my problem is when i receive messages from multiple devices at the same time, all those messages are appended to the same list-view in my broadcast receiver class. how can i separate the message based on the senders and append the current chat message to the listview. and make separate notifications for other messages based on the senders and when i click on the notification it should open the same list view with messages according to sender.
can any one give me an efficient way of doing this.if you have any sample code to handle this situation please post the code.
My current code:
public class Serious extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String action=intent.getAction();
if (action.equals("com.google.android.c2dm.intent.REGISTRATION"))
{
String registrationID=intent.getStringExtra("registration_id");
// Log.i("uo",registrationID);
String error=intent.getStringExtra("error");
String unregisterd=intent.getStringExtra("unregistered");
}
else if(action.equals("com.google.android.c2dm.intent.RECEIVE"))
{
String data1=intent.getStringExtra("data1");
String data2=intent.getStringExtra("data2");
addNewMessage(new Message(data2, false));
/* PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
new Intent(context, MainActivity.class), 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("My Notification")
.setDefaults(Notification.DEFAULT_SOUND)
.setAutoCancel(true)
.setContentText(data1+data2);
mBuilder.setContentIntent(contentIntent);
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, mBuilder.build());*/
}
}
void addNewMessage(Message m)
{
MainActivity.messages.add(m);
MainActivity.adapter.notifyDataSetChanged();
//MainActivity.getListView().setSelection(MainActivity.messages.size()-1);
}
}
You should pass in your gcm message a parameter that contains the sender id. Then, when you handle the arrived message, use that sender id to decide where to add that message. In order to show multiple notifications, pass different int values to notify. Currently you always pass 1, so a new notification overrides the old one.