support binary

This commit is contained in:
Naoyuki Kanezawa
2014-04-08 02:27:58 +09:00
parent e24ed3062b
commit 5884537431
5 changed files with 174 additions and 22 deletions

View File

@@ -348,9 +348,13 @@ public class Manager extends Emitter {
self.encoding = true; self.encoding = true;
this.encoder.encode(packet, new Parser.Encoder.Callback() { this.encoder.encode(packet, new Parser.Encoder.Callback() {
@Override @Override
public void call(String[] encodedPackets) { public void call(Object[] encodedPackets) {
for (int i = 0; i < encodedPackets.length; i++) { for (Object packet : encodedPackets) {
self.engine.write(encodedPackets[i]); if (packet instanceof String) {
self.engine.write((String)packet);
} else if (packet instanceof byte[]) {
self.engine.write((byte[])packet);
}
} }
self.encoding = false; self.encoding = false;
self.processPacketQueue(); self.processPacketQueue();

View File

@@ -134,26 +134,26 @@ public class Socket extends Emitter {
* @return a reference to this object. * @return a reference to this object.
*/ */
@Override @Override
public Emitter emit(final String event, final Object... arguments) { public Emitter emit(final String event, final Object... args) {
EventThread.exec(new Runnable() { EventThread.exec(new Runnable() {
@Override @Override
public void run() { public void run() {
if (events.containsKey(event)) { if (events.containsKey(event)) {
Socket.super.emit(event, arguments); Socket.super.emit(event, args);
return; return;
} }
List<Object> args = new ArrayList<Object>(arguments.length + 1); List<Object> _args = new ArrayList<Object>(args.length + 1);
args.add(event); _args.add(event);
args.addAll(Arrays.asList(arguments)); _args.addAll(Arrays.asList(args));
JSONArray _args = new JSONArray(args); JSONArray jsonArgs = new JSONArray(_args);
int parserType = Parser.EVENT; int parserType = Parser.EVENT;
if (HasBinaryData.hasBinary(_args)) { parserType = Parser.BINARY_EVENT; } if (HasBinaryData.hasBinary(jsonArgs)) { parserType = Parser.BINARY_EVENT; }
Packet packet = new Packet(parserType, _args); Packet packet = new Packet(parserType, jsonArgs);
if (args.get(args.size() - 1) instanceof Ack) { if (_args.get(_args.size() - 1) instanceof Ack) {
logger.fine(String.format("emitting packet with ack id %d", Socket.this.ids)); logger.fine(String.format("emitting packet with ack id %d", Socket.this.ids));
Socket.this.acks.put(Socket.this.ids, (Ack)args.remove(args.size() - 1)); Socket.this.acks.put(Socket.this.ids, (Ack)_args.remove(_args.size() - 1));
packet.id = Socket.this.ids++; packet.id = Socket.this.ids++;
} }

View File

@@ -0,0 +1,96 @@
package com.github.nkzawa.socketio.parser;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Binary {
private static final String KEY_PLACEHOLDER = "_placeholder";
private static final String KEY_NUM = "num";
public static DeconstructedPacket deconstructPacket(Packet packet) {
List<byte[]> buffers = new ArrayList<byte[]>();
packet.data = deconstructBinPackRecursive(packet.data, buffers);
packet.attachments = buffers.size();
DeconstructedPacket result = new DeconstructedPacket();
result.packet = packet;
result.buffers = buffers.toArray(new byte[buffers.size()][]);
return result;
}
private static Object deconstructBinPackRecursive(Object data, List<byte[]> buffers) {
if (data == null) return null;
if (data instanceof byte[]) {
JSONObject placeholder = new JSONObject();
placeholder.put(KEY_PLACEHOLDER, true);
placeholder.put(KEY_NUM, buffers.size());
buffers.add((byte[])data);
return placeholder;
} else if (data instanceof JSONArray) {
JSONArray newData = new JSONArray();
JSONArray _data = (JSONArray)data;
int len = _data.length();
for (int i = 0; i < len; i ++) {
newData.put(i, deconstructBinPackRecursive(_data.get(i), buffers));
}
return newData;
} else if (data instanceof JSONObject) {
JSONObject newData = new JSONObject();
JSONObject _data = (JSONObject)data;
Iterator<?> iterator = _data.keys();
while (iterator.hasNext()) {
String key = (String)iterator.next();
newData.put(key, deconstructBinPackRecursive(_data.get(key), buffers));
}
return newData;
}
return data;
}
public static Packet reconstructPacket(Packet packet, byte[][] buffers) {
packet.data = reconstructBinPackRecursive(packet.data, buffers);
packet.attachments = -1;
return packet;
}
private static Object reconstructBinPackRecursive(Object data, byte[][] buffers) {
if (data instanceof JSONArray) {
JSONArray _data = (JSONArray)data;
int len = _data.length();
for (int i = 0; i < len; i ++) {
_data.put(i, reconstructBinPackRecursive(_data.get(i), buffers));
}
return _data;
} else if (data instanceof JSONObject) {
JSONObject _data = (JSONObject)data;
if (_data.optBoolean(KEY_PLACEHOLDER)) {
int num = _data.optInt(KEY_NUM, -1);
return num >= 0 && num < buffers.length ? buffers[num] : null;
}
Iterator<?> iterator = _data.keys();
while (iterator.hasNext()) {
String key = (String)iterator.next();
_data.put(key, reconstructBinPackRecursive(_data.get(key), buffers));
}
return _data;
}
return data;
}
public static class DeconstructedPacket {
public Packet packet;
public byte[][] buffers;
}
}

View File

@@ -5,6 +5,7 @@ import org.json.JSONException;
import org.json.JSONTokener; import org.json.JSONTokener;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -113,12 +114,17 @@ public class Parser {
} }
private void encodeAsBinary(Packet obj, Callback callback) { private void encodeAsBinary(Packet obj, Callback callback) {
// TODO Binary.DeconstructedPacket deconstruction = Binary.deconstructPacket(obj);
String pack = encodeAsString(deconstruction.packet);
List<Object> buffers = new ArrayList<Object>(Arrays.asList(deconstruction.buffers));
buffers.add(0, pack);
callback.call(buffers.toArray());
} }
public interface Callback { public interface Callback {
public void call(String[] data); public void call(Object[] data);
} }
} }
@@ -242,7 +248,10 @@ public class Parser {
public Packet takeBinaryData(byte[] binData) { public Packet takeBinaryData(byte[] binData) {
this.buffers.add(binData); this.buffers.add(binData);
if (this.buffers.size() == this.reconPack.attachments) { if (this.buffers.size() == this.reconPack.attachments) {
// TODO: Packet packet = Binary.reconstructPacket(this.reconPack,
this.buffers.toArray(new byte[this.buffers.size()][]));
this.finishReconstruction();
return packet;
} }
return null; return null;
} }

View File

@@ -6,6 +6,8 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.JUnit4; import org.junit.runners.JUnit4;
import java.nio.charset.Charset;
import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
@@ -16,21 +18,21 @@ public class ParserTest {
@Test @Test
public void connect() { public void encodeConnection() {
Packet packet = new Packet(Parser.CONNECT); Packet packet = new Packet(Parser.CONNECT);
packet.nsp = "/woot"; packet.nsp = "/woot";
test(packet); test(packet);
} }
@Test @Test
public void disconnect() { public void encodeDisconnect() {
Packet packet = new Packet(Parser.DISCONNECT); Packet packet = new Packet(Parser.DISCONNECT);
packet.nsp = "/woot"; packet.nsp = "/woot";
test(packet); test(packet);
} }
@Test @Test
public void event() { public void encodeEvent() {
Packet packet1 = new Packet(Parser.EVENT); Packet packet1 = new Packet(Parser.EVENT);
packet1.data = new JSONTokener("[\"a\", 1, {}]").nextValue(); packet1.data = new JSONTokener("[\"a\", 1, {}]").nextValue();
packet1.nsp = "/"; packet1.nsp = "/";
@@ -43,7 +45,7 @@ public class ParserTest {
} }
@Test @Test
public void ack() { public void encodeAck() {
Packet packet = new Packet(Parser.ACK); Packet packet = new Packet(Parser.ACK);
packet.data = new JSONTokener("[\"a\", 1, {}]").nextValue(); packet.data = new JSONTokener("[\"a\", 1, {}]").nextValue();
packet.id = 123; packet.id = 123;
@@ -51,10 +53,19 @@ public class ParserTest {
test(packet); test(packet);
} }
@Test
public void encodeBytes() {
Packet packet = new Packet(Parser.BINARY_EVENT);
packet.data = "abc".getBytes(Charset.forName("UTF-8"));
packet.id = 23;
packet.nsp = "/cool";
testBin(packet);
}
private void test(final Packet obj) { private void test(final Packet obj) {
encoder.encode(obj, new Parser.Encoder.Callback() { encoder.encode(obj, new Parser.Encoder.Callback() {
@Override @Override
public void call(String[] encodedPackets) { public void call(Object[] encodedPackets) {
Parser.Decoder decoder = new Parser.Decoder(); Parser.Decoder decoder = new Parser.Decoder();
decoder.on(Parser.Decoder.EVENT_DECODED, new Emitter.Listener() { decoder.on(Parser.Decoder.EVENT_DECODED, new Emitter.Listener() {
@Override @Override
@@ -71,7 +82,39 @@ public class ParserTest {
assertThat(packet.attachments, is(obj.attachments)); assertThat(packet.attachments, is(obj.attachments));
} }
}); });
decoder.add(encodedPackets[0]); decoder.add((String)encodedPackets[0]);
}
});
}
private void testBin(final Packet obj) {
final Object originalData = obj.data;
encoder.encode(obj, new Parser.Encoder.Callback() {
@Override
public void call(Object[] encodedPackets) {
Parser.Decoder decoder = new Parser.Decoder();
decoder.on(Parser.Decoder.EVENT_DECODED, new Emitter.Listener() {
@Override
public void call(Object... args) {
Packet packet = (Packet)args[0];
obj.data = originalData;
obj.attachments = -1;
assertThat(packet.type, is(obj.type));
assertThat(packet.id, is(obj.id));
assertThat(packet.data, is(obj.data));
assertThat(packet.nsp, is(obj.nsp));
assertThat(packet.attachments, is(obj.attachments));
}
});
for (Object packet : encodedPackets) {
if (packet instanceof String) {
decoder.add((String)packet);
} else if (packet instanceof byte[]) {
decoder.add((byte[])packet);
}
}
} }
}); });
} }