Updates... Fixes...

This commit is contained in:
Gabriel Tofvesson 2016-06-24 00:19:22 +02:00
parent 2cab203cf7
commit b9740896da
17 changed files with 197 additions and 128 deletions

View File

@ -64,14 +64,6 @@
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
@ -80,6 +72,14 @@
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
@ -120,5 +120,6 @@
<orderEntry type="library" exported="" name="support-v4-24.0.0" level="project" /> <orderEntry type="library" exported="" name="support-v4-24.0.0" level="project" />
<orderEntry type="library" exported="" name="support-vector-drawable-24.0.0" level="project" /> <orderEntry type="library" exported="" name="support-vector-drawable-24.0.0" level="project" />
<orderEntry type="library" exported="" name="animated-vector-drawable-24.0.0" level="project" /> <orderEntry type="library" exported="" name="animated-vector-drawable-24.0.0" level="project" />
<orderEntry type="module" module-name="libcacher" exported="" />
</component> </component>
</module> </module>

View File

@ -33,4 +33,5 @@ dependencies {
compile 'com.android.support:appcompat-v7:24.0.0' compile 'com.android.support:appcompat-v7:24.0.0'
compile 'com.android.support:design:24.0.0' compile 'com.android.support:design:24.0.0'
compile 'org.jsoup:jsoup:1.9.2' compile 'org.jsoup:jsoup:1.9.2'
compile project(path: ':libcacher')
} }

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.gabriel.projectmonster"> package="com.gabriel.projectmonster">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
@ -29,10 +28,10 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<service android:name="com.gabriel.projectmonster.DSync"/> <service android:name="com.gabriel.projectmonster.network.DSync"/>
<activity <activity
android:name=".MainActivity" android:name=".activity.MainActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"> android:theme="@style/AppTheme.NoActionBar">
<intent-filter> <intent-filter>
@ -42,12 +41,12 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".PostActivity" android:name=".activity.PostActivity"
android:label="@string/title_activity_post" android:label="@string/title_activity_post"
android:theme="@style/AppTheme.NoActionBar"> android:theme="@style/AppTheme.NoActionBar">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="com.gabriel.projectmonster.MainActivity" /> android:value="com.gabriel.projectmonster.activity.MainActivity" />
</activity> </activity>
</application> </application>

View File

@ -4,13 +4,13 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
public class BootReceiver extends BroadcastReceiver { import com.gabriel.projectmonster.network.DSync;
public BootReceiver(){ super(); }
public class BootReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if(intent.getAction().equalsIgnoreCase(Intent.ACTION_BOOT_COMPLETED) || intent.getAction().equalsIgnoreCase(Intent.ACTION_PACKAGE_REPLACED) if(intent.getAction().equalsIgnoreCase(Intent.ACTION_BOOT_COMPLETED) || intent.getAction().equalsIgnoreCase(Intent.ACTION_PACKAGE_REPLACED) || intent.getAction()
|| intent.getAction().equalsIgnoreCase(Intent.ACTION_PACKAGE_ADDED)) .equalsIgnoreCase(Intent.ACTION_PACKAGE_ADDED))
context.startService(new Intent(context, DSync.class)); context.startService(new Intent(context, DSync.class));
} }
} }

View File

@ -1,51 +0,0 @@
package com.gabriel.projectmonster;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.IOException;
public class DSync extends Service {
public int cacheTimeoutSeconds = 3600;
public static final String url = "www.luckyprison.com/";
public static final String store = "store.luckyprison.com";
public static final String[] pages = {"?page=%p", "forums/", "members/"}; //Simple reference to pages on site
public static final String[] memberType = {"", "positive_ratings", "points", "staff"};
public static final String CACHE_FRONT_PAGE_NOID = "front_page_";
// Helpful classes
class DBinder extends Binder { DSync getDataSyncService(){ return DSync.this; } }
private static boolean running = false;
DBinder d = new DBinder();
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
running = true;
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
running = false;
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return d;
}
public static boolean isRunning(){ return running; }
//TODO: Not this
public String loadFrontPage() throws IOException { return null; }
}

