I'm using Sharp.Xmpp to receive upstream messages from Android Device via FCM. It connects fine and 'at times' I can receive the messages sent from Android on my app server but the ratio is 50% whereas Android device gives a successful onMessageSent event.
The server side code is:
try {
using (var cl = new XmppClient("fcm-xmpp.googleapis.com", "Username", "Password", 5236, Sharp.Xmpp.Core.TLSMode.TLSSocket)) {
// Setup any event handlers before connecting.
cl.Message += OnNewMessage;
// Connect and authenticate with the server.
cl.Connect();
SendPushNotification("Connected");
cl.Close(); }
}
catch (InvalidOperationException ex) { SendPushNotification("Error Invalid: " + ex); }
catch (IOException ex) { SendPushNotification("Error IO: " + ex); }
catch (XmppException ex) { SendPushNotification("Error XMPP: " + ex); }
catch (NullReferenceException ex) { SendPushNotification("Error Null: " + ex); }
New Message Received event is
private void OnNewMessage(object sender, Sharp.Xmpp.Im.MessageEventArgs e) {
SendPushNotification("Message from " + e.Jid + " " + e.Message.Body);
div_View_Message.InnerHtml = "Message xyz " + e.Message.Body.ToString();
//throw new NotImplementedException();
}
and the SendPushNotification(String str) is Downstream messages with HTTP protocol. Android Device receives a push notification of 'connected' fine but the 'e.Message.Body' is received at times and not others. What should be added/removed?
Android Sends the messages as
FirebaseMessaging.getInstance().send(new RemoteMessage.Builder("SENDER_ID#gcm.googleapis.com")
.setMessageId(Integer.toString(INT_VALUE)).addData("my_token", str).build());
As mentioned in the accepted answer to this question, XMPP must stay open at all times. Hence, switching for Web based application, that closes the connection after every few requests per second, to a Desktop application, hosted on a local server, solved the issue.
Also, it adding setTtl(86400); for message sending ensures onMessageSent call.
Related
I have built a chat application using an Openfire (xmpp) server. One-to-one person chats are working fine and the messages are delivered instantly. But when we send a message inside a group, the first message gets delayed and the second message is delivered instantly.
MultiUserChatManager groupChat =
MultiUserChatManager.getInstanceFor(connection).getMultiUserChat("group_name");
groupChat.send("Message object");
Why is the first message getting delayed?
MUC Creation is
MultiUserChatManager mchatManager = MultiUserChatManager.getInstanceFor(xmpptcpConnection);
MultiUserChat mchat = mchatManager.getMultiUserChat(group);
if (!mchat.isJoined()) {
Log.d("CONNECT", "Joining room !! " + group + " and username " + username);
boolean createNow = false;
try {
mchat.createOrJoin(username);
createNow = true;
} catch (Exception e) {
Log.d("CONNECT", "Error while creating the room " + group + e.getMessage());
}
if (createNow) {
Form form = mchat.getConfigurationForm();
Form submitForm = form.createAnswerForm();
List<FormField> formFieldList = submitForm.getFields();
for (FormField formField : formFieldList) {
if(!FormField.Type.hidden.equals(formField.getType()) && formField.getVariable() != null) {
submitForm.setDefaultAnswer(formField.getVariable());
}
}
submitForm.setAnswer("muc#roomconfig_persistentroom", true);
submitForm.setAnswer("muc#roomconfig_publicroom", true);
mchat.sendConfigurationForm(submitForm);
//mchat.sendConfigurationForm(
// new Form(DataForm.Type.submit)); //this is to create the room immediately after join.
}
}
Log.d("CONNECT", "Room created!!");
return true;
} catch (SmackException e) {
e.printStackTrace();
} catch (XMPPException.XMPPErrorException e) {
e.printStackTrace();
}
There's an issue about creation and a kind of side-effect propagated on sending.
I think simply that you need to join the chat the first time since you didn't before and the first message also activate the Groupchat on server, so the first message it's delayed because you didn't finalized the multiuserchat creation.
How to fix.
In creation phase, this part must be improved:
if (!mchat.isJoined()) {
Log.d("CONNECT", "Joining room !! " + group + " and username " + username);
boolean createNow = false;
try {
mchat.createOrJoin(username);
createNow = true;
} catch (Exception e) {
Log.d("CONNECT", "Error while creating the room " + group + e.getMessage());
}
With just:
boolean createNow
try
{
if (!mchat.isJoined())
{
createNow = mchat.createOrJoin(username);
}
}
catch (Exception e)
{
throw new Exception("ERROR!");
}
and after this invokation:
mchat.sendConfigurationForm(submitForm);
add:
if (!mchat.isJoined()) {
mchat.join(username);
}
creationOrJoin method it's about creation OR join (as name says): to activate the chat, you must join it after the creation phase.
However createOrJoin has maybe an unexpected behaviour due a double check about already joined rooms to keep syncro between session in client and session on server, so the mchat.join() must be invoked after.
An explicit name can sounds like: mustCreateBeforeOrCanJoinDirectly()
I'm new to asmack and openfire, looked a lot for a working answer to this but couldn't find it anywhere. How do I retrieve offline messages on Logging into my account on asmack?
I've used the following code:
configure(ProviderManager.getInstance()); //configuring providers before creating a connection
ConnectionConfiguration connConfig = new ConnectionConfiguration(HOST, PORT);
connConfig.setSendPresence(false);
connection = new XMPPConnection (connConfig);
try {
connection.connect();
} catch (XMPPException ex) {
setConnection(null);
}
try {
connection.login(username, password);
try {
OfflineMessageManager offlineManager = new OfflineMessageManager(
connection);
Iterator<org.jivesoftware.smack.packet.Message> it = offlineManager
.getMessages();
System.out.println(offlineManager.supportsFlexibleRetrieval());
System.out.println("Number of offline messages:: " + offlineManager.getMessageCount());
Map<String,ArrayList<Message>> offlineMsgs = new HashMap<String,ArrayList<Message>>();
while (it.hasNext()) {
org.jivesoftware.smack.packet.Message message = it.next();
System.out
.println("receive offline messages, the Received from [" + message.getFrom()
+ "] the message:" + message.getBody());
String fromUser = message.getFrom().split("/")[0];
if(offlineMsgs.containsKey(fromUser))
{
offlineMsgs.get(fromUser).add(message);
}else{
ArrayList<Message> temp = new ArrayList<Message>();
temp.add(message);
offlineMsgs.put(fromUser, temp);
}
}
// Deal with a collection of offline messages ...
offlineManager.deleteMessages();
} catch (Exception e) {
Log.e("CATCH","OFFLINE");
e.printStackTrace();
}
Presence presence = new Presence(Presence.Type.available);
connection.sendPacket(presence);
setConnection(connection);//Packet Listener
// Set the status to available
} catch (XMPPException ex) {
setConnection(null);
}
From what I've read, once a connection is established, Openfire automatically sends offline messages to the user. (if any) Which means that by just setting packet listeners after logging in, I should be able to retrieve the messages. However, this didn't work for me. Which's why I tried using OfflineMessageManager. It always shows 0 messages as the message count though. I even logged in to the mysql db which the server's using and checked the offline messages folder. The messages exist till the user logs in, which means that the messages are being sent but it isn't being retrieved by the app. I can't seem to find out how implement this. If anyone has a working solution, It'd be greatly appreciated.
i partially solved added a packet listener after login but the same problem persist when internet go down. in that case i intercept reconnectionSuccessful event and remove and add again the packet listener but the messages sent when the user was offline is lost .
Somebody have the best solution to solve it?
Send your presence afetr logging in to the XMPP server. You have forgot to add packetListener which listens for the upcoming offline messages.
Hope this works.
Has anyone been able to add custom commands in the ChromeCast API? I was successful in getting the TicTacToe example working with my developer ID as well as modified Protocol string (changed on both the client and server).
On the Android side, I have the existing "join" command which works, and I am adding a new "image" command:
public final void join(String name) {
try {
Log.d(TAG, "join: " + name);
JSONObject payload = new JSONObject();
payload.put(KEY_COMMAND, KEY_JOIN);
payload.put(KEY_NAME, name);
sendMessage(payload);
} catch (JSONException e) {
Log.e(TAG, "Cannot create object to join a game", e);
} catch (IOException e) {
Log.e(TAG, "Unable to send a join message", e);
} catch (IllegalStateException e) {
Log.e(TAG, "Message Stream is not attached", e);
}
}
public final void sendImage(String sURL) {
try {
Log.d(TAG, "sendImage");
JSONObject payload = new JSONObject();
payload.put(KEY_COMMAND, KEY_IMAGE);
payload.put(KEY_URL, sURL);
sendMessage(payload);
} catch (JSONException e) {
Log.e(TAG, "Cannot create object to send image", e);
} catch (IOException e) {
Log.e(TAG, "Unable to send an image message", e);
} catch (IllegalStateException e) {
Log.e(TAG, "Message Stream is not attached", e);
}
}
If I call the join command, it works fine and I can see the message logged through the console in the browser. But if I call the sendImage function, I get the following error:
"onEnded failed to connect channel: protocol error"
On the ChromeCast side, I can see when a valid command is received. This function is getting called when I send the join command, but not when I send my custom "image" command.
/**
* Message received event; determines event message and command, and
* choose function to call based on them.
* #param {event} event the event to be processed.
*/
onMessage: function(event) {
console.log('***== pre onMessage ==***');
var message = event.message;
var channel = event.target;
console.log('********onMessage********' + JSON.stringify(message));
console.log('mPlayer1: ' + this.mPlayer1);
console.log('mPlayer2: ' + this.mPlayer2);
if (message.command == 'join') {
this.onJoin(channel, message);
} else if (message.command == 'leave') {
this.onLeave(channel);
} else if (message.command == 'move') {
this.onMove(channel, message);
} else if (message.command == 'queue_layout_request') {
this.onQueueLayoutRequest(channel);
} else if (message.command == 'image') {
this.onImage(channel, message);
} else if (message.command == 'video') {
this.onVideo(channel, message);
} else if (message.command == 'song') {
this.onSong(channel, message);
} else {
cast.log.error('Invalid message command: ' + message.command);
}
},
Any ideas? Is there somewhere else where I need to define my custom commands?
EDITED: also showing the onImage prototype:
/**
* Image event: display an image
* #param {cast.receiver.channel} channel the source of the move, which
* determines the player.
* #param {Object|string} message contains the URL of the image
*/
onImage: function(channel, message) {
console.log('****onImage: ' + JSON.stringify(message));
//Hide video and show image
mVideo.style.visibility='hidden';
mImage.style.visibility='visible';
mImage.src = message.url;
},
That usually means there was a JavaScript error in your receiver. Open Chrome on port 9222 at the IP address of your ChromeCast device and use the Chrome developer tools to debug the issue.
Did you declare a new function "onImage" in your receiver prototype for the message handler?
I'm developing an Android real-time-data app that sends data (floats and ints) to a server on the local subnet via a TCP socket. The problem I'm facing is that after sending some data simultaneously the socket doesn't send anymore data at all. I debugged the app and it shows that data is being sent but doesn't show up on the server. After this happens if I close the connection the server doesn't even get the notification that the connection has been terminated which it should according to my design model. Meanwhile I get an exception on the app saying it can not write to a broken pipe. This tells me that the problem is with the app because I also did test using a desktop app and I can send huge amounts of data to the server and it gets delivered.
And please keep in mind that the data size I'm talking about here is 252 bytes per packet.
Here's my class I'm using. (This runs in an AsyncTask object )
public class Network
{
private Socket handle;
public static enum TASK
{
TASK_CONNECT, TASK_SEND, TASK_CLOSE
}
public Network()
{
}
public String lastError = "";
public boolean Connect(String host, int port)
{
try
{
lastError = "Connecting to server.";
handle = new Socket(host, port);
handle.setTcpNoDelay(true); //
handle.setSendBufferSize(SIZE_OF_PACKET); ///==> These don't seem to help at all
handle.setKeepAlive(true); ///
return true;
}catch(IOException e)
{
lastError += e.getMessage() != null ? " "+ e.getMessage() : "";
return false;
}
}
private void err(String e){
System.err.println(e);
}
private boolean SendPacket(byte buffer[])
{
OutputStream oStream = null;
err("sending: " + buffer.length + " bytes");
try
{
lastError = "Obtaining output stream.";
oStream = handle.getOutputStream();
lastError = "Error sending data.";
oStream.write(buffer);
oStream.flush();
return true;
}catch(Exception e)
{
lastError += e.getMessage() != null ? " "+ e.getMessage() : "";
}
return false;
}
public void Close()
{
try{ handle.close(); handle = null; }catch(Exception e){} // swallow exception
}
}
I send my data in a loop depending on how many numbers I have. I tried a Google search but didn't find anything relevant. Has anyone experienced this before? It's making me mad now.
EDIT: Wireshark shows incoming "red" packets that don't reach the desktop app (server)
Look at this picture.
You can see the first few have Len > 0 the red ones have 0.
I think it's time Google interfaced the USB so we can use it. At least that'd would have been my first option.
Should you not be calling oStream.close() after you flush the stream, given that you never use it again?
Also, you say that this is being run in an AsyncTask object. Is it possible that multiple threads could be attempting to send packets at the same time? If so, you might need some form of synchronisation around the SendPacket method.
Ok. I solved the issue by using UDP instead. Thank you all.
But I still didn't find the source of the problem.
I'm trying to connect my android application to my oracle 10g DB, i'm using JDK 1.6, OJDBC14.jar and working on a 4.+ application. I used to have a few problem with the driver but here comes the best one : after excecuting this code :
String url="jdbc:oracle:thin:usr/pwd#r2d2.iut-orsay.u-psud.fr:1521:etudom";
Connection co = null;
try {
Class.forName("oracle.jdbc.OracleDriver");
popUp("Driver Ok");
}
// Should never happend
catch (ClassNotFoundException e){
popUp("ERROR: Driver's missing");
//System.exit(1);
}
// Unknow problem
catch (Exception e){
popUp("ERROR : " + e.getMessage() + "\nFrom: " + e.getCause());
}
try {
co = DriverManager.getConnection(url);
popUp("Connection ok");
}
// In case of internet problem
catch (SQLException e) {
popUp("Throw from SQLException\nERROR : " + e.getMessage());
//System.exit(1);
}
// unknown problem
catch (Exception e){
popUp("ERROR from getConnection :\nMessage: " + e.getMessage() + "\nFrom: " + e.getCause() + "\nMessage extra: "+e.getLocalizedMessage());
}
And I've got a popUp like that :
ERROR from getConnection :
Message: null
From: null
Message extra: null
No output in the log or in the console.
I'm literaly lost
Any help would be great!
Ps: sorry for my bad english.
The reason why you are not able to connect the device to your Oracle DB is, mobile devices are not equipped to carry out such actions as they are not built with drivers for the vast amount of Databases that are out there. However, in order to connect your app to the Oracle DB you have to create what is called a Web Service or an API to get the job done. Check out these tutorials they should get you rolling:
How to connect Android with PHP, MySQL (the concept here is the same, just use your Oracle DB instead)
Oracle Mobile Database server
Android to Oracle connectivity through java