Skip to content

Commit

Permalink
feat: immediate request
Browse files Browse the repository at this point in the history
  • Loading branch information
arifBurakDemiray committed Sep 25, 2023
1 parent ce1ff84 commit d38cb1a
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package ly.count.sdk.java.internal;

interface ImmediateRequestI {
void doWork(String requestData, String customEndpoint, Transport cp, boolean requestShouldBeDelayed, boolean networkingIsEnabled, ImmediateRequestMaker.InternalImmediateRequestCallback callback, Log log);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package ly.count.sdk.java.internal;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.concurrent.CompletableFuture;
import org.json.JSONObject;

/**
* Async task for making immediate server requests
*/
class ImmediateRequestMaker implements ImmediateRequestI {

@Override
public void doWork(String requestData, String customEndpoint, Transport cp, boolean requestShouldBeDelayed, boolean networkingIsEnabled, InternalImmediateRequestCallback callback, Log log) {
CompletableFuture.supplyAsync(() -> doInBackground(requestData, customEndpoint, cp, requestShouldBeDelayed, networkingIsEnabled, callback, log))
.thenAcceptAsync(this::onFinished);
}

/**
* Used for callback from async task
*/
protected interface InternalImmediateRequestCallback {
void callback(JSONObject checkResponse);
}

InternalImmediateRequestCallback callback;
Log L;

/**
* params fields:
* 0 - requestData
* 1 - custom endpoint
* 2 - connection processor
* 3 - requestShouldBeDelayed
* 4 - networkingIsEnabled
* 5 - callback
* 6 - log module
*/
protected JSONObject doInBackground(String requestData, String customEndpoint, Transport cp, boolean requestShouldBeDelayed, boolean networkingIsEnabled, InternalImmediateRequestCallback callback, Log log) {
this.callback = callback;
L = log;

if (!networkingIsEnabled) {
L.w("[ImmediateRequestMaker] ImmediateRequestMaker, Networking config is disabled, request cancelled. Endpoint[" + customEndpoint + "] request[" + requestData + "]");

return null;
}

L.v("[ImmediateRequestMaker] Starting request");

HttpURLConnection connection = null;

try {
L.d("[ImmediateRequestMaker] delayed[" + requestShouldBeDelayed + "] hasCallback[" + (callback != null) + "] endpoint[" + customEndpoint + "] request[" + requestData + "]");

if (requestShouldBeDelayed) {
//used in cases after something has to be done after a device id change
L.v("[ImmediateRequestMaker] request should be delayed, waiting for 0.5 seconds");

try {
Thread.sleep(500);
} catch (InterruptedException e) {
L.w("[ImmediateRequestMaker] While waiting for 0.5 seconds in ImmediateRequestMaker, sleep was interrupted");
}
}

Request request = new Request();
request.params.add(requestData);
request.endpoint(customEndpoint);
//getting connection ready
try {
connection = cp.connection(request);
} catch (IOException e) {
L.e("[ImmediateRequestMaker] IOException while preparing remote config update request :[" + e.toString() + "]");

return null;
}

//connecting
connection.connect();

int code = connection.getResponseCode();

String receivedBuffer = cp.response(connection);

if (receivedBuffer == null) {
L.e("[ImmediateRequestMaker] Encountered problem while making a immediate server request, received result was null");
return null;
}

char firstChar = receivedBuffer.trim().charAt(0);
if (code >= 200 && code < 300 && (firstChar == '[' || receivedBuffer.contains("result"))) {
L.d("[ImmediateRequestMaker] Received the following response, :[" + receivedBuffer + "]");

// we check if the result was a json array or json object and convert the array into an object if necessary
if (firstChar == '[') {
return new JSONObject("{\"jsonArray\":" + receivedBuffer + "}");
}
return new JSONObject(receivedBuffer);
} else {
L.e("[ImmediateRequestMaker] Encountered problem while making a immediate server request, :[" + receivedBuffer + "]");
return null;
}
} catch (Exception e) {
L.e("[ImmediateRequestMaker] Received exception while making a immediate server request " + e.getMessage());
} finally {
if (connection != null) {
connection.disconnect();
}
}
L.v("[ImmediateRequestMaker] Finished request");
return null;
}

protected void onFinished(JSONObject result) {
L.v("[ImmediateRequestMaker] onPostExecute");

if (callback != null) {
callback.callback(result);
}
}
}
66 changes: 64 additions & 2 deletions sdk-java/src/main/java/ly/count/sdk/java/internal/Transport.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
Expand All @@ -30,13 +31,11 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import ly.count.sdk.java.User;
import org.json.JSONObject;

Expand Down Expand Up @@ -214,6 +213,69 @@ HttpURLConnection connection(final Request request, final User user) throws IOEx
return connection;
}

/**
* Open connection for particular request: choose GET or POST, choose multipart or urlencoded if POST,
* set SSL context, calculate and add checksum, load and send user picture if needed.
*
* @param request request to send
* @return connection, not {@link HttpURLConnection} yet
* @throws IOException from {@link HttpURLConnection} in case of error
*/
HttpURLConnection connection(final Request request) throws IOException {
String endpoint = request.params.remove(Request.ENDPOINT);
if (endpoint == null) {
endpoint = "/i?";
}

String path = config.getServerURL().toString() + endpoint;
boolean usingGET = !config.isUsePOST() && request.isGettable(config.getServerURL());

if (usingGET && config.getParameterTamperingProtectionSalt() != null) {
request.params.add(CHECKSUM, Utils.digestHex(PARAMETER_TAMPERING_DIGEST, request.params + config.getParameterTamperingProtectionSalt(), L));
}

HttpURLConnection connection = openConnection(path, request.params.toString(), usingGET);
connection.setConnectTimeout(1000 * config.getNetworkConnectionTimeout());
connection.setReadTimeout(1000 * config.getNetworkReadTimeout());

if (connection instanceof HttpsURLConnection && sslContext != null) {
HttpsURLConnection https = (HttpsURLConnection) connection;
https.setSSLSocketFactory(sslContext.getSocketFactory());
}

if (!usingGET) {
OutputStream output = null;
PrintWriter writer = null;
try {
if (config.getParameterTamperingProtectionSalt() != null) {
request.params.add(CHECKSUM, Utils.digestHex(PARAMETER_TAMPERING_DIGEST, request.params + config.getParameterTamperingProtectionSalt(), L));
}
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

output = connection.getOutputStream();
writer = new PrintWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8), true);

writer.write(request.params.toString());
writer.flush();
} finally {
if (writer != null) {
try {
writer.close();
} catch (Throwable ignored) {
}
}
if (output != null) {
try {
output.close();
} catch (Throwable ignored) {
}
}
}
}

return connection;
}

void addMultipart(OutputStream output, PrintWriter writer, String boundary, String contentType, String name, String value, Object file) throws IOException {
writer.append("--").append(boundary).append(Utils.CRLF);
if (file != null) {
Expand Down

0 comments on commit d38cb1a

Please sign in to comment.