001package com.pusher.client.user.impl; 002 003import com.google.gson.Gson; 004import com.google.gson.JsonSyntaxException; 005import com.pusher.client.AuthenticationFailureException; 006import com.pusher.client.UserAuthenticator; 007import com.pusher.client.channel.PusherEvent; 008import com.pusher.client.channel.SubscriptionEventListener; 009import com.pusher.client.channel.impl.ChannelManager; 010import com.pusher.client.connection.ConnectionEventListener; 011import com.pusher.client.connection.ConnectionState; 012import com.pusher.client.connection.ConnectionStateChange; 013import com.pusher.client.connection.impl.InternalConnection; 014import com.pusher.client.user.User; 015import com.pusher.client.user.impl.message.AuthenticationResponse; 016import com.pusher.client.user.impl.message.SigninMessage; 017import com.pusher.client.util.Factory; 018 019import java.util.Map; 020import java.util.logging.Logger; 021 022public class InternalUser implements User { 023 024 private static final Gson GSON = new Gson(); 025 private static final Logger log = Logger.getLogger(User.class.getName()); 026 027 private static class ConnectionStateChangeHandler implements ConnectionEventListener { 028 029 private final InternalUser user; 030 031 public ConnectionStateChangeHandler(InternalUser user) { 032 this.user = user; 033 } 034 035 @Override 036 public void onConnectionStateChange(ConnectionStateChange change) { 037 switch (change.getCurrentState()) { 038 case CONNECTED: 039 user.attemptSignin(); 040 break; 041 case CONNECTING: 042 case DISCONNECTED: 043 user.disconnect(); 044 break; 045 default: 046 // NOOP 047 } 048 } 049 050 @Override 051 public void onError(String message, String code, Exception e) { 052 log.warning(message); 053 } 054 } 055 056 private final InternalConnection connection; 057 private final UserAuthenticator userAuthenticator; 058 private final ChannelManager channelManager; 059 private boolean signinRequested; 060 private final ServerToUserChannel serverToUserChannel; 061 private String userId; 062 063 public InternalUser(InternalConnection connection, UserAuthenticator userAuthenticator, Factory factory) { 064 this.connection = connection; 065 this.userAuthenticator = userAuthenticator; 066 this.channelManager = factory.getChannelManager(); 067 this.signinRequested = false; 068 this.serverToUserChannel = new ServerToUserChannel(this, factory); 069 070 connection.bind(ConnectionState.ALL, new ConnectionStateChangeHandler(this)); 071 } 072 073 public void signin() throws AuthenticationFailureException { 074 if (signinRequested || userId != null) { 075 return; 076 } 077 078 signinRequested = true; 079 attemptSignin(); 080 } 081 082 public void handleEvent(PusherEvent event) { 083 if (event.getEventName().equals("pusher:signin_success")) { 084 onSigninSuccess(event); 085 } 086 } 087 088 private void attemptSignin() throws AuthenticationFailureException { 089 if (!signinRequested || userId != null) { 090 return; 091 } 092 093 if (connection.getState() != ConnectionState.CONNECTED) { 094 // Signin will be attempted when the connection is connected 095 return; 096 } 097 098 AuthenticationResponse authenticationResponse = getAuthenticationResponse(); 099 connection.sendMessage(authenticationResponseToSigninMessage(authenticationResponse)); 100 } 101 102 private static String authenticationResponseToSigninMessage(AuthenticationResponse authenticationResponse) { 103 return GSON.toJson(new SigninMessage(authenticationResponse.getAuth(), authenticationResponse.getUserData())); 104 } 105 106 private AuthenticationResponse getAuthenticationResponse() throws AuthenticationFailureException { 107 String response = userAuthenticator.authenticate(connection.getSocketId()); 108 try { 109 AuthenticationResponse authenticationResponse = GSON.fromJson(response, AuthenticationResponse.class); 110 if (authenticationResponse.getAuth() == null || authenticationResponse.getUserData() == null) { 111 throw new AuthenticationFailureException( 112 "Didn't receive all the fields expected from the UserAuthenticator. Expected auth and user_data" 113 ); 114 } 115 return authenticationResponse; 116 } catch (JsonSyntaxException e) { 117 throw new AuthenticationFailureException("Unable to parse response from AuthenticationResponse"); 118 } 119 } 120 121 private void onSigninSuccess(PusherEvent event) { 122 try { 123 String userData = (String) GSON.fromJson(event.getData(), Map.class).get("user_data"); 124 userId = (String) GSON.fromJson(userData, Map.class).get("id"); 125 } catch (Exception e) { 126 log.severe("Failed parsing user data after signin"); 127 return; 128 } 129 130 if (userId == null) { 131 log.severe("User data doesn't contain an id"); 132 return; 133 } 134 channelManager.subscribeTo(serverToUserChannel, null); 135 } 136 137 private void disconnect() { 138 if (serverToUserChannel.isSubscribed()) { 139 channelManager.unsubscribeFrom(serverToUserChannel.getName()); 140 } 141 userId = null; 142 } 143 144 @Override 145 public String userId() { 146 return userId; 147 } 148 149 @Override 150 public void bind(String eventName, SubscriptionEventListener listener) { 151 serverToUserChannel.bind(eventName, listener); 152 } 153 154 @Override 155 public void bindGlobal(SubscriptionEventListener listener) { 156 serverToUserChannel.bindGlobal(listener); 157 } 158 159 @Override 160 public void unbind(String eventName, SubscriptionEventListener listener) { 161 serverToUserChannel.unbind(eventName, listener); 162 } 163 164 @Override 165 public void unbindGlobal(SubscriptionEventListener listener) { 166 serverToUserChannel.unbindGlobal(listener); 167 } 168}