#include "apiImpl.h" #include "uptr.h" #include #include #include #include #include #include #include namespace MirrorSearch { SearchImpl::SearchImpl(IceTray::DatabasePoolPtr db) : IceTray::AbstractDatabaseClient(db), log(LOGMANAGER()->getLogger()) { } SearchServices SearchImpl::getServices(const ::Ice::Current&) { return fetch(sql::getServices); } template void libxmlErrorHandler(const std::string & fn, const P & ... p) { throw XmlError(Fmt::get(fn, xmlGetLastError()->message, p...)); } template auto lEHB(const P & ... p) { return std::bind(&libxmlErrorHandler, std::placeholders::_1, p...); } typedef UPtr xmlDocSPtr; typedef UPtr xmlXPathContextSPtr; typedef UPtr xmlXPathObjectSPtr; AdHocFormatter(Read, "Failed to read in %? (%?) [%?, %?]"); static auto getDoc(const ::std::string & url, int flags) { return make_unique(htmlReadFile, xmlFreeDoc, lEHB(url, flags), url.c_str(), (const char*)NULL, flags); } AdHocFormatter(XPathCtx, "Failed to create xpath context in %? (%?)"); static auto getXPathCxt(const xmlDocSPtr & doc) { return make_unique(xmlXPathNewContext, xmlXPathFreeContext, lEHB(), doc.get()); } AdHocFormatter(XPathEval, "Failed to evaluate xpath in %? (%?) [%?]"); static auto getXPathObj(const ::std::string & xpath, const xmlXPathContextSPtr & ctx, xmlXPathObjectType type) { auto xpathObj = make_unique(xmlXPathEvalExpression, xmlXPathFreeObject, lEHB(xpath), BAD_CAST xpath.c_str(), ctx.get()); if (xpathObj->type != type) { throw XmlError("Xpath evaluates to wrong type " + xpath); } return xpathObj; } void SearchImpl::callService(const ::std::string & fn, const SearchServicePtr & s, SearchHits & sh) const { auto fmt = AdHoc::Buffer::getFormat(s->baseurl); auto url = (*fmt % fn).str(); auto doc = getDoc(url, HTML_PARSE_RECOVER | HTML_PARSE_NODEFDTD | HTML_PARSE_NOIMPLIED | HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR); auto xpathCtx = getXPathCxt(doc); auto xpathObj = getXPathObj(s->listxpath, xpathCtx, xmlXPathObjectType::XPATH_NODESET); log->messagebf(LOG::INFO, "%d nodes matched %s", xpathObj->nodesetval->nodeNr, s->listxpath); for (int row = 0; row < xpathObj->nodesetval->nodeNr; row += 1) { xpathCtx->node = xpathObj->nodesetval->nodeTab[row]; auto xpathObjI = getXPathObj(s->urlxpath, xpathCtx, xmlXPathObjectType::XPATH_STRING); if (xpathObjI->stringval && *xpathObjI->stringval) { sh.push_back(new SearchHit(0, s->id, (const char *) xpathObjI->stringval)); } } } SearchHits SearchImpl::getMatches(const ::std::string & fn, const ::Ice::Current & c) { SearchHits sh; for (const auto & s : getServices(c)) { callService(fn, s, sh); } return sh; } ::IceUtil::Optional<::std::string> SearchImpl::feelingLucky(const ::std::string & fn, const ::Ice::Current & c) { const auto ms = getMatches(fn, c); if (ms.empty()) return IceUtil::None; return ms.front()->url; } }