/**
* Copyright 2014-present Liquid Data Intelligence S.A.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.lqd.sdk;
import android.content.Context;
import android.content.SharedPreferences;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import io.lqd.sdk.model.LQModel;
import io.lqd.sdk.model.LQNetworkRequest;
import io.lqd.sdk.model.LQNetworkResponse;
public class LQQueuer extends LQModel {
private static final int LIQUID_QUEUE_SIZE_LIMIT = 500;
private static final int LIQUID_DEFAULT_FLUSH_INTERVAL = 1;
private static final int LIQUID_MAX_NUMBER_OF_TRIES = 10;
private static final String PREF_FILE_NAME = "LQPrefs" ;
private int mFlushInterval;
private Context mContext;
private ArrayList<LQNetworkRequest> mHttpQueue;
private Timer mTimer;
private String mApiToken;
private Liquid mLiquidInstance;
public LQQueuer(Context context, String token) {
this(context, token, new ArrayList<LQNetworkRequest>());
}
public LQQueuer(Context context, String token, ArrayList<LQNetworkRequest> queue) {
mContext = context;
mHttpQueue = queue;
mApiToken = token;
mFlushInterval = LIQUID_DEFAULT_FLUSH_INTERVAL;
}
public boolean addToHttpQueue(LQNetworkRequest queuedEvent) {
mHttpQueue.add(queuedEvent);
if (mHttpQueue.size() > LIQUID_QUEUE_SIZE_LIMIT) {
mHttpQueue.remove(0);
return true;
}
save(mContext, mApiToken);
return false;
}
public synchronized void setFlushTimer(int seconds) {
stopFlushTimer();
mFlushInterval = seconds;
startFlushTimer();
}
public void setLiquidInstance(Liquid instance) {
mLiquidInstance = instance;
}
public synchronized int getFlushTimer() {
return mFlushInterval;
}
public ArrayList<LQNetworkRequest> getQueue() {
return mHttpQueue;
}
public void flush() {
if (LiquidTools.isNetworkAvailable(mContext)) {
Date now = Calendar.getInstance().getTime();
ArrayList<LQNetworkRequest> failedQueue = new ArrayList<LQNetworkRequest>();
LQNetworkResponse result = new LQNetworkResponse();
while (mHttpQueue.size() > 0) {
LQNetworkRequest queuedHttp = mHttpQueue.remove(0);
if (queuedHttp.canFlush(now)) {
LQLog.infoVerbose("Flushing " + queuedHttp.toString());
result = queuedHttp.sendRequest(mApiToken);
if (!result.hasSucceeded()) {
LQLog.error("HTTP (" + result.getHttpCode() + ") " + queuedHttp.toString());
if (queuedHttp.getNumberOfTries() < LIQUID_MAX_NUMBER_OF_TRIES) {
if (!result.hasForbidden()) {
queuedHttp.setLastTry(now);
}
queuedHttp.incrementNumberOfTries();
failedQueue.add(queuedHttp);
}
}
} else {
failedQueue.add(queuedHttp);
}
}
SharedPreferences preferences = mContext.getSharedPreferences(PREF_FILE_NAME, Context.MODE_PRIVATE);
preferences.edit().remove("queue").apply();
mHttpQueue.addAll(failedQueue);
save(mContext, mApiToken);
}
}
public void startFlushTimer() {
if (mFlushInterval <= 0 || mTimer != null) {
return;
}
mTimer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
mLiquidInstance.flush();
}
};
mTimer.scheduleAtFixedRate(task, 0, mFlushInterval * 1000);
LQLog.infoVerbose("Started flush timer");
}
public void stopFlushTimer() {
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
LQLog.infoVerbose("Stopped flush timer");
}
}
@Override
public void save(Context context, String path) {
super.save(context, path + ".queue");
}
@Override
public JSONObject toJSON() {
JSONArray array = new JSONArray();
for(LQNetworkRequest request : mHttpQueue) {
array.put(request.toJSON());
}
JSONObject json = new JSONObject();
try {
json.put("queue", array);
return json;
} catch (JSONException e) {
LQLog.error("Error creating JSONObject from queue.");
}
return null;
}
public static ArrayList<LQNetworkRequest> fromJSON(JSONObject jsonObject) {
ArrayList<LQNetworkRequest> list = new ArrayList<>();
try {
JSONArray jsonArray = jsonObject.getJSONArray("queue");
int length = jsonArray.length();
for(int i = 0 ; i < length; ++i) {
list.add((LQNetworkRequest) LQNetworkRequest.fromJSON(jsonArray.getJSONObject(i)));
}
} catch (JSONException e) {
LQLog.error("Error loading queue from JSONObject.");
}
return list;
}
public static LQQueuer load(Context context, String path) {
return new LQQueuer(context, path, fromJSON(retriveFromFile(context, path + ".queue")));
}
}