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;
this.encoder.encode(packet, new Parser.Encoder.Callback() {
@Override
public void call(String[] encodedPackets) {
for (int i = 0; i < encodedPackets.length; i++) {
self.engine.write(encodedPackets[i]);
public void call(Object[] encodedPackets) {
for (Object packet : encodedPackets) {
if (packet instanceof String) {
self.engine.write((String)packet);
} else if (packet instanceof byte[]) {
self.engine.write((byte[])packet);
}
}
self.encoding = false;
self.processPacketQueue();

View File

@@ -134,26 +134,26 @@ public class Socket extends Emitter {
* @return a reference to this object.
*/
@Override
public Emitter emit(final String event, final Object... arguments) {
public Emitter emit(final String event, final Object... args) {
EventThread.exec(new Runnable() {
@Override
public void run() {
if (events.containsKey(event)) {
Socket.super.emit(event, arguments);
Socket.super.emit(event, args);
return;
}
List<Object> args = new ArrayList<Object>(arguments.length + 1);
args.add(event);
args.addAll(Arrays.asList(arguments));
JSONArray _args = new JSONArray(args);
List<Object> _args = new ArrayList<Object>(args.length + 1);
_args.add(event);
_args.addAll(Arrays.asList(args));
JSONArray jsonArgs = new JSONArray(_args);
int parserType = Parser.EVENT;
if (HasBinaryData.hasBinary(_args)) { parserType = Parser.BINARY_EVENT; }
Packet packet = new Packet(parserType, _args);
if (HasBinaryData.hasBinary(jsonArgs)) { parserType = Parser.BINARY_EVENT; }
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));
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++;
}

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 java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;
@@ -113,12 +114,17 @@ public class Parser {
}
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 void call(String[] data);
public void call(Object[] data);
}
}
@@ -242,7 +248,10 @@ public class Parser {
public Packet takeBinaryData(byte[] binData) {
this.buffers.add(binData);
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;
}

View File

@@ -6,6 +6,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.nio.charset.Charset;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@@ -16,21 +18,21 @@ public class ParserTest {
@Test
public void connect() {
public void encodeConnection() {
Packet packet = new Packet(Parser.CONNECT);
packet.nsp = "/woot";
test(packet);
}
@Test
public void disconnect() {
public void encodeDisconnect() {
Packet packet = new Packet(Parser.DISCONNECT);
packet.nsp = "/woot";
test(packet);
}
@Test
public void event() {
public void encodeEvent() {
Packet packet1 = new Packet(Parser.EVENT);
packet1.data = new JSONTokener("[\"a\", 1, {}]").nextValue();
packet1.nsp = "/";
@@ -43,7 +45,7 @@ public class ParserTest {
}
@Test
public void ack() {
public void encodeAck() {
Packet packet = new Packet(Parser.ACK);
packet.data = new JSONTokener("[\"a\", 1, {}]").nextValue();
packet.id = 123;
@@ -51,10 +53,19 @@ public class ParserTest {
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) {
encoder.encode(obj, new Parser.Encoder.Callback() {
@Override
public void call(String[] encodedPackets) {
public void call(Object[] encodedPackets) {
Parser.Decoder decoder = new Parser.Decoder();
decoder.on(Parser.Decoder.EVENT_DECODED, new Emitter.Listener() {
@Override
@@ -71,7 +82,39 @@ public class ParserTest {
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);
}
}
}
});
}