Skip to content

Commit 26e56cb

Browse files
author
Nikita
committed
BinaryEvent sending from server to client. mrniko#178
1 parent 1f6a4de commit 26e56cb

File tree

8 files changed

+201
-25
lines changed

8 files changed

+201
-25
lines changed

src/main/java/com/corundumstudio/socketio/ClientOperations.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
public interface ClientOperations {
2525

2626
/**
27-
* Send packet
27+
* Send custom packet.
28+
* But {@link ClientOperations#sendEvent} method
29+
* usage is enough for most cases.
2830
*
2931
* @param packet - packet to send
3032
*/

src/main/java/com/corundumstudio/socketio/JsonSupportWrapper.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import io.netty.buffer.ByteBufOutputStream;
2020

2121
import java.io.IOException;
22+
import java.util.List;
2223

2324
import org.slf4j.Logger;
2425
import org.slf4j.LoggerFactory;
@@ -87,4 +88,9 @@ public void writeJsonpValue(ByteBufOutputStream out, Object value) throws IOExce
8788
delegate.writeJsonpValue(out, value);
8889
}
8990

91+
@Override
92+
public List<byte[]> getArrays() {
93+
return delegate.getArrays();
94+
}
95+
9096
}

src/main/java/com/corundumstudio/socketio/handler/EncoderHandler.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import io.netty.channel.ChannelHandlerContext;
3030
import io.netty.channel.ChannelOutboundHandlerAdapter;
3131
import io.netty.channel.ChannelPromise;
32+
import io.netty.handler.codec.base64.Base64;
33+
import io.netty.handler.codec.base64.Base64Dialect;
3234
import io.netty.handler.codec.http.DefaultHttpResponse;
3335
import io.netty.handler.codec.http.HttpHeaders;
3436
import io.netty.handler.codec.http.HttpResponse;
@@ -63,6 +65,7 @@
6365
@Sharable
6466
public class EncoderHandler extends ChannelOutboundHandlerAdapter {
6567

68+
private static final byte[] BINARY_HEADER = "b4".getBytes(CharsetUtil.UTF_8);
6669
private static final byte[] OK = "ok".getBytes(CharsetUtil.UTF_8);
6770

6871
public static final AttributeKey<String> ORIGIN = AttributeKey.valueOf("origin");
@@ -220,8 +223,14 @@ private void handleWebsocket(OutPacketMessage msg, ChannelHandlerContext ctx) th
220223
if (!out.isReadable()) {
221224
out.release();
222225
}
223-
}
224226

227+
for (ByteBuf buf : packet.getAttachments()) {
228+
ByteBuf outBuf = encoder.allocateBuffer(ctx.alloc());
229+
outBuf.writeBytes(BINARY_HEADER);
230+
outBuf.writeBytes(Base64.encode(buf, Base64Dialect.URL_SAFE));
231+
ctx.channel().writeAndFlush(outBuf);
232+
}
233+
}
225234
}
226235

