summaryrefslogtreecommitdiff
path: root/NET/worlds/network/Cache.java
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-02-12 22:33:32 -0800
committerFuwn <[email protected]>2026-02-12 22:33:32 -0800
commitc7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9 (patch)
treedf9f48bf128a6c0186a8e91857d6ff30fe0e9f18 /NET/worlds/network/Cache.java
downloadworldsplayer-c7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9.tar.xz
worldsplayer-c7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9.zip
Initial commit
Diffstat (limited to 'NET/worlds/network/Cache.java')
-rw-r--r--NET/worlds/network/Cache.java385
1 files changed, 385 insertions, 0 deletions
diff --git a/NET/worlds/network/Cache.java b/NET/worlds/network/Cache.java
new file mode 100644
index 0000000..aaf748d
--- /dev/null
+++ b/NET/worlds/network/Cache.java
@@ -0,0 +1,385 @@
+package NET.worlds.network;
+
+import NET.worlds.console.Gamma;
+import NET.worlds.console.Main;
+import NET.worlds.console.MainCallback;
+import NET.worlds.console.MainTerminalCallback;
+import NET.worlds.core.IniFile;
+import NET.worlds.core.Std;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OptionalDataException;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public class Cache implements MainCallback, MainTerminalCallback, Serializable {
+ private static final long serialVersionUID = -7557149391688293661L;
+ private static final long CACHE_VERSION = 0L;
+ private static String CACHE_DIR = Gamma.earlyURLUnalias("home:cachedir/").replace('/', '\\');
+ static final int CACHE_MIN_CHANGE = IniFile.gamma().getIniInt("NetCacheMinChange", 50);
+ static final long CACHE_MAX_DELAY = IniFile.gamma().getIniInt("NetCacheMaxDelay", 5) * 1000L * 60L;
+ private Date lastCacheSave = new Date();
+ static transient Cache cache = initLoad();
+ private transient Hashtable<Object, CacheEntry> table = new Hashtable<Object, CacheEntry>();
+ private transient CacheEntry terminator = new CacheEntry();
+ transient long totalBytes;
+ transient int hasChanged;
+ private int nextAvailable = 1;
+
+ public static void ClearCustomAvatars() {
+ Collection<CacheEntry> c = cache.table.values();
+ Iterator<CacheEntry> it = c.iterator();
+ Vector<CacheEntry> tmp = new Vector<CacheEntry>();
+
+ while (it.hasNext()) {
+ CacheEntry ce = it.next();
+ if (ce != null && ce.url.toString().contains("custom")) {
+ tmp.add(ce);
+ }
+ }
+
+ for (int i = 0; i < tmp.size(); i++) {
+ removeEntry(tmp.get(i));
+ }
+ }
+
+ static Cache initLoad() {
+ System.out.println("Initializing cache...");
+ Cache c = new Cache();
+ FileInputStream in = null;
+ ObjectInputStream s = null;
+
+ try {
+ System.out.println("Restoring cache...");
+ File fi = new File(CACHE_DIR + "cache.index");
+ if (!fi.exists()) {
+ fi = new File(CACHE_DIR + "cache.index.new");
+ if (!fi.exists()) {
+ fi = new File(CACHE_DIR + "cache.index.old");
+ }
+ }
+
+ in = new FileInputStream(fi);
+ s = new ObjectInputStream(in);
+ long version = s.readLong();
+ if (version != 0L) {
+ throw new Exception("Wrong version of cache.index");
+ }
+
+ c = (Cache)s.readObject();
+ c.terminator = new CacheEntry();
+ c.table = new Hashtable<Object, CacheEntry>();
+
+ Object obj;
+ while ((obj = s.readObject()) != null && obj instanceof CacheEntry) {
+ if (((CacheEntry)obj).url != null && ((CacheEntry)obj).localName != null && ((CacheEntry)obj).state >= 7) {
+ c.add((CacheEntry)obj);
+ }
+ }
+
+ s.close();
+ s = null;
+ in.close();
+ in = null;
+ System.out.println("Marking cache as closed...");
+ } catch (OptionalDataException var22) {
+ } catch (Exception var23) {
+ System.out.println(var23);
+ System.out.println("Flushing cache index.");
+ File findex = new File(CACHE_DIR + "cache.index");
+ findex.mkdirs();
+ findex.delete();
+ } finally {
+ if (s != null) {
+ try {
+ s.close();
+ } catch (Exception var21) {
+ }
+
+ ObjectInputStream var26 = null;
+ }
+
+ if (in != null) {
+ try {
+ in.close();
+ } catch (Exception var20) {
+ }
+
+ FileInputStream var25 = null;
+ }
+ }
+
+ String[] names = new File(CACHE_DIR).list();
+ Hashtable<String, String> files = new Hashtable<String, String>();
+ if (names != null) {
+ for (int i = 0; i < names.length; i++) {
+ files.put((CACHE_DIR + names[i]).toUpperCase(), "");
+ }
+
+ files.remove((CACHE_DIR + "cache.index").toUpperCase());
+ }
+
+ c.totalBytes = 0L;
+ c.hasChanged = 0;
+ CacheEntry p = c.terminator.next;
+
+ while (p != c.terminator) {
+ CacheEntry e = p;
+ p = p.next;
+ String name = e.localName.toUpperCase();
+ boolean isFile = files.get(name) != null;
+ files.remove(name);
+ c.totalBytes = c.totalBytes + e.bytes;
+ if (!e.done() || !isFile) {
+ c.remove(e);
+ if (isFile) {
+ new File(name).delete();
+ }
+ }
+ }
+
+ Enumeration<String> e = files.keys();
+
+ while (e.hasMoreElements()) {
+ new File(e.nextElement()).delete();
+ }
+
+ File f = new File("./avatars.zip");
+ if (f.exists()) {
+ cache = c;
+ InjectZipFile(f, "rel:avatar:");
+ }
+
+ c.lastCacheSave = new Date();
+ Main.register(c);
+ return c;
+ }
+
+ public static CacheFile getFile(URL url, boolean forceRecheck) {
+ return cache.getAFile(url, forceRecheck);
+ }
+
+ public static CacheFile getFile(URL url) {
+ return cache.getAFile(url, false);
+ }
+
+ public static CacheFile getFile(String url) {
+ return cache.getAFile(URL.make(url), false);
+ }
+
+ public static CacheEntry getEntry(URL url) {
+ return cache.get(url);
+ }
+
+ public static void removeEntry(CacheEntry ce) {
+ cache.remove(ce);
+ }
+
+ public static void InjectZipFile(File zipFile, String urlPrefix) {
+ long timeStamp = zipFile.lastModified();
+
+ try {
+ ZipFile zf = new ZipFile(zipFile);
+ System.out.println("Adding " + zf.size() + " entries from " + zipFile);
+ Enumeration<?> e = zf.entries();
+
+ while (e.hasMoreElements()) {
+ ZipEntry ze = (ZipEntry)e.nextElement();
+ InputStream is = zf.getInputStream(ze);
+ URL remoteName = URL.make(urlPrefix + ze.getName());
+ CacheEntry ce = cache.get(remoteName);
+ if (ce == null) {
+ String localName = assignLocalName(remoteName);
+ FileOutputStream fos = new FileOutputStream(localName);
+ byte[] buffer = new byte[4096];
+
+ while (true) {
+ try {
+ int bytesRead = is.read(buffer);
+ if (bytesRead == -1) {
+ break;
+ }
+
+ fos.write(buffer, 0, bytesRead);
+ } catch (IOException var14) {
+ break;
+ }
+ }
+
+ fos.close();
+ ce = new CacheEntry();
+ ce.localName = new String(localName);
+ ce.url = remoteName;
+ ce.state = 4;
+ ce.remoteTime = timeStamp;
+ ce.checkTime = new Date();
+ cache.add(ce);
+ }
+
+ is.close();
+ }
+
+ zf.close();
+ } catch (Exception var15) {
+ System.out.println("Error processing cache zip file: " + var15);
+ }
+ }
+
+ private synchronized CacheFile getAFile(URL url, boolean forceRecheck) {
+ CacheEntry e = null;
+ if (url.isRemote()) {
+ e = cache.get(url);
+ if (e == null) {
+ e = new CacheEntry(url);
+ cache.add(e);
+ } else if (forceRecheck) {
+ e.forceRecheck();
+ }
+ }
+
+ return new CacheFile(url, e);
+ }
+
+ private Cache() {
+ }
+
+ @Override
+ public void mainCallback() {
+ }
+
+ public synchronized void resyncIndex() {
+ if (this.hasChanged >= CACHE_MIN_CHANGE || this.lastCacheSave.before(new Date(new Date().getTime() - CACHE_MAX_DELAY))) {
+ this.saveIndex();
+ System.gc();
+ }
+ }
+
+ public void saveIndex() {
+ try {
+ System.out.println("Marking cache as open...");
+ File fin = new File(CACHE_DIR + "cache.index.new");
+ FileOutputStream o = new FileOutputStream(fin);
+ ObjectOutputStream s = new ObjectOutputStream(o);
+ s.writeLong(0L);
+ s.writeObject(this);
+
+ for (CacheEntry e = this.terminator.next; e != this.terminator; e = e.next) {
+ if (e.url != null && e.localName != null) {
+ s.writeObject(e);
+ }
+ }
+
+ s.writeInt(0);
+ s.flush();
+ s.close();
+ o.close();
+ this.lastCacheSave = new Date();
+ this.hasChanged = 0;
+ System.out.println("Marking cache as closed...");
+ File fi = new File(CACHE_DIR + "cache.index");
+ File fio = new File(CACHE_DIR + "cache.index.old");
+ fi.renameTo(fio);
+ fin.renameTo(fi);
+ fio.delete();
+ } catch (Exception var6) {
+ System.out.println("Error writing cache index: " + var6);
+ }
+ }
+
+ @Override
+ public void terminalCallback() {
+ Main.unregister(this);
+ this.saveIndex();
+ }
+
+ static String assignLocalName(URL url) {
+ String remoteName = url.unalias();
+ String ext = ".temp";
+ int lastDot = remoteName.lastIndexOf(46);
+ if (lastDot > remoteName.lastIndexOf(47) && remoteName.indexOf("?", lastDot) < 0 && remoteName.indexOf("#", lastDot) < 0) {
+ ext = remoteName.substring(lastDot);
+ }
+
+ return url.endsWith(".gr2") ? CACHE_DIR + url.getBase() : CACHE_DIR + Integer.toString(cache.nextAvailable++, 36) + ext;
+ }
+
+ public synchronized void add(CacheEntry e) {
+ this.table.put(e.url, e);
+ CacheEntry p = this.terminator.prev;
+ p.next = e;
+ e.prev = p;
+ e.next = this.terminator;
+ this.terminator.prev = e;
+ this.hasChanged++;
+ }
+
+ public int numEntries() {
+ return this.table.size();
+ }
+
+ public synchronized CacheEntry get(URL url) {
+ CacheEntry e = this.table.get(url);
+ if (e != null) {
+ this.markUsed(e);
+ }
+
+ return e;
+ }
+
+ private void markUsed(CacheEntry e) {
+ if (e != null && e.next != this.terminator) {
+ e.prev.next = e.next;
+ e.next.prev = e.prev;
+ this.terminator.prev.next = e;
+ e.prev = this.terminator.prev;
+ e.next = this.terminator;
+ this.terminator.prev = e;
+ }
+ }
+
+ public void remove(CacheEntry e) {
+ this.totalBytes = this.totalBytes - e.bytes;
+ e.prev.next = e.next;
+ e.next.prev = e.prev;
+ e.prev = null;
+ e.next = null;
+ this.table.remove(e.url);
+ this.hasChanged++;
+ new File(e.localName.toUpperCase()).delete();
+ }
+
+ private CacheEntry freeLRU() {
+ for (CacheEntry e = this.terminator.next; e != this.terminator; e = e.next) {
+ if (!e.inUse()) {
+ this.remove(e);
+ return e;
+ }
+ }
+
+ return null;
+ }
+
+ public synchronized void makeSpaceFor(int incomingSize) {
+ while (cache.numEntries() > CacheEntry.CACHE_MAX_ENTRIES && this.freeLRU() != null) {
+ }
+
+ while ((this.totalBytes + 2L * incomingSize) / 1024L > Std.GetDiskFreeSpace() && Std.GetDiskFreeSpace() > -1L) {
+ CacheEntry freed = this.freeLRU();
+ if (freed == null) {
+ break;
+ }
+ }
+ }
+}