trying to find out whats causing an occasional crash
[nodejs-repoproxy.git] / lib / cache.js
1 var fs = require("fs");
2 var http = require("http");
3 var url = require("url");
4
5 function maintainCache() {
6         // TODO i should check that im already running here and exit if i am
7         console.log("Cache maintainence routine starting...");
8         console.log("Cache maintainence routine ended...");
9 }
10
11 exports.startTimer = function() {
12         // our once-a-day cache maintainer
13         var cacheTimer = global.repoproxy.scancache*3600*1000;
14         //var cacheTimer = global.repoproxy.scancache*100;
15         setInterval(maintainCache, cacheTimer);
16 }
17
18 function upstreamRequest(unify) {
19         // first do a head request
20         console.log("upsteram as ", unify.requestFor);
21         
22         var endData = false;
23         var xpath = "";
24         var filefd = null;
25         if(unify.topPath !=null) if(unify.topPath != "") if(typeof global.repoproxy.repo[unify.topPath] != "undefined") {
26                 var uplink = global.repoproxy.repo[unify.topPath].url;
27                 xpath = uplink + unify.subPath;
28         }
29         
30         //unify.b.write("would send to '" + xpath + "'");
31         //unify.b.end();
32         
33         console.log("sending off to '%s'", xpath);
34         
35         var headReq = url.parse(xpath);
36         headReq["method"] = "HEAD";
37         
38         getup = http.request(xpath, function(res) {
39                 res.setEncoding("utf8");
40                 
41                 if(!endData) {
42                         console.log("status code is ", typeof res.statusCode);
43                         switch(res.statusCode) {
44                         // TODO: this 301 directory redirect thing needs to work better
45                         case 301:
46                         case 302:
47                                 
48                                 var loc = res.headers.location.substr(res.headers.location.length-4);
49                                 var against_t = xpath + "/";
50                                 var against = against_t.substr(against_t.length-4);
51                                 
52                                 if(loc == against) {
53                                         console.log("got a redirect, upstream for loc => loc/ assuming its a directory");
54                                         makeCacheDir(unify);
55                                         unify.b.writeHead(302, { "Location": unify.originalReq + "/" });
56                                 } else {
57                                         console.log("checked '%s' against '%s', was false, sending 404", loc, against);
58                                         unify.b.writeHead(404, {"Content-Type": "text/plain"});
59                                         unify.b.write("404 Not Found\n");
60                                 }
61                                 unify.b.end();
62                                 endData = true;
63                                 break;
64                                 
65                         case 404:
66                                 unify.b.writeHead(404, {"Content-Type": "text/plain"});
67                                 unify.b.write("404 Not Found\n");
68                                 unify.b.end();
69                                 endData = true;
70                                 break;
71                         case 200:
72                                 makeCacheDir(unify);
73                                 if(unify.isDirectoryRequest) {
74                                         serviceDirectory(unify);                                        
75                                         endData = true;
76                                 } else {
77                                         // this is where it gets ugly
78                                         console.log("do ugly write: ", unify);
79                                         //unify.b.write(data);
80                                         getAndService(unify, xpath);
81                                         
82                                 }
83                                 break;
84                         default:
85                                 console.log(".... data");
86                                 //unify.b.write(data);
87                         }
88                 }               
89                 //console.log("res is now ", res);
90         });
91         
92         getup.end();
93         
94         //console.log("getup: ", getup);
95 }
96
97 exports.upstreamRequest = upstreamRequest;
98
99 function getAndService(unify, xpath) {
100         
101         if(typeof global.repoproxy.downloads[unify.fullFilePath] != "undefined" && global.repoproxy.downloads[unify.fullFilePath] == 1) {
102                 
103                 console.log("service inline");
104                 unify.b.write("trying to service inline");
105                 unify.b.end();
106         } else {
107                 global.repoproxy.downloads[unify.fullFilePath] = 1;
108         
109                 http.get(xpath, function(res) {
110         
111                     var file = fs.createWriteStream(unify.fullFilePath);
112                 
113                     console.log("res: ", res);
114                 
115                     //res.setEncoding("utf8");
116                 
117                     res.on("data", function(data) {
118                             //console.log("chunk");
119                             file.write(data);
120                             unify.b.write(data);
121                     });
122                 
123                     res.on("end", function() {
124                             console.log("end...");
125                             unify.b.end();
126                             file.end();
127                             global.repoproxy.downloads[unify.fullFilePath] = 0;
128                     });
129                     
130                     res.on("error", function(err) {
131                         console.log("res threw error... ", err);
132                     });
133                 });
134         }
135 }
136
137 // the service file routine .... PLEASE KILL ME!
138 function serviceFile(unify) {
139         
140         // for now, ignore range.
141
142         // file should already exist, so we just poop it out
143         var inp = fs.createReadStream(unify.fullFilePath);
144         //inp.setEncoding("utf8");
145         inp.on("data", function(data) {
146                 unify.b.write(data);
147         });
148         
149         inp.on("end", function(closed) {
150                 unify.b.end();
151         });
152 }
153
154 exports.serviceFile = serviceFile;
155
156 function makeCacheDir(path) {
157         console.log("attempting to create... '%s' as '%s'", path.fullPathDirName, path.subPathDirName);
158         
159         var startAt = path.topFullPath;
160         var nextbits = path.subPathDirName.split("/");
161         for(var i=0; i < nextbits.length; i++) {
162                 startAt += "/" + nextbits[i];
163                 console.log("attempt mkdir on '%s'", startAt);
164                 try {
165                         fs.mkdirSync(startAt);
166                 } catch(e) {
167                         //console.log("e in mkdir, ", e);
168                 }
169         }
170         //process.exit(0);
171 }
172
173 function serviceDirectory(unify) {
174         var nfiles = 0;
175         var res = unify.b;
176         
177         res.write("<html><h1>Directory listing for " + unify.originalReq + "</h1><hr><pre>");
178         if(unify.originalReq != "/") res.write("<a href=\"..\">Parent</a>\n\n");
179         fs.readdir(unify.fullFilePath, function(err, files) {
180                 console.log("doing directory listing on: ", unify.fullFilePath);
181                 if(err == null) {
182                         
183                         // TODO: make this work asynchronously...
184                         for(var i=0; i<files.length; i++) {
185                                 // avoiding statSync is too hard for now, will fix later TODO: fix this sync bit
186                                 var stats = fs.statSync(unify.fullFilePath+"/"+files[i]);
187                                 
188                                 if(files[i].match(/^\..*/) == null) {
189                                         if(stats.isDirectory()) {
190                                                 
191                                                 res.write("Directory: <a href=\""+files[i]+"/\">"+files[i]+"/</a>\n");
192                                                 nfiles++;
193                                         } else if(stats.isFile()) {
194                                                 var padlength = 80 - (files[i].length) - stats.size.toString().length;
195                                                 var padding = "";
196                                                 if(padlength > 0) {
197                                                         padding = new Array(padlength).join(" ");
198                                                 }
199                                                 res.write("File:      <a href=\""+files[i]+"\">"+files[i]+"</a>"+padding+stats.size+" bytes\n");
200                                                 nfiles++;
201                                         }
202                                 } else {
203                                         console.log("ignoring file, ", files[i]);
204                                 }
205                         }
206                         
207                         if(nfiles == 0) res.write("Empty directory....\n");
208                         
209                         res.write("<hr></pre>");
210                         res.end();
211                 } else {
212                         res.write("we have entered bizaro world...\n");
213                         res.write("</pre>");
214                         res.end();
215                 }
216         });
217 }
218
219 exports.serviceDirectory = serviceDirectory;