diff options
| author | Fuwn <[email protected]> | 2026-02-12 22:33:32 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-12 22:33:32 -0800 |
| commit | c7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9 (patch) | |
| tree | df9f48bf128a6c0186a8e91857d6ff30fe0e9f18 /NET/worlds/network/CacheEntry.java | |
| download | worldsplayer-c7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9.tar.xz worldsplayer-c7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9.zip | |
Initial commit
Diffstat (limited to 'NET/worlds/network/CacheEntry.java')
| -rw-r--r-- | NET/worlds/network/CacheEntry.java | 479 |
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(); + } + } +} |