From c7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9 Mon Sep 17 00:00:00 2001 From: Fuwn Date: Thu, 12 Feb 2026 22:33:32 -0800 Subject: Initial commit --- NET/worlds/network/Cache.java | 385 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 385 insertions(+) create mode 100644 NET/worlds/network/Cache.java (limited to 'NET/worlds/network/Cache.java') 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 table = new Hashtable(); + private transient CacheEntry terminator = new CacheEntry(); + transient long totalBytes; + transient int hasChanged; + private int nextAvailable = 1; + + public static void ClearCustomAvatars() { + Collection c = cache.table.values(); + Iterator it = c.iterator(); + Vector tmp = new Vector(); + + 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 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 files = new Hashtable(); + 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 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; + } + } + } +} -- cgit v1.2.3