Package co.arcs.groove.thresher

Source Code of co.arcs.groove.thresher.Client

package co.arcs.groove.thresher;

import com.belladati.httpclientandroidlib.HttpHeaders;
import com.belladati.httpclientandroidlib.HttpResponse;
import com.belladati.httpclientandroidlib.client.HttpClient;
import com.belladati.httpclientandroidlib.client.config.RequestConfig;
import com.belladati.httpclientandroidlib.client.methods.HttpGet;
import com.belladati.httpclientandroidlib.client.methods.HttpPost;
import com.belladati.httpclientandroidlib.client.methods.HttpRequestBase;
import com.belladati.httpclientandroidlib.entity.BufferedHttpEntity;
import com.belladati.httpclientandroidlib.impl.client.HttpClients;
import com.belladati.httpclientandroidlib.impl.conn.PoolingHttpClientConnectionManager;
import com.belladati.httpclientandroidlib.message.BasicHeader;
import com.belladati.httpclientandroidlib.util.EntityUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.google.common.io.CharStreams;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.annotation.Nullable;

public class Client {

    static final String DOMAIN = "grooveshark.com";
    private static final int TIMEOUT = 10000;

    private boolean debugLogging = false;
    private final HttpClient httpClient;
    private final ObjectMapper jsonMapper;
    private Session session;

    public Client() {
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setDefaultMaxPerRoute(2);

        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(TIMEOUT)
                .setSocketTimeout(TIMEOUT)
                .build();

        List<BasicHeader> headers = Lists.newArrayList(new BasicHeader(HttpHeaders.ACCEPT_ENCODING,
                "gzip,deflate"));

        this.httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .setDefaultHeaders(headers)
                .setDefaultRequestConfig(requestConfig)
                .setUserAgent("")
                .build();

        this.jsonMapper = new ObjectMapper();
    }

    /**
     * Sends a request, and keeps the connection open for re-use.
     *
     * @param requestBuilder
     * @return JSON node containing the response body.
     * @throws IOException
     * @throws GroovesharkException
     */
    JsonNode sendRequest(RequestBuilder requestBuilder) throws IOException, GroovesharkException {

        createSessionIfRequired();
        session.createCommsTokenAsRequired();

        boolean sessionAlreadyRenewed = false;
        boolean commsTokenAlreadyRenewed = false;
        while (true) {

            // Renew out of date session/token
            if (!sessionAlreadyRenewed) {
                createSessionIfRequired();
            }
            if (!commsTokenAlreadyRenewed) {
                session.createCommsTokenAsRequired();
            }

            HttpPost httpRequest = requestBuilder.build(session);
            try {
                JsonNode jsonNode = executeRequest(httpRequest);

                // Handle fault codes from the API
                GroovesharkException exception = mapGroovesharkFaultCodeToException(jsonNode);
                if (exception != null) {
                    if (exception instanceof GroovesharkException.InvalidSessionException) {
                        // Attempt to renew session and retry
                        if (sessionAlreadyRenewed) {
                            throw new GroovesharkException.ServerErrorException(
                                    "Failed with invalid session. Renewed session still invalid.");
                        } else {
                            createSession();
                            sessionAlreadyRenewed = true;
                            continue;
                        }
                    } else if (exception instanceof GroovesharkException.InvalidCommsTokenException) {
                        // Attempt to renew token and retry
                        if (commsTokenAlreadyRenewed) {
                            throw new GroovesharkException.ServerErrorException(
                                    "Failed with invalid comms token. Renewed token also invalid.");
                        } else {
                            session.createCommsToken();
                            commsTokenAlreadyRenewed = true;
                            continue;
                        }
                    } else {
                        // The exception can't be handled internally
                        throw exception;
                    }
                }

                return jsonNode;
            } finally {
                // Finished with connection at this point, so make it reuseable
                httpRequest.reset();
            }
        }
    }

