11package com .danikula .videocache ;
22
33import android .content .Context ;
4- import android .os .SystemClock ;
54
65import com .danikula .videocache .file .DiskUsage ;
76import com .danikula .videocache .file .FileNameGenerator ;
1615
1716import java .io .File ;
1817import java .io .IOException ;
19- import java .io .OutputStream ;
2018import java .net .InetAddress ;
2119import java .net .ServerSocket ;
2220import java .net .Socket ;
2321import java .net .SocketException ;
24- import java .util .Arrays ;
2522import java .util .Locale ;
2623import java .util .Map ;
27- import java .util .concurrent .Callable ;
2824import java .util .concurrent .ConcurrentHashMap ;
2925import java .util .concurrent .CountDownLatch ;
30- import java .util .concurrent .ExecutionException ;
3126import java .util .concurrent .ExecutorService ;
3227import java .util .concurrent .Executors ;
33- import java .util .concurrent .Future ;
34- import java .util .concurrent .TimeoutException ;
3528
3629import static com .danikula .videocache .Preconditions .checkAllNotNull ;
3730import static com .danikula .videocache .Preconditions .checkNotNull ;
38- import static java .util .concurrent .TimeUnit .MILLISECONDS ;
3931
4032/**
4133 * Simple lightweight proxy server with file caching support that handles HTTP requests.
5951public class HttpProxyCacheServer {
6052
6153 private static final Logger LOG = LoggerFactory .getLogger ("HttpProxyCacheServer" );
62-
6354 private static final String PROXY_HOST = "127.0.0.1" ;
64- private static final String PING_REQUEST = "ping" ;
65- private static final String PING_RESPONSE = "ping ok" ;
6655
6756 private final Object clientsLock = new Object ();
6857 private final ExecutorService socketProcessor = Executors .newFixedThreadPool (8 );
@@ -71,7 +60,7 @@ public class HttpProxyCacheServer {
7160 private final int port ;
7261 private final Thread waitConnectionThread ;
7362 private final Config config ;
74- private boolean pinged ;
63+ private final Pinger pinger ;
7564
7665 public HttpProxyCacheServer (Context context ) {
7766 this (new Builder (context ).buildConfig ());
@@ -87,65 +76,16 @@ private HttpProxyCacheServer(Config config) {
8776 this .waitConnectionThread = new Thread (new WaitRequestsRunnable (startSignal ));
8877 this .waitConnectionThread .start ();
8978 startSignal .await (); // freeze thread, wait for server starts
90- LOG . info ( "Proxy cache server started. Ping it..." );
91- makeSureServerWorks ( );
79+ this . pinger = new Pinger ( PROXY_HOST , port );
80+ LOG . info ( "Proxy cache server started. Is it alive? " + isAlive () );
9281 } catch (IOException | InterruptedException e ) {
9382 socketProcessor .shutdown ();
9483 throw new IllegalStateException ("Error starting local proxy server" , e );
9584 }
9685 }
9786
98- private void makeSureServerWorks () {
99- int maxPingAttempts = 3 ;
100- int delay = 300 ;
101- int pingAttempts = 0 ;
102- while (pingAttempts < maxPingAttempts ) {
103- try {
104- Future <Boolean > pingFuture = socketProcessor .submit (new PingCallable ());
105- this .pinged = pingFuture .get (delay , MILLISECONDS );
106- if (this .pinged ) {
107- return ;
108- }
109- SystemClock .sleep (delay );
110- } catch (InterruptedException | ExecutionException | TimeoutException e ) {
111- LOG .error ("Error pinging server [attempt: " + pingAttempts + ", timeout: " + delay + "]. " , e );
112- }
113- pingAttempts ++;
114- delay *= 2 ;
115- }
116- LOG .error ("Shutdown server… Error pinging server [attempts: " + pingAttempts + ", max timeout: " + delay / 2 + "]. " +
117- "If you see this message, please, email me [email protected] " );
118- shutdown ();
119- }
120-
121- private boolean pingServer () throws ProxyCacheException {
122- String pingUrl = appendToProxyUrl (PING_REQUEST );
123- HttpUrlSource source = new HttpUrlSource (pingUrl );
124- try {
125- byte [] expectedResponse = PING_RESPONSE .getBytes ();
126- source .open (0 );
127- byte [] response = new byte [expectedResponse .length ];
128- source .read (response );
129- boolean pingOk = Arrays .equals (expectedResponse , response );
130- LOG .info ("Ping response: `" + new String (response ) + "`, pinged? " + pingOk );
131- return pingOk ;
132- } catch (ProxyCacheException e ) {
133- LOG .error ("Error reading ping response" , e );
134- return false ;
135- } finally {
136- source .close ();
137- }
138- }
139-
14087 public String getProxyUrl (String url ) {
141- if (!pinged ) {
142- LOG .
error (
"Proxy server isn't pinged. Caching doesn't work. If you see this message, please, email me [email protected] " );
143- }
144- return pinged ? appendToProxyUrl (url ) : url ;
145- }
146-
147- private String appendToProxyUrl (String url ) {
148- return String .format (Locale .US , "http://%s:%d/%s" , PROXY_HOST , port , ProxyCacheUtils .encode (url ));
88+ return isAlive () ? appendToProxyUrl (url ) : url ;
14989 }
15090
15191 public void registerCacheListener (CacheListener cacheListener , String url ) {
@@ -210,6 +150,14 @@ public void shutdown() {
210150 }
211151 }
212152
153+ private boolean isAlive () {
154+ return pinger .ping (3 , 70 ); // 70+140+280=max~500ms
155+ }
156+
157+ private String appendToProxyUrl (String url ) {
158+ return String .format (Locale .US , "http://%s:%d/%s" , PROXY_HOST , port , ProxyCacheUtils .encode (url ));
159+ }
160+
213161 private void shutdownClients () {
214162 synchronized (clientsLock ) {
215163 for (HttpProxyCacheServerClients clients : clientsMap .values ()) {
@@ -236,8 +184,8 @@ private void processSocket(Socket socket) {
236184 GetRequest request = GetRequest .read (socket .getInputStream ());
237185 LOG .debug ("Request to cache proxy:" + request );
238186 String url = ProxyCacheUtils .decode (request .uri );
239- if (PING_REQUEST . equals (url )) {
240- responseToPing (socket );
187+ if (pinger . isPingRequest (url )) {
188+ pinger . responseToPing (socket );
241189 } else {
242190 HttpProxyCacheServerClients clients = getClients (url );
243191 clients .processRequest (request , socket );
@@ -254,12 +202,6 @@ private void processSocket(Socket socket) {
254202 }
255203 }
256204
257- private void responseToPing (Socket socket ) throws IOException {
258- OutputStream out = socket .getOutputStream ();
259- out .write ("HTTP/1.1 200 OK\n \n " .getBytes ());
260- out .write (PING_RESPONSE .getBytes ());
261- }
262-
263205 private HttpProxyCacheServerClients getClients (String url ) throws ProxyCacheException {
264206 synchronized (clientsLock ) {
265207 HttpProxyCacheServerClients clients = clientsMap .get (url );
@@ -354,14 +296,6 @@ public void run() {
354296 }
355297 }
356298
357- private class PingCallable implements Callable <Boolean > {
358-
359- @ Override
360- public Boolean call () throws Exception {
361- return pingServer ();
362- }
363- }
364-
365299 /**
366300 * Builder for {@link HttpProxyCacheServer}.
367301 */
0 commit comments