Added support for Consul/CBS and multiple DFCs

Issue-ID: INT-1155
Change-Id: I3c1ed2f6072655c4396e406ddfd490d3786fe4d6
Signed-off-by: BjornMagnussonXA <bjorn.magnusson@est.tech>
diff --git a/test/mocks/datafilecollector-testharness/dr-sim/Dockerfile b/test/mocks/datafilecollector-testharness/dr-sim/Dockerfile
index 3d95492..da05eed 100644
--- a/test/mocks/datafilecollector-testharness/dr-sim/Dockerfile
+++ b/test/mocks/datafilecollector-testharness/dr-sim/Dockerfile
@@ -1,6 +1,6 @@
 #Common image for both dmmapDR and dmaapDR_redir
 
-FROM node:8
+FROM node:12
 
 WORKDIR /app
 
diff --git a/test/mocks/datafilecollector-testharness/dr-sim/dmaapDR.js b/test/mocks/datafilecollector-testharness/dr-sim/dmaapDR.js
index 5367c9e..f94600a 100644
--- a/test/mocks/datafilecollector-testharness/dr-sim/dmaapDR.js
+++ b/test/mocks/datafilecollector-testharness/dr-sim/dmaapDR.js
@@ -12,6 +12,12 @@
 var certificate = fs.readFileSync('cert/certificate.crt', 'utf8');
 var credentials = {key: privateKey, cert: certificate};
 
+var feeds="1:A";  //Comma separated list of feedId:filePrefix. Default is feedId=1 and file prefix 'A'
+var feedNames=[];
+var filePrefixes=[];
+var feedIndexes=[];
+
+
 //For execution time calculation
 var startTime = Date.now();
 
@@ -32,13 +38,18 @@
 var drr_sim_ip = '127.0.0.1'; //IP for redirect to DR redir sim. Can be changed by env DRR_SIM_IP
 
 //Counters
-var ctr_publish_query = 0;
-var ctr_publish_query_published = 0;
-var ctr_publish_query_not_published = 0;
-var ctr_publish_req = 0;
-var ctr_publish_req_redirect = 0;
-var ctr_publish_req_published = 0;
-var ctr_double_publish = 0
+var ctr_publish_query = [];
+var ctr_publish_query_bad_file_prefix = [];
+var ctr_publish_query_published = [];
+var ctr_publish_query_not_published = [];
+var ctr_publish_req = [];
+var ctr_publish_req_bad_file_prefix = [];
+var ctr_publish_req_redirect = [];
+var ctr_publish_req_published = [];
+var ctr_double_publish = [];
+
+//db of published files
+var published=[];
 
 var parser = new ArgumentParser({
 	  version: '0.0.1',
@@ -124,7 +135,9 @@
 app.use(bodyParser.json({ type: 'application/vnd.api+json' }))
 
 // parse some custom thing into a Buffer (to cater for 60MB files)
-app.use(bodyParser.raw({limit:1024*1024*60, type: 'application/octet-stream' }))
+//Removed-file data not used in this simulator
+//app.use(bodyParser.raw({limit:1024*1024*60, type: 'application/octet-stream' }))
+
 // parse an HTML body into a string
 app.use(bodyParser.text({ type: 'text/html' }))
 
@@ -135,49 +148,190 @@
 	res.send("ok");
 })
 
+function toCommaList(ctrArray) {
+	var str="";
+	for(i=0;i<feedNames.length;i++) {
+		if (i!=0) {
+			str=str+",";
+		}
+		str=str+ctrArray[i];
+	}
+	return str;
+}
+
+function sumList(ctrArray) {
+	var tmp=0;
+	for(i=0;i<feedNames.length;i++) {
+		tmp=tmp+ctrArray[i];
+	}
+	return ""+tmp;
+}
+
+function sumListLength(ctrArray) {
+	var tmp=0;
+	for(i=0;i<feedNames.length;i++) {
+		tmp=tmp+ctrArray[i].length;
+	}
+	return ""+tmp;
+}
+
 //Counter readout
 app.get("/ctr_publish_query",function(req, res){
-	res.send(""+ctr_publish_query);
+	res.send(""+sumList(ctr_publish_query));
 })
