package com.evernote.client.conn.mobile; import android.support.annotation.NonNull; import com.evernote.thrift.transport.TTransport; import com.evernote.thrift.transport.TTransportException; import com.squareup.okhttp.MediaType; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.Response; import com.squareup.okhttp.internal.Util; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import okio.BufferedSink; /** * A {@link TTransport} implementation, which uses an {@link OkHttpClient} to read and write data * to the Evernote service. * * @author rwondratschek */ @SuppressWarnings("unused") public class TAndroidTransport extends TTransport { private static final MediaType MEDIA_TYPE_THRIFT = MediaType.parse("application/x-thrift"); private final OkHttpClient mHttpClient; private final ByteStore mByteStore; private final String mUrl; private InputStream mResponseBody; private Map<String, String> mHeaders; /** * @param httpClient The HTTP client. * @param byteStore Holds the data until it's POSTed with the HTTP client. * @param url The note store URL. */ public TAndroidTransport(@NonNull OkHttpClient httpClient, @NonNull ByteStore byteStore, @NonNull String url) { this(httpClient, byteStore, url, null); } /** * * @param httpClient The HTTP client. * @param byteStore Holds the data until it's POSTed with the HTTP client. * @param url The note store URL. * @param headers Additional headers which are POSTed. */ public TAndroidTransport(OkHttpClient httpClient, ByteStore byteStore, String url, Map<String, String> headers) { mHttpClient = httpClient; mByteStore = byteStore; mUrl = url; mHeaders = headers; } public void addHeader(String name, String value) { if (mHeaders == null) { mHeaders = new HashMap<>(); } mHeaders.put(name, value); } public void addHeaders(Map<String, String> headers) { if (mHeaders == null) { mHeaders = new HashMap<>(); } mHeaders.putAll(headers); } @Override public boolean isOpen() { return true; } @Override public void open() throws TTransportException { // do nothing } @Override public void write(byte[] buf, int off, int len) throws TTransportException { try { mByteStore.write(buf, off, len); } catch (IOException e) { throw new TTransportException(e); } } @Override public void flush() throws TTransportException { Util.closeQuietly(mResponseBody); mResponseBody = null; RequestBody requestBody = new RequestBody() { @Override public MediaType contentType() { if (mHeaders != null && mHeaders.containsKey("Content-Type")) { return MediaType.parse(mHeaders.get("Content-Type")); } else { return MEDIA_TYPE_THRIFT; } } @Override public void writeTo(BufferedSink sink) throws IOException { sink.write(mByteStore.getData(), 0, mByteStore.getBytesWritten()); } }; try { Request.Builder builder = new Request.Builder() .url(mUrl) .post(requestBody); if (mHeaders != null) { for (String name : mHeaders.keySet()) { builder.header(name, mHeaders.get(name)); } } Response response = mHttpClient.newCall(builder.build()).execute(); if (response.code() != 200) { throw new TTransportException("HTTP Response code: " + response.code() + ", message " + response.message()); } mResponseBody = response.body().byteStream(); } catch (Exception e) { throw new TTransportException(e); } finally { try { mByteStore.reset(); } catch (IOException ignored) { } } } @Override public int read(byte[] buf, int off, int len) throws TTransportException { if (mResponseBody == null) { throw new TTransportException("Response buffer is empty, no request."); } try { int ret = mResponseBody.read(buf, off, len); if (ret == -1) { throw new TTransportException("No more data available."); } return ret; } catch (IOException e) { throw new TTransportException(e); } } @Override public void close() { Util.closeQuietly(mResponseBody); mResponseBody = null; } }