Skip to content

Commit 19dd2a6

Browse files
committed
Added EchoServer
1 parent f04b796 commit 19dd2a6

5 files changed

Lines changed: 138 additions & 4 deletions

File tree

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
buildscript {
22
repositories { jcenter() }
3-
dependencies { classpath 'io.reactivesocket:gradle-nebula-plugin-reactivesocket:1.0.5' }
3+
dependencies { classpath 'io.reactivesocket:gradle-nebula-plugin-reactivesocket:1.0.6' }
44
}
55

66
apply plugin: 'reactivesocket-project'

reactivesocket-netty/build.gradle

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
dependencies {
2-
compile 'io.netty:netty-handler:4.1.0.CR6'
3-
compile 'io.netty:netty-codec-http:4.1.0.CR6'
4-
}
2+
compile 'io.netty:netty-handler:4.1.0.CR7'
3+
compile 'io.netty:netty-codec-http:4.1.0.CR7'
4+
}
5+
6+
task echoServer(type: JavaExec) {
7+
classpath = sourceSets.examples.runtimeClasspath
8+
main = 'io.reactivesocket.netty.EchoServer'
9+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package io.reactivesocket.netty;
2+
3+
import io.netty.bootstrap.ServerBootstrap;
4+
import io.netty.channel.Channel;
5+
import io.netty.channel.ChannelInitializer;
6+
import io.netty.channel.ChannelPipeline;
7+
import io.netty.channel.EventLoopGroup;
8+
import io.netty.channel.nio.NioEventLoopGroup;
9+
import io.netty.channel.socket.nio.NioServerSocketChannel;
10+
import io.netty.handler.logging.LogLevel;
11+
import io.netty.handler.logging.LoggingHandler;
12+
13+
public class EchoServer {
14+
public static void main(String... args) throws Exception {
15+
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
16+
EventLoopGroup workerGroup = new NioEventLoopGroup();
17+
18+
try {
19+
ServerBootstrap b = new ServerBootstrap();
20+
b.group(bossGroup, workerGroup)
21+
.channel(NioServerSocketChannel.class)
22+
.handler(new LoggingHandler(LogLevel.INFO))
23+
.childHandler(new ChannelInitializer<Channel>() {
24+
@Override
25+
protected void initChannel(Channel ch) throws Exception {
26+
ChannelPipeline pipeline = ch.pipeline();
27+
pipeline.addLast(new EchoServerHandler());
28+
}
29+
});
30+
31+
Channel localhost = b.bind("localhost", 8025).sync().channel();
32+
localhost.closeFuture().sync();
33+
} finally {
34+
bossGroup.shutdownGracefully();
35+
workerGroup.shutdownGracefully();
36+
}
37+
}
38+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package io.reactivesocket.netty;
2+
3+
import io.netty.buffer.ByteBuf;
4+
import io.netty.channel.ChannelHandlerContext;
5+
import io.netty.channel.ChannelPipeline;
6+
import io.netty.channel.SimpleChannelInboundHandler;
7+
import io.netty.handler.codec.ByteToMessageDecoder;
8+
import io.netty.handler.codec.http.FullHttpRequest;
9+
import io.netty.handler.codec.http.HttpObjectAggregator;
10+
import io.netty.handler.codec.http.HttpServerCodec;
11+
import io.reactivesocket.RequestHandler;
12+
import io.reactivesocket.netty.tcp.server.ReactiveSocketServerHandler;
13+
14+
import java.util.List;
15+
16+
public class EchoServerHandler extends ByteToMessageDecoder {
17+
private static SimpleChannelInboundHandler<FullHttpRequest> httpHandler = new HttpServerHandler();
18+
19+
private static ReactiveSocketServerHandler reactiveSocketHandler = ReactiveSocketServerHandler.create((setupPayload, rs) ->
20+
new RequestHandler.Builder().withRequestResponse(payload -> s -> {
21+
s.onNext(payload);
22+
s.onComplete();
23+
}).build());
24+
25+
@Override
26+
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
27+
// Will use the first five bytes to detect a protocol.
28+
if (in.readableBytes() < 5) {
29+
return;
30+
}
31+
32+
final int magic1 = in.getUnsignedByte(in.readerIndex());
33+
final int magic2 = in.getUnsignedByte(in.readerIndex() + 1);
34+
if (isHttp(magic1, magic2)) {
35+
switchToHttp(ctx);
36+
} else {
37+
switchToReactiveSocket(ctx);
38+
}
39+
}
40+
41+
private static boolean isHttp(int magic1, int magic2) {
42+
return
43+
magic1 == 'G' && magic2 == 'E' || // GET
44+
magic1 == 'P' && magic2 == 'O' || // POST
45+
magic1 == 'P' && magic2 == 'U' || // PUT
46+
magic1 == 'H' && magic2 == 'E' || // HEAD
47+
magic1 == 'O' && magic2 == 'P' || // OPTIONS
48+
magic1 == 'P' && magic2 == 'A' || // PATCH
49+
magic1 == 'D' && magic2 == 'E' || // DELETE
50+
magic1 == 'T' && magic2 == 'R' || // TRACE
51+
magic1 == 'C' && magic2 == 'O'; // CONNECT
52+
}
53+
54+
private void switchToHttp(ChannelHandlerContext ctx) {
55+
ChannelPipeline p = ctx.pipeline();
56+
p.addLast(new HttpServerCodec());
57+
p.addLast(new HttpObjectAggregator(64 * 1024));
58+
p.addLast(httpHandler);
59+
p.remove(this);
60+
}
61+
62+
private void switchToReactiveSocket(ChannelHandlerContext ctx) {
63+
ChannelPipeline p = ctx.pipeline();
64+
p.addLast(reactiveSocketHandler);
65+
p.remove(this);
66+
}
67+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package io.reactivesocket.netty;
2+
3+
import io.netty.channel.ChannelHandler;
4+
import io.netty.channel.ChannelHandlerContext;
5+
import io.netty.channel.SimpleChannelInboundHandler;
6+
import io.netty.handler.codec.http.DefaultFullHttpResponse;
7+
import io.netty.handler.codec.http.FullHttpRequest;
8+
9+
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
10+
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
11+
12+
@ChannelHandler.Sharable
13+
public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
14+
@Override
15+
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
16+
ctx.flush();
17+
ctx.close();
18+
}
19+
20+
@Override
21+
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
22+
ctx.write(new DefaultFullHttpResponse(HTTP_1_1, OK, msg.content().copy()));
23+
}
24+
}

0 commit comments

Comments
 (0)