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 ...
}
}

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 {
}
3. Estrategia Concreta: AccountLoginStrategy
public class AccountLoginStrategy implements LoginStrategy {
}