I have been working in a chat app using nodejs and socket.io. I already have an Android client that works perfect in this schema. I started to use express.io instead of use express an socket.io separately. Everything works well except for my Android client. Im using https://github.com/socketio/socket.io-client-java socket client in Android, but my app never connect to my socket server.
I received the following error:
io.socket.engineio.client.EngineIOException: server error
Does anybody knows something about this issue?
Server side config:
var express = require('express.io');
var path = require('path');
var logger = require('morgan');
var bodyParser = require('body-parser');
var multer = require('multer');
var app = express();
app.http().io()
app.io.route('storeClientInfo', function(req) {
req.io.join(req.io.request.data.customId);
});
app.io.route('enviar_room', function(req) {
app.io.room(req.params.correo).broadcast('new visitor');
});
// Start the server
app.set('port', process.env.PORT || 3000);
var server = app.listen(app.get('port'), function() {
console.log('Express server listening on port ' + server.address().port);
});
Android side:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
mSocket = IO.socket(LoginActivity.URL_HOST);
mSocket.on(Socket.EVENT_CONNECT_ERROR, onConnectError);
mSocket.on("new visitor",onNuevoMensaje);
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
private Emitter.Listener onConnectError = new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.d("SocketMsg: ", args[0].toString());
for (Object o : args) {
Log.i("IO " + Socket.EVENT_CONNECT_ERROR, o.toString());
}
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(),
"CONNECT ERROR", Toast.LENGTH_LONG).show();
}
});
}
};
Currently I already have a Angularjs web version running with my server. The problem is that in Android i always received Socket.EVENT_CONNECT_ERROR.
After two days of tests I found that the problem was that Express.io include a socket.io version 0.9.6. The socket.io-client-java library (https://github.com/socketio/socket.io-client-java) support socket.io 1.x or later. I manually changed the socket.io version on Express.io to the 1.3.7 version. I just had to modify some parts of the code on the Express library.
Related
I successed to send ack to android client from nodejs server but I don't succeed to do reverse. I have this error: Callbacks are not supported when broadcasting at Socket.emit
Serveur nodejs:
socket.broadcast.to(socketid).emit('message', data, callThis);
//this function is executed when client calls it
function callThis (dataFromClient){
console.log("Call back fired: " + dataFromClient);
}
client android:
socket.on("message", new Emitter.Listener() {
#Override
public void call(Object... args) {
Ack ack = (Ack) args[args.length - 1];
ack.call();
JSONObject data = (JSONObject) args[0];
.....
}
}
What can I do to resolve this problem?
Basically support the answer of #Xeoncross. When a connection came, just saved the socket into a map, like below
this.connections = new Map<string, SocketIO.Socket>()
this.server.on("connection", (socket: SocketIO.Socket) => {
this.connections.set(socket.id, socket)
})
Then use a loop to send all users individually
public broadcast(msg: string) {
for(const socket of this.connections.values()) {
socket.emit("block", msg, (confirm: string) => {
console.log("confirmation msg: ", confirm)
})
}
}
As the error says, "Callbacks are not supported when broadcasting". It doesn't look like you are broadcasting though, as you are trying to send to a single client. So assuming socket is an actual client socket instance you can change your code:
socket.broadcast.to(socketid).emit('message', data, callThis);
to just send to that one person
socket.emit('message', data, callThis);
We setup socket.io in our node.js server. We try to use Socket.io Java Client and Socket.io iOS Client. We able to connect through iOS but we cannot able to connect through Android. We don't have any clue , why Android is not connecting.
Server Side:
var socketIO = require('socket.io');
//var io =
GLOBAL._io = socketIO(httpServer);
_io.on('connection', (socket) => {
console.log('Client connected');
setInterval(() => _io.emit('time', new Date().toTimeString()), 1000);
socket.on('disconnect', () => console.log('Client disconnected'));
});
Android Not Working
public void addSocketConnection() throws URISyntaxException {
Log.i("Socket.io","Init");
mSocket = IO.socket("http://dev.myapp.com/parse");
mSocket.on(Socket.EVENT_CONNECT,onConnect);
mSocket.on("time",onTime);
mSocket.on(Socket.EVENT_DISCONNECT,onDisconnect);
mSocket.on(Socket.EVENT_CONNECT_ERROR, onConnectError);
mSocket.on(Socket.EVENT_CONNECT_TIMEOUT, onConnectError);
mSocket.connect();
Log.i("Socket.io","Connect");
}
private Emitter.Listener onTime = new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.i("Socket.io","OnTime");
}
};
private Emitter.Listener onConnect = new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.i("Socket.io","OnConnect");
}
};
private Emitter.Listener onDisconnect = new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.i("Socket.io","DisConnect");
}
};
iOS Working
NSURL* url = [[NSURL alloc] initWithString:#"http://dev.myapp.com/parse"];
SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:url options:#{#"log": #YES, #"forcePolling": #YES}];
[socket on:#"connect" callback:^(NSArray* data, SocketAckEmitter* ack) {
NSLog(#"socket connected");
}];
[socket onAny:^(SocketAnyEvent *event) {
NSLog(#"On any event :%#",event.event);
}];
[socket on:#"time" callback:^(NSArray* data, SocketAckEmitter* ack) {
NSLog(#"Time %#",data[0]);
}];
[socket connect];
I have fixed and updated in github and forgot to update here.github issue link
A little bit confusion but fixed to work on both.
We have parse server URL : "http://dev.myapp.com/parse"
Our Node URL: "http://dev.myapp.com/"
By mistake we point to URL "http://dev.myapp.com/parse" for iOS, it is working.
So we point to the same URL for Android , it is not working.
Then we changed both urls to "http://dev.myapp.com", now working on both iOS and Android.
Note:
We have no clue why iOS is working for "http://dev.myapp.com/parse"
Software Stack:
Tomcat v7.0.62
Primefaces 5.0 application with Atmosphere (#PushEndpoint) - atmosphere-runtime v.2.1.3
External Android app with Atmosphere Wasync client v1.4.3
We have 2 separate applications. On the one hand, we have a PrimeFaces application that, among other things, send notifications. On the other hand, we have an independent android app. We're trying to figure out the best way for PF browser clients to send/receive messages with standalone android client using wAsync.
It seems that the android app is able to connect successfully. But, send notification with PF didn't have any effect, the app doesn't receive it, and there were no error messages on either android app or the server.
This is the primefaces code:
#PushEndpoint("/servicios")
public class ServiciosPushControlador implements ServiciosControladorListener {
#Override
#OnMessage(encoders = {JSONEncoder.class})
public String servicioActualizado(Servicio servicio) {
return "update";
}
}
And web.xml configuration for Atmosphere
<!-- PUSH PrimeFaces-->
<servlet>
<servlet-name>Push Servlet</servlet-name>
<servlet-class>org.primefaces.push.PushServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Push Servlet</servlet-name>
<url-pattern>/primepush/*</url-pattern>
</servlet-mapping>
And this is the Android code:
public <ResultType> void notificationSuscriber(Function<ResultType> succesFunction, Function<IOException> errorFunction, final Class<ResultType> clazz) throws IOException {
RequestBuilder request = client.newRequestBuilder()
.method(org.atmosphere.wasync.Request.METHOD.GET)
.uri("http://192.168.0.101:8080/calview/primepush/servicios")
.encoder(new Encoder<ResultType, String>() {
#Override
public String encode(ResultType s) {
try {
return mapper.writeValueAsString(s);
} catch (IOException iOEx) {
throw new RuntimeException(iOEx);
}
}
})
.decoder(new Decoder<String, ResultType>() {
#Override
public ResultType decode(Event e, String s) {
if (s.length() == 0)
return null;
if (e.equals(Event.MESSAGE)) {
try {
return new ObjectMapper().readValue(s, clazz);
} catch (IOException iOEx) {
iOEx.printStackTrace();
return null;
}
} else
return null;
}
})
.transport(org.atmosphere.wasync.Request.TRANSPORT.WEBSOCKET);
Socket socket = client.create();
socket.on("message", succesFunction)
.on(errorFunction)
.open(request.build());
}
i'm trying to write simple application with nodejs and express.io after reading some express.io document and successful connection to http://chat.socket.io i'm find simple sample for create server side with nodejs and express.io, after run this below code in command line and opening http://localhost:3000 in browser i dont get any error, i can not find any good document about coding in http://chat.socket.io server, now i want to try send request from android client to server with samples, but i get connection error:
Error:
CONNECTION ERROR
server.js:
// Setup basic express server
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('../..')(server);
var port = process.env.PORT || 3000;
server.listen(port, function () {
console.log('Server listening at port %d', port);
});
// Routing
app.use(express.static(__dirname + '/public'));
// Chatroom
// usernames which are currently connected to the chat
var usernames = {};
var numUsers = 0;
io.on('connection', function (socket) {
var addedUser = false;
// when the client emits 'new message', this listens and executes
socket.on('new message', function (data) {
// we tell the client to execute 'new message'
socket.broadcast.emit('new message', {
username: socket.username,
message: data
});
});
// when the client emits 'add user', this listens and executes
socket.on('add user', function (username) {
// we store the username in the socket session for this client
socket.username = username;
// add the client's username to the global list
usernames[username] = username;
++numUsers;
addedUser = true;
socket.emit('login', {
numUsers: numUsers
});
// echo globally (all clients) that a person has connected
socket.broadcast.emit('user joined', {
username: socket.username,
numUsers: numUsers
});
});
// when the client emits 'typing', we broadcast it to others
socket.on('typing', function () {
socket.broadcast.emit('typing', {
username: socket.username
});
});
// when the client emits 'stop typing', we broadcast it to others
socket.on('stop typing', function () {
socket.broadcast.emit('stop typing', {
username: socket.username
});
});
// when the user disconnects.. perform this
socket.on('disconnect', function () {
// remove the username from global usernames list
if (addedUser) {
delete usernames[socket.username];
--numUsers;
// echo globally that this client has left
socket.broadcast.emit('user left', {
username: socket.username,
numUsers: numUsers
});
}
});
});
my android code:
private Socket mSocket;
{
try {
/* connection successful to http://chat.socket.io */
mSocket = IO.socket("http://localhost:3000");
} catch (URISyntaxException e) {
Log.e("Error URI", String.valueOf(e));
throw new RuntimeException(e);
}
}
public void onCreate(Bundle savedInstanceState) {
...
mSocket.on(Socket.EVENT_CONNECT_ERROR, onConnectError);
mSocket.on(Socket.EVENT_CONNECT_TIMEOUT, onConnectError);
mSocket.on("new message", onNewMessage);
mSocket.on("user joined", onUserJoined);
mSocket.on("user left", onUserLeft);
mSocket.on("typing", onTyping);
mSocket.on("stop typing", onStopTyping);
mSocket.connect();
...
Button signInButton = (Button) findViewById(R.id.sign_in_button);
signInButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
attemptLogin();
}
});
mSocket.on("login", onLogin);
}
private void attemptLogin() {
mUsernameView.setError(null);
String username = mUsernameView.getText().toString().trim();
if (TextUtils.isEmpty(username)) {
mUsernameView.setError(getString(R.string.error_field_required));
mUsernameView.requestFocus();
return;
}
mUsername = username;
mSocket.emit("add user", username);
}
Android Error:
E/AndroidRuntime﹕ FATAL EXCEPTION: EventThread
java.lang.IllegalArgumentException: delay < 0: -432345566375051264
at java.util.Timer.schedule(Timer.java:457)
at com.github.nkzawa.socketio.client.Manager.reconnect(Manager.java:497)
at com.github.nkzawa.socketio.client.Manager.access$2000(Manager.java:20)
at com.github.nkzawa.socketio.client.Manager$8$1$1.call(Manager.java:519)
at com.github.nkzawa.socketio.client.Manager$1$3.call(Manager.java:282)
at com.github.nkzawa.emitter.Emitter.emit(Emitter.java:117)
at com.github.nkzawa.engineio.client.Socket.onError(Socket.java:754)
at com.github.nkzawa.engineio.client.Socket.access$800(Socket.java:29)
at com.github.nkzawa.engineio.client.Socket$4.call(Socket.java:293)
at com.github.nkzawa.emitter.Emitter.emit(Emitter.java:117)
at com.github.nkzawa.engineio.client.Transport.onError(Transport.java:63)
at com.github.nkzawa.engineio.client.transports.PollingXHR.access$100(PollingXHR.java:19)
at com.github.nkzawa.engineio.client.transports.PollingXHR$6$1.run(PollingXHR.java:126)
at com.github.nkzawa.thread.EventThread$2.run(EventThread.java:75)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:838)
I would blame this:
mSocket = IO.socket("http://localhost:3000");
I assume you are not running your node.js server on your android, but probably on your PC. If so, when testing on your android, you are trying to connect back on port 3000 to your android itself - as localhost links to device itself.
If you are using the same local network on your server and android, you should check your PC's IP and put it instead of localhost. If your server has public IP, you may want to use it instead.
edit
1
In other words, according to your comment: your PC IP is 192.168.1.5. As this is an internal IP, your android have to be connected to same sub-network your PC is, just because youre able to occur your connectin error. Basing to that, i assume you need to type http://192.168.1.5/ in adress bar in your android, to visit page your PC is serving. Assuming that, one remains nonchanged - the script "my android code" is running on your android. So instead of localhost there is required a proper host: 192.168.1.5. Cant tell if your android is blocking 3000 port, but localhost is improper from androids' point of view, as long as you are not running your nodejs server on that device.
Also that change may not take affect ad-hoc, during browser cache on mobile devices.
2
Looking into your code, I assume you will also occur some problems with users using same username. Yeah, sounds strange, but users may want to open few tabs in browser, connected to same socket server. Once that, your usernames and numUsers variables will corrupt.
As long as app is single-intance dedicated (eg. player#game), I would use
usernames[username] = socket
to store sockets aside, being able to post cross-player related events avoiding iteration over all opened sockets.
Also for chat-purposes, you may want to allow users being connected on few browser tabs at once. Usually I'm storing all sockets just this way:
if (!users[user]) {
users[user] = {
sockets: [socket]
};
console.log(sprintf('[%s] [CONNECTED] User %s', Date(), user));
} else {
users[user].sockets.push(socket);
}
your may be different, prolly based on chat-channels etc. Pushing sockets aside listeners allowed me to run separate UDP server in same node script file. It was in purpose of being able to monit/block/alert single user through all opened tabs, event if their are spread over two different browsers.
I'm working a project to integrate Stripe's payment service to my android app. I have the basic client code setup.
Card card = new Card("4242424242424242", 12, 2016, "123");
boolean validate = card.validateCard();
if (validate) {
try {
new Stripe(TEST_PUBLUSHABLE_KEY).createToken(card, new TokenCallback() {
#Override
public void onError(Exception e) {
System.out.println("ERROR");
}
#Override
public void onSuccess(Token token) {
System.out.println("SUCCESS");
}
});
} catch (AuthenticationException e) {
e.printStackTrace();
}
}
Now I need to setup a server, which I plan on using Node.js and Express. I followed their sample code on: https://stripe.com/docs/tutorials/charges
var express = require('express');
var bodyParser = require('body-parser');
var stripe = require('stripe')('sk_test_sGyqMsiFmf45xoZrDCy5ItcU'); // Test Secret Key
var app = express();
app.use(bodyParser());
app.post('/charge', function(req, res) {
var stripeToken = request.body.stripeToken;
var charge = stripe.charges.create({
amount: 1000, // amount in cents, again
currency: "cad",
card: stripeToken,
description: "payinguser#example.com"
},
function(err, charge) {
if (err && err.type === 'StripeCardError') {
console.log("The card has been declined");
}
});
});
app.use(express.static(__dirname + '/public'));
app.listen(3000);
I have never worked with servers, so I think I'm having trouble communicating between the android app and the server that is on my computer's localhost:3000.
According to Stripe's documentation, I need to have my server accept a HTTP POST call for the token, but I'm not quite sure how to do that.
Really appreciate your help.
Update #1:
Use Ultrahook to forward Stripe's POST to my localhost.
I use Node.js to setup my server, which receives all Stripe's requests and then get the information I need from the request body.
Still having trouble getting the onSuccess callback on Android to work, it always go to the onError callback.
Update #2:
Solved the onError callback error by printing the error message to console.
Permission denied (missing INTERNET permission?
Turns out I need to include this line to the AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
Link to the Stack Overflow post that solved this part of my problem:
What permission do I need to access Internet from an android application?