package com.mogujie.tt.imlib; import java.util.ArrayList; import java.util.List; import android.content.Intent; import android.os.Handler; import android.os.Message; import com.mogujie.tt.config.ProtocolConstant; import com.mogujie.tt.config.SysConstant; import com.mogujie.tt.entity.User; import com.mogujie.tt.imlib.common.ErrorCode; import com.mogujie.tt.imlib.db.IMDbManager; import com.mogujie.tt.imlib.network.LoginServerHandler; import com.mogujie.tt.imlib.network.MsgServerHandler; import com.mogujie.tt.imlib.network.SocketThread; import com.mogujie.tt.imlib.proto.LoginPacket; import com.mogujie.tt.imlib.proto.MsgServerPacket; import com.mogujie.tt.log.Logger; import com.mogujie.tt.packet.base.DataBuffer; import com.mogujie.tt.ui.utils.Md5Helper; public class IMLoginManager extends IMManager { private static IMLoginManager inst; public static IMLoginManager instance() { synchronized (IMLoginManager.class) { if (inst == null) { inst = new IMLoginManager(); } return inst; } } private Logger logger = Logger.getLogger(IMLoginManager.class); private String loginUserName; private String loginPwd; private String loginId; private SocketThread loginServerThread; private List<String> msgServerAddrs; private int msgServerPort; private SocketThread msgServerThread; // todo eric make it to ContactEntity too private User loginUser; private static final int MSG_SERVER_DISCONNECTED_EVENT = -1; private boolean loggined = false; private boolean everLogined = false; private boolean identityChanged = false; private static Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub if (msg.what == MSG_SERVER_DISCONNECTED_EVENT) { IMLoginManager.instance().disconnectMsgServer(); } // // todo eric don't put ui stuff here // Toast.makeText(ctx, "网络发生错误,已和服务器断开连接", // Toast.LENGTH_LONG).show(); super.handleMessage(msg); } }; private static final int STATUS_CONNECT_LOGIN_SERVER = 0; private static final int STATUS_REQ_MSG_SERVER_ADDRS = 1; private static final int STATUS_CONNECT_MSG_SERVER = 2; private static final int STATUS_LOGINING_MSG_SERVER = 3; private static final int STATUS_LOGIN_OK = 4; private static final int STATUS_LOGIN_FAILED = 5; private static final int STATUS_MSG_SERVER_DISCONNECTED = 6; private int currentStatus = STATUS_CONNECT_LOGIN_SERVER; public boolean isEverLoginned() { return everLogined; } public boolean isLoggined() { return loggined; } public User getLoginUser() { return loginUser; } public boolean isDoingLogin() { return currentStatus <= STATUS_LOGINING_MSG_SERVER; } public String getLoginId() { return loginId; } public void setLoginId(String loginId) { logger.d("login#setLoginId -> loginId:%s", loginId); this.loginId = loginId; } public IMLoginManager() { logger.d("login#creating IMLoginManager"); } public boolean relogin() { logger.d("login#relogin"); if (isDoingLogin()) { logger.d("login#isDoingLogin, no need"); return false; } if (loggined) { logger.d("login#already logined, no need"); return false; } connectLoginServer(); return true; } public void login(String userName, String password, boolean userNameChanged, boolean pwdChanged) { logger.i( "login#login -> userName:%s, userNameChanged:%s, pwdChanged:%s", userName, userNameChanged, pwdChanged); loginUserName = userName; if (pwdChanged) { loginPwd = Md5Helper.encode(password); } else { loginPwd = password; } identityChanged = userNameChanged || pwdChanged; connectLoginServer(); } private void connectLoginServer() { String ip = ProtocolConstant.LOGIN_IP1; int port = ProtocolConstant.LOGIN_PORT; logger.i("login#connect login server -> (%s:%d)", ip, port); loginServerThread = new SocketThread(ip, port, new LoginServerHandler()); loginServerThread.start(); } public void cancel() { // todo eric logger.i("login#cancel"); } public void onLoginServerUnconnected() { logger.i("login#onLoginServerUnConnected"); IMLoginManager.instance().onLoginFailed( ErrorCode.E_CONNECT_LOGIN_SERVER_FAILED); } public void onLoginFailed(int errorCode) { logger.i("login#onLoginFailed -> errorCode:%d", errorCode); currentStatus = STATUS_LOGIN_FAILED; loggined = false; Intent intent = new Intent(IMActions.ACTION_LOGIN_RESULT); intent.putExtra(SysConstant.lOGIN_ERROR_CODE_KEY, errorCode); if (ctx != null) { logger.i("login#broadcast login failed"); ctx.sendBroadcast(intent); } } public void onLoginOk() { logger.i("login#onLoginOk loginUser:%s", loginUser); currentStatus = STATUS_LOGIN_OK; loggined = true; everLogined = true; if (identityChanged) { IMDbManager.instance(ctx) .saveLoginIdentity(loginUserName, loginPwd); } Intent intent = new Intent(IMActions.ACTION_LOGIN_RESULT); intent.putExtra(SysConstant.lOGIN_ERROR_CODE_KEY, ErrorCode.S_OK); if (ctx != null) { logger.i("login#broadcast login ok"); ctx.sendBroadcast(intent); } fetchData(); } private void fetchData() { logger.i("login#fetch data"); IMContactManager.instance().fetchContacts(); IMGroupManager.instance().fetchGroupList(); } public void onLoginServerConnected() { logger.i("login#onLoginServerConnected"); fetchMsgServerAddrs(); } public void onLoginServerDisconnected() { logger.e("login#onLoginServerDisconnected"); // todo eric is enum capable of comparing just like int? if (currentStatus < STATUS_CONNECT_MSG_SERVER) { logger.e("login server disconnected unexpectedly"); onLoginFailed(ErrorCode.E_REQ_MSG_SERVER_ADDRS_FAILED); } } public void fetchMsgServerAddrs() { logger.i("login#fetchMsgServerAddr"); currentStatus = STATUS_REQ_MSG_SERVER_ADDRS; if (loginServerThread != null) { loginServerThread.sendPacket(new MsgServerPacket()); logger.d("login#send packet ok"); } } public void onRepMsgServerAddrs(DataBuffer buffer) { logger.i("login#onRepMsgServerAddrs"); MsgServerPacket packet = new MsgServerPacket(); packet.decode(buffer); MsgServerPacket.MsgServerResponse resp = (MsgServerPacket.MsgServerResponse) packet .getResponse(); if (resp == null) { logger.e("login#decode MsgServerResponse failed"); onLoginFailed(ErrorCode.E_REQ_MSG_SERVER_ADDRS_FAILED); return; } if (msgServerAddrs == null) { msgServerAddrs = new ArrayList<String>(); } msgServerAddrs.add(resp.getStrIp1()); msgServerAddrs.add(resp.getStrIp2()); msgServerPort = resp.getPort(); logger.i("login#msgserver ip1:%s, login ip2:%s, port:%d", resp.getStrIp1(), resp.getStrIp2(), resp.getPort()); connectMsgServer(); } private String pickLoginServerIp() { // todo eric // pick the second one right now return msgServerAddrs.get(1); } private void disconnectLoginServer() { logger.i("login#disconnectLoginServer"); if (loginServerThread != null) { loginServerThread.close(); logger.i("login#do real disconnectLoginServer ok"); // todo eric // loginServerThread = null; } } private void disconnectMsgServer() { logger.i("login#disconnectMsgServer"); if (msgServerThread != null) { msgServerThread.close(); logger.i("login#do real disconnectMsgServer ok"); // msgServerThread = null; } } private void connectMsgServer() { currentStatus = STATUS_CONNECT_MSG_SERVER; disconnectLoginServer(); String ip = pickLoginServerIp(); logger.i("login#connectMsgServer -> (%s:%d)", ip, msgServerPort); msgServerThread = new SocketThread(ip, msgServerPort, new MsgServerHandler()); msgServerThread.start(); } public void onMessageServerUnconnected() { logger.i("login#onMessageServerUnconnected"); onLoginFailed(ErrorCode.E_CONNECT_MSG_SERVER_FAILED); } public void onMsgServerConnected() { logger.i("login#onMsgServerConnected"); reqLoginMsgServer(); } private void broadcastDisconnectWithServer() { logger.i("login#broadcastDisconnectWithServer"); if (ctx != null) { ctx.sendBroadcast(new Intent(IMActions.ACTION_SERVER_DISCONNECTED)); } } public void onMsgServerDisconnected() { logger.w("login#onMsgServerDisconnected"); if (currentStatus < STATUS_LOGIN_OK) { onLoginFailed(ErrorCode.E_LOGIN_MSG_SERVER_FAILED); } else { broadcastDisconnectWithServer(); } currentStatus = STATUS_MSG_SERVER_DISCONNECTED; loggined = false; // only 2 threads(ui thread, network thread) would request sending // packet // let the ui thread to close the connection // so if the ui thread has a sending task, no synchronization issue handler.sendEmptyMessage(MSG_SERVER_DISCONNECTED_EVENT); } private void reqLoginMsgServer() { logger.i("login#reqLoginMsgServer"); currentStatus = STATUS_LOGINING_MSG_SERVER; if (msgServerThread != null) { msgServerThread.sendPacket(new LoginPacket(loginUserName, loginPwd, ProtocolConstant.ON_LINE, ProtocolConstant.CLIENT_TYPE, ProtocolConstant.CLIENT_VERSION)); } } public void onRepMsgServerLogin(DataBuffer buffer) { logger.i("login#onRepMsgServerLogin"); LoginPacket packet = new LoginPacket(); packet.decode(buffer); LoginPacket.LoginResponse resp = (LoginPacket.LoginResponse) packet .getResponse(); if (resp == null) { logger.e("login#decode LoginResponse failed"); onLoginFailed(ErrorCode.E_LOGIN_MSG_SERVER_FAILED); return; } int loginResult = resp.getResult(); logger.d("login#loginResult:%d", loginResult); if (loginResult == 0) { loginUser = resp.getUser(); setLoginId(loginUser.getUserId()); onLoginOk(); } else { // todo eric right now, no detail failed reason onLoginFailed(ErrorCode.E_LOGIN_GENERAL_FAILED); } } public SocketThread getMsgServerChannel() { return msgServerThread; } public void disconnect() { logger.d("login#disconnect"); disconnectLoginServer(); disconnectMsgServer(); } }