+app.get("/feeds/ctr_publish_query",function(req, res){
+	res.send(toCommaList(ctr_publish_query));
+})
+app.get("/ctr_publish_query/:feedId",function(req, res){
+	var feedId = req.params.feedId;
+	res.send(""+ctr_publish_query[feedIndexes[feedId]]);
+})
+
+app.get("/ctr_publish_query_bad_file_prefix",function(req, res){
+	res.send(""+sumList(ctr_publish_query_bad_file_prefix));
+})
+app.get("/feeds/ctr_publish_query_bad_file_prefix",function(req, res){
+	res.send(toCommaList(ctr_publish_query_bad_file_prefix));
+})
+app.get("/ctr_publish_query_bad_file_prefix/:feedId",function(req, res){
+	var feedId = req.params.feedId;
+	res.send(""+ctr_publish_query_bad_file_prefix[feedIndexes[feedId]]);
+})
+
 app.get("/ctr_publish_query_published",function(req, res){
-	res.send(""+ctr_publish_query_published);
+	res.send(""+sumList(ctr_publish_query_published));
 })
+app.get("/feeds/ctr_publish_query_published",function(req, res){
+	res.send(toCommaList(ctr_publish_query_published));
+})
+app.get("/ctr_publish_query_published/:feedId",function(req, res){
+	var feedId = req.params.feedId;
+	res.send(""+ctr_publish_query_published[feedIndexes[feedId]]);
+})
+
 app.get("/ctr_publish_query_not_published",function(req, res){
-	res.send(""+ctr_publish_query_not_published);
+	res.send(""+sumList(ctr_publish_query_not_published));
 })
+app.get("/feeds/ctr_publish_query_not_published",function(req, res){
+	res.send(toCommaList(ctr_publish_query_not_published));
+})
+app.get("/ctr_publish_query_not_published/:feedId",function(req, res){
+	var feedId = req.params.feedId;
+	res.send(""+ctr_publish_query_not_published[feedIndexes[feedId]]);
+})
+
 app.get("/ctr_publish_req",function(req, res){
-	res.send(""+ctr_publish_req);
+	res.send(""+sumList(ctr_publish_req));
 })
+app.get("/feeds/ctr_publish_req",function(req, res){
+	res.send(toCommaList(ctr_publish_req));
+})
+app.get("/ctr_publish_req/:feedId",function(req, res){
+	var feedId = req.params.feedId;
+	res.send(""+ctr_publish_req[feedIndexes[feedId]]);
+})
+
+app.get("/ctr_publish_req_bad_file_prefix",function(req, res){
+	res.send(""+sumList(ctr_publish_req_bad_file_prefix));
+})
+app.get("/feeds/ctr_publish_req_bad_file_prefix",function(req, res){
+	res.send(toCommaList(ctr_publish_req_bad_file_prefix));
+})
+app.get("/ctr_publish_req_bad_file_prefix/:feedId",function(req, res){
+	var feedId = req.params.feedId;
+	res.send(""+ctr_publish_req_bad_file_prefix[feedIndexes[feedId]]);
+})
+
 app.get("/ctr_publish_req_redirect",function(req, res){
-	res.send(""+ctr_publish_req_redirect);
+	res.send(""+sumList(ctr_publish_req_redirect));
 })
+app.get("/feeds/ctr_publish_req_redirect",function(req, res){
+	res.send(toCommaList(ctr_publish_req_redirect));
+})
+app.get("/ctr_publish_req_redirect/:feedId",function(req, res){
+	var feedId = req.params.feedId;
+	res.send(""+ctr_publish_req_redirect[feedIndexes[feedId]]);
+})
+
 app.get("/ctr_publish_req_published",function(req, res){
-	res.send(""+ctr_publish_req_published);
+	res.send(""+sumList(ctr_publish_req_published));
 })
+app.get("/feeds/ctr_publish_req_published",function(req, res){
+	res.send(toCommaList(ctr_publish_req_published));
+})
+app.get("/ctr_publish_req_published/:feedId",function(req, res){
+	var feedId = req.params.feedId;
+	res.send(""+ctr_publish_req_published[feedIndexes[feedId]]);
+})
+
 app.get("/ctr_published_files",function(req, res){
-	res.send(""+published.length);
+	res.send(""+sumListLength(published));
 })