227236
private void handleHTTP(OutPacketMessage msg, ChannelHandlerContext ctx) throws IOException {

src/main/java/com/corundumstudio/socketio/handler/InPacketHandler.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,9 @@
1616
package com.corundumstudio.socketio.handler;
1717

1818
import io.netty.buffer.ByteBuf;
19-
import io.netty.buffer.ByteBufUtil;
20-
import io.netty.buffer.Unpooled;
2119
import io.netty.channel.ChannelHandler.Sharable;
2220
import io.netty.channel.ChannelHandlerContext;
2321
import io.netty.channel.SimpleChannelInboundHandler;
24-
import io.netty.handler.codec.base64.Base64;
2522
import io.netty.util.CharsetUtil;
2623

2724
import org.slf4j.Logger;
@@ -31,8 +28,8 @@
3128
import com.corundumstudio.socketio.messages.PacketsMessage;
3229
import com.corundumstudio.socketio.namespace.Namespace;
3330
import com.corundumstudio.socketio.namespace.NamespacesHub;
34-
import com.corundumstudio.socketio.protocol.PacketDecoder;
3531
import com.corundumstudio.socketio.protocol.Packet;
32+
import com.corundumstudio.socketio.protocol.PacketDecoder;
3633
import com.corundumstudio.socketio.protocol.PacketType;
3734
import com.corundumstudio.socketio.transport.NamespaceClient;
3835

src/main/java/com/corundumstudio/socketio/protocol/JacksonJsonSupport.java

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
import io.netty.buffer.ByteBufOutputStream;
2020

2121
import java.io.IOException;
22+
import java.lang.reflect.Type;
2223
import java.util.ArrayList;
2324
import java.util.Arrays;
2425
import java.util.Collections;
26+
import java.util.HashMap;
2527
import java.util.Iterator;
2628
import java.util.List;
2729
import java.util.Map;
@@ -34,20 +36,36 @@
3436
import com.corundumstudio.socketio.MultiTypeAckCallback;
3537
import com.corundumstudio.socketio.namespace.Namespace;
3638
import com.fasterxml.jackson.annotation.JsonInclude.Include;
39+
import com.fasterxml.jackson.core.JsonGenerationException;
40+
import com.fasterxml.jackson.core.JsonGenerator;
3741
import com.fasterxml.jackson.core.JsonParser;
3842
import com.fasterxml.jackson.core.JsonProcessingException;
3943
import com.fasterxml.jackson.core.SerializableString;
4044
import com.fasterxml.jackson.core.io.CharacterEscapes;
4145
import com.fasterxml.jackson.core.io.SerializedString;
46+
import com.fasterxml.jackson.databind.BeanDescription;
4247
import com.fasterxml.jackson.databind.DeserializationContext;
4348
import com.fasterxml.jackson.databind.DeserializationFeature;
49+
import com.fasterxml.jackson.databind.JavaType;
50+
import com.fasterxml.jackson.databind.JsonMappingException;
4451
import com.fasterxml.jackson.databind.JsonNode;
52+
import com.fasterxml.jackson.databind.JsonSerializer;
4553
import com.fasterxml.jackson.databind.Module;
4654
import com.fasterxml.jackson.databind.ObjectMapper;
55+
import com.fasterxml.jackson.databind.SerializationConfig;
4756
import com.fasterxml.jackson.databind.SerializationFeature;
57+
import com.fasterxml.jackson.databind.SerializerProvider;
4858
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
59+
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonArrayFormatVisitor;
60+
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes;
61+
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
62+
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
4963
import com.fasterxml.jackson.databind.module.SimpleModule;
5064
import com.fasterxml.jackson.databind.node.ArrayNode;
65+
import com.fasterxml.jackson.databind.node.ObjectNode;
66+
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
67+
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
68+
import com.fasterxml.jackson.databind.type.ArrayType;
5169

5270
public class JacksonJsonSupport implements JsonSupport {
5371

@@ -218,6 +236,95 @@ public Event deserialize(JsonParser jp, DeserializationContext ctxt) throws IOEx
218236

219237
}
220238

239+
public static class ByteArraySerializer extends StdSerializer<byte[]>
240+
{
241+
242+
private final ThreadLocal<List<byte[]>> arrays = new ThreadLocal<List<byte[]>>() {
243+
protected List<byte[]> initialValue() {
244+
return new ArrayList<byte[]>();
245+
};
246+
};
247+
248+
public ByteArraySerializer() {
249+
super(byte[].class);
250+
}
251+
252+
@Override
253+
public boolean isEmpty(byte[] value) {
254+
return (value == null) || (value.length == 0);
255+
}
256+
257+
@Override
258+
public void serialize(byte[] value, JsonGenerator jgen, SerializerProvider provider)
259+
throws IOException, JsonGenerationException
260+
{
261+
Map<String, Object> map = new HashMap<String, Object>();
262+
map.put("num", arrays.get().size());
263+
map.put("_placeholder", true);
264+
jgen.writeObject(map);
265+
arrays.get().add(value);
266+
}
267+
268+
@Override
269+
public void serializeWithType(byte[] value, JsonGenerator jgen, SerializerProvider provider,
270+
TypeSerializer typeSer)
271+
throws IOException, JsonGenerationException
272+
{
273+
serialize(value, jgen, provider);
274+
}
275+
276+
@Override
277+
public JsonNode getSchema(SerializerProvider provider, Type typeHint)
278+
{
279+
ObjectNode o = createSchemaNode("array", true);
280+
ObjectNode itemSchema = createSchemaNode("string"); //binary values written as strings?
281+
return o.set("items", itemSchema);
282+
}
283+
284+
@Override
285+
public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)
286+
throws JsonMappingException
287+
{
288+
if (visitor != null) {
289+
JsonArrayFormatVisitor v2 = visitor.expectArrayFormat(typeHint);
290+
if (v2 != null) {
291+
v2.itemsFormat(JsonFormatTypes.STRING);
292+
}
293+
}
294+
}
295+
296+
public List<byte[]> getArrays() {
297+
return arrays.get();
298+
}
299+
300+
public void clear() {
301+
arrays.set(new ArrayList<byte[]>());
302+
}
303+
304+
}
305+
306+
307+
private class ExBeanSerializerModifier extends BeanSerializerModifier {
308+
309+
private final ByteArraySerializer serializer = new ByteArraySerializer();
310+
311+
@Override
312+
public JsonSerializer<?> modifyArraySerializer(SerializationConfig config, ArrayType valueType,
313+
BeanDescription beanDesc, JsonSerializer<?> serializer) {
314+
if (valueType.getRawClass().equals(byte[].class)) {
315+
return this.serializer;
316+
}
317+
318+
return super.modifyArraySerializer(config, valueType, beanDesc, serializer);
319+
}
320+
321+
public ByteArraySerializer getSerializer() {
322+
return serializer;
323+
}
324+
325+
}
326+
327+
private final ExBeanSerializerModifier modifier = new ExBeanSerializerModifier();
221328
private final ThreadLocal<String> namespaceClass = new ThreadLocal<String>();
222329
private final ThreadLocal<AckCallback<?>> currentAckClass = new ThreadLocal<AckCallback<?>>();
223330
private final ObjectMapper objectMapper = new ObjectMapper();
@@ -239,6 +346,7 @@ public JacksonJsonSupport(Module... modules) {
239346

240347
protected void init(ObjectMapper objectMapper) {
241348
SimpleModule module = new SimpleModule();
349+
module.setSerializerModifier(modifier);
242350
module.addDeserializer(Event.class, eventDeserializer);
243351
module.addDeserializer(AckArgs.class, ackArgsDeserializer);
244352
objectMapper.registerModule(module);
@@ -273,12 +381,19 @@ public AckArgs readAckArgs(ByteBufInputStream src, AckCallback<?> callback) thro
273381

274382
@Override
275383
public void writeValue(ByteBufOutputStream out, Object value) throws IOException {
384+
modifier.getSerializer().clear();
276385
objectMapper.writeValue(out, value);
277386
}
278387

279388
@Override
280389
public void writeJsonpValue(ByteBufOutputStream out, Object value) throws IOException {
390+
modifier.getSerializer().clear();
281391
jsonpObjectMapper.writeValue(out, value);
282392
}
283393

394+
@Override
395+
public List<byte[]> getArrays() {
396+
return modifier.getSerializer().getArrays();
397+
}
398+
284399
}

src/main/java/com/corundumstudio/socketio/protocol/JsonSupport.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import io.netty.buffer.ByteBufOutputStream;
2020

2121
import java.io.IOException;
22+
import java.util.List;
2223

2324
import com.corundumstudio.socketio.AckCallback;
2425

@@ -42,4 +43,6 @@ public interface JsonSupport {
4243

4344
void removeEventMapping(String namespaceName, String eventName);
4445

46+
List<byte[]> getArrays();
47+
4548
}

src/main/java/com/corundumstudio/socketio/protocol/Packet.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import java.io.Serializable;
2121
import java.util.ArrayList;
22+
import java.util.Collections;
2223
import java.util.List;
2324

2425
import com.corundumstudio.socketio.namespace.Namespace;
@@ -36,7 +37,7 @@ public class Packet implements Serializable {
3637

3738
private ByteBuf dataSource;
3839
private int attachmentsCount;
39-
private List<ByteBuf> attachments;
40+
private List<ByteBuf> attachments = Collections.emptyList();
4041

4142
protected Packet() {
4243
}

0 commit comments

Comments
 (0)