&rq) {
if (rq->parameters.empty()) {
rq->answer = ""
""
"MeOS Information Service"
""
""
"MeOS
" + ref.gdiBase().toUTF8(lang.tl(getMeosFullVersion())) + "
"
"
\n";
vector lists;
TabList::getPublicLists(ref, lists);
map listMap;
ref.getListTypes(listMap, false);
for (auto &lp : lists) {
wstring n = lp.getName();
if (n.empty()) {
n = listMap[lp.listCode].getName();
}
lp.setName(n);
int keyCand = lp.listCode * 100;
bool done = false;
for (int i = 0; i < 100; i++) {
if (!listCache.count(keyCand + i)) {
keyCand += i;
listCache[keyCand].first = lp;
done = true;
break;
}
else if(listCache[keyCand + i].first == lp) {
keyCand = keyCand + i;
done = true;
break;
}
}
if (!done) {
listCache[keyCand].first = lp;
listCache[keyCand].second.reset();
}
rq->answer += "- " + ref.gdiBase().toUTF8(n) + "
\n";
}
// "- Resultat
"
// "- Startlista
"
rq->answer += "
\n";
HINSTANCE hInst = GetModuleHandle(0);
HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(132), RT_HTML);
HGLOBAL res = LoadResource(hInst, hRes);
char *html = (char *)LockResource(res);
int resSize = SizeofResource(hInst, hRes);
if (html) {
string htmlS;
while (*html != 0 && resSize > 0) {
if (*html == '*')
htmlS += "<";
else if (*html == '#')
htmlS += "&";
else
htmlS += *html;
++html;
resSize--;
}
rq->answer += htmlS;
}
rq->answer += "\n\n";
}
else if (rq->parameters.count("get") > 0) {
string what = rq->parameters.find("get")->second;
getData(ref, what, rq->parameters, rq->answer);
}
else if (rq->parameters.count("html") > 0) {
string stype = rq->parameters.count("type") ? rq->parameters.find("type")->second : _EmptyString;
int type = atoi(stype.c_str());
auto res = listCache.find(type);
if (res != listCache.end()) {
gdioutput gdiPrint("print", ref.gdiBase().getScale(), ref.gdiBase().getCP());
gdiPrint.clearPage(false);
if (!res->second.second) {
res->second.second = make_shared();
ref.generateListInfo(res->second.first, gdiPrint.getLineHeight(), *res->second.second);
}
ref.generateList(gdiPrint, true, *res->second.second, false);
wstring exportFile = getTempFile();
gdiPrint.writeHTML(exportFile, ref.getName(), 30);
ifstream fin(exportFile.c_str());
string rbf;
while (std::getline(fin, rbf)) {
rq->answer += rbf;
}
removeTempFile(exportFile);
}
else {
rq->answer = "Error (MeOS): Unknown list";
}
}
else {
rq->answer = "Error (MeOS): Unknown request";
}
}
void writePerson(const GeneralResult::GeneralResultInfo &res,
xmlbuffer &reslist,
bool includeTeam,
bool includeCourse,
vector< pair > &rProp) {
int clsId = res.src->getClassId(true);
rProp.push_back(make_pair("cls", itow(clsId)));
if (includeCourse) {
pRunner pr = dynamic_cast(res.src);
if (pr && pr->getCourse(false))
rProp.push_back(make_pair("course", itow(pr->getCourse(false)->getId())));
}
bool hasTeam = res.src->getTeam() != 0 &&
clsId == res.src->getClassId(false) && // No Qualification/Final
(clsId == 0 || res.src->getClassRef(false)->getQualificationFinal() == 0); // // No Qualification/Final
if (includeTeam && hasTeam)
rProp.push_back(make_pair("team", itow(res.src->getTeam()->getId())));
if (hasTeam)
rProp.push_back(make_pair("leg", itow(1+pRunner(res.src)->getLegNumber())));
rProp.push_back(make_pair("stat", itow(res.status)));
if (res.score > 0)
rProp.push_back(make_pair("score", itow(res.score)));
rProp.push_back(make_pair("st", itow(10 * (res.src->getStartTime() + res.src->getEvent()->getZeroTimeNum()))));
if (res.src->getClassRef(false) == 0 || !res.src->getClassRef(true)->getNoTiming()) {
if (res.time > 0)
rProp.push_back(make_pair("rt", itow(10 * res.time)));
if (res.place > 0)
rProp.push_back(make_pair("place", itow(res.place)));
}
auto &subTag = reslist.startTag("person", rProp);
rProp.clear();
rProp.push_back(make_pair("id", itow(res.src->getId())));
subTag.write("name", rProp, res.src->getName());
rProp.clear();
if (res.src->getClubRef()) {
rProp.push_back(make_pair("id", itow(res.src->getClubId())));
subTag.write("org", rProp, res.src->getClub());
rProp.clear();
}
subTag.endTag();
}
void RestServer::getData(oEvent &oe, const string &what, const multimap ¶m, string &answer) {
xmlbuffer out;
out.setComplete(true);
bool okRequest = false;
if (what == "iofresult") {
wstring exportFile = getTempFile();
bool useUTC = false;
set cls;
if (param.count("class") > 0)
getSelection(param.find("class")->second, cls);
oe.exportIOFSplits(oEvent::IOF30, exportFile.c_str(), false, useUTC, cls, -1, false, false, true, false);
ifstream fin(exportFile.c_str());
string rbf;
while (std::getline(fin, rbf)) {
answer += rbf;
}
removeTempFile(exportFile);
okRequest = true;
}
else if (what == "iofstart") {
wstring exportFile = getTempFile();
bool useUTC = false;
set cls;
if (param.count("class") > 0)
getSelection(param.find("class")->second, cls);
oe.exportIOFStartlist(oEvent::IOF30, exportFile.c_str(), useUTC, cls, false, true, false);
ifstream fin(exportFile.c_str());
string rbf;
while (std::getline(fin, rbf)) {
answer += rbf;
}
removeTempFile(exportFile);
okRequest = true;
}
else if (what == "competition") {
InfoCompetition cmp(0);
cmp.synchronize(oe);
cmp.serialize(out, false);
okRequest = true;
}
else if (what == "class") {
vector cls;
oe.getClasses(cls, true);
set ctrlW;
vector ctrl;
oe.getControls(ctrl, true);
for (size_t k = 0; k < ctrl.size(); k++) {
if (ctrl[k]->isValidRadio()) {
vector cc;
ctrl[k]->getCourseControls(cc);
ctrlW.insert(cc.begin(), cc.end());
}
}
for (auto c : cls) {
InfoClass iCls(c->getId());
iCls.synchronize(*c, ctrlW);
iCls.serialize(out, false);
}
okRequest = true;
}
else if (what == "organization") {
vector clb;
oe.getClubs(clb, true);
for (auto c : clb) {
InfoOrganization iClb(c->getId());
iClb.synchronize(*c);
iClb.serialize(out, false);
}
okRequest = true;
}
else if (what == "competitor") {
vector r;
set selection;
if (param.count("class") > 0)
getSelection(param.find("class")->second, selection);
oe.getRunners(selection.size() == 1 ? *selection.begin() : 0, -1, r, true);
{
vector r2;
r2.reserve(r.size());
for (pRunner tr : r) {
pClass cls = tr->getClassRef(true);
if (cls && cls->getQualificationFinal() && tr->getLegNumber() != 0)
continue;
if (selection.empty() || (cls && selection.count(cls->getId())))
r2.push_back(tr);
}
r.swap(r2);
}
for (auto c : r) {
InfoCompetitor iR(c->getId());
iR.synchronize(false, *c);
iR.serialize(out, false);
}
okRequest = true;
}
else if (what == "team") {
vector teams;
set selection;
if (param.count("class") > 0)
getSelection(param.find("class")->second, selection);
oe.getTeams(selection.size() == 1 ? *selection.begin() : 0, teams, true);
if (selection.size() > 1) {
vector r2;
r2.reserve(teams.size());
for (pTeam tr : teams) {
if (selection.count(tr->getClassId(false)))
r2.push_back(tr);
}
teams.swap(r2);
}
for (auto c : teams) {
InfoTeam iT(c->getId());
iT.synchronize(*c);
iT.serialize(out, false);
}
okRequest = true;
}
else if (what == "control") {
vector ctrl;
oe.getControls(ctrl, true);
vector< pair > prop(1);
prop[0].first = "id";
for (pControl c : ctrl) {
int nd = c->getNumberDuplicates();
for (int k = 0; k < nd; k++) {
prop[0].second = itow(oControl::getCourseControlIdFromIdIndex(c->getId(), k));
if (nd > 1)
out.write("control", prop, c->getName() + L"-" + itow(k+1));
else
out.write("control", prop, c->getName());
}
}
okRequest = true;
}
else if (what == "result") {
okRequest = true;
vector r;
set selection;
pClass sampleClass = 0;
if (param.count("class") > 0) {
getSelection(param.find("class")->second, selection);
if (!selection.empty())
sampleClass = oe.getClass(*selection.begin());
}
if (sampleClass == 0) {
vector tt;
oe.getClasses(tt, false);
if (!tt.empty())
sampleClass = tt[0];
}
string resTag;
if (param.count("module") > 0)
resTag = param.find("module")->second;
pair controlId(oPunch::PunchStart, oPunch::PunchFinish);
bool totalResult = false;
if (param.count("total")) {
const string &tot = param.find("total")->second;
totalResult = atoi(tot.c_str()) > 0 || _stricmp(tot.c_str(), "true") == 0;
}
if (param.count("to")) {
const string &cid = param.find("to")->second;
controlId.second = atoi(cid.c_str());
if (controlId.second == 0)
controlId.second = oControl::getControlIdByName(oe, cid);
if (controlId.second == 0)
throw meosException("Unknown control: " + cid);
}
if (param.count("from")) {
const string &cid = param.find("from")->second;
controlId.first = atoi(cid.c_str());
if (controlId.first == 0)
controlId.first = oControl::getControlIdByName(oe, cid);
if (controlId.first == 0)
throw meosException("Unknown control: " + cid);
}
oListInfo::ResultType resType = oListInfo::Classwise;
wstring resTypeStr = L"classindividual";
ClassType ct = sampleClass ? sampleClass->getClassType() : ClassType::oClassIndividual;
bool team = ct == oClassPatrol || ct == oClassRelay;
int limit = 100000;
if (param.count("limit")) {
limit = atoi(param.find("limit")->second.c_str());
if (limit <= 0)
throw meosException("Invalid limit: " + param.find("limit")->second);
}
if (param.count("type")) {
string type = param.find("type")->second;
if (type == "GlobalIndividual") {
resType = oListInfo::Global;
team = false;
}
else if (type == "ClassIndividual") {
resType = oListInfo::Classwise;
team = false;
}
else if (type == "CourseIndividual") {
resType = oListInfo::Coursewise;
team = false;
}
else if (type == "LegIndividual") {
resType = oListInfo::Legwise;
team = false;
}
else if (type == "GlobalTeam") {
resType = oListInfo::Global;
team = true;
}
else if (type == "ClassTeam") {
resType = oListInfo::Classwise;
team = true;
}
else
throw meosException("Unknown type: " + type);
string2Wide(type, resTypeStr);
resTypeStr = canonizeName(resTypeStr.c_str());
}
else if (team) {
resTypeStr = L"classteam";
}
int inputNumber = 0;
if (param.count("argument")) {
const string &arg = param.find("argument")->second;
inputNumber = atoi(arg.c_str());
}
vector results;
vector< pair > prop, noProp, rProp;
prop.push_back(make_pair("type", resTypeStr));
int leg = -1;
if (param.count("leg") > 0) {
string legs = param.find("leg")->second;
leg = atoi(legs.c_str())-1;
if (leg < 0 || leg > 32)
throw meosException("Invalid leg: " + legs);
}
if (ct == oClassRelay) {
if (leg == -1)
prop.push_back(make_pair("leg", L"Last"));
else
prop.push_back(make_pair("leg", itow(leg + 1)));
}
if (!resTag.empty())
prop.push_back(make_pair("module", oe.gdiBase().widen(resTag) + L"(" + itow(inputNumber) + L")"));
if (controlId.first != oPunch::PunchStart) {
pair idIx = oControl::getIdIndexFromCourseControlId(controlId.first);
pControl ctrl = oe.getControl(idIx.first);
if (ctrl == 0)
throw meosException("Unknown control: " + itos(idIx.first));
wstring loc = ctrl->getName();
if (idIx.second > 0)
loc += L"-" + itow(idIx.second + 1);
prop.push_back(make_pair("from", loc));
}
if (controlId.second == oPunch::PunchFinish)
prop.push_back(make_pair("to", L"Finish"));
else {
pair idIx = oControl::getIdIndexFromCourseControlId(controlId.second);
pControl ctrl = oe.getControl(idIx.first);
if (ctrl == 0)
throw meosException("Unknown control: " + itos(idIx.first));
wstring loc = ctrl->getName();
if (idIx.second > 0)
loc += L"-" + itow(idIx.second+1);
prop.push_back(make_pair("to", loc));
}
if (!team) {
oe.getRunners(selection.size() == 1 ? *selection.begin() : 0, -1, r, false);
{
vector r2;
r2.reserve(r.size());
for (pRunner tr : r) {
pClass cls = tr->getClassRef(true);
if (cls && cls->getQualificationFinal() && tr->getLegNumber() != 0)
continue;
if (selection.empty() || (cls && selection.count(cls->getId())))
r2.push_back(tr);
}
r.swap(r2);
}
GeneralResult::calculateIndividualResults(r, controlId, totalResult, resTag, resType, inputNumber, oe, results);
if (resType == oListInfo::Classwise)
sort(results.begin(), results.end());
/*else if (resType == oListInfo::Coursewise) {
sort(results.begin(), results.end(),
[](const GeneralResult::GeneralResultInfo &a, const GeneralResult::GeneralResultInfo &b)->
bool {
pCourse ac = dynamic_cast(*a.src).getCourse(false);
pCourse bc = dynamic_cast(*b.src).getCourse(false);
if (ac != bc)
return ac->getId() < bc->getId();
return a.compareResult(b);
}
);
}*/
auto &reslist = out.startTag("results", prop);
int place = -1;
int cClass = -1;
int counter = 0;
for (const auto &res : results) {
if (res.src->getClassId(true) != cClass) {
counter = 0;
place = 1;
cClass = res.src->getClassId(true);
}
if (++counter > limit && (place != res.place || res.status != StatusOK))
continue;
place = res.place;
writePerson(res, reslist, true, resType == oListInfo::Coursewise, rProp);
}
reslist.endTag();
}
else {
//Teams
vector teams;
oe.getTeams(selection.size() == 1 ? *selection.begin() : 0, teams, true);
if (selection.size() > 1) {
vector r2;
r2.reserve(teams.size());
for (pTeam tr : teams) {
if (selection.count(tr->getClassId(true)))
r2.push_back(tr);
}
teams.swap(r2);
}
auto context = GeneralResult::calculateTeamResults(teams, leg, controlId, totalResult, resTag, resType, inputNumber, oe, results);
sort(results.begin(), results.end());
auto &reslist = out.startTag("results", prop);
int place = -1;
int cClass = -1;
int counter = 0;
for (const auto &res : results) {
pTeam team = pTeam(res.src);
if (leg >= team->getNumRunners())
continue;
if (res.src->getClassId(true) != cClass) {
counter = 0;
place = 1;
cClass = res.src->getClassId(true);
}
if (++counter > limit && (place != res.place || res.status != StatusOK))
continue;
place = res.place;
rProp.push_back(make_pair("cls", itow(res.src->getClassId(true))));
rProp.push_back(make_pair("stat", itow(res.status)));
if (res.score > 0)
rProp.push_back(make_pair("score", itow(res.score)));
if (res.src->getStartTime() > 0)
rProp.push_back(make_pair("st", itow(10 * (res.src->getStartTime() + oe.getZeroTimeNum()))));
if (res.src->getClassRef(false) == 0 || !res.src->getClassRef(true)->getNoTiming()) {
if (res.time > 0)
rProp.push_back(make_pair("rt", itow(10 * res.time)));
if (res.place > 0)
rProp.push_back(make_pair("place", itow(res.place)));
}
auto &subTag = reslist.startTag("team", rProp);
rProp.clear();
rProp.push_back(make_pair("id", itow(res.src->getId())));
subTag.write("name", rProp, res.src->getName());
rProp.clear();
if (res.src->getClubRef()) {
rProp.push_back(make_pair("id", itow(res.src->getClubId())));
subTag.write("org", rProp, res.src->getClub());
rProp.clear();
}
int subRes = res.getNumSubresult(*context);
GeneralResult::GeneralResultInfo out;
for (int k = 0; k < subRes; k++) {
if (res.getSubResult(*context, k, out)) {
writePerson(out, subTag, false, false, rProp);
}
}
subTag.endTag();
}
reslist.endTag();
}
}
if (out.size() > 0) {
xmlparser mem;
mem.openMemoryOutput(false);
mem.startTag("MOPComplete", "xmlns", "http://www.melin.nu/mop");
out.commit(mem, 100000);
mem.endTag();
mem.getMemoryOutput(answer);
}
else if (!okRequest) {
answer = "Error (MeOS): Unknown command '" + what + "'";
}
}
void RestServer::getSelection(const string ¶m, set &sel) {
vector sw;
split(param, ";,", sw);
for (auto &s : sw) {
int id = atoi(s.c_str());
if (id > 0)
sel.insert(id);
}
}
shared_ptr RestServer::getRequest() {
shared_ptr res;
if (hasAnyRequest) {
lock_guard lg(lock);
if (!requests.empty()) {
res = requests.front();
requests.pop_front();
}
if (requests.empty())
hasAnyRequest = false;
}
return res;
}
shared_ptr RestServer::addRequest(multimap ¶m) {
auto rq = make_shared();
rq->parameters.swap(param);
lock_guard lg(lock);
requests.push_back(rq);
hasAnyRequest = true;
return rq;
}
void RestServer::getStatistics(Statistics &s) {
lock_guard lg(lock);
s.numRequests = responseTimes.size();
s.maxResponseTime = 0;
s.averageResponseTime = 0;
for (int t : responseTimes) {
s.maxResponseTime = max(s.maxResponseTime, t);
s.averageResponseTime += t;
}
if (s.numRequests > 0) {
s.averageResponseTime /= s.numRequests;
}
}