Skip to content

Commit 7279919

Browse files
committed
enable to implement custom parser
1 parent 0606865 commit 7279919

File tree

6 files changed

+279
-213
lines changed

6 files changed

+279
-213
lines changed

src/main/java/io/socket/client/Manager.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.socket.backo.Backoff;
44
import io.socket.emitter.Emitter;
5+
import io.socket.parser.IOParser;
56
import io.socket.parser.Packet;
67
import io.socket.parser.Parser;
78
import io.socket.thread.EventThread;
@@ -148,8 +149,10 @@ public Manager(URI uri, Options opts) {
148149
this.uri = uri;
149150
this.encoding = false;
150151
this.packetBuffer = new ArrayList<Packet>();
151-
this.encoder = new Parser.Encoder();
152-
this.decoder = new Parser.Decoder();
152+
153+
Parser parser = opts.parser != null ? opts.parser : new IOParser();
154+
this.encoder = parser.getEncoder();
155+
this.decoder = parser.getDecoder();
153156
}
154157

155158
private void emitAll(String event, Object... args) {
@@ -385,12 +388,12 @@ public void call(Object... objects) {
385388
Manager.this.onclose((String)objects[0]);
386389
}
387390
}));
388-
this.subs.add(On.on(this.decoder, Parser.Decoder.EVENT_DECODED, new Listener() {
391+
this.decoder.onDecoded(new Parser.Decoder.Callback() {
389392
@Override
390-
public void call(Object... objects) {
391-
Manager.this.ondecoded((Packet) objects[0]);
393+
public void call (Packet packet) {
394+
Manager.this.ondecoded(packet);
392395
}
393-
}));
396+
});
394397
}
395398