View File

@ -1,7 +0,0 @@
package com.gabriel.projectmonster;
import org.jsoup.nodes.Document;
public interface INetworkCallback {
public void onDataReceived(Document data);
}

View File

@ -1,4 +1,4 @@
package com.gabriel.projectmonster; package com.gabriel.projectmonster.activity;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
@ -6,10 +6,10 @@ import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper;
import android.support.design.widget.FloatingActionButton; import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.view.View;
import android.support.design.widget.NavigationView; import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
import android.support.v4.view.GravityCompat; import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.ActionBarDrawerToggle;
@ -19,9 +19,9 @@ import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.TextView; import android.widget.TextView;
import org.jsoup.Jsoup; import com.gabriel.projectmonster.R;
import com.gabriel.projectmonster.network.DSync;
import java.io.IOException; import com.gabriel.projectmonster.network.NetworkConnection;
public class MainActivity extends AppCompatActivity public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener { implements NavigationView.OnNavigationItemSelectedListener {
@ -34,24 +34,18 @@ public class MainActivity extends AppCompatActivity
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
NetworkConnection.getDataAsync("https://luckyprison.com/", d -> ((TextView) MainActivity.this.findViewById(R.id.text)).setText(d.getElementsByTag("html").get(0).toString()), true); NetworkConnection.getDataAsync("https://luckyprison.com/", d -> ((TextView) MainActivity.this.findViewById(R.id.text)).setText(d.getElementsByTag("html").get(0).toString()), Looper.getMainLooper());
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() { fab.setOnClickListener(view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show());
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle); drawer.addDrawerListener(toggle);
toggle.syncState(); toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);

View File

@ -1,4 +1,4 @@
package com.gabriel.projectmonster; package com.gabriel.projectmonster.activity;
import android.os.Bundle; import android.os.Bundle;
import android.support.design.widget.FloatingActionButton; import android.support.design.widget.FloatingActionButton;
@ -7,6 +7,9 @@ import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.view.View; import android.view.View;
import com.gabriel.projectmonster.R;
import com.gabriel.projectmonster.network.DSync;
public class PostActivity extends AppCompatActivity { public class PostActivity extends AppCompatActivity {
DSync d; DSync d;

View File

@ -0,0 +1,69 @@
package com.gabriel.projectmonster.network;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.Looper;
import android.support.annotation.Nullable;
import com.tofvesson.Cacher;
import org.jsoup.Jsoup;
import java.io.IOException;
public class DSync extends Service {
// Helpful classes
public class DBinder extends Binder { public DSync getDataSyncService(){ return DSync.this; } }
// Public values
public static int cacheTimeoutSeconds = 3600;
public static final String url = "www.luckyprison.com/";
public static final String store = "store.luckyprison.com";
public static final String[] pages = {"?page=%p", "forums/", "members/"}; //Simple reference to pages on site
public static final String pageID = "%p";
public static final String[] memberType = {"", "positive_ratings", "points", "staff"};
public static final String CACHE_FRONT_PAGE_NOID = "front_page_";
private Cacher cache;
// Defines if service is running
private static boolean running = false;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
running = true;
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
running = false;
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new DBinder();
}
public static boolean isRunning(){ return running; }
//TODO: Add code to load front page
public void loadFrontPage(INetworkCallback onLoad, Looper whereToExecute) throws IOException {
if(cache.containsKey(CACHE_FRONT_PAGE_NOID+"COUNT"))
if((System.currentTimeMillis()/1000-cache.load(CACHE_FRONT_PAGE_NOID+0).unixTimeCached)<cacheTimeoutSeconds) onLoad.onDataReceived(Jsoup.parse(cache.load(CACHE_FRONT_PAGE_NOID+0).data));
else cache.remove(CACHE_FRONT_PAGE_NOID+0);
else{
NetworkConnection.getDataAsync(url+pages[0].replace(pageID, "0"), d ->
{
String s;
cache.store(CACHE_FRONT_PAGE_NOID+0, d.toString());
cache.store(CACHE_FRONT_PAGE_NOID, (s = (s = d.getElementsByClass("pageNavHeader").get(0).toString()).substring(s.indexOf(">")+1, s.substring(s.indexOf(">")).indexOf("<")+s.indexOf(">")))
.substring(s.lastIndexOf(" ")+1, s.length()) );
onLoad.onDataReceived(d);
}, whereToExecute);
}
}
public void loadFrontPage(INetworkCallback onLoad){ try { loadFrontPage(onLoad, Looper.getMainLooper()); } catch (IOException e) { e.printStackTrace(); } }
}

View File

@ -0,0 +1,7 @@
package com.gabriel.projectmonster.network;
import org.jsoup.nodes.Document;
public interface INetworkCallback {
void onDataReceived(Document data);
}

View File

@ -1,6 +1,5 @@
package com.gabriel.projectmonster; package com.gabriel.projectmonster.network;
import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
@ -13,39 +12,36 @@ import java.io.IOException;
public class NetworkConnection { public class NetworkConnection {
private static volatile boolean callbackInMain = true; static volatile Looper whereToRun;
private static volatile Document data; static volatile Document data;
private static volatile String page = ""; static volatile String page = "";
private static volatile INetworkCallback callback = null; static volatile INetworkCallback callback = null;
private static Thread t; static Thread t;
private static final Runnable grabData = new Runnable(){ static final Runnable grabData = new Runnable(){
@Override @Override
public void run() { public void run() {
// Local variables to make thread functionally compatible with static methods Looper runIn = whereToRun;
boolean call = callbackInMain;
final INetworkCallback c = callback; final INetworkCallback c = callback;
try { data = Jsoup.connect(page).userAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36").get(); } try { data = Jsoup.connect(page).get(); }
catch (IOException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
final Document dat = data; final Document dat = data;
Runnable r = c!=null ? () -> c.onDataReceived(dat) : null; Runnable r = c!=null ? () -> c.onDataReceived(dat) : null;
if(c != null) if(c != null) new Handler(runIn).post(r);
if (call) new Handler(Looper.getMainLooper()).post(r);
else r.run();
} }
}; };
public static Document getData(String page){ public static Document getData(String page){
NetworkConnection.callback = null;
NetworkConnection.page = page; NetworkConnection.page = page;
(t = new Thread(grabData)).start(); (t = new Thread(grabData)).start();
try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); }
return data; return data;
} }
public static void getDataAsync(@NonNull String page, @Nullable INetworkCallback callback, boolean callbackInMainThread){ public static void getDataAsync(@NonNull String page, @Nullable INetworkCallback callback, @NonNull Looper runIn){
callbackInMain = callbackInMainThread; runIn = whereToRun;
NetworkConnection.page = page; NetworkConnection.page = page;
NetworkConnection.callback = callback; NetworkConnection.callback = callback;
(t = new Thread(grabData)).start(); (t = new Thread(grabData)).start();
NetworkConnection.callback = null;
} }
} }

View File

@ -5,7 +5,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
tools:context="com.gabriel.projectmonster.PostActivity"> tools:context="com.gabriel.projectmonster.activity.PostActivity">
<android.support.design.widget.AppBarLayout <android.support.design.widget.AppBarLayout
android:id="@+id/app_bar" android:id="@+id/app_bar"

View File

@ -5,7 +5,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
tools:context="com.gabriel.projectmonster.MainActivity"> tools:context="com.gabriel.projectmonster.activity.MainActivity">
<android.support.design.widget.AppBarLayout <android.support.design.widget.AppBarLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -9,7 +9,7 @@
android:paddingRight="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin" android:paddingTop="@dimen/activity_vertical_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior" app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.gabriel.projectmonster.MainActivity" tools:context="com.gabriel.projectmonster.activity.MainActivity"
tools:showIn="@layout/app_bar_main"> tools:showIn="@layout/app_bar_main">
<TextView <TextView

View File

@ -5,7 +5,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.gabriel.projectmonster.PostActivity" tools:context="com.gabriel.projectmonster.activity.PostActivity"
tools:showIn="@layout/activity_post"> tools:showIn="@layout/activity_post">
<TextView <TextView

View File

@ -1,7 +1,7 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:context="com.gabriel.projectmonster.PostActivity"> tools:context="com.gabriel.projectmonster.activity.PostActivity">
<item <item
android:id="@+id/action_settings" android:id="@+id/action_settings"
android:orderInCategory="100" android:orderInCategory="100"

View File

@ -5,15 +5,12 @@ import com.sun.istack.internal.Nullable;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.Closeable; import java.io.Closeable;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream; import java.io.PrintStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -21,13 +18,15 @@ import java.util.Map;
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public class Cacher implements Closeable{ public class Cacher implements Closeable{
private class CacheDataHolder{ int unixTimeCached = 0; String data = ""; public CacheDataHolder(String s, int i){ unixTimeCached=i; data=s; } } public class CacheDataHolder{ public int unixTimeCached = 0; public String data = ""; public CacheDataHolder(String s, int i){ unixTimeCached=i; data=s; } }
private PrintStream cache; boolean verbose;
private BufferedReader cacheIn; Thread purger;
private FileReader cacheFileReader; PrintStream cache;
private File cacheFile; BufferedReader cacheIn;
private Map<String, CacheDataHolder> cachedValues = new HashMap<>(); FileReader cacheFileReader;
File cacheFile;
Map<String, CacheDataHolder> cachedValues = new HashMap<>();
public Cacher(File file, String s) throws FileNotFoundException, UnsupportedEncodingException { public Cacher(File file, String s) throws FileNotFoundException, UnsupportedEncodingException {
if(!(cacheFile = file).isFile()) try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } if(!(cacheFile = file).isFile()) try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); }
@ -102,6 +101,8 @@ public class Cacher implements Closeable{
return false; return false;
} }
public boolean containsKey(String k){ return cachedValues.containsKey(k) || cacheContainsKey(k); }
public void store(String k, String v, int cacheTime){ public void store(String k, String v, int cacheTime){
if(cachedValues.containsKey(k = k.replace("[", "[lb").replace(" ", "[sp"))) cachedValues.replace(k, new CacheDataHolder(v.replace("[", "[lb").replace(" ", "[sp"), cacheTime)); if(cachedValues.containsKey(k = k.replace("[", "[lb").replace(" ", "[sp"))) cachedValues.replace(k, new CacheDataHolder(v.replace("[", "[lb").replace(" ", "[sp"), cacheTime));
else cachedValues.put(k, new CacheDataHolder(v.replace("[", "[lb").replace(" ", "[sp"), cacheTime)); else cachedValues.put(k, new CacheDataHolder(v.replace("[", "[lb").replace(" ", "[sp"), cacheTime));
@ -118,13 +119,24 @@ public class Cacher implements Closeable{
return null; return null;
} }
public void remove(String k){
if(cachedValues.containsKey(k)) cachedValues.remove(k);
if(cacheContainsKey(k)){
for(String s : loadKeysFromCache())
if(!cachedValues.containsKey(k))
cachedValues.put(k, loadFromCache(k));
cachedValues.remove(k);
try { overwriteCache(); } catch (IOException e) { e.printStackTrace(); }
}
}
@Nullable @Nullable
private CacheDataHolder loadFromCache(String k){ private CacheDataHolder loadFromCache(String k){
k = k.replace("[", "[lb").replace(" ", "[sp"); k = k.replace("[", "[lb").replace(" ", "[sp");
String s = ""; String s = "";
try { try {
while((s = cacheIn.readLine())!=null) if(s.substring(0, s.indexOf(" ")).equals(k)) //value 123 while((s = cacheIn.readLine())!=null) if(s.substring(0, s.indexOf(" ")).equals(k)) //value 123
return new CacheDataHolder(s.substring(s.indexOf(" ")+1, s.substring(s.indexOf(" ")+1).indexOf(" ")+s.indexOf(" ")).replace(" ", "[sp").replace("[", "[lb"), return new CacheDataHolder(s.substring(s.indexOf(" ")+1, s.substring(s.indexOf(" ")+1).indexOf(" ")+s.indexOf(" ")).replace("[sp", " ").replace("[lb", "["),
Integer.parseInt(s.substring(s.substring(s.indexOf(" ")+1).indexOf(" ")+1+s.indexOf(" ")))); Integer.parseInt(s.substring(s.substring(s.indexOf(" ")+1).indexOf(" ")+1+s.indexOf(" "))));
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@ -136,15 +148,22 @@ public class Cacher implements Closeable{
String s = ""; String s = "";
List<String> keys = new ArrayList<>(); List<String> keys = new ArrayList<>();
try { resetReader(); while((s = cacheIn.readLine())!=null) keys.add(s.substring(s.indexOf(" "))); } catch (IOException e) { e.printStackTrace(); } try { resetReader(); while((s = cacheIn.readLine())!=null) keys.add(s.substring(s.indexOf(" "))); } catch (IOException e) { e.printStackTrace(); }
return keys; return keys;
} }
public void flush() throws IOException { public void flush() {
List<String> fileKeys = loadKeysFromCache(); List<String> fileKeys = loadKeysFromCache();
for(String k : fileKeys) for(String k : fileKeys)
if(cachedValues.containsKey(k)) cachedValues.replace(k, loadFromCache(k)); if(cachedValues.containsKey(k)) cachedValues.replace(k, loadFromCache(k));
else cachedValues.put(k, loadFromCache(k)); else cachedValues.put(k, loadFromCache(k));
try{
overwriteCache();
}catch(IOException e){
e.printStackTrace();
}
}
private void overwriteCache() throws IOException {
cacheFile.delete(); cacheFile.delete();
cacheFile.createNewFile(); cacheFile.createNewFile();
cache = new PrintStream(cacheFile); cache = new PrintStream(cacheFile);
@ -184,16 +203,54 @@ public class Cacher implements Closeable{
return true; return true;
} }
private int allOccurrencesOf(String s, String sequence){ private int allOccurrencesOf(String s, String regex){
int i = 0; int i = 0;
//Assign string to the substring *after* first instance of sequence by incrementing counter, dividing counter variable by itself (i/i = 1) //Assign string to the substring *after* first instance of sequence by incrementing counter, dividing counter variable by itself (i/i = 1)
//and multiplying by length of sequence to exclude it from new string //and multiplying by length of sequence to exclude it from new string
while(s.indexOf(sequence)!=0) s = s.substring(s.indexOf(sequence)+(((++i)/i)*sequence.length())); while(s.indexOf(regex)!=0) s = s.substring(s.indexOf(regex)+(((++i)/i)*regex.length()));
return i; return i;
} }
public void purge(int timeout) {
for (String k : cachedValues.keySet())
if (timeout < (System.currentTimeMillis() / 1000) - cachedValues.get(k).unixTimeCached)
cachedValues.remove(k);
for (String k : loadKeysFromCache())
if (timeout < (System.currentTimeMillis() / 1000) - loadFromCache(k).unixTimeCached)
remove(k);
}
/**
* Starts a thread that will automatically purge old/unusable resources
* @param maxTime The maximum time in seconds between the current time and the time when resource was cached before the resource is purged
* @param timedelay Time interval between purges (choose a relatively high number to minimize high proceeor loads)
* @param verbose Whether or not to output debug to System.out
*/
public void startAutoPurge(final int maxTime, final int timedelay, final boolean verbose){
purger = new Thread(new Runnable() {
@Override
public void run() {
while(true) {
if (verbose) System.out.println("Purging cache...");
purge(maxTime);
try {
Thread.sleep(timedelay * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
purger.start();
}
@Override @Override
public void close() throws IOException { public void close() throws IOException {
this.flush();
closeNoFlush();
}
public void closeNoFlush() throws IOException {
cache.close(); cache.close();
cacheIn.close(); cacheIn.close();
} }