How to keep chat history locally on android? - xmpp

I am using openfire and aSmack for my chat application.
I am able to send and receive messages using aSmack library.
Can anyone tell me how to keep these messages in local(android) storage, so that whenever user opens application next time, he can see his previous chat history ? Is there any api provided by aSmack/Smack ?

Simply register a packet listener and interceptor and log the messages to the backing store of your choice.

use packetListener as:
PacketFilter gc_filter = new MessageTypeFilter(Message.Type.groupchat);
XMPPconnection.addPacketListener(new PacketListener()
{
public void processPacket(Packet packet)
{
final Message message = (Message) packet;
String body = message.getBody();
String from_jid = message.getFrom();
// save it in data base
}
)};

Related

Is there a way to listen to the number of consumers present in a RabbitMQ queue using Flutter?

i am developing a local messaging application in Flutter using RabbitMQ as message broker service. I am using the package called "dart_amqp" with version 0.2.1
For messaging, i am creating a new durable queue for every user with the name format [username]_channel_chatapp and i want to check the consumer number in this queue to get the information of user presence.
So if "consumerCount" in that queue is equal to 0, then this means targeted user is offline and if it is 1 then the targeted user is online.
The problem is, when a user opens/closes the application, i need to check the queue again to update user presence. I think i need a listener for that but don't know how to do that.
Thank you for your answers and time.
Future<int> connectToTarget(String consumerName) async{
try{
targetChannel = await client.channel();
target = await targetChannel!.queue("${consumerName}_channel_flowchat", passive: true);
}
catch(exp){
print(exp.runtimeType);
target = null;
return -1; //means queue does not exist!!
}
if(target!.consumerCount != 0){
return 1; //means consumer online
}
else{
return 0; //means consumer offline
}
}
This code shows how i check the target user presence when they are first selected.

VertX multiple Worker Instances processing same message

