"use strict"; var cmn=require("../$common.js"), persist=require("node-persist"), crypto=require("crypto"), http=require("http"), https=require("https"), URL=require("url"), child_process=require("child_process"); var moddir=null; persist=persist.create({ dir:"persist/changes", continuous:false, interval:false }); persist.initSync(); //urls: map(url => URLobject) //url: String //URLobject: {url, timeline: [[Date, hash, contents]]} var urls=persist.getItemSync("urls"); if(!urls){ urls={}; persist.setItemSync("urls",urls); } else { (function(){ var url,i; for(url in urls){ for(i=0;i"); nwaiting++; fetch("GET",url,function(url,status,body){ nwaiting--; console.log("Got <"+url+">; status = "+status); if(status==-1){ hashes[url]=[new Date(),null,null]; } else { var hash=crypto.createHash("sha256"); hash.update(body); hashes[url]=[new Date(),hash.digest("hex"),body]; } if(!urls[url]){ console.log("WARNING: url <"+url+"> from hashes not found in urls!"); } else { //var last=urls[url].timeline[urls[url].timeline.length-1]; //if(last==undefined||hashes[url][1]==null||hashes[url][1]!=last[1]){ urls[url].timeline.push(hashes[url]); //} } if(nwaiting==0&&cb)process.nextTick(cb); if(refresh_persist_timeout!=null)clearTimeout(refresh_persist_timeout); refresh_persist_timeout=setTimeout(function(){ persist.setItemSync("urls",urls); console.log("(persisted after refresh)") refresh_persist_timeout=null; },2000); }.bind(null,url)); } } function collectLastHashes(){ var lasthashes={}; var idx; for(var url in urls){ if(urls[url].timeline.length==0){ lasthashes[url]=null; } else { idx=urls[url].timeline.length-1; lasthashes[url]={ hash: urls[url].timeline[idx][1], date: urls[url].timeline[idx][0] }; } } return lasthashes; } function sendMail(tomail,body,cb){ var proc=child_process.spawn("sendmail",[tomail],{stdio:["pipe",process.stdout,process.stderr]}); proc.stdin.on("error",function(e){ console.log(e); cb(e); }); proc.stdin.write(body,function(){ proc.stdin.end(); cb(); }); } function constructMailBody(tomail,diffs){ var body="To: "+tomail+"\n"+ "From: changes \n"+ "Subject: changes notification mail\n\n"+ "The changes module recorded some changes in watched webpages.\n"+ "The URLs and their old and new content hashes are shown below.\n\n"; var i; for(i=0;i=0;i--){ if(urls[url].timeline[i][1]!=lasthash){ prevhash=urls[url].timeline[i][1]; prevhashidx=i; break; } } if(prevhash==null){ urls[url].timeline.splice(0,tllen-1); } else { urls[url].timeline.splice(prevhashidx+1,tllen-prevhashidx-2); urls[url].timeline.splice(0,prevhashidx); } */ //keep only the last record of a specific hash intact var i; for(i=urls[url].timeline.length-2;i>=0;i--){ if(urls[url].timeline[i][1]==urls[url].timeline[i+1][1]){ urls[url].timeline.splice(i,1); } } } } module.exports=function(app,io,_moddir){ moddir=_moddir; app.all(["/changes","/changes/*"],cmn.authgen()); app.get("/changes",function(req,res){ res.sendFile(moddir+"/changes.html"); }); app.get("/changes/urls",function(req,res){ var list=[]; var url; for(url in urls)list.push(url); res.json(list); }); app.get("/changes/url",function(req,res){ var url=req.query.url; if(!urls[url]){ res.status(404); res.send("URL not found in watch list"); return; } res.json(urls[url]); }); app.post("/changes/url",function(req,res){ var url=req.body; urls[url]=new URLobject(url); persist.setItemSync("urls",urls); // refreshURLs(); res.send(); }); app.delete("/changes/url",function(req,res){ var url=req.body; if(!urls[url]){ res.status(404); res.send("URL not found in watch list"); return; } delete urls[url]; persist.setItemSync("urls",urls); res.send(); }); app.delete("/changes/url/history",function(req,res){ var param; try {param=JSON.parse(req.body);} catch(e){ res.status(400); res.send("Invalid JSON sent"); } var url=param.url; var todate=new Date(param.todate); if(!urls[url]){ res.status(404); res.send("URL not found in watch list"); return; } if(todate.getTime()==NaN){ res.status(400); res.send("Invalid time sent"); } var tl=urls[url].timeline; var i; for(i=0;i