396399
private void onping() {
@@ -631,6 +634,7 @@ public static class Options extends io.socket.engineio.client.Socket.Options {
631634
public long reconnectionDelay;
632635
public long reconnectionDelayMax;
633636
public double randomizationFactor;
637+
public Parser parser;
634638

635639
/**
636640
* Connection timeout (ms). Set -1 to disable.
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
package io.socket.parser;
2+
3+
import io.socket.hasbinary.HasBinary;
4+
import org.json.JSONException;
5+
import org.json.JSONTokener;
6+
7+
import java.util.ArrayList;
8+
import java.util.Arrays;
9+
import java.util.List;
10+
import java.util.logging.Level;
11+
import java.util.logging.Logger;
12+
13+
final public class IOParser implements Parser {
14+
15+
private static final Logger logger = Logger.getLogger(IOParser.class.getName());
16+
17+
private static Packet<String> error() {
18+
return new Packet<String>(ERROR, "parser error");
19+
}
20+
21+
public IOParser() {}
22+
23+
@Override
24+
public Parser.Encoder getEncoder () {
25+
return new Encoder();
26+
}
27+
28+
@Override
29+
public Parser.Decoder getDecoder () {
30+
return new Decoder();
31+
}
32+
33+
final public static class Encoder implements Parser.Encoder {
34+
35+
public Encoder() {}
36+
37+
@Override
38+
public void encode(Packet obj, Callback callback) {
39+
if ((obj.type == EVENT || obj.type == ACK) && HasBinary.hasBinary(obj.data)) {
40+
obj.type = obj.type == EVENT ? BINARY_EVENT : BINARY_ACK;
41+
}
42+
43+
logger.fine(String.format("encoding packet %s", obj));
44+
45+
if (BINARY_EVENT == obj.type || BINARY_ACK == obj.type) {
46+
encodeAsBinary(obj, callback);
47+
} else {
48+
String encoding = encodeAsString(obj);
49+
callback.call(new String[] {encoding});
50+
}
51+
}
52+
53+
private String encodeAsString(Packet obj) {
54+
StringBuilder str = new StringBuilder("" + obj.type);
55+
56+
if (BINARY_EVENT == obj.type || BINARY_ACK == obj.type) {
57+
str.append(obj.attachments);
58+
str.append("-");
59+
}
60+
61+
if (obj.nsp != null && obj.nsp.length() != 0 && !"/".equals(obj.nsp)) {
62+
str.append(obj.nsp);
63+
str.append(",");
64+
}
65+
66+
if (obj.id >= 0) {
67+
str.append(obj.id);
68+
}
69+
70+
if (obj.data != null) {
71+
str.append(obj.data);
72+
}
73+
74+
logger.fine(String.format("encoded %s as %s", obj, str));
75+
return str.toString();
76+
}
77+
78+
private void encodeAsBinary(Packet obj, Callback callback) {
79+
Binary.DeconstructedPacket deconstruction = Binary.deconstructPacket(obj);
80+
String pack = encodeAsString(deconstruction.packet);
81+
List<Object> buffers = new ArrayList<Object>(Arrays.asList(deconstruction.buffers));
82+
83+
buffers.add(0, pack);
84+
callback.call(buffers.toArray());
85+
}
86+
}
87+
88+
final public static class Decoder implements Parser.Decoder {
89+
90+
/*package*/ BinaryReconstructor reconstructor;
91+
92+
private Decoder.Callback onDecodedCallback;
93+
94+
public Decoder() {
95+
this.reconstructor = null;
96+
}
97+
98+
@Override
99+
public void add(String obj) {
100+
Packet packet = decodeString(obj);
101+
if (BINARY_EVENT == packet.type || BINARY_ACK == packet.type) {
102+
this.reconstructor = new BinaryReconstructor(packet);
103+
104+
if (this.reconstructor.reconPack.attachments == 0) {
105+
if (this.onDecodedCallback != null) {
106+
this.onDecodedCallback.call(packet);
107+
}
108+
}
109+
} else {
110+
if (this.onDecodedCallback != null) {
111+
this.onDecodedCallback.call(packet);
112+
}
113+
}
114+
}
115+
116+
@Override
117+
public void add(byte[] obj) {
118+
if (this.reconstructor == null) {
119+
throw new RuntimeException("got binary data when not reconstructing a packet");
120+
} else {
121+
Packet packet = this.reconstructor.takeBinaryData(obj);
122+
if (packet != null) {
123+
this.reconstructor = null;
124+
if (this.onDecodedCallback != null) {
125+
this.onDecodedCallback.call(packet);
126+
}
127+
}
128+
}
129+
}
130+
131+
private static Packet decodeString(String str) {
132+
int i = 0;
133+
int length = str.length();
134+
135+
Packet<Object> p = new Packet<Object>(Character.getNumericValue(str.charAt(0)));
136+
137+
if (p.type < 0 || p.type > types.length - 1) return error();
138+
139+
if (BINARY_EVENT == p.type || BINARY_ACK == p.type) {
140+
if (!str.contains("-") || length <= i + 1) return error();
141+
StringBuilder attachments = new StringBuilder();
142+
while (str.charAt(++i) != '-') {
143+
attachments.append(str.charAt(i));
144+
}
145+
p.attachments = Integer.parseInt(attachments.toString());
146+
}
147+
148+
if (length > i + 1 && '/' == str.charAt(i + 1)) {
149+
StringBuilder nsp = new StringBuilder();
150+
while (true) {
151+
++i;
152+
char c = str.charAt(i);
153+
if (',' == c) break;
154+
nsp.append(c);
155+
if (i + 1 == length) break;
156+
}
157+
p.nsp = nsp.toString();
158+
} else {
159+
p.nsp = "/";
160+
}
161+
162+
if (length > i + 1){
163+
Character next = str.charAt(i + 1);
164+
if (Character.getNumericValue(next) > -1) {
165+
StringBuilder id = new StringBuilder();
166+
while (true) {
167+
++i;
168+
char c = str.charAt(i);
169+
if (Character.getNumericValue(c) < 0) {
170+
--i;
171+
break;
172+
}
173+
id.append(c);
174+
if (i + 1 == length) break;
175+
}
176+
try {
177+
p.id = Integer.parseInt(id.toString());
178+
} catch (NumberFormatException e){
179+
return error();
180+
}
181+
}
182+
}
183+
184+
if (length > i + 1){
185+
try {
186+
str.charAt(++i);
187+
p.data = new JSONTokener(str.substring(i)).nextValue();
188+
} catch (JSONException e) {
189+
logger.log(Level.WARNING, "An error occured while retrieving data from JSONTokener", e);
190+
return error();
191+
}
192+
}
193+
194+
logger.fine(String.format("decoded %s as %s", str, p));
195+
return p;
196+
}
197+
198+
@Override
199+
public void destroy() {
200+
if (this.reconstructor != null) {
201+
this.reconstructor.finishReconstruction();
202+
}
203+
this.onDecodedCallback = null;
204+
}
205+
206+
@Override
207+
public void onDecoded (Callback callback) {
208+
this.onDecodedCallback = callback;
209+
}
210+
}
211+
212+
213+
/*package*/ static class BinaryReconstructor {
214+
215+
public Packet reconPack;
216+
217+
/*package*/ List<byte[]> buffers;
218+
219+
BinaryReconstructor(Packet packet) {
220+
this.reconPack = packet;
221+
this.buffers = new ArrayList<byte[]>();
222+
}
223+
224+
public Packet takeBinaryData(byte[] binData) {
225+
this.buffers.add(binData);
226+
if (this.buffers.size() == this.reconPack.attachments) {
227+
Packet packet = Binary.reconstructPacket(this.reconPack,
228+
this.buffers.toArray(new byte[this.buffers.size()][]));
229+
this.finishReconstruction();
230+
return packet;
231+
}
232+
return null;
233+
}
234+
235+
public void finishReconstruction () {
236+
this.reconPack = null;
237+
this.buffers = new ArrayList<byte[]>();
238+
}
239+
}
240+
}
241+
242+

0 commit comments

Comments
 (0)