var fs = require("fs");
var http = require("http");
var url = require("url");
+var path = require("path");
function maintainCache() {
// TODO i should check that im already running here and exit if i am
setInterval(maintainCache, cacheTimer);
}
-function upstreamRequest(unify, callback) {
+function upstreamRequest(unify) {
// first do a head request
console.log("upsteram as ", unify.requestFor);
- var splpath = unify.requestFor.split("/");
- var topdir = splpath[1];
- var toppath = "";
- for(var i=2; i < splpath.length; i++) {
- if(toppath == "") {
- toppath = splpath[i];
- } else {
- toppath += "/" + splpath[i];
- }
- }
- console.log("uppath = '%s' and '%s'", topdir, toppath);
- if(typeof global.repoproxy.repo[topdir] != "undefined") {
- console.log("which is ", global.repoproxy.repo[topdir]);
- console.log("so upstream is, ", global.repoproxy.repo[topdir].url + toppath);
+ var endData = false;
+ var xpath = "";
+ var filefd = null;
+ if(unify.topPath !=null) if(unify.topPath != "") if(typeof global.repoproxy.repo[unify.topPath] != "undefined") {
+ var uplink = global.repoproxy.repo[unify.topPath].url;
+ xpath = uplink + unify.subPath;
}
+ //unify.b.write("would send to '" + xpath + "'");
+ //unify.b.end();
+
+ console.log("sending off to '%s'", xpath);
+
+ var headReq = url.parse(xpath);
+ headReq["method"] = "HEAD";
+
+ getup = http.request(headReq, function(res) {
+ //res.setEncoding("utf8");
+
+ if(!endData) {
+ console.log("status code is ", typeof res.statusCode);
+ switch(res.statusCode) {
+ // TODO: this 301 directory redirect thing needs to work better
+ case 301:
+ case 302:
+
+ var loc = res.headers.location.substr(res.headers.location.length-4);
+ var against_t = xpath + "/";
+ var against = against_t.substr(against_t.length-4);
+
+ if(loc == against) {
+ console.log("got a redirect, upstream for loc => loc/ assuming its a directory");
+ makeCacheDir(unify);
+ unify.b.writeHead(302, { "Location": unify.originalReq + "/" });
+ } else {
+ console.log("checked '%s' against '%s', was false, sending 404", loc, against);
+ unify.b.writeHead(404, {"Content-Type": "text/plain"});
+ unify.b.write("404 Not Found\n");
+ }
+ unify.b.end();
+ endData = true;
+ break;
+
+ case 404:
+ unify.b.writeHead(404, {"Content-Type": "text/plain"});
+ unify.b.write("404 Not Found\n");
+ unify.b.end();
+ endData = true;
+ break;
+ case 200:
+ makeCacheDir(unify);
+ if(unify.isDirectoryRequest) {
+ serviceDirectory(unify);
+ endData = true;
+ } else {
+ // this is where it gets ugly
+ var filesize = res.headers["content-length"];
+ console.log("do ugly write: ", unify);
+ //unify.b.write(data);
+ var metafilename = unify.fullPathDirName + "/.meta."+ path.basename(unify.requestFor) +".filesize";
+ var metafile = fs.createWriteStream(metafilename);
+ metafile.write(filesize);
+ metafile.end();
+ getAndService(unify, xpath, filesize);
+
+ }
+ break;
+ default:
+ console.log(".... data");
+ //unify.b.write(data);
+ }
+ }
+ //console.log("res is now ", res);
+ });
+
+ getup.end();
+
+ //console.log("getup: ", getup);
}
exports.upstreamRequest = upstreamRequest;
+function getAndService(unify, xpath, filesize) {
+
+ console.log("calling in here with filesize, ", filesize)
+ unify.b.writeHead(200, {'Content-Length' : filesize});
+
+
+ if(typeof global.repoproxy.downloads[unify.fullFilePath] != "undefined" && global.repoproxy.downloads[unify.fullFilePath] == 1) {
+
+ console.log("service inline");
+ unify.b.write("trying to service inline");
+ unify.b.end();
+ } else {
+ global.repoproxy.downloads[unify.fullFilePath] = 1;
+
+
+ http.get(xpath, function(res) {
+
+ var file = fs.createWriteStream(unify.fullFilePath);
+
+ //console.log("res: ", res);
+
+ //res.setEncoding("utf8");
+
+ res.on("data", function(data) {
+ //console.log("chunk");
+ file.write(data);
+ unify.b.write(data);
+ });
+
+ res.on("end", function() {
+ console.log("end...");
+ unify.b.end();
+ file.end();
+ global.repoproxy.downloads[unify.fullFilePath] = 0;
+ });
+
+ res.on("error", function(err) {
+ console.log("res threw error... ", err);
+ });
+ });
+ }
+}
+
// the service file routine .... PLEASE KILL ME!
function serviceFile(unify) {
// for now, ignore range.
+ // however we need to check if a metadata file exists describing the filesize, check if its all correct
+ // and if not, erase the file (and metafile) and forward the request back to upstream request
- // file should already exist, so we just poop it out
- var inp = fs.createReadStream(unify.fullFilePath);
- inp.setEncoding("utf8");
- inp.on("data", function(data) {
- unify.b.write(data);
- });
- inp.on("end", function(closed) {
- unify.b.end();
+ checkFile(unify, function() {
+
+ // file should already exist, so we just poop it out
+ var inp = fs.createReadStream(unify.fullFilePath);
+ //inp.setEncoding("utf8");
+ inp.on("data", function(data) {
+ unify.b.write(data);
+ });
+
+ inp.on("end", function(closed) {
+ unify.b.end();
+ });
});
}
exports.serviceFile = serviceFile;
+
+function checkFile(unify, callback) {
+ // in here we do the metadata checks
+ var metafilename = unify.fullPathDirName + "/.meta."+ path.basename(unify.requestFor) +".filesize";
+
+ fs.exists(metafilename, function(existence) {
+ if(existence) {
+ var fsizef = fs.createReadStream(metafilename);
+ var fsize = "";
+ fsizef.on("data", function(data) {
+ fsize += data;
+ });
+
+ fsizef.on("end", function() {
+ fs.stat(unify.fullFilePath, function(err, stats) {
+ var rfsize = stats["size"];
+ if(rfsize != fsize.trim()) {
+ // remove the file and start again
+ console.log("reported filesizes dont match, '%s', '%s', removing file and starting again", rfsize, stats["size"]);
+ try {
+ fs.unlink(metafilename, function(){
+ fs.unlink(unify.fullFilePath, function(){
+ upstreamRequest(unify);
+ })
+ });
+ } catch(e) {
+ upstreamRequest(unify);
+ }
+ } else {
+ // we're good
+ unify.b.writeHead(200, {"Content-Length" : unify.fileSize})
+ callback();
+ }
+ });
+ });
+ } else {
+ console.log("file, '%s' exists but has no filesize meta data, assuming it was put here manually and servicing", unify.fullFilePath);
+ unify.b.writeHead(200, {"Content-Length" : unify.fileSize})
+ callback();
+ }
+ });
+}
+
+function makeCacheDir(path) {
+ console.log("attempting to create... '%s' as '%s'", path.fullPathDirName, path.subPathDirName);
+
+ var startAt = path.topFullPath;
+ var nextbits = path.subPathDirName.split("/");
+ for(var i=0; i < nextbits.length; i++) {
+ startAt += "/" + nextbits[i];
+ console.log("attempt mkdir on '%s'", startAt);
+ try {
+ fs.mkdirSync(startAt);
+ } catch(e) {
+ //console.log("e in mkdir, ", e);
+ }
+ }
+ //process.exit(0);
+}
+
function serviceDirectory(unify) {
var nfiles = 0;
var res = unify.b;
res.write("<html><h1>Directory listing for " + unify.originalReq + "</h1><hr><pre>");
- if(unify.fullFilePath != "/") res.write("<a href=\"..\">Parent</a>\n\n");
+ if(unify.originalReq != "/") res.write("<a href=\"..\">Parent</a>\n\n");
fs.readdir(unify.fullFilePath, function(err, files) {
console.log("doing directory listing on: ", unify.fullFilePath);
if(err == null) {