package io.netty.protocol.wamp; import com.fasterxml.jackson.core.TreeNode; import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.protocol.wamp.messages.*; import io.netty.protocol.wamp.server.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; // WARNING: This handler is stateful, do not reuse public class WampServerHandler extends SimpleChannelInboundHandler<WampMessage> { private static final Logger logger = LoggerFactory.getLogger(WampServerHandler.class); private final WampServer wampServer; private Session session; private ChannelHandlerContext ctx; private RpcHandler.HandlerContext handlerContext; public WampServerHandler(WampServer wampServer, ObjectMapper objectMapper) { this.wampServer = wampServer; handlerContext = new RpcHandler.HandlerContext(wampServer, objectMapper); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { this.ctx = ctx; session = new Session(ctx); handlerContext.setSession(session); ctx.write(new WelcomeMessage(session.id, wampServer.serverIdent)); //super.channelActive(ctx); } @Override protected void channelRead0(ChannelHandlerContext ctx, final WampMessage message) throws Exception { assert ctx == this.ctx; switch (message.type) { case PREFIX: handlePrefixMessage((PrefixMessage) message); break; case CALL: handleCallMessage((CallMessage) message); break; case SUBSCRIBE: handleSubscribeMessage((SubscribeMessage) message); break; case UNSUBSCRIBE: handleUnsubscribeMessage((UnsubscribeMessage) message); break; case PUBLISH: handlePublishMessage((PublishMessage) message); break; default: logger.debug("Not a client-to-server message received: {}", message.toString()); } } public void handlePrefixMessage(PrefixMessage pm) { final String pref = pm.prefix; if (pref.equals("http") || pref.equals("https") || pref.equals("ws")) return; session.prefixes.put(pm.prefix, pm.URI); } public void handleCallMessage(CallMessage cm) { RpcHandler rpcHandler = wampServer.getHandler(cm.procURI); if (rpcHandler == null) rpcHandler = wampServer.getHandler(resolveCURI(cm.procURI)); if (rpcHandler == null) { ctx.write(new CallErrorMessage(cm.callId, "http:/wamp.ws/error#nosuchproc", "Such procedure does not exist")); return; } TreeNode callResult; try { callResult = rpcHandler.call(cm.args, handlerContext); } catch (CallErrorException cex) { ctx.write(new CallErrorMessage(cm.callId, cex)); return; } ctx.write(new CallResultMessage(cm.callId, callResult)); } public void handleSubscribeMessage(SubscribeMessage sm) { Topic topic = getTopic(sm.topicURI); if (topic == null) return; topic.add(session); } public void handleUnsubscribeMessage(UnsubscribeMessage usm) { Topic topic = getTopic(usm.topicURI); if (topic == null) return; topic.remove(session); } public void handlePublishMessage(PublishMessage pm) { Topic topic = getTopic(pm.topicURI); if (topic == null) return; topic.post(pm.event, session); } private Topic getTopic(String topicURI) { Topic topic = wampServer.getTopic(topicURI); if (topic == null) { topicURI = resolveCURI(topicURI); topic = wampServer.getTopic(topicURI); } if (topic == null) { logger.debug("Topic not found: {}", topicURI); } return topic; } String resolveCURI(final String curi) { if (curi.startsWith("http:") || curi.startsWith("https:") || curi.startsWith("ws:")) return curi; String[] parts = curi.split(":"); if (parts.length < 2) return session.prefixes.get(curi); else return session.prefixes.get(parts[0]) + parts[1]; } }