diff --git a/src/main/java/com/github/nkzawa/socketio/client/Socket.java b/src/main/java/com/github/nkzawa/socketio/client/Socket.java index 9ea09ac..f2b4390 100644 --- a/src/main/java/com/github/nkzawa/socketio/client/Socket.java +++ b/src/main/java/com/github/nkzawa/socketio/client/Socket.java @@ -5,9 +5,8 @@ import com.github.nkzawa.socketio.parser.Packet; import com.github.nkzawa.socketio.parser.Parser; import com.google.gson.Gson; import com.google.gson.JsonArray; -import com.google.gson.reflect.TypeToken; +import com.google.gson.JsonElement; -import java.lang.reflect.Type; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; @@ -82,11 +81,11 @@ public class Socket extends Emitter { LinkedList _args = new LinkedList(Arrays.asList(args)); if (_args.peekLast() instanceof Ack) { Ack ack = (Ack)_args.pollLast(); - return this.emit(event, ack, _args.toArray()); + return this.emit(event, _args.toArray(), ack); } _args.offerFirst(event); - Packet packet = new Packet(Parser.EVENT, gson.toJsonTree(_args.toArray())); + Packet packet = new Packet(Parser.EVENT, toJsonArray(_args)); this.packet(packet); } @@ -94,19 +93,19 @@ public class Socket extends Emitter { } /** - * An alias method for `emit` with `ack` + * emit with an ack callback * * @param event - * @param ack * @param args + * @param ack * @return */ - public Emitter emit(final String event, Ack ack, final Object... args) { + public Emitter emit(final String event, final Object[] args, Ack ack) { List _args = new ArrayList() {{ add(event); addAll(Arrays.asList(args)); }}; - Packet packet = new Packet(Parser.EVENT, gson.toJsonTree(_args.toArray())); + Packet packet = new Packet(Parser.EVENT, toJsonArray(_args)); int ids = this.ids.getAndIncrement(); logger.info(String.format("emitting packet with ack id %d", ids)); @@ -138,14 +137,13 @@ public class Socket extends Emitter { this.subs.add(On.on(io, Manager.EVENT_PACKET, new Listener() { @Override public void call(Object... objects) { - Packet packet = objects.length > 0 ? (Packet)objects[0] : null; - Socket.this.onpacket(packet); + Socket.this.onpacket((Packet)objects[0]); } })); this.subs.add(On.on(io, Manager.EVENT_CLOSE, new Listener() { @Override public void call(Object... objects) { - String reason = objects.length > 0 ? (String)objects[0] : null; + String reason = objects.length > 0 ? (String) objects[0] : null; Socket.this.onclose(reason); } })); @@ -185,8 +183,7 @@ public class Socket extends Emitter { } private void onevent(Packet packet) { - Type type = new TypeToken>(){}.getType(); - LinkedList args = gson.fromJson(packet.data != null ? packet.data : new JsonArray(), type); + LinkedList args = new LinkedList(fromJsonArray(packet.data.getAsJsonArray())); logger.info(String.format("emitting event %s", args)); if (packet.id >= 0) { @@ -221,7 +218,7 @@ public class Socket extends Emitter { private void onack(Packet packet) { logger.info(String.format("calling ack %s with %s", packet.id, packet.data)); Ack fn = this.acks.remove(packet.id); - fn.call(gson.fromJson(packet.data, Object[].class)); + fn.call(fromJsonArray(packet.data.getAsJsonArray()).toArray()); } private void onconnect() { @@ -273,6 +270,22 @@ public class Socket extends Emitter { return this.close(); } + private static JsonArray toJsonArray(List list) { + JsonArray data = new JsonArray(); + for (Object v : list) { + data.add(v instanceof JsonElement ? (JsonElement)v : gson.toJsonTree(v)); + } + return data; + } + + private static List fromJsonArray(JsonArray array) { + List data = new ArrayList(); + for (JsonElement v : array) { + data.add(v.isJsonPrimitive() ? gson.fromJson(v, Object.class) : v); + } + return data; + } + public static interface Ack { diff --git a/src/test/java/com/github/nkzawa/socketio/client/IOTest.java b/src/test/java/com/github/nkzawa/socketio/client/IOTest.java index be5da7d..7ed701c 100644 --- a/src/test/java/com/github/nkzawa/socketio/client/IOTest.java +++ b/src/test/java/com/github/nkzawa/socketio/client/IOTest.java @@ -1,6 +1,8 @@ package com.github.nkzawa.socketio.client; import com.github.nkzawa.emitter.Emitter; +import com.google.gson.Gson; +import com.google.gson.JsonElement; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -11,6 +13,8 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.*; import static org.hamcrest.CoreMatchers.is; @@ -110,7 +114,7 @@ public class IOTest { @Test(timeout = TIMEOUT) public void message() throws URISyntaxException, InterruptedException { - final BlockingQueue events = new LinkedBlockingQueue(); + final BlockingQueue events = new LinkedBlockingQueue(); IO.Options opts = new IO.Options(); opts.forceNew = true; @@ -119,19 +123,82 @@ public class IOTest { @Override public void call(Object... objects) { System.out.println("connect:"); - socket.send("hi"); + socket.send("foo", "bar"); } }).on(Socket.EVENT_MESSAGE, new Emitter.Listener() { @Override public void call(Object... objects) { - System.out.println("message: " + objects); - events.offer((String) objects[0]); + System.out.println(String.format( + objects.length > 1 ? "message: %s, %s" : "message: %s", objects)); + events.offer(objects); } }); socket.connect(); - assertThat(events.take(), is("hello client")); - assertThat(events.take(), is("hi")); + assertThat(events.take(), is(new Object[] {"hello client"})); + assertThat(events.take(), is(new Object[] {"foo", "bar"})); + socket.disconnect(); + } + + @Test(timeout = TIMEOUT) + public void event() throws URISyntaxException, InterruptedException { + final BlockingQueue events = new LinkedBlockingQueue(); + + Map data = new HashMap() {{ + put("foo", "1"); + }}; + final JsonElement jsonData = new Gson().toJsonTree(data, Map.class); + + IO.Options opts = new IO.Options(); + opts.forceNew = true; + socket = IO.socket("http://localhost:" + PORT, opts); + socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() { + @Override + public void call(Object... objects) { + System.out.println("connect:"); + socket.emit("echo", jsonData, "bar"); + } + }).on("echoBack", new Emitter.Listener() { + @Override + public void call(Object... objects) { + System.out.println(String.format("echoBack: %s, %s", objects)); + events.offer(objects); + } + }); + socket.connect(); + + assertThat(events.take(), is(new Object[] {jsonData, "bar"})); + socket.disconnect(); + } + + @Test(timeout = TIMEOUT) + public void ack() throws URISyntaxException, InterruptedException { + final BlockingQueue events = new LinkedBlockingQueue(); + + Map data = new HashMap() {{ + put("foo", "1"); + }}; + final JsonElement jsonData = new Gson().toJsonTree(data, Map.class); + + IO.Options opts = new IO.Options(); + opts.forceNew = true; + socket = IO.socket("http://localhost:" + PORT, opts); + socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() { + @Override + public void call(Object... objects) { + System.out.println("connect:"); + socket.emit("ack", new Object[] {jsonData, "bar"}, new Socket.Ack() { + @Override + public void call(Object... args) { + System.out.println(String.format("ack: %s, %s", args)); + events.offer(args); + } + }); + } + }); + socket.connect(); + + assertThat(events.take(), is(new Object[] {jsonData, "bar"})); socket.disconnect(); } } diff --git a/src/test/resources/index.js b/src/test/resources/index.js index ea558c0..7c2fd39 100644 --- a/src/test/resources/index.js +++ b/src/test/resources/index.js @@ -5,14 +5,23 @@ var server = require('http').Server() io.on('connection', function(socket) { socket.send('hello client'); - socket.on('message', function(data) { - console.log('message:', data); - socket.send(data); + socket.on('message', function() { + var args = Array.prototype.slice.call(arguments); + console.log('message:', args); + socket.send.apply(socket, args); }); - socket.on('echo', function(data) { - console.log('echo:', data); - socket.emit('echoBack', data); + socket.on('echo', function() { + var args = Array.prototype.slice.call(arguments); + console.log('echo:', args); + socket.emit.apply(socket, ['echoBack'].concat(args)); + }); + + socket.on('ack', function() { + var args = Array.prototype.slice.call(arguments), + callback = args.pop(); + console.log('ack:', args); + callback.apply(null, args); }); socket.on('disconnect', function() {