I have ejabberd as my local server and smack as the android side api.
When user comes online and there is number of offline messages to deliver , the ejabberd server just floods me with the messages .and i get every message but the order is just not perfect. the order in which message is sent and saved in server is not how i receive the messages.
I can handle the offline messages on smack by the OfflineMessageManager class . but this is not supported in ejabberd. i used supportsFlexibleRetrieval() to check it and it returned false.
I also checked it with the Xabber android app and surprisingly here i get all the messages in correct order from the ejabberd server. so the problem is at my android client side. my receiver is as follows-
PacketListener myListener;
String new_msg_body, new_msg_from;
final StanzaFilter filter = new AndFilter(new StanzaTypeFilter(Message.class));
PacketCollector myCollector = conn1.createPacketCollector(filter);
myListener = new PacketListener() {
#Override
public void processPacket(Stanza packet) throws SmackException.NotConnectedException {
Message msg = (Message) packet;
new_msg_body = msg.getBody();
new_msg_from = msg.getFrom();
Log.i("log", "message recived :" + new_msg_body + " from : " + new_msg_from +" msg id : " + msg.getStanzaId());
}
};
conn1.addPacketListener(myListener, filter);
Do any one have any suggestion for this problem.
Progress
Till now i have found that each message has its id and the ids of each message is in order if their sending time. so i can may be do a sorting here to get the messages in order.
got to know that each packet that comes that fires its own receiver instance. and this will make the device flood with number of messages at a time . this might be causing the problem.
ejabberd 16.02 or latest version support Flexible Offline Message Retrieval (XEP-0013) .download and install latest version of ejabberd. check this link
XEP-0013: Flexible Offline Message Retrieval is from 2003, maybe it is time to move to the much more modern XEP-0313: Message Archive Management? It is far better for multiple devices environments, such as the concurrent use of mobile and web apps.
MongooseIM has a strong support for MAM: MongooseIM 1.6.2 supports MAM v0.2, but our master branch (next version) supports MAM v0.5.1. You can store your message archive in MySQL, PostgreSQL, Riak KV, and Cassandra!
Related
Does anybody know of an easy way to trigger an event when a device on Google Core IoT goes offline? Before I switched to Google's IoT implementation, this was very easily handled by triggering an event when MQTT disconnects, but it seems Google has no easy way of doing this.
Does anybody know if there is something planned for this?
Who's back do I need to scratch to get them to see that something like this is a basic requirement for IoT device management!
Other platforms like AWS and Microsoft already have this implemented (or some way to handle it easily):
https://docs.aws.amazon.com/iot/latest/developerguide/life-cycle-events.html
Device connectivity(online/offline)status with the Auzure iot hub
I wish I had known this before writing all my code and implementing my setup using Google's IoT platform, I guess that's my fault for assuming something so simple and that should be standard for IoT devices would be available.
How are you going to compete with other IoT providers if you can't even provide basic offline/online events?!
My reply in this SO question shows how I had to write 100+ lines of code just to create a firebase function to check if a device is online (but that still doesn't handle offline events, and is just a hack for something that should be native to ANY IoT service provider!):
https://stackoverflow.com/a/54609628/378506
I'm hoping someone else has figured out a way to do this, as i've spent numerous days searching SO, Google, Google Core IoT Documentation, and still have not found anything.
Even if MQTT Last Will was supported we could make that work, but even that IS NOT SUPPORTED by Google (https://cloud.google.com/iot/docs/requirements) ... come on guys!
Your cloud project does have access to the individual MQTT connect/disconnect events, but currently they only show up in the Stackdriver logs. Within the cloud console, you can create an exporter that will publish these events to a Pub/Sub topic:
Visit the Stackdriver Logs in the
Cloud Console.
Enter the following advanced filter:
resource.type="cloudiot_device"
jsonPayload.eventType="DISCONNECT" OR "CONNECT"
Click CREATE EXPORT
Enter a value for Sink Name
Select Cloud Pub/Sub for Sink Service
Create a new Cloud Pub/Sub topic as the Sink Destination
The exporter publishes the full LogEntry, which you can then consume from a cloud function subscribed to the same Pub/Sub topic:
export const checkDeviceOnline = functions.pubsub.topic('online-state').onPublish(async (message) => {
const logEntry = JSON.parse(Buffer.from(message.data, 'base64').toString());
const deviceId = logEntry.labels.device_id;
let online;
switch (logEntry.jsonPayload.eventType) {
case 'CONNECT':
online = true;
break;
case 'DISCONNECT':
online = false;
break;
default:
throw new Error('Invalid message type');
}
// ...write updated state to Firebase...
});
Note that in cases of connectivity loss, the time lag between the device being unreachable and an actual DISCONNECT event could be as long the MQTT keep-alive interval. If you need an immediate check on whether a device is reachable, you can send a command to that device.
The best solution i think is that
We need 3 things
cloud sheduler ,
and 2 cloud functions
The first function will be the #devunwired answer but instant of
// ...write updated state to Firebase... schedule a second function to trigger in 2-3 min (let device to recconect)
the seccond function will send a command to device
if the device resposne to command
if stored status is connected dont do nothing
else if the stored status is disconnected then update the status to connected and do what ever you want maybe email
else
if stored status is disconnected dont do nothing
if stored status is connected change the status alert by email or something
I already have an app and I want to start sending notification to the users. I already set up everything in the app(using react native) and I checked manually that I can send notification to the devices and it works.
Now I want to run a job in the server who will push the message (with the device token) to the cloud messaging in firebase.
I can't find a lot of details about how to do it. I would like if someone can give me any guide I can use with. my server is in Kotlin(java can be good too) and I m working with gradle.
Thank you so much for the help
From a Java server you can use the Firebase Admin SDK to send messages. From that documentation comes this minimal example:
// This registration token comes from the client FCM SDKs.
String registrationToken = "YOUR_REGISTRATION_TOKEN";
// See documentation on defining a message payload.
Message message = Message.builder()
.putData("score", "850")
.putData("time", "2:45")
.setToken(registrationToken)
.build();
// Send a message to the device corresponding to the provided
// registration token.
String response = FirebaseMessaging.getInstance().send(message);
// Response is a message ID string.
System.out.println("Successfully sent message: " + response);
Note that this sends a data message, so that will always be delivered to your code, where you can decide to display a notification or not. To send a notification message, which is what the Firebase console does, you'd use:
Message message = Message.builder()
.setNotification(new Notification("This is the title", "This is the body"))
.setToken(registrationToken)
.build();
Both of these send the message to a specific registration token, so only to a single device/app instance. This means you will need to maintain a list of these tokens, in a way that allows you to send the messages to fit your needs. E.g. a common way is to store the tokens per user. For an example of that, see the functions-samples repo. While this example is in Node.js, the same logic could be applied to a Java server.
Finally: you can also send message to topics. For an example of that (again: using a Node.js server), have a look at this blog post Sending notifications between Android devices with Firebase Database and Cloud Messaging.
I've been struggling from past 4 days to implement push notification in vert.x framework using java(at server side) and javascript(client side). I've been studying example from this link.
I am not able to understand what is the significance of "prefix" in below line of code.
How to put my custom message to json array, so that it will sent to client as notification.
sockJSServer.bridge(new JsonObject().putString("prefix", "/eventbus"), permitted, permitted);
And I am also unable to implement client side according to my need. My requirement is get data from database and than vert.x server publish that data to n number of clients. What will be the prerequisite for that whole scenario?
In above mentioned link, index.html is there. I debugged this on browser. It successfully connect the server.
One more point is, what is the significance of "/eventbus" in index.html(line no #108)
eb = new vertx.EventBus("http://localhost:8080/eventbus");
After successful connection with server.Should every client subscribe to server in order to get notification from server ? I want every client will get notification without any client intervention.
Now, the last point is in below code, what is address? Is it client ip address or server or any other thing.
function publish(address, message) {
if (eb) {
var json = {text: message};
eb.publish(address, json);
$('#sent').append($("<code>").text("Address:" + address + " Message:" + message));
$('#sent').append($("</code><br>"));
}
}
function subscribe(address) {
if (eb) {
eb.registerHandler(address, function(msg, replyTo) {
$('#received').append("Address:" + address + " Message:" + msg.text + "<br>");
});
$('#subscribed').append($("<code>").text("Address:" + address));
$('#subscribed').append($("</code><br>"));
}
}
Any help will be appreciable.
The callback function in registerHandler() receive message from server in Json form. You can get your custom message by message.notification where notification is your unique key that is to be set at server side.
I am novice in IBM WebSphere MQ and I would like to ask you about the best approach to solve the following task.
I use WebSphere MQ 7.0 and I have implemented an java app to check MQ queue on incoming messages.
Incoming queue opened via the following code:
int openOptions = MQC.MQOO_INPUT_AS_Q_DEF | MQC.MQOO_INQUIRE;
MQQueue incomingQueue =
qManager.accessQueue(qName, openOptions, null, null, null);
Now, the task is to check in real-time mode when new messages appear in incomingQueue and process them.
I permanently check queue depth via invocation of incomingQueue.getCurrentDepth() in while-loop and check if it is bigger than zero then I get new messages.
That works, but I believe it is not a good approach.
What is the best approach to be notified when a new incoming message appeared in MQ Queue?
Thank you.
Just call the queue.Get(msg) method. This is a blocking call and will return only when there is a message on a queue.
If the above is not suitable as it is a blocking call, you could look at WMQ JMS that provides a message listener. The message listener is used to receive messages on a callback method while the main thread can continue to do other work.
There are good samples that comes with MQ. You can find them under (on Windows) \tools\jms\samples and tools\wmqjava\samples.
Try to use the below open options to access a queue
openOptions = MQConstants.MQOO_INQUIRE + MQConstants.MQOO_FAIL_IF_QUIESCING
+ MQConstants.MQOO_INPUT_AS_Q_DEF + MQConstants.MQOO_READ_AHEAD;
And following get options to get the messages
MQGetMessageOptions getOptions = new MQGetMessageOptions();
getOptions.options = MQConstants.MQGMO_WAIT + MQConstants.MQGMO_PROPERTIES_COMPATIBILITY
+ MQConstants.MQGMO_ALL_SEGMENTS_AVAILABLE + MQConstants.MQGMO_COMPLETE_MSG
+ MQConstants.MQGMO_ALL_MSGS_AVAILABLE;
MQConstants.MQGMO_WAIT option will help us to read the messages when arrives to the queue. But make sure a Java thread/program should be there to run your class all the time to listen to the queue
Am trying to implement a Java program which sends an Apple Push Notification to an iPhone client app... Found the following library: Java APNs
Provider code:
Created the following code (from Javapns) to use in my app:
try {
PayLoad payLoad = new PayLoad();
payLoad.addAlert("My alert message");
payLoad.addBadge(45);
payLoad.addSound("default");
PushNotificationManager pushManager = PushNotificationManager.getInstance();
pushManager.addDevice("iPhone", "f4201f5d8278fe39545349d0868a24a3b60ed732");
log.warn("Initializing connectiong with APNS...");
// Connect to APNs
pushManager.initializeConnection(HOST, PORT,
"/etc/Certificates.p12", "password",
SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);
Device client = pushManager.getDevice("Lambo");
// Send Push
log.warn("Sending push notification...");
PushNotificationManager.getInstance().sendNotification(client, payLoad);
}
catch (Exception e) {
throw new ApnsPushNotificationException("Unable to send push " + e);
}
When I run this app (as you can see through the Log4j statements) there's no exceptions which occur:
WARN [MyCode] Initializing connectiong with APNS...
WARN [MyCode] Sending push notification...
But my client app doesn't receive any notifications!
IDPP Registration Process:
Also, did the following on the iPhone Developer Program Portal (IDPP):
Created the APNS based SSL Certificate and Keys
Created and installed the provisioning profile
Installed the SSL Certificate and Key on the server.
Have read over the Apple Push Notification Service Guide several times and noticed a few things:
(1) On page 15, it states that the device token is not the same as the device UDID (which I am currently incorrectly passing in as the second parameter inside the PushNotificationManager.addDevice() method (see above)).
On page 17, it states:
"APNs generates a device token using information contained in the unique device certificate. The device token contains an identifier of the device. It then encrypts the device token with a token key and returns it to the device. The device returns the device token to the requesting application as an NSData object. The application then must deliver the device token to its provider in either binary or hexidecimal format."
iPhone OS Client Implementation
(2) After reading pages 33 - 34, I discovered that I didn't include the Objective-C code to have the app register with APNs.
Am not an Objective-C developer, so is this where I can recover the device code or do I have to get it from the certificate?
Where do I obtain the device token (sorry, someone else wrote the Objective-C client app and I am a Java Developer)?
Question(s):
(1) With the exception of not knowing where to get the device token and the mobile client code registration, is there anything else that I have not looked over or missed?
(2) Am I using the Javapns library the right way?
Thank you for taking the time to read this...
As a shameful self-advertising, I encourage to use java-apns library. Your code will look like:
ApnsService service =
APNS.newService()
.withCert("/etc/Certificates.p12", "password")
.withSandboxDestination() // or .withProductionDestination()
.build();
String payload =
APNS.newPayload()
.alertBody("My alert message")
.badge(45)
.sound("default")
.build();
String deviceToken = "f4201f5d8278fe39545349d0868a24a3b60ed732";
log.warn("Sending push notification...");
service.push(deviceToken, payload);
Just a little tip, in order to convert your received token into a format suitable for registration with javapns, this code will do the trick:
- (NSString *)convertTokenToDeviceID:(NSData *)token {
NSMutableString *deviceID = [NSMutableString string];
// iterate through the bytes and convert to hex
unsigned char *ptr = (unsigned char *)[token bytes];
for (NSInteger i=0; i < 32; ++i) {
[deviceID appendString:[NSString stringWithFormat:#"%02x", ptr[i]]];
}
return deviceID;
}
I tried this and I keep getting hanged when sending the notification, and nothing gets sent.
The issue stems from the following function:
public void sendNotification(Device device, PayLoad payload)
It seems that the bufferedreader has NULL
BufferedReader in =
new BufferedReader(new InputStreamReader(this.socket.getInputStream() ) );
So when this portion of the code gets hit it just hangs there in endless loop
logger.debug( "In: [" + in.readLine() + "]" );
This output is [null]
So then right after then the loops get executed:
while ( ! this.socket.isInputShutdown() ) {
while( in.ready() ) {
logger.debug("ready now");
logger.debug(in.readLine());
System.out.println( this.socket.getInputStream().read() );
}
}
The code enters the first while loop and waits for the BufferedReader in to be ready
and just keeps waiting..... ad that is your hanging
Your Java code looks solid! However, don't forget to close the connection, through PushNotificationManager.closeConnection(). It's important to cleanup after yourself.
As a side comment, I notice that you are adding the device 'iPhone' but querying for 'Lambo' afterwards. This is an indication of a bug.
The device token shown in the code is incorrect. Device tokens, currently, as 32-bit long value, which gets hexed into 64 characters. I assume that the server is failing silently when pushing the notification to invalid token!
The only way to get the device token is from the app itself. As provided by the Push Notification guide suggests, the iPhone app needs to register for notification upon launch. In the application:didRegisterForRemoteNotificationsWithDeviceToken:, the iPhone needs to send the device token to your java provider server. (For debugging purposes, you can just NSLog the device token and use it; it never changes across runs).
I would recommend that you create a server in your java provider server to receive device tokens. Set up a ServerSocket to receive connections from the iPhone and their device token (and any additional info you need) and insert the tokens in the database.
JavaPNS was recently updated to 2.0, and fixed ALL reported issues up to the release date. It does fix the issue you are describing, and using the library is MUCH simpler than it ever was (you can push a notification with a single line of code now).
You seem to be missing the token
pushManager.addDevice("iPhone", "f4201f5d8278fe39545349d0868a24a3b60ed732");
Takes id and token check:
https://github.com/o-sam-o/javapns/blob/master/src/javapns/notification/PushNotificationManager.java#L501
The only way to get a token is from the iphone app. A valid token looks something like this:
1d2d6f34 c5028bca c50df5f9 1992c912 ce7deae8 3bbe7da5 447f6a68 cfecdc0e
Regarding the comment for notnoop here:
If you are landing on this post in 2022, you'll find that the java-apns library doesn't work since 2021. Instead they recommend using pushy library.
I have tried this one just by following their example in the README file and it works really well. They have added examples for both authorisation types: by certificate or by token.