Package org.menacheri.jetserver.handlers.netty

Source Code of org.menacheri.jetserver.handlers.netty.LoginHandler

package org.menacheri.jetserver.handlers.netty;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.atomic.AtomicInteger;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandler.Sharable;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.menacheri.jetserver.app.GameRoom;
import org.menacheri.jetserver.app.Player;
import org.menacheri.jetserver.app.PlayerSession;
import org.menacheri.jetserver.app.Session;
import org.menacheri.jetserver.communication.NettyTCPMessageSender;
import org.menacheri.jetserver.event.Event;
import org.menacheri.jetserver.event.Events;
import org.menacheri.jetserver.event.impl.ReconnetEvent;
import org.menacheri.jetserver.server.netty.AbstractNettyServer;
import org.menacheri.jetserver.service.LookupService;
import org.menacheri.jetserver.service.SessionRegistryService;
import org.menacheri.jetserver.service.UniqueIDGeneratorService;
import org.menacheri.jetserver.service.impl.ReconnectSessionRegistry;
import org.menacheri.jetserver.util.Credentials;
import org.menacheri.jetserver.util.JetConfig;
import org.menacheri.jetserver.util.NettyUtils;
import org.menacheri.jetserver.util.SimpleCredentials;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


@Sharable
public class LoginHandler extends SimpleChannelUpstreamHandler
{
  private static final Logger LOG = LoggerFactory
      .getLogger(LoginHandler.class);

  protected LookupService lookupService;
  protected SessionRegistryService<SocketAddress> udpSessionRegistry;
  protected ReconnectSessionRegistry reconnectRegistry;
  protected UniqueIDGeneratorService idGeneratorService;
 
  /**
   * Used for book keeping purpose. It will count all open channels. Currently
   * closed channels will not lead to a decrement.
   */
  private static final AtomicInteger CHANNEL_COUNTER = new AtomicInteger(0);

  public void messageReceived(final ChannelHandlerContext ctx,
      final MessageEvent e) throws Exception
  {
    final Event event = (Event) e.getMessage();
    final ChannelBuffer buffer = (ChannelBuffer) event.getSource();
    final Channel channel = e.getChannel();
    int type = event.getType();
    if (Events.LOG_IN == type)
    {
      LOG.debug("Login attempt from {}", channel.getRemoteAddress());
      Player player = lookupPlayer(buffer, channel);
      handleLogin(player, channel, buffer);
    }
    else if (Events.RECONNECT == type)
    {
      LOG.debug("Reconnect attempt from {}", channel.getRemoteAddress());
      String reconnectKey = NettyUtils.readString(buffer);
      PlayerSession playerSession = lookupSession(reconnectKey);
      handleReconnect(playerSession, channel, buffer);
    }
    else
    {
      LOG.error("Invalid event {} sent from remote address {}. "
          + "Going to close channel {}",
          new Object[] { event.getType(), channel.getRemoteAddress(),
              channel.getId() });
      closeChannelWithLoginFailure(channel);
    }
  }

