waf

FORK: waf with some random patches
git clone https://git.neptards.moe/neptards/waf.git
Log | Files | Refs | README

Netcache.java (6951B)


      1 // Thomas Nagy, 2011
      2 
      3 // TODO security
      4 // TODO handle all exceptions properly
      5 
      6 import java.util.HashMap;
      7 import java.util.Map;
      8 import java.util.List;
      9 import java.util.Date;
     10 import java.util.ArrayList;
     11 import java.util.Comparator;
     12 import java.util.Collections;
     13 import java.lang.Math;
     14 import java.lang.StringBuilder;
     15 import java.io.*;
     16 import java.net.*;
     17 import java.security.*;
     18 
     19 public class Netcache implements Runnable, Comparator<Object[]> {
     20 	private static int PORT_UPLOAD   = 11001;
     21 	private static int PORT_DOWNLOAD = 12001;
     22 	private static String CACHEDIR = "/tmp/wafcache/";
     23 	private static long MAX = 10l * 1024l * 1024l * 1024l;
     24 	private static double CLEANRATIO = 0.8;
     25 	private static int BUF = 16 * 8192;
     26 
     27 	private final static HashMap<String, Object[]> flist = new HashMap<String, Object[]>();
     28 	private Socket sock = null;
     29 	private int port = 0;
     30 
     31 	public Netcache(Socket sock, int port) {
     32 		this.sock = sock;
     33 		this.port = port;
     34 	}
     35 
     36 	public void run () {
     37 		try {
     38 			if (sock != null)
     39 			{
     40 				while (true) {
     41 					InputStream in = sock.getInputStream();
     42 					OutputStream out = sock.getOutputStream();
     43 
     44 					byte b[] = new byte[128];
     45 					int off = 0;
     46 					while (off < b.length) {
     47 						off += in.read(b, off, b.length - off);
     48 					}
     49 
     50 					//System.out.println(new String(b));
     51 					String[] args = new String(b).split(",");
     52 					if (args[0].equals("LST")) {
     53 						lst(args, in, out);
     54 					}
     55 					else if (args[0].equals("PUT") && port == PORT_UPLOAD) {
     56 						put(args, in, out);
     57 					}
     58 					else if (args[0].equals("GET") && port == PORT_DOWNLOAD) {
     59 						get(args, in, out);
     60 					}
     61 					else if (args[0].equals("CLEAN") && port == PORT_UPLOAD) {
     62 						clean(args, in, out);
     63 					}
     64 					else if (args[0].equals("BYE")) {
     65 						sock.close();
     66 						break;
     67 					}
     68 					else {
     69 						System.out.println("Invalid command " + new String(b) + " on port " + this.port);
     70 						sock.close();
     71 						break;
     72 					}
     73 				}
     74 			} else {
     75 				// magic trick to avoid creating a new inner class
     76 				ServerSocket server = new ServerSocket(port);
     77 				server.setReuseAddress(true);
     78 				while(true) {
     79 					Netcache tmp = new Netcache(server.accept(), port);
     80 					Thread t = new Thread(tmp);
     81 					t.start();
     82 				}
     83 			}
     84 		} catch (IOException e) {
     85 			e.printStackTrace();
     86 		}
     87 	}
     88 
     89 	public void lst(String[] args, InputStream in, OutputStream out) throws IOException {
     90 		StringBuilder b = new StringBuilder();
     91 		int k = 0;
     92 		synchronized(flist) {
     93 			for (String name : flist.keySet()) {
     94 				b.append(name);
     95 				if (k <= flist.size()) {
     96 					k++;
     97 					b.append("\n");
     98 				}
     99 			}
    100 		}
    101 
    102 		byte[] ret = b.toString().getBytes();
    103 		String header = String.format("%-128s", String.format("%d,", ret.length));
    104 
    105 		out.write(header.getBytes());
    106 		out.write(ret);
    107 	}
    108 
    109 	public void put(String[] args, InputStream in, OutputStream out) throws IOException {
    110 		File cachedir = new File(CACHEDIR);
    111 		File temp = File.createTempFile("foo", ".suffix", cachedir);
    112 
    113 		long size = new Long(args[3].trim());
    114 
    115 		//System.out.println("" + args[1] + " " + args[2] + " " + args[3] + " " + args.length);
    116 
    117 		byte[] buf = new byte[BUF];
    118 		long cnt = 0;
    119 		OutputStream w = new FileOutputStream(temp);
    120 		try {
    121 			while (cnt < size) {
    122 				int c = in.read(buf, 0, (int) Math.min(BUF, size-cnt));
    123 				if (c == 0) {
    124 					throw new RuntimeException("Connection closed too early");
    125 				}
    126 				w.write(buf, 0, c);
    127 				cnt += c;
    128 			}
    129 		} finally {
    130 			w.close();
    131 		}
    132 
    133 		/*if (cnt != size) {
    134 		  System.out.println("error!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
    135 		  }*/
    136 
    137 		File parent = new File(new File(new File(CACHEDIR), args[1].substring(0, 2)), args[1]);
    138 		File dest = new File(parent, args[2]);
    139 		try {
    140 			dest.getParentFile().mkdirs();
    141 		} catch (Exception e) {
    142 		}
    143 
    144 		if (!temp.renameTo(dest)) {
    145 			throw new RuntimeException("Could not rename the file");
    146 		}
    147 
    148 		long total = 0;
    149 		for (File f : parent.listFiles()) {
    150 			total += f.length();
    151 		}
    152 
    153 		synchronized(flist) {
    154 			if (flist.containsKey(parent.getName())) {
    155 				flist.get(parent.getName())[0] = parent.lastModified();
    156 			}
    157 			else
    158 			{
    159 				flist.put(parent.getName(), new Object[] {parent.lastModified(), total, parent.getName()});
    160 			}
    161 		}
    162 	}
    163 
    164 	public void get(String[] args, InputStream in, OutputStream out) throws IOException {
    165 		File f = new File(new File(new File(new File(CACHEDIR), args[1].substring(0, 2)), args[1]), args[2].trim());
    166 		long fsize = -1;
    167 		try {
    168 			fsize = f.length();
    169 		} catch (Exception e) {
    170 			// return -1 to the client
    171 		}
    172 
    173 		String ret = String.format("%-128s", String.format("%d,", fsize));
    174 		out.write(ret.getBytes());
    175 
    176 		byte[] buf = new byte[BUF];
    177 
    178 		long cnt = 0;
    179 		InputStream s = new FileInputStream(f);
    180 		try {
    181 			while (cnt < fsize) {
    182 				long c = s.read(buf);
    183 				cnt += c;
    184 				out.write(buf, 0, (int) c);
    185 			}
    186 		} finally {
    187 			s.close();
    188 		}
    189 
    190 		File parent = f.getParentFile();
    191 		Date d = new Date();
    192 		parent.setLastModified(d.getTime());
    193 		synchronized(flist) {
    194 			flist.get(parent.getName())[0] = parent.lastModified();
    195 		}
    196 	}
    197 
    198 	public void clean(String[] args, InputStream in, OutputStream out) throws IOException {
    199 		synchronized(flist) {
    200 			long total = 0;
    201 			for (Map.Entry<String, Object[]> entry : flist.entrySet()) {
    202 				total += (Long) entry.getValue()[1];
    203 			}
    204 
    205 			List<Object[]> k = new ArrayList<Object[]>(flist.values());
    206 			Collections.sort(k, this);
    207 
    208 			int cur = 0;
    209 			while (total > MAX * CLEANRATIO) {
    210 				Object[] kk = k.get(cur);
    211 
    212 				String name = (String) kk[2];
    213 				File f = new File(new File(new File(CACHEDIR), name.substring(0, 2)), name);
    214 				//System.out.println("removing " + cur + " " + kk[0] + " " + kk[1] + " " + f.getAbsolutePath());
    215 				rm(f);
    216 
    217 				total -= (Long) kk[1];
    218 
    219 				flist.remove(name);
    220 				cur++;
    221 			}
    222 		}
    223 	}
    224 
    225 	public static void init_flist() {
    226 		synchronized(flist) {
    227 			flist.clear();
    228 			File dir = new File(CACHEDIR);
    229 			try {
    230 				dir.mkdirs();
    231 			} catch (Exception e) {
    232 
    233 			}
    234 
    235 			for (File d : dir.listFiles()) {
    236 				if (!d.isDirectory()) continue;
    237 				for (File sd : d.listFiles()) {
    238 					if (!sd.isDirectory()) continue;
    239 					long total = 0;
    240 					for (File f : sd.listFiles()) {
    241 						total += f.length();
    242 					}
    243 					//System.out.println(sd.getName());
    244 					flist.put(sd.getName(), new Object[] {sd.lastModified(), total, sd.getName()});
    245 				}
    246 			}
    247 		}
    248 	}
    249 
    250 	public int compare(Object[] a, Object[] b) {
    251 		return ((Long) a[0]).compareTo((Long) b[0]);
    252 	}
    253 
    254 	public static void rm(File dir) {
    255 		if (dir.isDirectory()) {
    256 			for (File f: dir.listFiles())
    257 			{
    258 				rm(f);
    259 			}
    260 		}
    261 		dir.delete();
    262 	}
    263 
    264 	public static void main(String[] args) {
    265 		init_flist();
    266 		System.out.println("ready (" + flist.keySet().size() + " dirs)");
    267 
    268 		// different ports for upload and download, another port could be added for the clean command
    269 		Thread upload = null;
    270 		if (PORT_UPLOAD != PORT_DOWNLOAD) {
    271 			Netcache tmp = new Netcache(null, PORT_UPLOAD);
    272 			upload = new Thread(tmp);
    273 			upload.start();
    274 		}
    275 
    276 		Netcache tmp = new Netcache(null, PORT_DOWNLOAD);
    277 		tmp.run();
    278 	}
    279 }
    280