I have a simple Vertx worker vertical with 4 instances for scaling as defined below. When multiple requests come, I was expecting that each worker instances will process individual request concurrently (4 requests at a time).
Vertx vertx = Vertx.vertx();
DeploymentOptions deploymentOptions = new DeploymentOptions()
.setWorker(true)
.setInstances(4);
vertx.deployVerticle(MailVertical.class.getName(), deploymentOptions);
some code to plumb incoming mail message to publishing method.
// This is executed once per incoming message
this.vertx.eventBus().publish("anAddress", messageString);
Vertical Consumer code to log incoming mail message
public class MailVertical extends AbstractVerticle {
private static final Logger logger = LoggerFactory.getLogger(MailVertical.class);
#Override
public void start(Promise<Void> future) {
logger.info("Welcome to Vertx: MailVertical.");
vertx.eventBus().consumer("anAddress", message -> {
String msg = message.body().toString();
for(int i=0;i<50;i++){
logger.info(msg);
}
try {
updateStatusInDB(msg);
} catch (SQLException e) {
e.printStackTrace();
}
});
}
However, I am observing that each request is processed by all 4 instances somewhat concurrently i.e. if 1 request come in, total 4 processing events occur = 200 log messages.
...
...
[vert.x-worker-thread-7] INFO com.vertx.mailproject.MailVertical - {"msg":"sample message for app-2123x mail notification","appname":"app-1","msgid":"64fd684b-45a8-48c7-9526-4606d6adc311"}
[vert.x-worker-thread-6] INFO com.vertx.mailproject.MailVertical - Msg: sample message for app-2123x mail notification updated to SENT in DB.
[vert.x-worker-thread-7] INFO com.vertx.mailproject.MailVertical - Msg: sample message for app-2123x mail notification updated to SENT in DB.
[vert.x-worker-thread-4] INFO com.vertx.mailproject.MailVertical - Msg: sample message for app-2123x mail notification updated to SENT in DB.
[vert.x-worker-thread-5] INFO com.vertx.mailproject.MailVertical - Msg: sample message for app-2123x mail notification updated to SENT in DB.
Any suggestion what am I doing wrong here? Or is this expected.
vertx-core = 4.2.3
Yes this is indeed a correct behavior. You are starting 4 worker threads and then registering all of them against the same address "anAddress".
Publish Subscribe pattern is being used here. With the method publish() all the registered consumer/handler will receive this event. see Publish / subscribe messaging
If you want only one of worker to receive this event, then use Point-to-point and Request-Response messaging. Basically replace publish() with send()
But looking at your code, I would suggest instead of using worker verticle use executeBlocking in standard verticle

Vert.x Event Bus to retain message

I am following the vertx sockjs example to transfer data over the SockJS event bus bridge.
The sending code:
eventBus.publish(ebAddress, data);
The consumer code:
var eb = new EventBus("http://localhost:8088/eventbus");
eb.onopen = function () {
eb.registerHandler("/ebaddress", function (err, msg) {
var str = "<code>" + msg.body + "</code><br>";
console.log(str);
})
}
The first client works fine. However, for the second connected client, since it is subscribing the same eb address, it cannot get the most current data that has been sent to the first client. It won't be an issue if the data is coming in fast. But if the time interval between data points are long, the second client will have no data for a long time until the next new data point arrive.
So, is the event bus of Vert.x able to retain message so that whenever a new client connects, it can get the most recent data right away?
I am pretty new to Vert.x, so any comments will be greatly appreciated.
Simple answer: no, Vert.x EventBus doesn't persist messages. Nor does it able to replay them, for that reason. It just that: a bus to send events on. After all, when you write in JavaScript element.on("click", function() {}), you don't usually expect to receive all previous clicks, right?
But, it doesn't mean it's not possible.
In your JavaScript:
eb.onopen = function () {
// On connect your client asks on a different channel to get some previously stored messages
eb.send("/replay", {count: 10}, null, function(err, msg) {
// Populate your code
});
// Continue here as usual
eb.registerHandler("/ebaddress", function (err, msg) {
// Something happens here
})
}
Of course on your server side you'll need to
Persist some amount of messages, either in-memory or in some storage of your choice
Listen to this new /replay channel
Use .send() to reply to specific client with previous messages

How to set custom Message.Type string in Smack?

I am trying to send a chat using Smack. Here is the code
Chat chat = connection.getChatManager().createChat("2#coolcast.com", this);
Message _msg = new Message();
_msg.setBody("Hello this is a test message");
chat.sendMessage(_msg);
This message shows up at the recipient's end with type = "chat". How can I change this message type to a custom string e.g. "my_custom_string"?
I tried this but it is easy to see why the following won't work
Message.Type _type = Message.Type.fromString("my_custom_string");
_msg.setType(_type);
Message is final class in smack, also it follows the xmpp protocol for message Stanza, so you cannot modify the Type field in Message.
But we cannot end giving up, here you can try a small trick by adding your custom extension in Message Stanza you just need to create a ExtensionElement using provider architecture of smack and then add it to Message Packet by calling addExtension() method on Message Object.
it will be like this :
<message from="demo#mydomain.com" to="demo2#mydomain.com" type="chat">
<body>Hi this is demo 1</body>
<my_custom_element xmlns="some_name_space" attributr="some_attribute">Some custom message</my_custom_element>
</message>
you can multiple Extenstion to any Packet/Stanza in smack.
to learn more about Smack Provider Architecture follow this link

CometD Subscription Listeners

I’m having a problem processing Subscription Requests from Clients and carrying out some processing based on the request. I’d like to be able to invoke a method and carry out some processing when an incoming subscription request is received on the Server. I’ve had a look at the following CometD documentation and tried the example outlined in “Subscription Configuration Support” but I’m not having much luck.
http://www.cometd.org/documentation/2.x/cometd-java/server/services/annotated
I’ve already created the Bayeux Server using a Spring Bean and I’m able to publish data to other channel names I’ve created on the Server side. Any help or additional info. on the topic would be appreciated!
The code example I’m using:
#Service("CometDSubscriptionListener")
public class CometDSubscriptionListener {
private final String channel = "/subscription";
private static final Logger logger = Logger.getLogger(CometDSubscriptionListener.class);
private Heartbeat heartbeat;
#Inject
private BayeuxServer bayeuxserver;
#Session
private ServerSession sender;
public CometDSubscriptionListener(BayeuxServer bayeuxserver){
logger.info("CometDSubscriptionListener constructor called");
}
#Subscription(channel)
public void processClientRequest(Message message)
{
logger.info("Received request from client for channel " + channel);
PublishData();
}
Have a look at the documentation for annotated services, and also to the CometD concepts.
If I read your question correctly, you want to be able to perform some logic when clients subscribe to a channel, not when messages arrive to that channel.
You're confusing the meaning of the #Subscription annotation, so read the links above that should clarify its semantic.
To do what I understood you want to do it, you need this:
#Service
public class CometDSubscriptionListener
{
...
#Listener(Channel.META_SUBSCRIBE)
public void processSubscription(ServerSession remote, ServerMessage message)
{
// What channel the client wants to subscribe to ?
String channel = (String)message.get(Message.SUBSCRIPTION_FIELD);
// Do your logic here
}
}