vjudge-description-spider
Version:
This project is the spider API for a number of Online Judge Systems.
427 lines (363 loc) • 14.1 kB
JavaScript
var http = require("http");
var serverName = "VJudge Description Spider Tester Server Engine";
var logger = require("log4js").getLogger("SRV");
var mime = require("./mime");
var url = require("url");
var querystring = require("querystring");
String.prototype.replaceAll = stringReplaceAll;
function stringReplaceAll(AFindText,ARepText){
var raRegExp = new RegExp(AFindText.replace(/([\(\)\[\]\{\}\^\$\+\-\*\?\.\"\'\|\/\\])/g,"\\$1"),"ig");
return this.replace(raRegExp,ARepText);
}
/**
* No enough error handle because it's just a tester
* @param problemObject
*/
function getProblem(ojname, problemObject, resp) {
var fs = require("fs");
var path = require("path");
var dir = path.dirname(__filename);
fs.readFile(dir + "/template/randomproblem.html", function(err, data) {
var StringDecoder = require('string_decoder').StringDecoder;
var decoder = new StringDecoder('utf8');
var text = decoder.write(data);
text = text.replaceAll("_OJNAME_", ojname);
text = text.replaceAll("_ID_", problemObject["id"]);
text = text.replaceAll("_TITLE_", problemObject["title"]);
text = text.replaceAll("_TIME_", problemObject["time"]);
text = text.replaceAll("_MEMO_", problemObject["memo"]);
text = text.replaceAll("_AC_", problemObject["accept"]);
text = text.replaceAll("_SUB_", problemObject["submit"]);
text = text.replaceAll("_RATIO_", problemObject["ratioString"]);
text = text.replaceAll("_DESCRIPTION_", problemObject["description"]);
text = text.replaceAll("_INPUT_", problemObject["input"]);
text = text.replaceAll("_OUTPUT_", problemObject["output"]);
text = text.replaceAll("_SINPUT_", problemObject["sampleInput"]);
text = text.replaceAll("_SOUTPUT_", problemObject["sampleOutput"]);
text = text.replaceAll("_HINT_", problemObject["hint"]);
text = text.replaceAll("_SOURCE_", problemObject["source"]);
resp.writeHead(200, {
"content-type" : "text/html",
"server" : serverName
});
resp.write(text);
resp.end();
});
};
/**
* Show the error page.
* @param req
* @param resp
* @param err
*/
function showErrorPage(req, resp, msg, status, errtemplate) {
if(undefined === status) status = 404;
var fs = require("fs");
var path = require("path");
var dir = path.dirname(__filename);
var filename = dir + "/template/error.html";
if(errtemplate !== undefined) {
filename = dir + "/" + errtemplate;
}
fs.readFile(filename, function(err, data) {
if(err) {
resp.writeHead(status, {
"content-type" : "text/html",
"server" : serverName
});
resp.write("Fatal Error: " + err.message);
resp.end();
return;
}
resp.writeHead(status, {
"content-type" : "text/html",
"server" : serverName
});
var StringDecoder = require('string_decoder').StringDecoder;
var decoder = new StringDecoder('utf8');
var text = decoder.write(data);
if(typeof msg === "string") {
text = text.replaceAll("_ERROR_", msg);
} else {
text = text.replaceAll("_ERROR_", msg.message);
}
resp.write(text);
resp.end();
});
};
/**
* Get the static resources from server.
* e.g. foo.css and bar.js and so on.
*
* @param req
* @param resp
*/
function getStatic(req, resp, errtemplate) {
var fs = require("fs");
var path = require("path");
var dir = path.dirname(__filename);
var filename = dir + "/static" + req["url"];
fs.readFile(filename, "binary", function(err, data) {
if(err) {
logger.error("Failed in fetching static resources [ " + req["url"] + " ] : " + err.message + ".");
showErrorPage(req, resp, err, errtemplate);
return;
}
var ext = path.extname(filename);
ext = ext ? ext.slice(1) : 'unknown';
var contentType = mime[ext] || "text/plain";
resp.writeHead(200, {
"content-type" : contentType,
"server" : serverName
});
resp.write(data, "binary");
resp.end();
});
}
function testerServer() { }
/**
* Start a test server.
* @param ojname
* @param showname
* @param port
*/
testerServer.prototype.start = function(ojname, showname, port) {
if(port === undefined) port = 8888;
var index = require("../../index");
var self = this;
try {
this.oj = index.getOJSpider(ojname);
this.ojname = showname;
if(this.oj === null) {
logger.error("Can't start test server: this oj name is not supported.");
return;
}
/**
* Get page count
*/
this.oj.getPageCount(function(status, msg, count) {
if(status === false) {
logger.error("Can't start test server: " + msg);
return;
}
self.pageCount = count;
/**
* Create the server and listen
*/
http.createServer(function(req, resp) {
logger.info("Received a request : " + req["url"] + " (" + req["headers"]["user-agent"] + ") from " + req.socket.remoteAddress + ".");
if(req["url"] === "/") {
resp.writeHead(302, {
"content-type" : "text/html",
"location" : "list",
"server" : serverName
});
resp.end();
return;
} else if(url.parse(req["url"]).pathname === "/list") {
self.processList(req, resp);
return;
} else if(url.parse(req["url"]).pathname === "/problem") {
self.processProblem(req, resp);
return;
} else {
getStatic(req, resp);
return;
}
}).listen(port);
logger.info("Test Server started at listening port " + port + ".");
});
} catch(e) {
logger.error("Can't start test server: " + e.message);
}
}
/**
* Process a certain problem
* @param req
* @param resp
*/
testerServer.prototype.processProblem = function(req, resp) {
var id = NaN;
var self = this;
var qs = url.parse(req["url"]).query;
qs = querystring.parse(qs);
if(qs["id"] !== null) {
id = parseInt(qs["id"]);
}
this.oj.getProblemByID(id, function(status, msg, problemObject) {
if(!status) {
showErrorPage(req, resp, msg, 500);
return;
}
var fs = require("fs");
var path = require("path");
var dir = path.dirname(__filename);
fs.readFile(dir + "/template/problem.html", function(err, data) {
if(err) {
showErrorPage(req, resp, err, 500);
return;
}
var StringDecoder = require('string_decoder').StringDecoder;
var decoder = new StringDecoder('utf8');
var text = decoder.write(data);
text = text.replaceAll("_OJNAME_", self.ojname);
text = text.replaceAll("_ID_", problemObject["id"]);
text = text.replaceAll("_TITLE_", problemObject["title"]);
text = text.replaceAll("_TIME_", problemObject["time"]);
text = text.replaceAll("_MEMO_", problemObject["memo"]);
text = text.replaceAll("_AC_", problemObject["accept"]);
text = text.replaceAll("_SUB_", problemObject["submit"]);
text = text.replaceAll("_RATIO_", problemObject["ratioString"]);
text = text.replaceAll("_DESCRIPTION_", problemObject["description"]);
text = text.replaceAll("_INPUT_", problemObject["input"]);
text = text.replaceAll("_OUTPUT_", problemObject["output"]);
text = text.replaceAll("_SINPUT_", problemObject["sampleInput"]);
text = text.replaceAll("_SOUTPUT_", problemObject["sampleOutput"]);
text = text.replaceAll("_HINT_", problemObject["hint"]);
text = text.replaceAll("_SOURCE_", problemObject["source"]);
text = text.replaceAll("_URL_", problemObject["url"]);
text = text.replaceAll("_BASEURL_", problemObject["baseurl"]);
if(problemObject["specialJudge"] === true) {
text = text.replaceAll("_SPECIALJUDGE_", ' <small class="muted">Special Judge</small>')
} else {
text = text.replaceAll("_SPECIALJUDGE_", "");
}
resp.writeHead(200, {
"content-type" : "text/html",
"server" : serverName
});
resp.write(text);
resp.end();
});
});
}
/**
* Process with list page
* @param req
* @param resp
*/
testerServer.prototype.processList = function(req, resp) {
var page = 1;
var self = this;
var qs = url.parse(req["url"]).query;
qs = querystring.parse(qs);
if(qs["page"] !== undefined) {
page = parseInt(qs["page"]);
}
/**
* Page exceeded.
*/
if(page > this.pageCount) {
resp.writeHead(302, {
"content-type" : "text/plain",
"server" : serverName,
"location" : "list"
});
resp.end();
return;
}
this.oj.getProblemIDListFromPage(page, function(status, msg, list) {
if(!status) {
showErrorPage(req, resp, msg, 500);
return;
}
var fs = require("fs");
var path = require("path");
var dir = path.dirname(__filename);
fs.readFile(dir + "/template/problist.html", function(err, data) {
if(err) {
showErrorPage(req, resp, err, 500);
return;
}
resp.writeHead(200, {
"content-type" : "text/html",
"server" : serverName
});
var StringDecoder = require('string_decoder').StringDecoder;
var decoder = new StringDecoder('utf8');
var text = decoder.write(data);
var listReg = /{{ problist }}([\s\S]*){{ \/problist }}/;
var listEleResult = listReg.exec(text);
if(listEleResult !== null && listEleResult.length === 2) {
var listEleText = listEleResult[1];
var listString = "";
for(var i = 0; i < list.length; i++) {
var temp = listEleText;
temp = temp.replaceAll("_PROB_.TITLE", list[i].title);
temp = temp.replaceAll("_PROB_.ID", list[i].id);
temp = temp.replaceAll("_PROB_.ACCEPTED", list[i].accepted);
temp = temp.replaceAll("_PROB_.SUBMITTED", list[i].submitted);
temp = temp.replaceAll("_PROB_.RATIO", ((list[i].accepted / list[i].submitted * 100).toFixed(2)) + "%");
temp = temp.replaceAll("_PROB_.URL", "problem?id=" + list[i].id);
listString += temp;
}
listReg = /{{ problist }}([\s\S]*){{ \/problist }}/g;
text = text.replace(listReg, listString);
text = text.replaceAll("_OJNAME_", self.ojname);
}
var pagination = '<div class="pagination pagination-mini pagination-centered"><ul>';
if(page === 1) {
pagination += '<li class="disabled"><a href="#">«</a></li>';
} else {
pagination += '<li><a href="/list?page=1">«</a></li>'
}
for(var i = 1; i <= self.pageCount; i++) {
var href = "/list?page=" + i;
if(i === page) {
pagination += '<li class="active"><a href="' + href + '">' + i + '</a></li>';
} else {
pagination += '<li><a href="' + href + '">' + i + '</a></li>';
}
}
if(page === self.pageCount) {
pagination += '<li class="disabled"><a href="#">»</a></li>';
} else {
pagination += '<li><a href="/list?page=' + self.pageCount + '">»</a></li>';
}
pagination += '</ul></div>';
text = text.replaceAll("_PAGINATION_", pagination);
resp.write(text);
resp.end();
});
}, true);
}
/**
* Start a test server.
* @param ojname
* @param port
*/
exports.startTestServer = function(ojname, showname, port) {
var srv = new testerServer();
srv.start(ojname, showname, port);
};
/**
* Start a pre-dev test server.
* @param callback(serverCallback(ojname, problemObject, resp), resp)
* @param port
*/
exports.startPreDev = function(callback, port) {
if(port === undefined) port = 8888;
try {
http.createServer(function(req, resp) {
logger.info("Received a request : " + req["url"] + " (" + req["headers"]["user-agent"] + ") from " + req.socket.remoteAddress + ".");
if(req["url"] === "/") {
resp.writeHead(302, {
"content-type" : "text/html",
"location" : "randomProblem",
"server" : serverName
});
resp.end();
return;
} else if(req["url"] === "/randomProblem") {
callback(getProblem, resp);
return;
} else {
getStatic(req, resp);
return;
}
}).listen(port);
logger.info("Pre-Dev Test Server started at listening port " + port + ".");
} catch(e) {
logger.error("Can't start test server: " + e.message);
}
};