  @Override
  public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e)
      throws Exception {
    AbstractNettyServer.ALL_CHANNELS.add(e.getChannel());
    LOG.debug("Added Channel with id: {} as the {}th open channel", e
        .getChannel().getId(), CHANNEL_COUNTER.incrementAndGet());
  }
 
  public Player lookupPlayer(final ChannelBuffer buffer, final Channel channel)
  {
    Credentials credentials = new SimpleCredentials(buffer);
    Player player = lookupService.playerLookup(credentials);
    if(null == player){
      LOG.error("Invalid credentials provided by user: {}",credentials);
    }
    return player;
  }
 
  public PlayerSession lookupSession(final String reconnectKey)
  {
    PlayerSession playerSession = (PlayerSession)reconnectRegistry.getSession(reconnectKey);
    if(null != playerSession)
    {
      synchronized(playerSession){
        // if its an already active session then do not allow a
        // reconnect. So the only state in which a client is allowed to
        // reconnect is if it is "NOT_CONNECTED"
        if(playerSession.getStatus() == Session.Status.NOT_CONNECTED)
        {
          playerSession.setStatus(Session.Status.CONNECTING);
        }
        else
        {
          playerSession = null;
        }
      }
    }
    return playerSession;
  }
 
  public void handleLogin(Player player, Channel channel, ChannelBuffer buffer)
  {
    if (null != player)
    {
      channel.write(NettyUtils
          .createBufferForOpcode(Events.LOG_IN_SUCCESS));
      handleGameRoomJoin(player, channel, buffer);
    }
    else
    {
      // Write future and close channel
      closeChannelWithLoginFailure(channel);
    }
  }

  protected void handleReconnect(PlayerSession playerSession, Channel channel, ChannelBuffer buffer)
  {
    if (null != playerSession)
    {
      channel.write(NettyUtils
          .createBufferForOpcode(Events.LOG_IN_SUCCESS));
      GameRoom gameRoom = playerSession.getGameRoom();
      gameRoom.disconnectSession(playerSession);
      if (null != playerSession.getTcpSender())
        playerSession.getTcpSender().close();

      if (null != playerSession.getUdpSender())
        playerSession.getUdpSender().close();
     
      handleReJoin(playerSession, gameRoom, channel, buffer);
    }
    else
    {
      // Write future and close channel
      closeChannelWithLoginFailure(channel);
    }
  }

  /**
   * Helper method which will close the channel after writing
   * {@link Events#LOG_IN_FAILURE} to remote connection.
   *
   * @param channel
   *            The tcp connection to remote machine that will be closed.
   */
  private void closeChannelWithLoginFailure(Channel channel)
  {
    ChannelFuture future = channel.write(NettyUtils
        .createBufferForOpcode(Events.LOG_IN_FAILURE));
    future.addListener(ChannelFutureListener.CLOSE);
  }
 
  public void handleGameRoomJoin(Player player, Channel channel, ChannelBuffer buffer)
  {
    String refKey = NettyUtils.readString(buffer);
   
    GameRoom gameRoom = lookupService.gameRoomLookup(refKey);
    if(null != gameRoom)
    {
      PlayerSession playerSession = gameRoom.createPlayerSession(player);
      gameRoom.onLogin(playerSession);
      String reconnectKey = (String)idGeneratorService
          .generateFor(playerSession.getClass());
      playerSession.setAttribute(JetConfig.RECONNECT_KEY, reconnectKey);
      playerSession.setAttribute(JetConfig.RECONNECT_REGISTRY, reconnectRegistry);
      LOG.trace("Sending GAME_ROOM_JOIN_SUCCESS to channel {}", channel.getId());
      ChannelBuffer reconnectKeyBuffer = ChannelBuffers.wrappedBuffer(NettyUtils.createBufferForOpcode(Events.GAME_ROOM_JOIN_SUCCESS), NettyUtils.writeString(reconnectKey));
      ChannelFuture future = channel.write(reconnectKeyBuffer);
      connectToGameRoom(gameRoom, playerSession, future);
      loginUdp(playerSession, buffer);
    }
    else
    {
      // Write failure and close channel.
      ChannelFuture future = channel.write(NettyUtils.createBufferForOpcode(Events.GAME_ROOM_JOIN_FAILURE));
      future.addListener(ChannelFutureListener.CLOSE);
      LOG.error("Invalid ref key provided by client: {}. Channel {} will be closed",refKey,channel.getId());
    }
  }
 
  protected void handleReJoin(PlayerSession playerSession, GameRoom gameRoom, Channel channel,
      ChannelBuffer buffer)
  {
    LOG.trace("Going to clear pipeline");
    // Clear the existing pipeline
    NettyUtils.clearPipeline(channel.getPipeline());
    // Set the tcp channel on the session.
    NettyTCPMessageSender sender = new NettyTCPMessageSender(channel);
    playerSession.setTcpSender(sender);
    // Connect the pipeline to the game room.
    gameRoom.connectSession(playerSession);
    playerSession.setWriteable(true);// TODO remove if unnecessary. It should be done in start event
    // Send the re-connect event so that it will in turn send the START event.
    playerSession.onEvent(new ReconnetEvent(sender));
    loginUdp(playerSession, buffer);
  }
 
  public void connectToGameRoom(final GameRoom gameRoom, final PlayerSession playerSession, ChannelFuture future)
  {
    future.addListener(new ChannelFutureListener()
    {
      @Override
      public void operationComplete(ChannelFuture future)
          throws Exception
      {
        Channel channel = future.getChannel();
        LOG.trace("Sending GAME_ROOM_JOIN_SUCCESS to channel {} completed", channel.getId());
        if (future.isSuccess())
        {
          LOG.trace("Going to clear pipeline");
          // Clear the existing pipeline
          NettyUtils.clearPipeline(channel.getPipeline());
          // Set the tcp channel on the session.
          NettyTCPMessageSender sender = new NettyTCPMessageSender(channel);
          playerSession.setTcpSender(sender);
          // Connect the pipeline to the game room.
          gameRoom.connectSession(playerSession);
          // Send the connect event so that it will in turn send the START event.
          playerSession.onEvent(Events.connectEvent(sender));
        }
        else
        {
          LOG.error("GAME_ROOM_JOIN_SUCCESS message sending to client was failure, channel will be closed");
          channel.close();
        }
      }
    });
  }
 
  /**
   * This method adds the player session to the
   * {@link SessionRegistryService}. The key being the remote udp address of
   * the client and the session being the value.
   *
   * @param playerSession
   * @param buffer
   *            Used to read the remote address of the client which is
   *            attempting to connect via udp.
   */
  protected void loginUdp(PlayerSession playerSession, ChannelBuffer buffer)
  {
    InetSocketAddress remoteAdress = NettyUtils.readSocketAddress(buffer);
    if(null != remoteAdress)
    {
      udpSessionRegistry.putSession(remoteAdress, playerSession);
    }
  }
 
  public LookupService getLookupService()
  {
    return lookupService;
  }

  public void setLookupService(LookupService lookupService)
  {
    this.lookupService = lookupService;
  }

  public UniqueIDGeneratorService getIdGeneratorService() {
    return idGeneratorService;
  }

  public void setIdGeneratorService(UniqueIDGeneratorService idGeneratorService) {
    this.idGeneratorService = idGeneratorService;
  }

  public SessionRegistryService<SocketAddress> getUdpSessionRegistry()
  {
    return udpSessionRegistry;
  }

  public void setUdpSessionRegistry(
      SessionRegistryService<SocketAddress> udpSessionRegistry)
  {
    this.udpSessionRegistry = udpSessionRegistry;
  }

  public ReconnectSessionRegistry getReconnectRegistry()
  {
    return reconnectRegistry;
  }

  public void setReconnectRegistry(ReconnectSessionRegistry reconnectRegistry)
  {
    this.reconnectRegistry = reconnectRegistry;
  }

}
TOP

Related Classes of org.menacheri.jetserver.handlers.netty.LoginHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.