package plugins.CENO.Client; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.TimeUnit; import plugins.CENO.Client.Signaling.Channel; import plugins.CENO.Common.URLtoUSKTools; public class RequestSender { private static volatile RequestSender requestSender = new RequestSender(); private Hashtable<String, Long> requestTable; private List<String> batchList; private Timer timer; private Boolean newUrlArrived = false; /** * Time to wait since a request for a URL was originally received from CC before sending * a request to the bridge. */ private static final long SHOULD_QUEUE_URL = TimeUnit.MINUTES.toMillis(2); /** * Time to wait before sending a new request for the same URL */ private static final long REQUEST_TIMEOUT = TimeUnit.MINUTES.toMillis(40); /** * Maximum size in bytes of a batch request in order to fit within the USK chunk */ private static final long MAX_BATCH_SIZE = 1024; private RequestSender() { this.requestTable = new Hashtable<String, Long>(); batchList = new ArrayList<String>(); timer = new Timer("BatchRequestTimer", true); timer.schedule(new BatchReqInserter(), 0, TimeUnit.MINUTES.toMillis(3)); } public void stopTimerTasks() { if (timer != null) { timer.cancel(); timer.purge(); } } public static RequestSender getInstance() { return requestSender; } public void requestFromBridge(String url) { if (shouldSignalBridge(url)) { synchronized (newUrlArrived) { newUrlArrived = true; addInBatch(url); requestTable.put(url, System.currentTimeMillis() + REQUEST_TIMEOUT - SHOULD_QUEUE_URL); } } } public synchronized boolean shouldSignalBridge(String url) { String urlValidated = null; try { urlValidated = URLtoUSKTools.validateURL(url); } catch (MalformedURLException e) { return false; } if (URLtoUSKTools.isFeedURL(urlValidated)) { return false; } if (!requestTable.containsKey(urlValidated)) { requestTable.put(url, System.currentTimeMillis()); } return (System.currentTimeMillis() - requestTable.get(urlValidated) > SHOULD_QUEUE_URL); } private void addInBatch(String url) { synchronized (batchList) { if (!batchList.contains(url)) { batchList.add(url); } } } public void removeFromBatch(String url) { synchronized (batchList) { batchList.remove(url); } } private class BatchReqInserter extends TimerTask { public BatchReqInserter() {} @Override public void run() { synchronized (newUrlArrived) { if(!newUrlArrived || !CENOClient.channelMaker.sentPrivUSK()) { return; } int batchSize = 0; StringBuilder batchListStr = new StringBuilder(); for (int i = batchList.size() - 1; i >= 0; i--) { String url = batchList.get(i); batchSize += url.getBytes().length; if (batchSize < MAX_BATCH_SIZE) { batchListStr.append(url); batchListStr.append("\n"); } } String batchReq = batchListStr.toString(); if (batchReq.isEmpty()) { return; } if (Channel.insertBatch(batchReq)) { newUrlArrived = false; } } } } }