Skip to content

Bug: LoginHandler no responde ante tipos de login no soportados #123

Description

@gabordonp

Hola @jzyong,
En LoginHandler.run(), el switch(request.getLoginType()) solo maneja el caso ACCOUNT y no tiene rama default. Si se recibe cualquier otro LoginType, el método termina sin enviar respuesta al cliente, que queda esperando indefinidamente.
Además, la lógica de login está embebida directamente en el handler, lo que dificulta agregar nuevos mecanismos de autenticación (dispositivo, invitado, OAuth) sin hacer crecer el switch.
Solución propuesta:
Aplicar el patrón Strategy, extrayendo la lógica actual a una clase AccountLoginStrategy que implemente una interfaz LoginStrategy, seleccionada desde un mapa LoginType -> LoginStrategy. Si no existe una estrategia registrada, se responde explícitamente con un error en lugar de dejar la conexión colgada.
Quedamos atentos a sus comentarios.

1. Interfaz LoginStrategy
package com.jzy.game.hall.tcp.login.strategy;

import com.jzy.game.message.hall.HallLoginMessage.LoginRequest;

public interface LoginStrategy {
void login(LoginRequest request);
}
2. Contexto: LoginHandler
public class LoginHandler extends TcpHandler {

private static final Logger LOGGER = LoggerFactory.getLogger(LoginHandler.class);
private static final Map<LoginType, LoginStrategy> STRATEGIES = new EnumMap<>(LoginType.class);

static {
    STRATEGIES.put(LoginType.ACCOUNT, new AccountLoginStrategy());
    // Nuevo tipo de login (dispositivo, invitado, OAuth, ...) = una línea nueva aquí,
    // sin modificar este handler.
}

@Override
public void run() {
    LoginRequest request = getMsg();
    LoginStrategy strategy = STRATEGIES.get(request.getLoginType());
    
    if (strategy == null) {
        LOGGER.warn("Tipo de login no soportado: {}", request.getLoginType());
        sendMsg(buildUnsupportedLoginError()); // antes: la conexión quedaba colgada
        return;
    }
    strategy.login(request);
}

private Object buildUnsupportedLoginError() {
    // Construir aquí una respuesta de error explícita para el cliente.
    return null;
}

}
3. Estrategia Concreta: AccountLoginStrategy
public class AccountLoginStrategy implements LoginStrategy {

@Override
public void login(LoginRequest request) {
    if (request.getAccount() == null || request.getPassword() == null) {
        return;
    }

    User user = UserDao.findByAccount(request.getAccount());
    if (user == null) {
        user = UserManager.getInstance().createUser(u -> {
            u.setAccount(request.getAccount());
            u.setPassword(request.getPassword());
        });
        UserDao.saveUser(user);
    }

    Role role = RoleDao.getRoleByUserId(user.getId());
    if (role == null) {
        role = RoleManager.getInstance().createUser(user.getId(), r -> {
            r.setNick("jzy");
            r.setGem(1000);
        });
    } else {
        Map<String, String> hgetAll = JedisManager.getJedisCluster()
            .hgetAll(HallKey.Role_Map_Info.getKey(role.getId()));
        JsonUtil.map2Object(hgetAll, role);
    }

    RoleManager.getInstance().login(role, Reason.UserLogin);
    JedisPubSubMessage message = new JedisPubSubMessage(role.getId(), Config.SERVER_ID);
    JedisManager.getJedisCluster().publish(HallChannel.LoginHall.name(), message.toString());
    
    HallLoginMessage.LoginResponse.Builder builder = HallLoginMessage.LoginResponse.newBuilder();
    builder.setIsOk(true);
    builder.setUid(user.getId());
    // ... finalizar construcción y envío ...
}

}

Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions