From 7366ce87b2915a347730212d40a8402552aa42c1 Mon Sep 17 00:00:00 2001 From: JayThomason Date: Thu, 15 May 2014 00:41:13 -0700 Subject: [PATCH] Server now pings clients instead of vice versa when checking to remove clients from jam. --- src/com/stanford/tutti/Client.java | 8 ++ src/com/stanford/tutti/Jam.java | 117 ++++++++++++-------- src/com/stanford/tutti/JoinJamActivity.java | 2 +- src/com/stanford/tutti/MainActivity.java | 4 +- src/com/stanford/tutti/Server.java | 17 +++ 5 files changed, 99 insertions(+), 49 deletions(-) diff --git a/src/com/stanford/tutti/Client.java b/src/com/stanford/tutti/Client.java index 6c41f53..cd97a86 100644 --- a/src/com/stanford/tutti/Client.java +++ b/src/com/stanford/tutti/Client.java @@ -132,6 +132,14 @@ public void removeAllFrom(Client clientToRemove, client.get(url, responseHandler); } + /* + * Sends a ping message to the client to check if it is still there. + */ + public void ping(AsyncHttpResponseHandler responseHandler) { + String url = getUrl("/ping", ""); + client.get(url, responseHandler); + } + private String getUrl(String path, String query) { return "http://" + ipAddress + ":" + port + path + query; } diff --git a/src/com/stanford/tutti/Jam.java b/src/com/stanford/tutti/Jam.java index 63b78c1..e5415a2 100644 --- a/src/com/stanford/tutti/Jam.java +++ b/src/com/stanford/tutti/Jam.java @@ -14,11 +14,13 @@ import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.AsyncHttpResponseHandler; +import android.content.Context; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnPreparedListener; import android.net.Uri; import android.os.Message; +import android.os.PowerManager; public class Jam { ArrayList songList; @@ -76,8 +78,10 @@ public void addClient(Client client) { synchronized (clientSet) { clientSet.add(client); } - usernameMap.put(client.getIpAddress(), client.getUsername()); - keepAliveTimestampMap.put(client.getIpAddress(), System.currentTimeMillis() / 1000L); + usernameMap.put(client.getIpAddress(), client.getUsername()); + synchronized (keepAliveTimestampMap) { + keepAliveTimestampMap.put(client.getIpAddress(), System.currentTimeMillis() / 1000L); + } } public boolean checkMaster() { @@ -179,7 +183,7 @@ public void changeSongIndexInJam(int from, int to) { } currentSong = songList.get(currentSongIndex); } - + public void shuffle() { if (!isShuffled()) { System.out.println("SHUFFLING"); @@ -187,14 +191,14 @@ public void shuffle() { isShuffled = true; // Add a helper to just reload song list from jam database. } else { - + } } - + public void unShuffle() { isShuffled = false; } - + public boolean isShuffled() { return isShuffled; } @@ -433,12 +437,19 @@ public void run() { if (clientKeepAlive.get()) { client.get(url, new AsyncHttpResponseHandler() { @Override + public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { + if (statusCode == 200) { + System.out.println("successfully sent keep alive to master"); + } + else { + System.out.println("failed to send keep alive to master!"); + } + } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { // TODO: in this case we want to display some notification to the user and exit the jam System.out.println("failed keepAlive to master..."); } }); - System.out.println("send keep alive to master"); } else { return; @@ -457,53 +468,38 @@ public void endClientKeepAlive() { clientKeepAlive.set(false); } } - - public void startMasterKeepAliveThread() { + + /* + * Periodically checks if the master has received + */ + public void startMasterClientPingThread() { masterKeepAliveThread = new Thread() { public void run() { + int secondsToSleep = 5; while (true) { try { - Thread.sleep(8 * 1000); - Long currTimestamp = System.currentTimeMillis() / 1000L; - Set clientSet = g.jam.getClientSet(); - Set removeSet = new HashSet(); - // add clients to remove set + Thread.sleep(secondsToSleep * 1000); + Set clientSet = getClientSet(); synchronized (clientSet) { - for (Client client : g.jam.getClientSet()) { - Long lastTimestamp = g.jam.keepAliveTimestampMap.get(client.getIpAddress()); - System.out.println("last timestamp: " + lastTimestamp); - if (lastTimestamp < (currTimestamp - 8)) { // remove if no - System.out.println("Removing " + client.getUsername() + " from jam."); - removeSet.add(client); - } - } - // remove clients in remove set from library and clientSet - for (Client client : removeSet) { - String ipAddr = client.getIpAddress(); - g.db.deleteJamSongsFromIp(ipAddr); - g.db.deleteSongsFromIp(ipAddr); - g.sendUIMessage(0); - clientSet.remove(client); - } - // tell other clients to remove music - for (final Client client : clientSet) { - for (final Client clientToRemove : removeSet) { - client.removeAllFrom(clientToRemove, new AsyncHttpResponseHandler() { - @Override - public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { - if (statusCode == 200) { - System.out.println("client " + client.getUsername() + - " removed client " + clientToRemove.getUsername() + " from jam."); - } - else { - System.out.println("client " + client.getUsername() + - " failed to remove client " + clientToRemove.getUsername() + " from jam."); } + System.out.println("Pinging clients..."); + for (final Client client : getClientSet()) { + client.ping(new AsyncHttpResponseHandler() { + @Override + public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { + if (statusCode != 200) { + removeFromJam(client); } - }); - } + } + + @Override + public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { + removeFromJam(client); + } + }); } } - } catch (Exception e) { + } + catch (Exception e) { e.printStackTrace(); } } @@ -511,4 +507,33 @@ public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { }; masterKeepAliveThread.start(); } + + /* + * Removes the specified client from the jam by removing all of its songs from + * the library and jam and sending a message to all clients telling them to + * remove its songs. + */ + private void removeFromJam(final Client clientToRemove) { + g.db.deleteJamSongsFromIp(clientToRemove.getIpAddress()); + g.db.deleteSongsFromIp(clientToRemove.getIpAddress()); + g.sendUIMessage(0); + synchronized (clientSet) { + clientSet.remove(clientToRemove); + for (final Client client : clientSet) { + client.removeAllFrom(clientToRemove, new AsyncHttpResponseHandler() { + @Override + public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { + if (statusCode == 200) { + System.out.println("client " + client.getUsername() + + " removed client " + clientToRemove.getUsername() + " from jam."); + } + else { + System.out.println("client " + client.getUsername() + + " failed to remove client " + clientToRemove.getUsername() + " from jam."); + } + } + }); + } + } + } } diff --git a/src/com/stanford/tutti/JoinJamActivity.java b/src/com/stanford/tutti/JoinJamActivity.java index a143479..a79cf7e 100644 --- a/src/com/stanford/tutti/JoinJamActivity.java +++ b/src/com/stanford/tutti/JoinJamActivity.java @@ -158,7 +158,7 @@ public void handleMessage(Message msg) { e.printStackTrace(); } - g.jam.startClientKeepAliveThread(); +// g.jam.startClientKeepAliveThread(); Thread getLibraryThread = new RequestLibraryThread(g, ipAddr, PORT); getLibraryThread.start(); diff --git a/src/com/stanford/tutti/MainActivity.java b/src/com/stanford/tutti/MainActivity.java index 79fd69e..f7480c4 100644 --- a/src/com/stanford/tutti/MainActivity.java +++ b/src/com/stanford/tutti/MainActivity.java @@ -42,7 +42,7 @@ protected void onRestart() { super.onRestart(); System.out.println("Main Activity Restarted."); g.jam.endServerKeepAlive(); - g.jam.endClientKeepAlive(); +// g.jam.endClientKeepAlive(); } @Override @@ -181,7 +181,7 @@ public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { if (statusCode == 200) { System.out.println("Successfully created jam on server."); g.jam.startServerKeepAlive(serverHostname); - g.jam.startMasterKeepAliveThread(); + g.jam.startMasterClientPingThread(); g.jam.setMaster(true); if (jamName != null && !jamName.equals("")) { g.jam.setJamName(jamName); diff --git a/src/com/stanford/tutti/Server.java b/src/com/stanford/tutti/Server.java index 5df0d43..b39a031 100644 --- a/src/com/stanford/tutti/Server.java +++ b/src/com/stanford/tutti/Server.java @@ -45,6 +45,7 @@ public class Server extends NanoHTTPD { private static final String JAM_RESTART = "/restart"; private static final String REMOVE_USER_FROM_JAM = "/removeAllFrom"; private static final String KEEP_ALIVE = "/keepAlive"; + private static final String PING = "/ping"; private static final String HTTP_CLIENT_IP = "http-client-ip"; private Globals g = null; @@ -133,6 +134,9 @@ else if (uri.startsWith(UPDATE_JAM)) { else if (uri.startsWith(REMOVE_USER_FROM_JAM)) { return removeUserFromJamResponse(parameters); } + else if (uri.startsWith(PING)) { + return pingResponse(headers.get(HTTP_CLIENT_IP)); + } else if (uri.startsWith(KEEP_ALIVE)) { return keepAliveResponse(headers.get(HTTP_CLIENT_IP)); } @@ -460,4 +464,17 @@ private Response keepAliveResponse(String ipAddr) { } return new NanoHTTPD.Response("OK"); } + + /* + * Returns an OK Http response if the correct master phone performs the ping and a + * bad request response if any other phone performs the ping. + */ + private Response pingResponse(String masterIpAddr) { + if (g.jam.getMasterIpAddr().equals(masterIpAddr)) { + return new NanoHTTPD.Response("OK"); + } + else { + return badRequestResponse(); + } + } } \ No newline at end of file