    /**
     * Boilerplate to send the request and parse the response payload as JSON.
     */
    private JsonNode executeRequest(HttpPost request) throws IOException, GroovesharkException {

        HttpResponse response = httpClient.execute(request);

        if (debugLogging) {
            logRequest(request, response);
        }

        String responsePayload = CharStreams.toString(new InputStreamReader(response.getEntity()
                .getContent(), Charsets.UTF_8));

        // Parse response JSON
        try {
            return jsonMapper.readTree(new StringReader(responsePayload));
        } catch (JsonProcessingException e) {
            throw new GroovesharkException.ServerErrorException(
                    "Failed to parse response - received data was not valid JSON: " + responsePayload);
        }
    }

    private static GroovesharkException mapGroovesharkFaultCodeToException(JsonNode jsonNode) {
        if (jsonNode.has("fault")) {
            JsonNode faultNode = jsonNode.get("fault");
            int faultCode = faultNode.get("code").asInt();
            switch (faultCode) {
                case FaultCodes.INVALID_SESSION:
                    return new GroovesharkException.InvalidSessionException(faultNode);
                case FaultCodes.INVALID_TOKEN:
                    return new GroovesharkException.InvalidCommsTokenException(faultNode);
                case FaultCodes.RATE_LIMITED:
                    return new GroovesharkException.RateLimitedException(faultNode);
                case FaultCodes.INVALID_CLIENT:
                case FaultCodes.HTTP_ERROR:
                case FaultCodes.HTTP_TIMEOUT:
                case FaultCodes.MAINTENANCE:
                case FaultCodes.MUST_BE_LOGGED_IN:
                case FaultCodes.PARSE_ERROR:
                default:
                    // Something has gone unrecoverably wrong, so just
                    // return a generic exception with debugging info.
                    return new GroovesharkException.ServerErrorException(faultNode);
            }
        }
        return null;
    }

    private void createSessionIfRequired() throws IOException, GroovesharkException {
        if ((session == null) || session.isExpired()) {
            createSession();
        }
    }

    private void createSession() throws IOException, GroovesharkException {
        User userFromOldSession = (session == null) ? null : session.getUser();
        HttpGet request = new HttpGet("http://" + DOMAIN + "/preload.php?getCommunicationToken");
        HttpResponse response = httpClient.execute(request);

        if (debugLogging) {
            logRequest(request, response);
        }

        Session session = new Session(this, response);
        if (userFromOldSession != null) {
            // If old session was logged in, make sure the new one is too
            login(userFromOldSession.getEmail(), userFromOldSession.getPassword());
        } else {
            this.session = session;
        }
    }

    private void logRequest(HttpRequestBase request, HttpResponse response) throws IOException {
        try {
            ObjectWriter writer = jsonMapper.writer().withDefaultPrettyPrinter();

            System.out.println("=== REQUEST ===");
            System.out.println(request.getURI().toString());

            if (request instanceof HttpPost) {
                String requestPayload = CharStreams.toString(new InputStreamReader(((HttpPost) request)
                        .getEntity()
                        .getContent()));
                JsonNode requestNode = jsonMapper.readTree(requestPayload);
                System.out.println(writer.writeValueAsString(requestNode));
            } else {
                System.out.println("(No body)");
            }

            System.out.println("=== RESPONSE ===");
            if (response.getEntity() != null) {
                BufferedHttpEntity entity = new BufferedHttpEntity(response.getEntity());
                response.setEntity(entity);
                String responsePayload = CharStreams.toString(new InputStreamReader(entity.getContent()));

                try {
                    JsonNode responseNode = jsonMapper.readTree(responsePayload);
                    System.out.println(writer.writeValueAsString(responseNode));
                } catch (JsonProcessingException e) {
                    System.out.println(responsePayload);
                }
            } else {
                System.out.println("(No body)");
            }

            System.out.println();
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
    }

    public InputStream getStream(final Song song) throws IOException, GroovesharkException {
        return getStream(song.getId());
    }

    public InputStream getStream(final long songId) throws IOException, GroovesharkException {
        return getStreamResponse(songId).getEntity().getContent();
    }

    public HttpResponse getStreamResponse(final Song song) throws IOException, GroovesharkException {
        return getStreamResponse(song.getId());
    }

    public HttpResponse getStreamResponse(final long songId) throws IOException, GroovesharkException {
        HttpResponse response = httpClient.execute(new HttpGet(getStreamUrl(songId).toString()));
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode != 200) {
            EntityUtils.consumeQuietly(response.getEntity());
            throw new IOException("API returned " + statusCode + " status code");
        }
        return response;
    }

