X-Git-Url: http://git.pjr.cc/?p=nodejs-repoproxy.git;a=blobdiff_plain;f=lib%2Fcache.js;h=588bc7315ef3c6ef9ab13a30708c02ba6f3d17f1;hp=6b6327d629d0da2e42f8d82e036c0c8205848351;hb=d7478970127408f056b157f18df74fef7db3f892;hpb=8b95cb4f106b906a362babc2c21b18d57c7a4748 diff --git a/lib/cache.js b/lib/cache.js index 6b6327d..588bc73 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -2,19 +2,7 @@ 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 - console.log("Cache maintainence routine starting..."); - console.log("Cache maintainence routine ended..."); -} - -exports.startTimer = function() { - // our once-a-day cache maintainer - var cacheTimer = global.repoproxy.scancache*3600*1000; - //var cacheTimer = global.repoproxy.scancache*100; - setInterval(maintainCache, cacheTimer); -} +var crypto = require("crypto"); function upstreamRequest(unify) { // first do a head request @@ -31,6 +19,13 @@ function upstreamRequest(unify) { //unify.b.write("would send to '" + xpath + "'"); //unify.b.end(); + // not doing this properly yet... + if(typeof global.repoproxy.downloads[unify.fullFilePath] != undefined && global.repoproxy.downloads[unify.fullFilePath] == 1) { + console.log("request for file thats being downloaded already, doing inline request"); + inlineService(unify); + return; + } + console.log("sending off to '%s'", xpath); var headReq = url.parse(xpath); @@ -108,41 +103,103 @@ function getAndService(unify, xpath, 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; - + global.repoproxy.downloads[unify.fullFilePath] = 1; - http.get(xpath, function(res) { + + http.get(xpath, function(res) { + + var file = fs.createWriteStream(unify.fullFilePath); - var file = fs.createWriteStream(unify.fullFilePath); - - //console.log("res: ", res); + //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); + }); + }); +} + +// this is nasty nasty thing that can go horribly wrong in some ways, but currently works... +function inlineService(unify) { + // this method is called when we need to service a file thats being downloaded by something else + var metafilename = unify.fullPathDirName + "/.meta."+ path.basename(unify.requestFor) +".filesize"; + var fsizef = fs.createReadStream(metafilename); + var fsize = ""; + var lastchunk = 0; + fsizef.on("data", function(data) { + fsize += data; + }); + + fsizef.on("end", function() { + var sentSoFar = 0; + unify.b.writeHead(200, {"Content-Length" : fsize }); - //res.setEncoding("utf8"); + // now we go into the file reading loop. + console.log("start of inline services"); + // we loop every 0.5s and do our thing - res.on("data", function(data) { - //console.log("chunk"); - file.write(data); - unify.b.write(data); - }); + function sendPieces() { + // this is going to be so fun i want to play real life frogger in real life traffic... + fs.stat(unify.fullFilePath, function(err, stats) { + if(err == null) { + if(stats["size"] > sentSoFar) { + // if file size changed between last chunk and this chunk, send the chunks + + lastChunk = 0; + // open the file, send the data + var rs = fs.createReadStream(unify.fullFilePath, {start: sentSoFar, end: stats["size"]}); + + rs.on("data", function(thisdata) { + //console.log("inline chunk: ", thisdata.length); + unify.b.write(thisdata); + }); + + rs.on("end", function() { + sentSoFar = stats["size"]; + // every second, we start again + if(sentSoFar != fsize) { + setTimeout(sendPieces, 1000); + } else { + // we're done! + unify.b.end(); + } + }); + } else { + // if file size did not change between last timeout and this one, incremement the chunk counter + // if we reach 60, we had a problem, and so we bomb out + + lastChunk++; + + // we bombed out somehow + if(lastChunk > 60) { + unify.b.end(); + } else { + setTimeout(sendPieces, 1000); + } + } + } else { + console.log("inline service - we're in a very bad place"); + } + }); + + } - 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); - }); - }); - } + setTimeout(sendPieces, 100); + }); } // the service file routine .... PLEASE KILL ME! @@ -276,4 +333,22 @@ function serviceDirectory(unify) { }); } -exports.serviceDirectory = serviceDirectory; \ No newline at end of file +function moveToCleanup(file_or_dir) { + // err..? + var cleanup = global.repoproxy.cacheDir + "/.cleanup"; + var ctime = new Date().getTime(); + var encoded = (++global.repoproxy.fileid).toString(); + var toloc = cleanup + "/" + ctime.toString() + "." + encoded; + + //console.log("Moving %s to %s for cleanup", file_or_dir.replace(/\/$/, ""), toloc); + + fs.renameSync(file_or_dir.replace(/\/$/, ""), toloc); +} + +function cleanupRoutine() { + +} + + +exports.serviceDirectory = serviceDirectory; +exports.moveToCleanup = moveToCleanup;