package org.rsbot.script.util.io; import org.rsbot.Configuration; import org.rsbot.script.methods.Web; import org.rsbot.script.wrappers.RSTile; import java.io.*; import java.util.*; import java.util.logging.Logger; /** * The web queue class, passes data to Cache writer. * * @author Timer */ public class WebQueue { public static boolean weAreBuffering = false; public static int bufferingCount = 0; private static final List<String> queue = new ArrayList<String>(), queueOutList = new ArrayList<String>(), removeQueue = new ArrayList<String>(), removeStack = new ArrayList<String>(); private static QueueWriter writer; private static final Logger log = Logger.getLogger(WebQueue.class.getName()); private static final Object queueLock = new Object(), bufferLock = new Object(), removeLock = new Object(); static { writer = new QueueWriter(Configuration.Paths.getWebDatabase()); } /** * Adds collected data to the queue. * * @param gameTiles The data. */ public static void Add(final HashMap<RSTile, Integer> gameTiles) { Web.rs_map.putAll(gameTiles); final int count = gameTiles.size(); new Thread() { @Override public void run() { try { final HashMap<RSTile, Integer> safeMapData = new HashMap<RSTile, Integer>(); safeMapData.putAll(gameTiles); bufferingCount = bufferingCount + count; for (Map.Entry<RSTile, Integer> rsTileIntegerEntry : safeMapData.entrySet()) { final Map.Entry<RSTile, Integer> tileData = rsTileIntegerEntry; final RSTile tile = tileData.getKey(); final int key = tileData.getValue(); if (tileData != null) { synchronized (queueLock) { queue.add(tile.getX() + "," + tile.getY() + "," + tile.getZ() + "k" + key); } synchronized (bufferLock) { bufferingCount--; try { weAreBuffering = true; Thread.sleep(1); } catch (final InterruptedException ignored) { } } } } if (bufferingCount < 0) { bufferingCount = 0; } weAreBuffering = false; } catch (final Exception e) { bufferingCount = count; if (bufferingCount < 0) { bufferingCount = 0; } e.printStackTrace(); } } }.start(); } /** * Removes a tile from the database. * * @param tile The tile to remove. */ public static void Remove(final RSTile tile) { synchronized (removeLock) { Web.rs_map.remove(tile); Remove(tile.getX() + "," + tile.getY() + "," + tile.getZ()); } } /** * Starts the cache writer. */ public static void Start() { if (writer.destroy && !writer.isAlive()) { writer.destroy = false; writer.start(); } } /** * Destroys the cache writer. */ public static void Destroy() { writer.destroyWriter(); } /** * Gets the queue size. * * @param id The id to grab. * @return The size of the queue. */ public static int queueSize(final int id) { switch (id) { case 0: return queue.size(); case 1: return removeQueue.size(); case 2: return removeStack.size(); } return -1; } public static boolean isEmpty() { return queue.size() == 0 && queueOutList.size() == 0 && removeQueue.size() == 0 && removeStack.size() == 0; } /** * The threaded writer class. * * @author Timer */ private static class QueueWriter extends Thread { private boolean destroy = true; private final File file, tmpFile; public QueueWriter(final String fileName) { file = new File(fileName); tmpFile = new File(fileName + ".tmp"); if (!file.exists()) { log.fine("File not created, creating: " + fileName); try { if (file.createNewFile()) { file.setExecutable(false); file.setReadable(true); file.setWritable(true); } } catch (final Exception e) { destroy = true; } } } /** * The main method... doesn't stop until all data is written. */ @Override public void run() { while ((!destroy || queue.size() > 0 || WebQueue.weAreBuffering) && file.exists() && file.canWrite()) { try { if (removeQueue.size() > 0) { synchronized (removeLock) { removeStack.clear(); if (removeQueue.size() > 100) { final List<String> removeQueueSub = new ArrayList<String>(); removeQueueSub.addAll(removeQueue.subList(0, 99)); removeStack.addAll(removeQueueSub); removeQueue.remove(removeQueueSub); } else { removeStack.addAll(removeQueue); removeQueue.clear(); } } final BufferedReader br = new BufferedReader(new FileReader(file)); final PrintWriter pw = new PrintWriter(new FileWriter(tmpFile)); String line; while ((line = br.readLine()) != null) { boolean good = true; final Iterator<String> removeLines = removeStack.listIterator(); while (removeLines.hasNext()) { final String str = removeLines.next(); if (str != null && line.contains(str)) { good = false; break; } } if (good) { pw.println(line); pw.flush(); } } pw.close(); br.close(); if (file.delete()) { if (!tmpFile.renameTo(file)) { destroyWriter(); continue; } } removeStack.clear(); } synchronized (queueLock) { if (queue.size() > 0) { final FileWriter fileWriter = new FileWriter(file, true); final BufferedWriter out = new BufferedWriter(fileWriter); queueOutList.clear(); queueOutList.addAll(queue); queue.clear(); final Iterator<String> outLines = queueOutList.listIterator(); while (outLines.hasNext()) { final String line = outLines.next(); out.write(line + "\n"); } out.flush(); out.close(); } } try { if (!destroy) { Thread.sleep(5000); } } catch (final InterruptedException ignored) { } } catch (final IOException ignored) { } } } public void remove(final String str) { synchronized (removeLock) { removeQueue.add(str); } } public void destroyWriter() { destroy = true; } } /** * Adds a string to remove to the queue. * * @param str The string to remove. */ public static void Remove(final String str) { synchronized (removeLock) { writer.remove(str); } } }