    public URL getStreamUrl(final Song song) throws IOException, GroovesharkException {
        return getStreamUrl(song.getId());
    }

    public URL getStreamUrl(final long songId) throws IOException, GroovesharkException {
        JsonNode response = sendRequest(new RequestBuilder("getStreamKeyFromSongIDEx", false) {

            @Override
            void populateParameters(Session session, ObjectNode parameters) {
                parameters.put("type", 0);
                parameters.put("prefetch", false);
                parameters.put("songID", songId);
                parameters.put("country", session.getCountry());
                parameters.put("mobile", false);
            }
        });
        JsonNode result = response.get("result");
        if (result.size() == 0) {
            throw new GroovesharkException.ServerErrorException("Received empty response");
        }
        String ip = result.get("ip").asText();
        String streamKey = result.get("streamKey").asText();
        return new URL("http://" + ip + "/stream.php?streamKey=" + streamKey);
    }

    public List<Song> searchSongs(final String query) throws IOException, GroovesharkException {
        JsonNode response = sendRequest(new RequestBuilder("getResultsFromSearch", false) {

            @Override
            void populateParameters(Session session, ObjectNode parameters) {
                parameters.put("type", "Songs");
                parameters.put("query", query);
            }
        });
        ArrayList<Song> songs = Lists.newArrayList();
        Iterator<JsonNode> elements = response.get("result").get("result").elements();
        while (elements.hasNext()) {
            songs.add(new Song(elements.next()));
        }
        return songs;
    }

    public List<Song> searchPopularSongs() throws IOException, GroovesharkException {
        JsonNode response = sendRequest(new RequestBuilder("popularGetSongs", false) {

            @Override
            void populateParameters(Session session, ObjectNode parameters) {
                parameters.put("type", "daily");
            }
        });
        ArrayList<Song> songs = Lists.newArrayList();
        Iterator<JsonNode> elements = response.get("result").get("Songs").elements();
        while (elements.hasNext()) {
            songs.add(new Song(elements.next()));
        }
        return songs;
    }

    /**
     * Logs in as the given user, allowing access to various
     * authentication-requiring methods in the {@link User} class.
     *
     * @param username
     * @param password
     * @return The logged in user. Also available via {@link #getUser()};
     * @throws IOException
     * @throws GroovesharkException
     */
    public User login(final String username,
            final String password) throws IOException, GroovesharkException {
        JsonNode node = sendRequest(new RequestBuilder("authenticateUser", true) {

            @Override
            void populateParameters(Session session, ObjectNode parameters) {
                parameters.put("username", username);
                parameters.put("password", password);
            }
        });
        // Success: the session that created this request is now authenticated,
        // so we can mark is as such.
        User user = new User(this, username, password, node);
        session.setAuthenticated(user);
        return user;
    }

    /**
     * @return The user that logged in via this client, or null.
     */
    @Nullable
    public User getUser() {
        return session.getUser();
    }

    /**
     * Set whether debug information is written to standard output. Default
     * value is disabled.
     */
    public void setDebugLoggingEnabled(boolean enabled) {
        debugLogging = enabled;
    }

    HttpClient getHttpClient() {
        return httpClient;
    }

    ObjectMapper getJsonMapper() {
        return jsonMapper;
    }
}
TOP

Related Classes of co.arcs.groove.thresher.Client

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.