summaryrefslogtreecommitdiff
path: root/NET/worlds/network/CacheEntry.java
diff options
context:
space:
mode:
Diffstat (limited to 'NET/worlds/network/CacheEntry.java')
-rw-r--r--NET/worlds/network/CacheEntry.java479
1 files changed, 479 insertions, 0 deletions
diff --git a/NET/worlds/network/CacheEntry.java b/NET/worlds/network/CacheEntry.java
new file mode 100644
index 0000000..b7675b4
--- /dev/null
+++ b/NET/worlds/network/CacheEntry.java
@@ -0,0 +1,479 @@
+package NET.worlds.network;
+
+import NET.worlds.core.IniFile;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URLConnection;
+import java.net.UnknownHostException;
+import java.util.Date;
+import java.util.Observer;
+import java.util.Vector;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
+
+public class CacheEntry implements Runnable, Serializable {
+ private static final long serialVersionUID = 4845526825815464122L;
+ static boolean httpFaulted = IniFile.override().getIniInt("Offline", 0) == 1 || IniFile.gamma().getIniInt("Offline", 0) == 1;
+ static boolean stopOnFault = IniFile.gamma().getIniInt("StopOnHttpFault", 0) == 1;
+ static final int CACHE_MAX_ENTRIES = IniFile.gamma().getIniInt("NetCacheEntries", 1000);
+ static final int MAX_THREADS = IniFile.gamma().getIniInt("NetCacheThreads", 2);
+ static final long CACHE_MOD_TIMEOUT = 3600000L * IniFile.gamma().getIniInt("NetCacheModifiedCheck", 8);
+ static final long CACHE_MOD_TIMEDELAY = 60000L * IniFile.gamma().getIniInt("NetCacheDelay", 5);
+ static final Date refreshStartDate = new Date(new Date().getTime() + CACHE_MOD_TIMEDELAY);
+ static Vector<CacheEntry> threadQueue = new Vector<CacheEntry>();
+ public static final int START = 0;
+ public static final int REFRESHING = 2;
+ public static final int LOADING = 3;
+ public static final int DONE = 4;
+ public static final int ERROR = 5;
+ public static final int NOSUCHFILE = 6;
+ public static final int LOADED = 7;
+ public transient CacheEntry next;
+ public transient CacheEntry prev;
+ int state;
+ private transient int count;
+ URL url;
+ transient int lastRefTime;
+ transient String encoding;
+ String localName;
+ transient Vector<Observer> observers;
+ public long remoteTime = 0L;
+ public Date checkTime;
+ public int netSize = -1;
+ public int bytes;
+ private transient CacheEntry nextDec;
+ private static CacheEntry endDec = new CacheEntry();
+ private static CacheEntry baseDec = endDec;
+ static int refTime = 0;
+ static int numActiveThreads = 0;
+ private static Object finalizeSafeLock = new Object();
+ private static int nextDownloader = 0;
+
+ public static int getConcurrentDownloads() {
+ return numActiveThreads;
+ }
+
+ public static synchronized void setOffline() {
+ httpFaulted = true;
+ stopOnFault = true;
+ }
+
+ public static boolean getOffline() {
+ return httpFaulted;
+ }
+
+ public boolean inUse() {
+ return this.count > 0 || this.state == 3 || this.state == 2;
+ }
+
+ private synchronized void setState(int val) {
+ this.state = val;
+ if (val >= 4) {
+ this.notifyAll();
+ }
+ }
+
+ boolean done() {
+ return this.state >= 4;
+ }
+
+ CacheEntry() {
+ this.next = this;
+ this.prev = this;
+ }
+
+ CacheEntry(URL u) {
+ this.url = u;
+ this.localName = Cache.assignLocalName(u);
+ this.setState(0);
+ }
+
+ public void incRef() {
+ synchronized (finalizeSafeLock) {
+ this.count++;
+ }
+
+ if (this.count == 1) {
+ this.load();
+ }
+ }
+
+ void safeDecRef() {
+ synchronized (finalizeSafeLock) {
+ if (this.nextDec == null) {
+ this.nextDec = baseDec;
+ baseDec = this;
+ } else {
+ this.count--;
+ this.lastRefTime = refTime++;
+ }
+ }
+ }
+
+ synchronized void fullDecRef() {
+ this.notifyAll();
+ synchronized (Cache.cache) {
+ synchronized (finalizeSafeLock) {
+ this.count--;
+ this.lastRefTime = refTime++;
+ }
+
+ if (this.count == 0 && this.remoteTime <= 0L && this.state == 7) {
+ Cache.cache.remove(this);
+ }
+ }
+ }
+
+ void addObserver(Observer o) {
+ if (this.state >= 4) {
+ o.update(null, this.url);
+ } else {
+ synchronized (this) {
+ if (this.observers == null) {
+ this.observers = new Vector<Observer>();
+ }
+
+ this.observers.addElement(o);
+ }
+ }
+ }
+
+ void notifyObservers() {
+ Vector<Observer> v;
+ synchronized (this) {
+ v = this.observers;
+ this.observers = null;
+ }
+
+ if (v != null) {
+ int len = v.size();
+
+ for (int i = 0; i < len; i++) {
+ v.elementAt(i).update(null, this.url);
+ }
+ }
+ }
+
+ URLConnection openURL() throws Exception {
+ int retryCount = IniFile.gamma().getIniInt("NetCacheRetries", 8);
+ java.net.URL u = null;
+ URLConnection uc = null;
+
+ while (!httpFaulted) {
+ try {
+ if (u == null) {
+ String us = this.url.unalias();
+ if (us.endsWith("upgrades.lst")) {
+ us = us + "?" + (int)(Math.random() * 1000000.0);
+ }
+
+ u = DNSLookup.lookup(new java.net.URL(us));
+ }
+
+ uc = u.openConnection();
+ uc.setRequestProperty("Accept-Encoding", "gzip,deflate");
+ if (this.remoteTime > 0L && this.bytes > 0) {
+ uc.setIfModifiedSince(this.remoteTime);
+ }
+
+ uc.connect();
+ this.encoding = uc.getContentEncoding();
+ if (this.encoding == null) {
+ this.encoding = new String("none");
+ }
+
+ this.remoteTime = uc.getLastModified();
+ this.netSize = uc.getContentLength();
+ return uc;
+ } catch (UnknownHostException var5) {
+ if (NetUpdate.isInternalVersion() || stopOnFault) {
+ httpFaulted = true;
+ }
+
+ throw var5;
+ } catch (IOException var6) {
+ retryCount--;
+ if (wasHttpNoSuchFile(var6, uc)) {
+ throw new FileNotFoundException("Http " + this.url);
+ }
+
+ if (retryCount <= 0 || var6 instanceof MalformedURLException) {
+ throw var6;
+ }
+
+ if (this.state == 2) {
+ throw var6;
+ }
+
+ System.out.println("Exception " + var6 + " opening " + this.url + ", retrying...");
+ }
+ }
+
+ throw new FileNotFoundException("Http " + this.url);
+ }
+
+ private static boolean wasHttpNoSuchFile(Exception e, URLConnection uc) {
+ try {
+ if (((HttpURLConnection)uc).getResponseCode() == 404) {
+ return true;
+ }
+ } catch (Exception var3) {
+ }
+
+ return false;
+ }
+
+ public void forceRecheck() {
+ this.checkTime = null;
+ }
+
+ public void load() {
+ if (this.state != 2 && this.state != 3) {
+ Date now = new Date();
+ if (this.state == 5 || this.state == 0) {
+ this.setState(3);
+ } else if (this.localName != null) {
+ if (this.checkTime != null && now.before(refreshStartDate)) {
+ this.notifyObservers();
+ return;
+ }
+
+ Date aWhileAgo = new Date(now.getTime() - CACHE_MOD_TIMEOUT);
+ if (this.checkTime != null && this.checkTime.after(aWhileAgo) && (this.remoteTime > 0L || this.state == 6)) {
+ this.notifyObservers();
+ return;
+ }
+
+ this.setState(2);
+ }
+
+ this.checkTime = now;
+ synchronized (threadQueue) {
+ if (numActiveThreads < MAX_THREADS) {
+ this.startThread();
+ } else {
+ threadQueue.addElement(this);
+ }
+ }
+ }
+ }
+
+ private void startThread() {
+ numActiveThreads++;
+ Thread t = new Thread(this, "File Downloader " + ++nextDownloader);
+ t.setDaemon(true);
+ t.start();
+ }
+
+ @Override
+ public void run() {
+ InputStream in = null;
+ FileOutputStream out = null;
+ URLConnection uc = null;
+
+ try {
+ try {
+ long oldRemoteTime = this.remoteTime;
+ int oldsize = this.netSize;
+ int oldbytes = this.bytes;
+ if (this.state == 2) {
+ if (getOffline()) {
+ this.setState(7);
+ return;
+ }
+
+ long dirTime = DirTimeStamp.request(this.url);
+ if (dirTime > 0L && dirTime <= oldRemoteTime && new Date().getTime() < oldRemoteTime) {
+ this.setState(7);
+ this.finishedLoad();
+ return;
+ }
+
+ uc = this.openURL();
+ if (this.remoteTime > 0L
+ && this.remoteTime <= oldRemoteTime
+ && (oldsize == -1 || this.netSize == -1 || oldsize == this.netSize || this.netSize == oldbytes)) {
+ in = uc.getInputStream();
+ if (in != null) {
+ in.close();
+ }
+
+ this.setState(7);
+ this.finishedLoad();
+ return;
+ }
+
+ if (uc instanceof HttpURLConnection) {
+ int responseCode = ((HttpURLConnection)uc).getResponseCode();
+ boolean keep = false;
+ switch (responseCode) {
+ case 304:
+ case 400:
+ case 500:
+ case 502:
+ case 503:
+ case 504:
+ keep = true;
+ }
+
+ if (keep) {
+ in = uc.getInputStream();
+ if (in != null) {
+ in.close();
+ }
+
+ this.setState(7);
+ this.finishedLoad();
+ return;
+ }
+ }
+
+ this.setState(3);
+ }
+
+ Cache.cache.totalBytes = Cache.cache.totalBytes - this.bytes;
+
+ int tries;
+ for (tries = 0; tries < 2; tries++) {
+ this.bytes = 0;
+ in = null;
+ out = null;
+ if (uc == null) {
+ uc = this.openURL();
+ uc.connect();
+ }
+
+ if (uc instanceof HttpURLConnection) {
+ int responseCode = ((HttpURLConnection)uc).getResponseCode();
+ boolean keep = false;
+ switch (responseCode) {
+ case 304:
+ case 500:
+ case 502:
+ case 503:
+ case 504:
+ keep = true;
+ }
+
+ if (keep) {
+ in = uc.getInputStream();
+ if (in != null) {
+ in.close();
+ }
+
+ this.bytes = oldbytes;
+ Cache.cache.totalBytes = Cache.cache.totalBytes + this.bytes;
+ this.netSize = oldsize;
+ this.setState(7);
+ this.finishedLoad();
+ return;
+ }
+ }
+
+ if (this.encoding != null && this.encoding.equalsIgnoreCase("gzip")) {
+ in = new GZIPInputStream(uc.getInputStream());
+ } else if (this.encoding != null && this.encoding.equalsIgnoreCase("deflate")) {
+ in = new InflaterInputStream(uc.getInputStream(), new Inflater(true));
+ } else {
+ in = uc.getInputStream();
+ }
+
+ Cache.cache.makeSpaceFor(this.netSize);
+ out = new FileOutputStream(this.localName);
+ byte[] buf = new byte[4096];
+
+ int count;
+ while ((count = in.read(buf)) > 0) {
+ out.write(buf, 0, count);
+ this.bytes += count;
+ }
+
+ in.close();
+ in = null;
+ out.close();
+ out = null;
+ if (this.netSize == -1 || this.bytes >= this.netSize || this.encoding.equalsIgnoreCase("gzip") || this.encoding.equalsIgnoreCase("deflate")) {
+ this.setState(7);
+ break;
+ }
+
+ if (tries == 0) {
+ System.out.println("Network error while downloading, trying again...");
+ }
+
+ uc = null;
+ }
+
+ if (this.netSize >= 0 && this.bytes < this.netSize && !this.encoding.equalsIgnoreCase("gzip") && !this.encoding.equalsIgnoreCase("deflate")) {
+ throw new InterruptedException("Network error, got " + this.bytes + " rather than " + this.netSize + " bytes.");
+ }
+
+ if (tries > 0) {
+ System.out.println("Second download attempt succeeded.");
+ }
+
+ Cache.cache.hasChanged++;
+ this.setState(7);
+ } catch (Exception var17) {
+ System.out.println("Download error for " + this.url);
+ System.out.println("\t" + var17.getMessage());
+ System.out.println("\t" + var17.toString());
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException var16) {
+ }
+
+ new File(this.localName).delete();
+ }
+
+ if (wasHttpNoSuchFile(var17, uc) || var17 instanceof FileNotFoundException) {
+ this.setState(6);
+ this.bytes = 0;
+ return;
+ } else {
+ if (this.state == 2) {
+ Cache.cache.hasChanged++;
+ this.setState(7);
+ } else {
+ this.bytes = 0;
+ this.setState(5);
+ }
+
+ return;
+ }
+ }
+ } finally {
+ Cache.cache.totalBytes = Cache.cache.totalBytes + this.bytes;
+ if (this.netSize <= 0) {
+ this.netSize = this.bytes;
+ }
+
+ this.finishedLoad();
+ }
+ }
+
+ private void finishedLoad() {
+ this.notifyObservers();
+ synchronized (threadQueue) {
+ numActiveThreads--;
+
+ while (numActiveThreads < MAX_THREADS && !threadQueue.isEmpty()) {
+ CacheEntry eNext = threadQueue.elementAt(0);
+ threadQueue.removeElementAt(0);
+ eNext.startThread();
+ }
+ }
+
+ if (numActiveThreads <= 0 && threadQueue.isEmpty()) {
+ Cache.cache.resyncIndex();
+ }
+ }
+}