+app.get("/feeds/ctr_published_files",function(req, res){
+	var str="";
+	for(i=0;i<feedNames.length;i++) {
+		if (i!=0) {
+			str=str+",";
+		}
+		str=str+published[i].length;
+	}
+	res.send(str);
+})
+app.get("/ctr_published_files/:feedId",function(req, res){
+	var feedId = req.params.feedId;
+	res.send(""+published[feedIndexes[feedId]].length);
+})
+
 app.get("/tc_info",function(req, res){
 	res.send(args.tc);
 })
 app.get("/ctr_double_publish",function(req, res){
-	res.send(""+ctr_double_publish);
+	res.send(""+sumList(ctr_double_publish));
 })
+app.get("/feeds/ctr_double_publish",function(req, res){
+	var str="";
+	for(i=0;i<feedNames.length;i++) {
+		if (i!=0) {
+			str=str+",";
+		}
+		str=str+ctr_double_publish[i];
+	}
+	res.send(str);
+})
+app.get("/ctr_double_publish/:feedId",function(req, res){
+	var feedId = req.params.feedId;
+	res.send(""+ctr_double_publish[feedIndexes[feedId]]);
+})
+
 function fmtMSS(s){
 	return(s-(s%=60))/60+(9<s?':':':0')+s    //Format time diff in mm:ss
 }
 app.get("/execution_time",function(req, res){
-	diff = fmtMSS(Math.floor((Date.now()-startTime)/1000));
+	var diff = fmtMSS(Math.floor((Date.now()-startTime)/1000));
 	res.send(""+diff);
 })
+app.get("/feeds",function(req, res){
+	res.send(feeds);
+})
 
-//db of published files
-var published = [];
+function filenameStartsWith(fileName, feedIndex) {
+	for(i=0;i<filePrefixes[feedIndex].length;i++) {
+		var prefix=filePrefixes[feedIndex][i];
+		if (fileName.startsWith(prefix)) {
+			return true;
+		}
+	}
+	return false;
+}
 
-app.get('/feedlog/1/',function(req, res){
+app.get('/feedlog/:feedId',function(req, res){
 	console.log("url:"+req.url);
-	ctr_publish_query++;
+	var feedId = req.params.feedId;
+	ctr_publish_query[feedIndexes[feedId]]++;
 	var filename = req.query.filename;
+	if (!filenameStartsWith(filename, feedIndexes[feedId])) {
+		ctr_publish_query_bad_file_prefix[feedIndexes[feedId]]++;
+	}
 	console.log(filename);
 	var qtype = req.query.type;
 	if(typeof(filename) == 'undefined'){
@@ -187,41 +341,41 @@
 		res.status(400).send({error: 'No type provided.'});
 		return;
 	}
-	
+	var ctr = ctr_publish_query[feedIndexes[feedId]];
 	//Ugly fix, plus signs replaces with spaces in query params....need to put them back
 	filename = filename.replace(/ /g,"+");
-	
+
 	var sleeptime=0;
 	if (args.tc==tc_normal) {
 		sleeptime=0;
-	} else if (args.tc==tc_10p_no_response && (ctr_publish_query%10) == 0) {
+	} else if (args.tc==tc_10p_no_response && (ctr%10) == 0) {
 		return;
-	} else if (args.tc==tc_10first_no_response && ctr_publish_query<11) {
+	} else if (args.tc==tc_10first_no_response && ctr<11) {
 		return;
-	} else if (args.tc==tc_100first_no_response && ctr_publish_query<101) {
+	} else if (args.tc==tc_100first_no_response && ctr<101) {
 		return;
 	} else if (args.tc==tc_all_delay_1s) {
 		sleeptime=1000;
 	} else if (args.tc==tc_all_delay_10s) {
 		sleeptime=10000;
-	} else if (args.tc==tc_10p_delay_10s && (ctr_publish_query%10) == 0) {
+	} else if (args.tc==tc_10p_delay_10s && (ctr%10) == 0) {
 		sleeptime=10000;
-	} else if (args.tc==tc_10p_error_response && (ctr_publish_query%10) == 0) {
+	} else if (args.tc==tc_10p_error_response && (ctr%10) == 0) {
 		res.send(400);
 		return;
-	} else if (args.tc==tc_10first_error_response && ctr_publish_query<11) {
+	} else if (args.tc==tc_10first_error_response && ctr<11) {
 		res.send(400);
 		return;
-	} else if (args.tc==tc_100first_error_response & ctr_publish_query<101) {
+	} else if (args.tc==tc_100first_error_response & ctr<101) {
 		res.send(400);
 		return;
 	}
 
-	if (published.includes(filename)) {
-		ctr_publish_query_published++;
+	if (published[feedIndexes[feedId]].includes(filename)) {
+		ctr_publish_query_published[feedIndexes[feedId]]++;
 		strToSend="[" + filename + "]";
 	} else {
-		ctr_publish_query_not_published++;
+		ctr_publish_query_not_published[feedIndexes[feedId]]++;
 		strToSend="[]";
 	}
 	if (sleeptime > 0) {
@@ -234,68 +388,73 @@
 });
 
 
-app.put('/publish/1/:filename', function (req, res) {
+app.put('/publish/:feedId/:filename', function (req, res) {
 	console.log("url:"+req.url);
-	console.log("body (first 25 bytes):"+req.body.slice(0,25));
+//	console.log("body (first 25 bytes):"+req.body.slice(0,25));
 	console.log("headers:"+req.headers);
-	ctr_publish_req++;
+	console.log(JSON.stringify(req.headers));
+	var feedId = req.params.feedId;
+	ctr_publish_req[feedIndexes[feedId]]++;
 
 	var filename = req.params.filename;
 	console.log(filename);
-
+	if (!filenameStartsWith(filename, feedIndexes[feedId])) {
+		ctr_publish_req_bad_file_prefix[feedIndexes[feedId]]++;
+	}
+    var ctr = ctr_publish_req[feedIndexes[feedId]];
 	if (args.tc==tc_normal) {
 	// Continue
 	} else if (args.tc==tc_none_published) {
-		ctr_publish_req_redirect++;
-		res.redirect(301, 'http://' + drr_sim_ip + ':3908/publish/1/'+filename);
+		ctr_publish_req_redirect[feedIndexes[feedId]]++;
+		res.redirect(301, 'http://' + drr_sim_ip + ':3908/publish/'+feedId+'/'+filename);
 		return;
 	} else if (args.tc==tc_all_published) {
-		ctr_publish_req_published++;
+		ctr_publish_req_published[feedIndexes[feedId]]++;
 		res.send("ok");
 		return;
-	}else if (args.tc==tc_10p_no_response && (ctr_publish_req%10) == 0) {
+	}else if (args.tc==tc_10p_no_response && (ctr%10) == 0) {
 		return;
-	} else if (args.tc==tc_10first_no_response && ctr_publish_req<11) {
+	} else if (args.tc==tc_10first_no_response && ctr<11) {
 		return;
-	} else if (args.tc==tc_100first_no_response && ctr_publish_req<101) {
+	} else if (args.tc==tc_100first_no_response && ctr<101) {
 		return;
 	} else if (args.tc==tc_all_delay_1s) {
-		do_publish_delay(res, filename, 1000);
+		do_publish_delay(res, filename, 1000, feedId);
 		return;
 	} else if (args.tc==tc_all_delay_10s) {
-		do_publish_delay(res, filename, 10000);
+		do_publish_delay(res, filename, 10000, feedId);
 		return;
-	} else if (args.tc==tc_10p_delay_10s && (ctr_publish_req%10) == 0) {
-		do_publish_delay(res, filename, 10000);
+	} else if (args.tc==tc_10p_delay_10s && (ctr%10) == 0) {
+		do_publish_delay(res, filename, 10000, feedId);
 		return;
-	} else if (args.tc==tc_10p_error_response && (ctr_publish_req%10) == 0) {
+	} else if (args.tc==tc_10p_error_response && (ctr%10) == 0) {
 		res.send(400);
 		return;
-	} else if (args.tc==tc_10first_error_response && ctr_publish_req<11) {
+	} else if (args.tc==tc_10first_error_response && ctr<11) {
 		res.send(400);
 		return;
-	} else if (args.tc==tc_100first_error_response & ctr_publish_req<101) {
+	} else if (args.tc==tc_100first_error_response & ctr<101) {
 		res.send(400);
 		return;
 	}
 	if (!published.includes(filename)) {
-		ctr_publish_req_redirect++;
-		res.redirect(301, 'http://'+drr_sim_ip+':3908/publish/1/'+filename);
+		ctr_publish_req_redirect[feedIndexes[feedId]]++;
+		res.redirect(301, 'http://'+drr_sim_ip+':3908/publish/'+feedId+'/'+filename);
 	} else {
-		ctr_publish_req_published++;
+		ctr_publish_req_published[feedIndexes[feedId]]++;
 		res.send("ok");
 	}
 	return;
 })
 
-function do_publish_delay(res, filename, sleeptime) {
+function do_publish_delay(res, filename, sleeptime, feedId) {
 	if (!published.includes(filename)) {
-		ctr_publish_req_redirect++;
+		ctr_publish_req_redirect[feedIndexes[feedId]]++;
 		sleep(1000).then(() => {
-			res.redirect(301, 'http://'+drr_sim_ip+':3908/publish/1/'+filename);
+			res.redirect(301, 'http://'+drr_sim_ip+':3908/publish/'+feedId+'/'+filename);
 		});
 	} else {
-		ctr_publish_req_published++;
+		ctr_publish_req_published[feedIndexes[feedId]]++;
 		sleep(1000).then(() => {
 			res.send("ok");
 		});
@@ -303,17 +462,18 @@
 }
 
 //Callback from DR REDIR server, when file is published ok this PUT request update the list of published files.
-app.put('/dr_redir_publish/:filename', function (req, res) {
+app.put('/dr_redir_publish/:feedId/:filename', function (req, res) {
 	console.log("url:"+req.url);
+	var feedId = req.params.feedId;
 	var filename = req.params.filename;
 	console.log(filename);
 
-	if (!published.includes(filename)) {
+	if (!published[feedIndexes[feedId]].includes(filename)) {
 		console.log("File marked as published by callback from DR redir SIM. url: " + req.url);
-		published.push(filename);
+		published[feedIndexes[feedId]].push(filename);
 	} else {
 		console.log("File already marked as published. Callback from DR redir SIM. url: " + req.url);
-		ctr_double_publish = ctr_double_publish+1;
+		ctr_double_publish[feedIndexes[feedId]]++;
 	}
 
 	res.send("ok");
@@ -331,5 +491,42 @@
 
 if (process.env.DRR_SIM_IP) {
 	drr_sim_ip=process.env.DRR_SIM_IP;
-} 
-console.log("Using IP " + drr_sim_ip + " for redirect to DR redir sim");
\ No newline at end of file
+}
+console.log("Using IP " + drr_sim_ip + " for redirect to DR redir sim");
+
+if (process.env.DR_FEEDS) {
+	feeds=process.env.DR_FEEDS;
+}
+
+console.log("Configured list of feeds mapped to file name prefixes: " + feeds);
+
+feedNames=feeds.split(',');
+for(i=0;i<feedNames.length;i++) {
+	var tmp=feedNames[i].split(':');
+	feedNames[i]=tmp[0].trim();
+	feedIndexes[feedNames[i]]=i;
+	filePrefixes[i]=[]
+	for(j=1;j<tmp.length;j++) {
+		filePrefixes[i][j-1]=tmp[j];
+	}
+
+    ctr_publish_query[i] = 0;
+    ctr_publish_query_published[i] = 0;
+    ctr_publish_query_not_published[i] = 0;
+    ctr_publish_req[i] = 0;
+    ctr_publish_req_redirect[i] = 0;
+    ctr_publish_req_published[i] = 0;
+    ctr_double_publish[i] = 0;
+    ctr_publish_query_bad_file_prefix[i] = 0;
+	ctr_publish_req_bad_file_prefix[i] = 0;
+	published[i] = [];
+}
+
+console.log("Parsed mapping between feed id and file name prefix");
+for(i=0;i<feedNames.length;i++) {
+	var fn = feedNames[i];
+	for (j=0;j<filePrefixes[i].length;j++) {
+		console.log("Feed id: " + fn + ", file name prefix: " + filePrefixes[i][j]);
+	}
+}
+
diff --git a/test/mocks/datafilecollector-testharness/dr-sim/dmaapDR_redir.js b/test/mocks/datafilecollector-testharness/dr-sim/dmaapDR_redir.js
index 970c183..a5f1beb 100644
--- a/test/mocks/datafilecollector-testharness/dr-sim/dmaapDR_redir.js
+++ b/test/mocks/datafilecollector-testharness/dr-sim/dmaapDR_redir.js
@@ -14,6 +14,15 @@
 var certificate = fs.readFileSync('cert/certificate.crt', 'utf8');
 var credentials = {key: privateKey, cert: certificate};
 
+var total_first_publish=0;
+var total_last_publish=0
+var total_files=0;
+var speed=0;
+
+var feeds="1:A";  //Comma separated list of feedId:filePrefix. Default is feedId=1 and file prefix 'A'
+var feedNames=[];
+var filePrefixes=[];
+var feedIndexes=[];
 
 var bodyParser = require('body-parser')
 var startTime = Date.now();
@@ -21,10 +30,11 @@
 var dr_callback_ip = '192.168.100.2'; //IP for DR when running as container. Can be changed by env DR_SIM_IP
 
 //Counters
-var ctr_publish_requests = 0;
-var ctr_publish_responses = 0;
-var lastPublish = "";
-var dwl_volume = 0;
+var ctr_publish_requests = [];
+var ctr_publish_requests_bad_file_prefix = [];
+var ctr_publish_responses = [];
+var lastPublish = [];
+var dwl_volume = [];
 
 var parser = new ArgumentParser({
 	version: '0.0.1',
@@ -134,66 +144,194 @@
 	res.send("ok");
 })
 
+function toCommaList(ctrArray) {
+	var str="";
+	for(i=0;i<feedNames.length;i++) {
+		if (i!=0) {
+			str=str+",";
+		}
+		str=str+ctrArray[i];
+	}
+	return str;
+}
+
+function toCommaListTime(ctrArray) {
+	var str="";
+	for(i=0;i<feedNames.length;i++) {
+		if (i!=0) {
+			str=str+",";
+		}
+		if (ctrArray[i] < 0) {
+			str=str+"--:--";
+		} else {
+			str=str+fmtMSS(ctrArray[i]);
+		}
+	}
+	return str;
+}
+
+function sumList(ctrArray) {
+	var tmp=0;
+	for(i=0;i<feedNames.length;i++) {
+		tmp=tmp+ctrArray[i];
+	}
+	return ""+tmp;
+}
+
+function largestInListTime(ctrArray) {
+	var tmp=-1;
+	var str=""
+	for(i=0;i<feedNames.length;i++) {
+		if (ctrArray[i] > tmp) {
+			tmp = ctrArray[i];
+		}
+	}
+	if (tmp < 0) {
+		str="--:--";
+	} else {
+		str=fmtMSS(tmp);
+	}
+	return str;
+}
+
 //Counter readout
 app.get("/ctr_publish_requests",function(req, res){
-	res.send(""+ctr_publish_requests);
+	res.send(""+sumList(ctr_publish_requests));
 })
+app.get("/feeds/ctr_publish_requests/",function(req, res){
+	res.send(toCommaList(ctr_publish_requests));
+})
+app.get("/ctr_publish_requests/:feedId",function(req, res){
+	var feedId = req.params.feedId;
+	res.send(""+ctr_publish_requests[feedIndexes[feedId]]);
+})
+
+app.get("/ctr_publish_requests_bad_file_prefix",function(req, res){
+	res.send(""+sumList(ctr_publish_requests_bad_file_prefix));
+})
+app.get("/feeds/ctr_publish_requests_bad_file_prefix/",function(req, res){
+	res.send(toCommaList(ctr_publish_requests_bad_file_prefix));
+})
+app.get("/ctr_publish_requests_bad_file_prefix/:feedId",function(req, res){
+	var feedId = req.params.feedId;
+	res.send(""+ctr_publish_requests_bad_file_prefix[feedIndexes[feedId]]);
+})
+
 app.get("/ctr_publish_responses",function(req, res){
-	res.send(""+ctr_publish_responses);
+	res.send(""+sumList(ctr_publish_responses));
 })
+app.get("/feeds/ctr_publish_responses/",function(req, res){
+	res.send(toCommaList(ctr_publish_responses));
+})
+app.get("/ctr_publish_responses/:feedId",function(req, res){
+	var feedId = req.params.feedId;
+	res.send(""+ctr_publish_responses[feedIndexes[feedId]]);
+})
+
 app.get("/execution_time",function(req, res){
-	diff = fmtMSS(Math.floor((Date.now()-startTime)/1000));
+	var diff = fmtMSS(Math.floor((Date.now()-startTime)/1000));
 	res.send(""+diff);
 })
 app.get("/time_lastpublish",function(req, res){
-	res.send(""+lastPublish);
+	res.send(""+largestInListTime(lastPublish));
 })
+app.get("/feeds/time_lastpublish/",function(req, res){
+	res.send(toCommaListTime(lastPublish));
+})
+app.get("/time_lastpublish/:feedId",function(req, res){
+	var feedId = req.params.feedId;
+	if (lastPublish[feedIndexes[feedId]] < 0) {
+		res.send("--:--");
+	}
+	res.send(""+fmtMSS(lastPublish[feedIndexes[feedId]]));
+})
+
 app.get("/dwl_volume",function(req, res){
-	res.send(""+fmtLargeNumber(dwl_volume));
+	res.send(""+fmtLargeNumber(sumList(dwl_volume)));
 })
+app.get("/feeds/dwl_volume/",function(req, res){
+	var str="";
+	for(i=0;i<feedNames.length;i++) {
+		if (i!=0) {
+			str=str+",";
+		}
+		str=str+fmtLargeNumber(dwl_volume[i]);
+	}
+	res.send(str);
+})
+app.get("/dwl_volume/:feedId",function(req, res){
+	var feedId = req.params.feedId;
+	res.send(""+fmtLargeNumber(dwl_volume[feedIndexes[feedId]]));
+})
+
 app.get("/tc_info",function(req, res){
 	res.send(args.tc);
 })
 
-app.put('/publish/1/:filename', function (req, res) {
+app.get("/feeds",function(req, res){
+	res.send(feeds);
+})
+
+app.get("/speed",function(req, res){
+	res.send(""+speed);
+})
+
+function filenameStartsWith(fileName, feedIndex) {
+	var i=0;
+	for(i=0;i<filePrefixes[feedIndex].length;i++) {
+		var prefix=filePrefixes[feedIndex][i];
+		if (fileName.startsWith(prefix)) {
+			return true;
+		}
+	}
+	return false;
+}
+
+app.put('/publish/:feedId/:filename', function (req, res) {
+
 	console.log(req.url);
-	console.log("First 25 bytes of body: " + req.body.slice(0,25))
+	var feedId=req.params.feedId;
+//	console.log("First 25 bytes of body: " + req.body.slice(0,25))
 	console.log(req.headers)
-	ctr_publish_requests++;
+	ctr_publish_requests[feedIndexes[feedId]]++;
+	var filename = req.params.filename;
+	if (!filenameStartsWith(filename, feedIndexes[feedId])) {
+		ctr_publish_requests_bad_file_prefix[feedIndexes[feedId]]++;
+	}
+	var ctr = ctr_publish_requests[feedIndexes[feedId]];
 	if (args.tc == tc_no_publish) {
-		tr_publish_responses++;
+		ctr_publish_responses[feedIndexes[feedId]]++;
 		res.send("ok")
 		return;
-	} else if (args.tc==tc_10p_no_response && (ctr_publish_requests%10)==0) {
+	} else if (args.tc==tc_10p_no_response && (ctr%10)==0) {
 		return;
-	} else if (args.tc==tc_10first_no_response && ctr_publish_requests<11) {
+	} else if (args.tc==tc_10first_no_response && ctr<11) {
 		return;
-	} else if (args.tc==tc_100first_no_response && ctr_publish_requests<101) {
+	} else if (args.tc==tc_100first_no_response && ctr<101) {
 		return;
-	} else if (args.tc==tc_10p_error_response && (ctr_publish_requests%10)==0) {
-		tr_publish_responses++;
+	} else if (args.tc==tc_10p_error_response && (ctr%10)==0) {
+		ctr_publish_responses[feedIndexes[feedId]]++;
 		res.send(400, "");
 		return;
-	} else if (args.tc==tc_10first_error_response && ctr_publish_requests<11) {
-		tr_publish_responses++;
+	} else if (args.tc==tc_10first_error_response && ctr<11) {
+		ctr_publish_responses[feedIndexes[feedId]]++;
 		res.send(400, "");
 		return;
-	} else if (args.tc==tc_100first_error_response && ctr_publish_requests<101) {
-		tr_publish_responses++;
+	} else if (args.tc==tc_100first_error_response && ctr<101) {
+		ctr_publish_responses[feedIndexes[feedId]]++;
 		res.send(400, "");
 		return;
 	}
 
 	//Remaining part if normal file publish
 
-	var filename = req.params.filename;
 	console.log(filename);
-	//Create filename (appending file size to name) to store
-  	var storedFilename = path.resolve(__dirname, filename+"-"+req.body.length); 
+	//Create filename (appending file size and feedid to name) to store
+  	var storedFilename = path.resolve(__dirname, filename+"-"+feedId+"-"+req.body.length); 
   	fs.writeFile(storedFilename, "", function (error) {  //Store file with zero size
   		if (error) { console.error(error); }
 	});
-	
+
 	//Make callback to update list of publish files in DR sim
 	//Note the hard code ip-adress, DR sim get this ip if simulators started from the
 	//script in the 'simulatorgroup' dir.
@@ -201,24 +339,23 @@
 	var util = require('util');
 	var exec = require('child_process').exec;
 
-	var command = 'curl -s -X PUT http://' + dr_callback_ip + ':3906/dr_redir_publish/' +req.params.filename;
+	var command = 'curl -s -X PUT http://' + dr_callback_ip + ':3906/dr_redir_publish/'+feedId+'/'+filename;
 
 	console.log("Callback to DR sim to report file published, cmd: " + command);
-	child = exec(command, function(error, stdout, stderr){
+	var child = exec(command, function(error, stdout, stderr){
 		console.log('stdout: ' + stdout);
 		console.log('stderr: ' + stderr);
 		if(error !== null) {
 			console.log('exec error: ' + error);
 		}
-		
 	});
 
 	//Update status variables
-	ctr_publish_responses++;
-	lastPublish = fmtMSS(Math.floor((Date.now()-startTime)/1000));
-	dwl_volume = dwl_volume + req.body.length;
+	ctr_publish_responses[feedIndexes[feedId]]++;
+	lastPublish[feedIndexes[feedId]] = Math.floor((Date.now()-startTime)/1000);
+	dwl_volume[feedIndexes[feedId]] = dwl_volume[feedIndexes[feedId]] + req.body.length;
 
-	if (args.tc==tc_10p_delay_10s && (ctr_publish_requests%10)==0) {
+	if (args.tc==tc_10p_delay_10s && (ctr%10)==0) {
         sleep(10000).then(() => {
 			res.send("ok");
 		});
@@ -234,6 +371,15 @@
 		});
 		return;
 	}
+	if (total_first_publish == 0) {
+		total_first_publish=Date.now()/1000;
+	}
+	total_last_publish=Date.now()/1000;
+	total_files++;
+	if (total_last_publish > total_first_publish) {
+		speed = Math.round((total_files/(total_last_publish-total_first_publish))*10)/10;
+	}
+
 	res.send("ok")
 });
 
@@ -250,5 +396,36 @@
 
 if (process.env.DR_SIM_IP) {
 	dr_callback_ip=process.env.DR_SIM_IP;
-} 
+}
 console.log("Using IP " + dr_callback_ip + " for callback to DR sim");
+
+if (process.env.DR_REDIR_FEEDS) {
+	feeds=process.env.DR_REDIR_FEEDS;
+}
+console.log("Configured list of feeds: " + feeds);
+
+var i=0;
+feedNames=feeds.split(',');
+for(i=0;i<feedNames.length;i++) {
+	var tmp=feedNames[i].split(':');
+	feedNames[i]=tmp[0].trim();
+	feedIndexes[feedNames[i]]=i;
+	filePrefixes[i]=[]
+	var j=0;
+	for(j=1;j<tmp.length;j++) {
+		filePrefixes[i][j-1]=tmp[j];
+	}
+
+	ctr_publish_requests[i] = 0;
+	ctr_publish_requests_bad_file_prefix[i] = 0;
+	ctr_publish_responses[i] = 0;
+	lastPublish[i] = -1;
+	dwl_volume[i] = 0;
+}
+console.log("Parsed mapping between feed id and file name prefix");
+for(i=0;i<feedNames.length;i++) {
+	var fn = feedNames[i];
+	for (j=0;j<filePrefixes[i].length;j++) {
+		console.log("Feed id: " + fn + ", file name prefix: " + filePrefixes[i][j]);
+	}
+}