mirror of
https://github.com/kiwix/libkiwix.git
synced 2025-12-24 06:57:59 -05:00
Compare commits
16 Commits
dirScan
...
opds_name_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1124704f9 | ||
|
|
1fcc2ad709 | ||
|
|
7d83127d58 | ||
|
|
37ccfb54ed | ||
|
|
6815a4c6a9 | ||
|
|
3e54e56291 | ||
|
|
422e71a017 | ||
|
|
92c0e145d4 | ||
|
|
3d75f24a29 | ||
|
|
4842fa0355 | ||
|
|
0bd5a5ec3b | ||
|
|
5896691b31 | ||
|
|
85f58b8e01 | ||
|
|
24472e03dd | ||
|
|
96fb4236a6 | ||
|
|
cc849b31da |
@@ -37,10 +37,10 @@ namespace kiwix
|
||||
class LibraryManipulator
|
||||
{
|
||||
public: // functions
|
||||
explicit LibraryManipulator(Library* library);
|
||||
explicit LibraryManipulator(std::shared_ptr<Library> library);
|
||||
virtual ~LibraryManipulator();
|
||||
|
||||
Library& getLibrary() const { return library; }
|
||||
Library& getLibrary() const { return *library.get(); }
|
||||
|
||||
bool addBookToLibrary(const Book& book);
|
||||
void addBookmarkToLibrary(const Bookmark& bookmark);
|
||||
@@ -52,7 +52,7 @@ class LibraryManipulator
|
||||
virtual void booksWereRemovedFromLibrary();
|
||||
|
||||
private: // data
|
||||
kiwix::Library& library;
|
||||
std::shared_ptr<kiwix::Library> library;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -65,7 +65,7 @@ class Manager
|
||||
|
||||
public: // functions
|
||||
explicit Manager(LibraryManipulator* manipulator);
|
||||
explicit Manager(Library* library);
|
||||
explicit Manager(std::shared_ptr<Library> library);
|
||||
|
||||
/**
|
||||
* Read a `library.xml` and add book in the file to the library.
|
||||
|
||||
@@ -50,7 +50,7 @@ class HumanReadableNameMapper : public NameMapper {
|
||||
std::map<std::string, std::string> m_nameToId;
|
||||
|
||||
public:
|
||||
HumanReadableNameMapper(kiwix::Library& library, bool withAlias);
|
||||
HumanReadableNameMapper(const kiwix::Library& library, bool withAlias);
|
||||
virtual ~HumanReadableNameMapper() = default;
|
||||
virtual std::string getNameForId(const std::string& id) const;
|
||||
virtual std::string getIdForName(const std::string& name) const;
|
||||
@@ -59,7 +59,7 @@ class HumanReadableNameMapper : public NameMapper {
|
||||
class UpdatableNameMapper : public NameMapper {
|
||||
typedef std::shared_ptr<NameMapper> NameMapperHandle;
|
||||
public:
|
||||
UpdatableNameMapper(Library& library, bool withAlias);
|
||||
UpdatableNameMapper(std::shared_ptr<Library> library, bool withAlias);
|
||||
|
||||
virtual std::string getNameForId(const std::string& id) const;
|
||||
virtual std::string getIdForName(const std::string& name) const;
|
||||
@@ -71,7 +71,7 @@ class UpdatableNameMapper : public NameMapper {
|
||||
|
||||
private:
|
||||
mutable std::mutex mutex;
|
||||
Library& library;
|
||||
std::shared_ptr<Library> library;
|
||||
NameMapperHandle nameMapper;
|
||||
const bool withAlias;
|
||||
};
|
||||
|
||||
@@ -23,10 +23,11 @@
|
||||
#include <time.h>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <pugixml.hpp>
|
||||
|
||||
#include "library.h"
|
||||
#include "server.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -40,8 +41,7 @@ namespace kiwix
|
||||
class OPDSDumper
|
||||
{
|
||||
public:
|
||||
OPDSDumper() = default;
|
||||
OPDSDumper(Library* library);
|
||||
OPDSDumper(Server::Configuration configuration);
|
||||
~OPDSDumper();
|
||||
|
||||
/**
|
||||
@@ -92,13 +92,6 @@ class OPDSDumper
|
||||
*/
|
||||
void setLibraryId(const std::string& id) { this->libraryId = id;}
|
||||
|
||||
/**
|
||||
* Set the root location used when generating url.
|
||||
*
|
||||
* @param rootLocation the root location to use.
|
||||
*/
|
||||
void setRootLocation(const std::string& rootLocation) { this->rootLocation = rootLocation; }
|
||||
|
||||
/**
|
||||
* Set some informations about the search results.
|
||||
*
|
||||
@@ -109,9 +102,8 @@ class OPDSDumper
|
||||
void setOpenSearchInfo(int totalResult, int startIndex, int count);
|
||||
|
||||
protected:
|
||||
kiwix::Library* library;
|
||||
Server::Configuration m_configuration;
|
||||
std::string libraryId;
|
||||
std::string rootLocation;
|
||||
int m_totalResults;
|
||||
int m_startIndex;
|
||||
int m_count;
|
||||
|
||||
@@ -46,7 +46,7 @@ class SearchRenderer
|
||||
* @param start The start offset used for the srs.
|
||||
* @param estimatedResultCount The estimatedResultCount of the whole search
|
||||
*/
|
||||
SearchRenderer(zim::SearchResultSet srs, NameMapper* mapper,
|
||||
SearchRenderer(zim::SearchResultSet srs, std::shared_ptr<NameMapper> mapper,
|
||||
unsigned int start, unsigned int estimatedResultCount);
|
||||
|
||||
/**
|
||||
@@ -58,7 +58,7 @@ class SearchRenderer
|
||||
* @param start The start offset used for the srs.
|
||||
* @param estimatedResultCount The estimatedResultCount of the whole search
|
||||
*/
|
||||
SearchRenderer(zim::SearchResultSet srs, NameMapper* mapper, Library* library,
|
||||
SearchRenderer(zim::SearchResultSet srs, std::shared_ptr<NameMapper> mapper, std::shared_ptr<Library> library,
|
||||
unsigned int start, unsigned int estimatedResultCount);
|
||||
|
||||
~SearchRenderer();
|
||||
@@ -106,8 +106,8 @@ class SearchRenderer
|
||||
protected:
|
||||
std::string beautifyInteger(const unsigned int number);
|
||||
zim::SearchResultSet m_srs;
|
||||
NameMapper* mp_nameMapper;
|
||||
Library* mp_library;
|
||||
std::shared_ptr<NameMapper> mp_nameMapper;
|
||||
std::shared_ptr<Library> mp_library;
|
||||
std::string searchBookQuery;
|
||||
std::string searchPattern;
|
||||
std::string protocolPrefix;
|
||||
|
||||
109
include/server.h
109
include/server.h
@@ -29,15 +29,81 @@ namespace kiwix
|
||||
class NameMapper;
|
||||
class InternalServer;
|
||||
|
||||
|
||||
class Server {
|
||||
public:
|
||||
public:
|
||||
class Configuration {
|
||||
public:
|
||||
explicit Configuration(std::shared_ptr<Library> library, std::shared_ptr<NameMapper> nameMapper=nullptr);
|
||||
|
||||
Configuration& setRoot(const std::string& root);
|
||||
Configuration& setAddress(const std::string& addr) {
|
||||
m_addr = addr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Configuration& setPort(int port) {
|
||||
m_port = port;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Configuration& setNbThreads(int threads) {
|
||||
m_nbThreads = threads;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Configuration& setMultiZimSearchLimit(unsigned int limit) {
|
||||
m_multizimSearchLimit = limit;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Configuration& setIpConnectionLimit(int limit) {
|
||||
m_ipConnectionLimit = limit;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Configuration& setVerbose(bool verbose) {
|
||||
m_verbose = verbose;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Configuration& setIndexTemplateString(const std::string& indexTemplateString) {
|
||||
m_indexTemplateString = indexTemplateString;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Configuration& setTaskbar(bool withTaskbar, bool withLibraryButton) {
|
||||
m_withTaskbar = withTaskbar;
|
||||
m_withLibraryButton = withLibraryButton;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Configuration& setBlockExternalLinks(bool blockExternalLinks) {
|
||||
m_blockExternalLinks = blockExternalLinks;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::shared_ptr<Library> mp_library;
|
||||
std::shared_ptr<NameMapper> mp_nameMapper;
|
||||
std::string m_root = "";
|
||||
std::string m_addr = "";
|
||||
std::string m_indexTemplateString = "";
|
||||
int m_port = 80;
|
||||
int m_nbThreads = 1;
|
||||
unsigned int m_multizimSearchLimit = 0;
|
||||
bool m_verbose = false;
|
||||
bool m_withTaskbar = true;
|
||||
bool m_withLibraryButton = true;
|
||||
bool m_blockExternalLinks = false;
|
||||
int m_ipConnectionLimit = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* The default constructor.
|
||||
*
|
||||
* @param library The library to serve.
|
||||
*/
|
||||
Server(Library* library, NameMapper* nameMapper=nullptr);
|
||||
|
||||
explicit Server(const Configuration& configuration);
|
||||
virtual ~Server();
|
||||
|
||||
/**
|
||||
@@ -50,35 +116,22 @@ namespace kiwix
|
||||
*/
|
||||
void stop();
|
||||
|
||||
void setRoot(const std::string& root);
|
||||
void setAddress(const std::string& addr) { m_addr = addr; }
|
||||
void setPort(int port) { m_port = port; }
|
||||
void setNbThreads(int threads) { m_nbThreads = threads; }
|
||||
void setMultiZimSearchLimit(unsigned int limit) { m_multizimSearchLimit = limit; }
|
||||
void setIpConnectionLimit(int limit) { m_ipConnectionLimit = limit; }
|
||||
void setVerbose(bool verbose) { m_verbose = verbose; }
|
||||
void setIndexTemplateString(const std::string& indexTemplateString) { m_indexTemplateString = indexTemplateString; }
|
||||
void setTaskbar(bool withTaskbar, bool withLibraryButton)
|
||||
{ m_withTaskbar = withTaskbar; m_withLibraryButton = withLibraryButton; }
|
||||
void setBlockExternalLinks(bool blockExternalLinks)
|
||||
{ m_blockExternalLinks = blockExternalLinks; }
|
||||
/**
|
||||
* Tell if the server is running or not.
|
||||
*/
|
||||
bool isRunning();
|
||||
|
||||
/**
|
||||
* Get the port of the server
|
||||
*/
|
||||
int getPort();
|
||||
|
||||
/**
|
||||
* Get the ipAddress of the server
|
||||
*/
|
||||
std::string getAddress();
|
||||
|
||||
protected:
|
||||
Library* mp_library;
|
||||
NameMapper* mp_nameMapper;
|
||||
std::string m_root = "";
|
||||
std::string m_addr = "";
|
||||
std::string m_indexTemplateString = "";
|
||||
int m_port = 80;
|
||||
int m_nbThreads = 1;
|
||||
unsigned int m_multizimSearchLimit = 0;
|
||||
bool m_verbose = false;
|
||||
bool m_withTaskbar = true;
|
||||
bool m_withLibraryButton = true;
|
||||
bool m_blockExternalLinks = false;
|
||||
int m_ipConnectionLimit = 0;
|
||||
std::unique_ptr<InternalServer> mp_server;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -41,8 +41,8 @@ struct NoDelete
|
||||
// LibraryManipulator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LibraryManipulator::LibraryManipulator(Library* library)
|
||||
: library(*library)
|
||||
LibraryManipulator::LibraryManipulator(std::shared_ptr<Library> library)
|
||||
: library(library)
|
||||
{}
|
||||
|
||||
LibraryManipulator::~LibraryManipulator()
|
||||
@@ -50,7 +50,7 @@ LibraryManipulator::~LibraryManipulator()
|
||||
|
||||
bool LibraryManipulator::addBookToLibrary(const Book& book)
|
||||
{
|
||||
const auto ret = library.addBook(book);
|
||||
const auto ret = library->addBook(book);
|
||||
if ( ret ) {
|
||||
bookWasAddedToLibrary(book);
|
||||
}
|
||||
@@ -59,13 +59,13 @@ bool LibraryManipulator::addBookToLibrary(const Book& book)
|
||||
|
||||
void LibraryManipulator::addBookmarkToLibrary(const Bookmark& bookmark)
|
||||
{
|
||||
library.addBookmark(bookmark);
|
||||
library->addBookmark(bookmark);
|
||||
bookmarkWasAddedToLibrary(bookmark);
|
||||
}
|
||||
|
||||
uint32_t LibraryManipulator::removeBooksNotUpdatedSince(Library::Revision rev)
|
||||
{
|
||||
const auto n = library.removeBooksNotUpdatedSince(rev);
|
||||
const auto n = library->removeBooksNotUpdatedSince(rev);
|
||||
if ( n != 0 ) {
|
||||
booksWereRemovedFromLibrary();
|
||||
}
|
||||
@@ -95,7 +95,7 @@ Manager::Manager(LibraryManipulator* manipulator):
|
||||
{
|
||||
}
|
||||
|
||||
Manager::Manager(Library* library) :
|
||||
Manager::Manager(std::shared_ptr<Library> library) :
|
||||
writableLibraryPath(""),
|
||||
manipulator(new LibraryManipulator(library))
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
namespace kiwix {
|
||||
|
||||
HumanReadableNameMapper::HumanReadableNameMapper(kiwix::Library& library, bool withAlias) {
|
||||
HumanReadableNameMapper::HumanReadableNameMapper(const kiwix::Library& library, bool withAlias) {
|
||||
for (auto& bookId: library.filter(kiwix::Filter().local(true).valid(true))) {
|
||||
auto& currentBook = library.getBookById(bookId);
|
||||
auto bookName = currentBook.getHumanReadableIdFromPath();
|
||||
@@ -63,7 +63,7 @@ std::string HumanReadableNameMapper::getIdForName(const std::string& name) const
|
||||
// UpdatableNameMapper
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UpdatableNameMapper::UpdatableNameMapper(Library& lib, bool withAlias)
|
||||
UpdatableNameMapper::UpdatableNameMapper(std::shared_ptr<Library> lib, bool withAlias)
|
||||
: library(lib)
|
||||
, withAlias(withAlias)
|
||||
{
|
||||
@@ -72,7 +72,7 @@ UpdatableNameMapper::UpdatableNameMapper(Library& lib, bool withAlias)
|
||||
|
||||
void UpdatableNameMapper::update()
|
||||
{
|
||||
const auto newNameMapper = new HumanReadableNameMapper(library, withAlias);
|
||||
const auto newNameMapper = new HumanReadableNameMapper(*library, withAlias);
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
nameMapper.reset(newNameMapper);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "opds_dumper.h"
|
||||
#include "book.h"
|
||||
#include "library.h"
|
||||
#include "name_mapper.h"
|
||||
|
||||
#include "libkiwix-resources.h"
|
||||
#include <mustache.hpp>
|
||||
@@ -30,8 +32,8 @@ namespace kiwix
|
||||
{
|
||||
|
||||
/* Constructor */
|
||||
OPDSDumper::OPDSDumper(Library* library)
|
||||
: library(library)
|
||||
OPDSDumper::OPDSDumper(Server::Configuration configuration)
|
||||
: m_configuration(configuration)
|
||||
{
|
||||
}
|
||||
/* Destructor */
|
||||
@@ -71,17 +73,17 @@ IllustrationInfo getBookIllustrationInfo(const Book& book)
|
||||
return illustrations;
|
||||
}
|
||||
|
||||
std::string fullEntryXML(const Book& book, const std::string& rootLocation)
|
||||
std::string fullEntryXML(const Server::Configuration& configuration, const Book& book)
|
||||
{
|
||||
const auto bookDate = book.getDate() + "T00:00:00Z";
|
||||
const kainjow::mustache::object data{
|
||||
{"root", rootLocation},
|
||||
{"root", configuration.m_root},
|
||||
{"id", book.getId()},
|
||||
{"name", book.getName()},
|
||||
{"title", book.getTitle()},
|
||||
{"description", book.getDescription()},
|
||||
{"language", book.getLanguage()},
|
||||
{"content_id", urlEncode(book.getHumanReadableIdFromPath(), true)},
|
||||
{"content_id", urlEncode(configuration.mp_nameMapper->getNameForId(book.getId()), true)},
|
||||
{"updated", bookDate}, // XXX: this should be the entry update datetime
|
||||
{"book_date", bookDate},
|
||||
{"category", book.getCategory()},
|
||||
@@ -98,12 +100,12 @@ std::string fullEntryXML(const Book& book, const std::string& rootLocation)
|
||||
return render_template(RESOURCE::templates::catalog_v2_entry_xml, data);
|
||||
}
|
||||
|
||||
std::string partialEntryXML(const Book& book, const std::string& rootLocation)
|
||||
std::string partialEntryXML(const Server::Configuration& configuration, const Book& book)
|
||||
{
|
||||
const auto bookDate = book.getDate() + "T00:00:00Z";
|
||||
const kainjow::mustache::object data{
|
||||
{"root", rootLocation},
|
||||
{"endpoint_root", rootLocation + "/catalog/v2"},
|
||||
{"root", configuration.m_root},
|
||||
{"endpoint_root", configuration.m_root + "/catalog/v2"},
|
||||
{"id", book.getId()},
|
||||
{"title", book.getTitle()},
|
||||
{"updated", bookDate}, // XXX: this should be the entry update datetime
|
||||
@@ -112,15 +114,15 @@ std::string partialEntryXML(const Book& book, const std::string& rootLocation)
|
||||
return render_template(xmlTemplate, data);
|
||||
}
|
||||
|
||||
BooksData getBooksData(const Library* library, const std::vector<std::string>& bookIds, const std::string& rootLocation, bool partial)
|
||||
BooksData getBooksData(const Server::Configuration& configuration, const std::vector<std::string>& bookIds, bool partial)
|
||||
{
|
||||
BooksData booksData;
|
||||
for ( const auto& bookId : bookIds ) {
|
||||
try {
|
||||
const Book book = library->getBookByIdThreadSafe(bookId);
|
||||
const Book book = configuration.mp_library->getBookByIdThreadSafe(bookId);
|
||||
const auto entryXML = partial
|
||||
? partialEntryXML(book, rootLocation)
|
||||
: fullEntryXML(book, rootLocation);
|
||||
? partialEntryXML(configuration, book)
|
||||
: fullEntryXML(configuration, book);
|
||||
booksData.push_back(kainjow::mustache::object{ {"entry", entryXML} });
|
||||
} catch ( const std::out_of_range& ) {
|
||||
// the book was removed from the library since its id was obtained
|
||||
@@ -188,10 +190,10 @@ std::string getLanguageSelfName(const std::string& lang) {
|
||||
|
||||
string OPDSDumper::dumpOPDSFeed(const std::vector<std::string>& bookIds, const std::string& query) const
|
||||
{
|
||||
const auto booksData = getBooksData(library, bookIds, rootLocation, false);
|
||||
const auto booksData = getBooksData(m_configuration, bookIds, false);
|
||||
const kainjow::mustache::object template_data{
|
||||
{"date", gen_date_str()},
|
||||
{"root", rootLocation},
|
||||
{"root", m_configuration.m_root},
|
||||
{"feed_id", gen_uuid(libraryId + "/catalog/search?"+query)},
|
||||
{"filter", onlyAsNonEmptyMustacheValue(query)},
|
||||
{"totalResults", to_string(m_totalResults)},
|
||||
@@ -205,8 +207,8 @@ string OPDSDumper::dumpOPDSFeed(const std::vector<std::string>& bookIds, const s
|
||||
|
||||
string OPDSDumper::dumpOPDSFeedV2(const std::vector<std::string>& bookIds, const std::string& query, bool partial) const
|
||||
{
|
||||
const auto endpointRoot = rootLocation + "/catalog/v2";
|
||||
const auto booksData = getBooksData(library, bookIds, rootLocation, partial);
|
||||
const auto endpointRoot = m_configuration.m_root + "/catalog/v2";
|
||||
const auto booksData = getBooksData(m_configuration, bookIds, partial);
|
||||
|
||||
const char* const endpoint = partial ? "/partial_entries" : "/entries";
|
||||
const kainjow::mustache::object template_data{
|
||||
@@ -227,17 +229,17 @@ string OPDSDumper::dumpOPDSFeedV2(const std::vector<std::string>& bookIds, const
|
||||
|
||||
std::string OPDSDumper::dumpOPDSCompleteEntry(const std::string& bookId) const
|
||||
{
|
||||
const auto book = library->getBookById(bookId);
|
||||
const auto book = m_configuration.mp_library->getBookById(bookId);
|
||||
return XML_HEADER
|
||||
+ "\n"
|
||||
+ fullEntryXML(book, rootLocation);
|
||||
+ fullEntryXML(m_configuration, book);
|
||||
}
|
||||
|
||||
std::string OPDSDumper::categoriesOPDSFeed() const
|
||||
{
|
||||
const auto now = gen_date_str();
|
||||
kainjow::mustache::list categoryData;
|
||||
for ( const auto& category : library->getBooksCategories() ) {
|
||||
for ( const auto& category : m_configuration.mp_library->getBooksCategories() ) {
|
||||
const auto urlencodedCategoryName = urlEncode(category);
|
||||
categoryData.push_back(kainjow::mustache::object{
|
||||
{"name", category},
|
||||
@@ -251,7 +253,7 @@ std::string OPDSDumper::categoriesOPDSFeed() const
|
||||
RESOURCE::templates::catalog_v2_categories_xml,
|
||||
kainjow::mustache::object{
|
||||
{"date", now},
|
||||
{"endpoint_root", rootLocation + "/catalog/v2"},
|
||||
{"endpoint_root", m_configuration.m_root + "/catalog/v2"},
|
||||
{"feed_id", gen_uuid(libraryId + "/categories")},
|
||||
{"categories", categoryData }
|
||||
}
|
||||
@@ -263,7 +265,7 @@ std::string OPDSDumper::languagesOPDSFeed() const
|
||||
const auto now = gen_date_str();
|
||||
kainjow::mustache::list languageData;
|
||||
std::call_once(fillLanguagesFlag, fillLanguagesMap);
|
||||
for ( const auto& langAndBookCount : library->getBooksLanguagesWithCounts() ) {
|
||||
for ( const auto& langAndBookCount : m_configuration.mp_library->getBooksLanguagesWithCounts() ) {
|
||||
const std::string languageCode = langAndBookCount.first;
|
||||
const int bookCount = langAndBookCount.second;
|
||||
const auto languageSelfName = getLanguageSelfName(languageCode);
|
||||
@@ -280,7 +282,7 @@ std::string OPDSDumper::languagesOPDSFeed() const
|
||||
RESOURCE::templates::catalog_v2_languages_xml,
|
||||
kainjow::mustache::object{
|
||||
{"date", now},
|
||||
{"endpoint_root", rootLocation + "/catalog/v2"},
|
||||
{"endpoint_root", m_configuration.m_root + "/catalog/v2"},
|
||||
{"feed_id", gen_uuid(libraryId + "/languages")},
|
||||
{"languages", languageData }
|
||||
}
|
||||
|
||||
@@ -36,12 +36,12 @@ namespace kiwix
|
||||
{
|
||||
|
||||
/* Constructor */
|
||||
SearchRenderer::SearchRenderer(zim::SearchResultSet srs, NameMapper* mapper,
|
||||
SearchRenderer::SearchRenderer(zim::SearchResultSet srs, std::shared_ptr<NameMapper> mapper,
|
||||
unsigned int start, unsigned int estimatedResultCount)
|
||||
: SearchRenderer(srs, mapper, nullptr, start, estimatedResultCount)
|
||||
{}
|
||||
|
||||
SearchRenderer::SearchRenderer(zim::SearchResultSet srs, NameMapper* mapper, Library* library,
|
||||
SearchRenderer::SearchRenderer(zim::SearchResultSet srs, std::shared_ptr<NameMapper> mapper, std::shared_ptr<Library> library,
|
||||
unsigned int start, unsigned int estimatedResultCount)
|
||||
: m_srs(srs),
|
||||
mp_nameMapper(mapper),
|
||||
|
||||
@@ -26,52 +26,38 @@
|
||||
|
||||
#include <zim/item.h>
|
||||
#include "server/internalServer.h"
|
||||
#include "tools/otherTools.h"
|
||||
|
||||
namespace kiwix {
|
||||
|
||||
Server::Server(Library* library, NameMapper* nameMapper) :
|
||||
Server::Configuration::Configuration(std::shared_ptr<Library> library, std::shared_ptr<NameMapper> nameMapper) :
|
||||
mp_library(library),
|
||||
mp_nameMapper(nameMapper),
|
||||
mp_server(nullptr)
|
||||
mp_nameMapper(nameMapper ? nameMapper : std::make_shared<HumanReadableNameMapper>(*library, true))
|
||||
{}
|
||||
|
||||
Server::Configuration& Server::Configuration::setRoot(const std::string& root)
|
||||
{
|
||||
m_root = normalizeRootUrl(root);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Server::Server(const Server::Configuration& configuration) :
|
||||
mp_server(new InternalServer(configuration))
|
||||
{
|
||||
}
|
||||
|
||||
Server::~Server() = default;
|
||||
|
||||
bool Server::start() {
|
||||
mp_server.reset(new InternalServer(
|
||||
mp_library,
|
||||
mp_nameMapper,
|
||||
m_addr,
|
||||
m_port,
|
||||
m_root,
|
||||
m_nbThreads,
|
||||
m_multizimSearchLimit,
|
||||
m_verbose,
|
||||
m_withTaskbar,
|
||||
m_withLibraryButton,
|
||||
m_blockExternalLinks,
|
||||
m_indexTemplateString,
|
||||
m_ipConnectionLimit));
|
||||
return mp_server->start();
|
||||
}
|
||||
|
||||
void Server::stop() {
|
||||
if (mp_server) {
|
||||
mp_server->stop();
|
||||
mp_server.reset(nullptr);
|
||||
}
|
||||
mp_server->stop();
|
||||
}
|
||||
|
||||
void Server::setRoot(const std::string& root)
|
||||
{
|
||||
m_root = root;
|
||||
if (m_root[0] != '/') {
|
||||
m_root = "/" + m_root;
|
||||
}
|
||||
if (m_root.back() == '/') {
|
||||
m_root.erase(m_root.size() - 1);
|
||||
}
|
||||
bool Server::isRunning() {
|
||||
return mp_server->isRunning();
|
||||
}
|
||||
|
||||
int Server::getPort()
|
||||
|
||||
@@ -85,16 +85,6 @@ namespace kiwix {
|
||||
namespace
|
||||
{
|
||||
|
||||
inline std::string normalizeRootUrl(std::string rootUrl)
|
||||
{
|
||||
while ( !rootUrl.empty() && rootUrl.back() == '/' )
|
||||
rootUrl.pop_back();
|
||||
|
||||
while ( !rootUrl.empty() && rootUrl.front() == '/' )
|
||||
rootUrl = rootUrl.substr(1);
|
||||
return rootUrl.empty() ? rootUrl : "/" + rootUrl;
|
||||
}
|
||||
|
||||
Filter get_search_filter(const RequestContext& request, const std::string& prefix="")
|
||||
{
|
||||
auto filter = kiwix::Filter().valid(true).local(true);
|
||||
@@ -333,8 +323,6 @@ zim::Query SearchInfo::getZimQuery(bool verbose) const {
|
||||
return query;
|
||||
}
|
||||
|
||||
static IdNameMapper defaultNameMapper;
|
||||
|
||||
static MHD_Result staticHandlerCallback(void* cls,
|
||||
struct MHD_Connection* connection,
|
||||
const char* url,
|
||||
@@ -366,33 +354,10 @@ public:
|
||||
};
|
||||
|
||||
|
||||
InternalServer::InternalServer(Library* library,
|
||||
NameMapper* nameMapper,
|
||||
std::string addr,
|
||||
int port,
|
||||
std::string root,
|
||||
int nbThreads,
|
||||
unsigned int multizimSearchLimit,
|
||||
bool verbose,
|
||||
bool withTaskbar,
|
||||
bool withLibraryButton,
|
||||
bool blockExternalLinks,
|
||||
std::string indexTemplateString,
|
||||
int ipConnectionLimit) :
|
||||
m_addr(addr),
|
||||
m_port(port),
|
||||
m_root(normalizeRootUrl(root)),
|
||||
m_nbThreads(nbThreads),
|
||||
m_multizimSearchLimit(multizimSearchLimit),
|
||||
m_verbose(verbose),
|
||||
m_withTaskbar(withTaskbar),
|
||||
m_withLibraryButton(withLibraryButton),
|
||||
m_blockExternalLinks(blockExternalLinks),
|
||||
m_indexTemplateString(indexTemplateString.empty() ? RESOURCE::templates::index_html : indexTemplateString),
|
||||
m_ipConnectionLimit(ipConnectionLimit),
|
||||
InternalServer::InternalServer(const Server::Configuration& configuration) :
|
||||
Server::Configuration(configuration),
|
||||
m_indexTemplateString(configuration.m_indexTemplateString.empty() ? RESOURCE::templates::index_html : configuration.m_indexTemplateString),
|
||||
mp_daemon(nullptr),
|
||||
mp_library(library),
|
||||
mp_nameMapper(nameMapper ? nameMapper : &defaultNameMapper),
|
||||
searchCache(getEnvVar<int>("KIWIX_SEARCH_CACHE_SIZE", DEFAULT_CACHE_SIZE)),
|
||||
suggestionSearcherCache(getEnvVar<int>("KIWIX_SUGGESTION_SEARCHER_CACHE_SIZE", std::max((unsigned int) (mp_library->getBookCount(true, true)*0.1), 1U))),
|
||||
m_customizedResources(new CustomizedResources)
|
||||
@@ -406,7 +371,7 @@ bool InternalServer::start() {
|
||||
#else
|
||||
int flags = MHD_USE_POLL_INTERNALLY;
|
||||
#endif
|
||||
if (m_verbose.load())
|
||||
if (m_verbose)
|
||||
flags |= MHD_USE_DEBUG;
|
||||
|
||||
struct sockaddr_in sockAddr;
|
||||
@@ -450,8 +415,13 @@ bool InternalServer::start() {
|
||||
void InternalServer::stop()
|
||||
{
|
||||
MHD_stop_daemon(mp_daemon);
|
||||
mp_daemon = nullptr;
|
||||
}
|
||||
|
||||
bool InternalServer::isRunning() const
|
||||
{
|
||||
return mp_daemon != nullptr;
|
||||
}
|
||||
static MHD_Result staticHandlerCallback(void* cls,
|
||||
struct MHD_Connection* connection,
|
||||
const char* url,
|
||||
@@ -481,14 +451,14 @@ MHD_Result InternalServer::handlerCallback(struct MHD_Connection* connection,
|
||||
void** cont_cls)
|
||||
{
|
||||
auto start_time = std::chrono::steady_clock::now();
|
||||
if (m_verbose.load() ) {
|
||||
if (m_verbose) {
|
||||
printf("======================\n");
|
||||
printf("Requesting : \n");
|
||||
printf("full_url : %s\n", url);
|
||||
}
|
||||
RequestContext request(connection, m_root, url, method, version);
|
||||
|
||||
if (m_verbose.load() ) {
|
||||
if (m_verbose) {
|
||||
request.print_debug_info();
|
||||
}
|
||||
/* Unexpected method */
|
||||
@@ -504,7 +474,7 @@ MHD_Result InternalServer::handlerCallback(struct MHD_Connection* connection,
|
||||
|
||||
if (response->getReturnCode() == MHD_HTTP_INTERNAL_SERVER_ERROR) {
|
||||
printf("========== INTERNAL ERROR !! ============\n");
|
||||
if (!m_verbose.load()) {
|
||||
if (!m_verbose) {
|
||||
printf("Requesting : \n");
|
||||
printf("full_url : %s\n", url);
|
||||
request.print_debug_info();
|
||||
@@ -517,7 +487,7 @@ MHD_Result InternalServer::handlerCallback(struct MHD_Connection* connection,
|
||||
auto ret = response->send(request, connection);
|
||||
auto end_time = std::chrono::steady_clock::now();
|
||||
auto time_span = std::chrono::duration_cast<std::chrono::duration<double>>(end_time - start_time);
|
||||
if (m_verbose.load()) {
|
||||
if (m_verbose) {
|
||||
printf("Request time : %fs\n", time_span.count());
|
||||
printf("----------------------\n");
|
||||
}
|
||||
@@ -650,7 +620,7 @@ class InternalServer::LockableSuggestionSearcher : public zim::SuggestionSearche
|
||||
|
||||
std::unique_ptr<Response> InternalServer::handle_suggest(const RequestContext& request)
|
||||
{
|
||||
if (m_verbose.load()) {
|
||||
if (m_verbose) {
|
||||
printf("** running handle_suggest\n");
|
||||
}
|
||||
|
||||
@@ -681,7 +651,7 @@ std::unique_ptr<Response> InternalServer::handle_suggest(const RequestContext& r
|
||||
count = 10;
|
||||
}
|
||||
|
||||
if (m_verbose.load()) {
|
||||
if (m_verbose) {
|
||||
printf("Searching suggestions for: \"%s\"\n", queryString.c_str());
|
||||
}
|
||||
|
||||
@@ -734,7 +704,7 @@ std::unique_ptr<Response> InternalServer::handle_suggest(const RequestContext& r
|
||||
|
||||
std::unique_ptr<Response> InternalServer::handle_viewer_settings(const RequestContext& request)
|
||||
{
|
||||
if (m_verbose.load()) {
|
||||
if (m_verbose) {
|
||||
printf("** running handle_viewer_settings\n");
|
||||
}
|
||||
|
||||
@@ -748,7 +718,7 @@ std::unique_ptr<Response> InternalServer::handle_viewer_settings(const RequestCo
|
||||
|
||||
std::unique_ptr<Response> InternalServer::handle_skin(const RequestContext& request)
|
||||
{
|
||||
if (m_verbose.load()) {
|
||||
if (m_verbose) {
|
||||
printf("** running handle_skin\n");
|
||||
}
|
||||
|
||||
@@ -771,7 +741,7 @@ std::unique_ptr<Response> InternalServer::handle_skin(const RequestContext& requ
|
||||
|
||||
std::unique_ptr<Response> InternalServer::handle_search(const RequestContext& request)
|
||||
{
|
||||
if (m_verbose.load()) {
|
||||
if (m_verbose) {
|
||||
printf("** running handle_search\n");
|
||||
}
|
||||
|
||||
@@ -800,7 +770,7 @@ std::unique_ptr<Response> InternalServer::handle_search(const RequestContext& re
|
||||
try {
|
||||
search = searchCache.getOrPut(searchInfo,
|
||||
[=](){
|
||||
return make_shared<zim::Search>(searcher->search(searchInfo.getZimQuery(m_verbose.load())));
|
||||
return make_shared<zim::Search>(searcher->search(searchInfo.getZimQuery(m_verbose)));
|
||||
}
|
||||
);
|
||||
} catch(std::runtime_error& e) {
|
||||
@@ -872,7 +842,7 @@ std::unique_ptr<Response> InternalServer::handle_search(const RequestContext& re
|
||||
|
||||
std::unique_ptr<Response> InternalServer::handle_random(const RequestContext& request)
|
||||
{
|
||||
if (m_verbose.load()) {
|
||||
if (m_verbose) {
|
||||
printf("** running handle_random\n");
|
||||
}
|
||||
|
||||
@@ -924,7 +894,7 @@ std::unique_ptr<Response> InternalServer::handle_captured_external(const Request
|
||||
|
||||
std::unique_ptr<Response> InternalServer::handle_catch(const RequestContext& request)
|
||||
{
|
||||
if (m_verbose.load()) {
|
||||
if (m_verbose) {
|
||||
printf("** running handle_catch\n");
|
||||
}
|
||||
|
||||
@@ -938,7 +908,7 @@ std::unique_ptr<Response> InternalServer::handle_catch(const RequestContext& req
|
||||
|
||||
std::unique_ptr<Response> InternalServer::handle_catalog(const RequestContext& request)
|
||||
{
|
||||
if (m_verbose.load()) {
|
||||
if (m_verbose) {
|
||||
printf("** running handle_catalog");
|
||||
}
|
||||
|
||||
@@ -967,8 +937,7 @@ std::unique_ptr<Response> InternalServer::handle_catalog(const RequestContext& r
|
||||
}
|
||||
|
||||
zim::Uuid uuid;
|
||||
kiwix::OPDSDumper opdsDumper(mp_library);
|
||||
opdsDumper.setRootLocation(m_root);
|
||||
kiwix::OPDSDumper opdsDumper(*this);
|
||||
opdsDumper.setLibraryId(m_library_id);
|
||||
std::vector<std::string> bookIdsToDump;
|
||||
if (url == "root.xml") {
|
||||
@@ -1030,7 +999,7 @@ std::unique_ptr<Response> InternalServer::handle_content(const RequestContext& r
|
||||
{
|
||||
const std::string url = request.get_url();
|
||||
const std::string pattern = url.substr((url.find_last_of('/'))+1);
|
||||
if (m_verbose.load()) {
|
||||
if (m_verbose) {
|
||||
printf("** running handle_content\n");
|
||||
}
|
||||
|
||||
@@ -1071,14 +1040,14 @@ std::unique_ptr<Response> InternalServer::handle_content(const RequestContext& r
|
||||
}
|
||||
auto response = ItemResponse::build(*this, request, entry.getItem());
|
||||
|
||||
if (m_verbose.load()) {
|
||||
if (m_verbose) {
|
||||
printf("Found %s\n", entry.getPath().c_str());
|
||||
printf("mimeType: %s\n", entry.getItem(true).getMimetype().c_str());
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch(zim::EntryNotFound& e) {
|
||||
if (m_verbose.load())
|
||||
if (m_verbose)
|
||||
printf("Failed to find %s\n", urlStr.c_str());
|
||||
|
||||
std::string searchURL = m_root + "/search?content=" + bookName + "&pattern=" + kiwix::urlEncode(pattern, true);
|
||||
@@ -1091,7 +1060,7 @@ std::unique_ptr<Response> InternalServer::handle_content(const RequestContext& r
|
||||
|
||||
std::unique_ptr<Response> InternalServer::handle_raw(const RequestContext& request)
|
||||
{
|
||||
if (m_verbose.load()) {
|
||||
if (m_verbose) {
|
||||
printf("** running handle_raw\n");
|
||||
}
|
||||
|
||||
@@ -1141,7 +1110,7 @@ std::unique_ptr<Response> InternalServer::handle_raw(const RequestContext& reque
|
||||
return ItemResponse::build(*this, request, entry.getItem());
|
||||
}
|
||||
} catch (zim::EntryNotFound& e ) {
|
||||
if (m_verbose.load()) {
|
||||
if (m_verbose) {
|
||||
printf("Failed to find %s\n", itemPath.c_str());
|
||||
}
|
||||
return HTTP404Response(*this, request)
|
||||
@@ -1157,13 +1126,13 @@ bool InternalServer::isLocallyCustomizedResource(const std::string& url) const
|
||||
|
||||
std::unique_ptr<Response> InternalServer::handle_locally_customized_resource(const RequestContext& request)
|
||||
{
|
||||
if (m_verbose.load()) {
|
||||
if (m_verbose) {
|
||||
printf("** running handle_locally_customized_resource\n");
|
||||
}
|
||||
|
||||
const CustomizedResourceData& crd = m_customizedResources->at(request.get_url());
|
||||
|
||||
if (m_verbose.load()) {
|
||||
if (m_verbose) {
|
||||
std::cout << "Reading " << crd.resourceFilePath << std::endl;
|
||||
}
|
||||
const auto resourceData = getFileContent(crd.resourceFilePath);
|
||||
|
||||
@@ -26,7 +26,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
#include "library.h"
|
||||
#include "name_mapper.h"
|
||||
#include "server.h"
|
||||
|
||||
#include <zim/search.h>
|
||||
#include <zim/suggestion.h>
|
||||
@@ -90,21 +90,9 @@ class SearchInfo {
|
||||
typedef kainjow::mustache::data MustacheData;
|
||||
class OPDSDumper;
|
||||
|
||||
class InternalServer {
|
||||
class InternalServer : Server::Configuration {
|
||||
public:
|
||||
InternalServer(Library* library,
|
||||
NameMapper* nameMapper,
|
||||
std::string addr,
|
||||
int port,
|
||||
std::string root,
|
||||
int nbThreads,
|
||||
unsigned int multizimSearchLimit,
|
||||
bool verbose,
|
||||
bool withTaskbar,
|
||||
bool withLibraryButton,
|
||||
bool blockExternalLinks,
|
||||
std::string indexTemplateString,
|
||||
int ipConnectionLimit);
|
||||
InternalServer(const Server::Configuration& configuration);
|
||||
virtual ~InternalServer();
|
||||
|
||||
MHD_Result handlerCallback(struct MHD_Connection* connection,
|
||||
@@ -116,6 +104,7 @@ class InternalServer {
|
||||
void** cont_cls);
|
||||
bool start();
|
||||
void stop();
|
||||
bool isRunning() const;
|
||||
std::string getAddress() { return m_addr; }
|
||||
int getPort() { return m_port; }
|
||||
|
||||
@@ -161,21 +150,9 @@ class InternalServer {
|
||||
|
||||
private: // data
|
||||
std::string m_addr;
|
||||
int m_port;
|
||||
std::string m_root;
|
||||
int m_nbThreads;
|
||||
unsigned int m_multizimSearchLimit;
|
||||
std::atomic_bool m_verbose;
|
||||
bool m_withTaskbar;
|
||||
bool m_withLibraryButton;
|
||||
bool m_blockExternalLinks;
|
||||
std::string m_indexTemplateString;
|
||||
int m_ipConnectionLimit;
|
||||
struct MHD_Daemon* mp_daemon;
|
||||
|
||||
Library* mp_library;
|
||||
NameMapper* mp_nameMapper;
|
||||
|
||||
SearchCache searchCache;
|
||||
SuggestionSearcherCache suggestionSearcherCache;
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace kiwix {
|
||||
|
||||
std::unique_ptr<Response> InternalServer::handle_catalog_v2(const RequestContext& request)
|
||||
{
|
||||
if (m_verbose.load()) {
|
||||
if (m_verbose) {
|
||||
printf("** running handle_catalog_v2");
|
||||
}
|
||||
|
||||
@@ -95,8 +95,7 @@ std::unique_ptr<Response> InternalServer::handle_catalog_v2_root(const RequestCo
|
||||
|
||||
std::unique_ptr<Response> InternalServer::handle_catalog_v2_entries(const RequestContext& request, bool partial)
|
||||
{
|
||||
OPDSDumper opdsDumper(mp_library);
|
||||
opdsDumper.setRootLocation(m_root);
|
||||
OPDSDumper opdsDumper(*this);
|
||||
opdsDumper.setLibraryId(m_library_id);
|
||||
const auto bookIds = search_catalog(request, opdsDumper);
|
||||
const auto opdsFeed = opdsDumper.dumpOPDSFeedV2(bookIds, request.get_query(), partial);
|
||||
@@ -116,8 +115,7 @@ std::unique_ptr<Response> InternalServer::handle_catalog_v2_complete_entry(const
|
||||
+ urlNotFoundMsg;
|
||||
}
|
||||
|
||||
OPDSDumper opdsDumper(mp_library);
|
||||
opdsDumper.setRootLocation(m_root);
|
||||
OPDSDumper opdsDumper(*this);
|
||||
opdsDumper.setLibraryId(m_library_id);
|
||||
const auto opdsFeed = opdsDumper.dumpOPDSCompleteEntry(entryId);
|
||||
return ContentResponse::build(
|
||||
@@ -129,8 +127,7 @@ std::unique_ptr<Response> InternalServer::handle_catalog_v2_complete_entry(const
|
||||
|
||||
std::unique_ptr<Response> InternalServer::handle_catalog_v2_categories(const RequestContext& request)
|
||||
{
|
||||
OPDSDumper opdsDumper(mp_library);
|
||||
opdsDumper.setRootLocation(m_root);
|
||||
OPDSDumper opdsDumper(*this);
|
||||
opdsDumper.setLibraryId(m_library_id);
|
||||
return ContentResponse::build(
|
||||
*this,
|
||||
@@ -141,8 +138,7 @@ std::unique_ptr<Response> InternalServer::handle_catalog_v2_categories(const Req
|
||||
|
||||
std::unique_ptr<Response> InternalServer::handle_catalog_v2_languages(const RequestContext& request)
|
||||
{
|
||||
OPDSDumper opdsDumper(mp_library);
|
||||
opdsDumper.setRootLocation(m_root);
|
||||
OPDSDumper opdsDumper(*this);
|
||||
opdsDumper.setLibraryId(m_library_id);
|
||||
return ContentResponse::build(
|
||||
*this,
|
||||
|
||||
@@ -114,7 +114,7 @@ Response::Response(bool verbose)
|
||||
|
||||
std::unique_ptr<Response> Response::build(const InternalServer& server)
|
||||
{
|
||||
return std::unique_ptr<Response>(new Response(server.m_verbose.load()));
|
||||
return std::unique_ptr<Response>(new Response(server.m_verbose));
|
||||
}
|
||||
|
||||
std::unique_ptr<Response> Response::build_304(const InternalServer& server, const ETag& etag)
|
||||
@@ -390,7 +390,7 @@ std::unique_ptr<ContentResponse> ContentResponse::build(
|
||||
{
|
||||
return std::unique_ptr<ContentResponse>(new ContentResponse(
|
||||
server.m_root,
|
||||
server.m_verbose.load(),
|
||||
server.m_verbose,
|
||||
content,
|
||||
mimetype));
|
||||
}
|
||||
@@ -435,7 +435,7 @@ std::unique_ptr<Response> ItemResponse::build(const InternalServer& server, cons
|
||||
}
|
||||
|
||||
return std::unique_ptr<Response>(new ItemResponse(
|
||||
server.m_verbose.load(),
|
||||
server.m_verbose,
|
||||
item,
|
||||
mimetype,
|
||||
byteRange));
|
||||
|
||||
@@ -370,6 +370,16 @@ std::string kiwix::gen_uuid(const std::string& s)
|
||||
return kiwix::to_string(zim::Uuid::generate(s));
|
||||
}
|
||||
|
||||
std::string kiwix::normalizeRootUrl(std::string rootUrl)
|
||||
{
|
||||
while ( !rootUrl.empty() && rootUrl.back() == '/' )
|
||||
rootUrl.pop_back();
|
||||
|
||||
while ( !rootUrl.empty() && rootUrl.front() == '/' )
|
||||
rootUrl = rootUrl.substr(1);
|
||||
return rootUrl.empty() ? rootUrl : "/" + rootUrl;
|
||||
}
|
||||
|
||||
kainjow::mustache::data kiwix::onlyAsNonEmptyMustacheValue(const std::string& s)
|
||||
{
|
||||
return s.empty()
|
||||
|
||||
@@ -51,6 +51,8 @@ namespace kiwix
|
||||
std::string gen_date_str();
|
||||
std::string gen_uuid(const std::string& s);
|
||||
|
||||
std::string normalizeRootUrl(std::string rootUrl);
|
||||
|
||||
// if s is empty then returns kainjow::mustache::data(false)
|
||||
// otherwise kainjow::mustache::data(value)
|
||||
kainjow::mustache::data onlyAsNonEmptyMustacheValue(const std::string& s);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include <string>
|
||||
|
||||
#include "testing_tools.h"
|
||||
|
||||
const char * sampleOpdsStream = R"(
|
||||
<feed xmlns="http://www.w3.org/2005/Atom"
|
||||
@@ -237,7 +238,7 @@ namespace
|
||||
TEST(LibraryOpdsImportTest, allInOne)
|
||||
{
|
||||
kiwix::Library lib;
|
||||
kiwix::Manager manager(&lib);
|
||||
kiwix::Manager manager{NotOwned<kiwix::Library>(lib)};
|
||||
manager.readOpds(sampleOpdsStream, "library-opds-import.unittests.dev");
|
||||
|
||||
EXPECT_EQ(10U, lib.getBookCount(true, true));
|
||||
@@ -297,8 +298,11 @@ class LibraryTest : public ::testing::Test {
|
||||
typedef kiwix::Library::BookIdCollection BookIdCollection;
|
||||
typedef std::vector<std::string> TitleCollection;
|
||||
|
||||
explicit LibraryTest()
|
||||
{}
|
||||
|
||||
void SetUp() override {
|
||||
kiwix::Manager manager(&lib);
|
||||
kiwix::Manager manager{NotOwned<kiwix::Library>(lib)};
|
||||
manager.readOpds(sampleOpdsStream, "foo.urlHost");
|
||||
manager.readXml(sampleLibraryXML, false, "./test/library.xml", true);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,13 @@ protected:
|
||||
const int PORT = 8002;
|
||||
|
||||
protected:
|
||||
void resetServer(ZimFileServer::Options options) {
|
||||
zfs1_.reset();
|
||||
zfs1_.reset(new ZimFileServer(PORT, options, "./test/library.xml"));
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
zfs1_.reset(new ZimFileServer(PORT, "./test/library.xml"));
|
||||
zfs1_.reset(new ZimFileServer(PORT, ZimFileServer::DEFAULT_OPTIONS, "./test/library.xml"));
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
@@ -70,20 +75,20 @@ std::string maskVariableOPDSFeedData(std::string s)
|
||||
" type=\"application/opensearchdescription+xml\"" \
|
||||
" href=\"/ROOT/catalog/searchdescription.xml\" />\n"
|
||||
|
||||
#define CHARLES_RAY_CATALOG_ENTRY \
|
||||
#define CATALOG_ENTRY(UUID, TITLE, SUMMARY, LANG, NAME, CATEGORY, TAGS, EXTRA_LINK, CONTENT_NAME, FILE_NAME, LENGTH) \
|
||||
" <entry>\n" \
|
||||
" <id>urn:uuid:charlesray</id>\n" \
|
||||
" <title>Charles, Ray</title>\n" \
|
||||
" <id>urn:uuid:" UUID "</id>\n" \
|
||||
" <title>" TITLE "</title>\n" \
|
||||
" <updated>YYYY-MM-DDThh:mm:ssZ</updated>\n" \
|
||||
" <summary>Wikipedia articles about Ray Charles</summary>\n" \
|
||||
" <language>fra</language>\n" \
|
||||
" <name>wikipedia_fr_ray_charles</name>\n" \
|
||||
" <summary>" SUMMARY "</summary>\n" \
|
||||
" <language>" LANG "</language>\n" \
|
||||
" <name>" NAME "</name>\n" \
|
||||
" <flavour></flavour>\n" \
|
||||
" <category>jazz</category>\n" \
|
||||
" <tags>unittest;wikipedia;_category:jazz;_pictures:no;_videos:no;_details:no;_ftindex:yes</tags>\n" \
|
||||
" <category>" CATEGORY "</category>\n" \
|
||||
" <tags>" TAGS "</tags>\n" \
|
||||
" <articleCount>284</articleCount>\n" \
|
||||
" <mediaCount>2</mediaCount>\n" \
|
||||
" <link type=\"text/html\" href=\"/ROOT/content/zimfile%26other\" />\n" \
|
||||
" " EXTRA_LINK "<link type=\"text/html\" href=\"/ROOT/content/" CONTENT_NAME "\" />\n" \
|
||||
" <author>\n" \
|
||||
" <name>Wikipedia</name>\n" \
|
||||
" </author>\n" \
|
||||
@@ -91,59 +96,57 @@ std::string maskVariableOPDSFeedData(std::string s)
|
||||
" <name>Kiwix</name>\n" \
|
||||
" </publisher>\n" \
|
||||
" <dc:issued>2020-03-31T00:00:00Z</dc:issued>\n" \
|
||||
" <link rel=\"http://opds-spec.org/acquisition/open-access\" type=\"application/x-zim\" href=\"https://github.com/kiwix/libkiwix/raw/master/test/data/zimfile%26other.zim\" length=\"569344\" />\n" \
|
||||
" <link rel=\"http://opds-spec.org/acquisition/open-access\" type=\"application/x-zim\" href=\"https://github.com/kiwix/libkiwix/raw/master/test/data/" FILE_NAME ".zim\" length=\"" LENGTH "\" />\n" \
|
||||
" </entry>\n"
|
||||
|
||||
#define RAY_CHARLES_CATALOG_ENTRY \
|
||||
" <entry>\n" \
|
||||
" <id>urn:uuid:raycharles</id>\n" \
|
||||
" <title>Ray Charles</title>\n" \
|
||||
" <updated>YYYY-MM-DDThh:mm:ssZ</updated>\n" \
|
||||
" <summary>Wikipedia articles about Ray Charles</summary>\n" \
|
||||
" <language>eng</language>\n" \
|
||||
" <name>wikipedia_en_ray_charles</name>\n" \
|
||||
" <flavour></flavour>\n" \
|
||||
" <category>wikipedia</category>\n" \
|
||||
" <tags>public_tag_without_a_value;_private_tag_without_a_value;wikipedia;_category:wikipedia;_pictures:no;_videos:no;_details:no;_ftindex:yes</tags>\n" \
|
||||
" <articleCount>284</articleCount>\n" \
|
||||
" <mediaCount>2</mediaCount>\n" \
|
||||
" <link rel=\"http://opds-spec.org/image/thumbnail\"\n" \
|
||||
" href=\"/ROOT/catalog/v2/illustration/raycharles/?size=48\"\n" \
|
||||
" type=\"image/png;width=48;height=48;scale=1\"/>\n" \
|
||||
" <link type=\"text/html\" href=\"/ROOT/content/zimfile\" />\n" \
|
||||
" <author>\n" \
|
||||
" <name>Wikipedia</name>\n" \
|
||||
" </author>\n" \
|
||||
" <publisher>\n" \
|
||||
" <name>Kiwix</name>\n" \
|
||||
" </publisher>\n" \
|
||||
" <dc:issued>2020-03-31T00:00:00Z</dc:issued>\n" \
|
||||
" <link rel=\"http://opds-spec.org/acquisition/open-access\" type=\"application/x-zim\" href=\"https://github.com/kiwix/libkiwix/raw/master/test/data/zimfile.zim\" length=\"569344\" />\n" \
|
||||
" </entry>\n"
|
||||
|
||||
#define UNCATEGORIZED_RAY_CHARLES_CATALOG_ENTRY \
|
||||
" <entry>\n" \
|
||||
" <id>urn:uuid:raycharles_uncategorized</id>\n" \
|
||||
" <title>Ray (uncategorized) Charles</title>\n" \
|
||||
" <updated>YYYY-MM-DDThh:mm:ssZ</updated>\n" \
|
||||
" <summary>No category is assigned to this library entry.</summary>\n" \
|
||||
" <language>rus</language>\n" \
|
||||
" <name>wikipedia_ru_ray_charles</name>\n" \
|
||||
" <flavour></flavour>\n" \
|
||||
" <category></category>\n" \
|
||||
" <tags>public_tag_with_a_value:value_of_a_public_tag;_private_tag_with_a_value:value_of_a_private_tag;wikipedia;_pictures:no;_videos:no;_details:no</tags>\n" \
|
||||
" <articleCount>284</articleCount>\n" \
|
||||
" <mediaCount>2</mediaCount>\n" \
|
||||
" <link type=\"text/html\" href=\"/ROOT/content/zimfile\" />\n" \
|
||||
" <author>\n" \
|
||||
" <name>Wikipedia</name>\n" \
|
||||
" </author>\n" \
|
||||
" <publisher>\n" \
|
||||
" <name>Kiwix</name>\n" \
|
||||
" </publisher>\n" \
|
||||
" <dc:issued>2020-03-31T00:00:00Z</dc:issued>\n" \
|
||||
" <link rel=\"http://opds-spec.org/acquisition/open-access\" type=\"application/x-zim\" href=\"https://github.com/kiwix/libkiwix/raw/master/test/data/zimfile.zim\" length=\"125952\" />\n" \
|
||||
" </entry>\n"
|
||||
#define _CHARLES_RAY_CATALOG_ENTRY(CONTENT_NAME) CATALOG_ENTRY( \
|
||||
"charlesray", \
|
||||
"Charles, Ray", \
|
||||
"Wikipedia articles about Ray Charles", \
|
||||
"fra", \
|
||||
"wikipedia_fr_ray_charles",\
|
||||
"jazz",\
|
||||
"unittest;wikipedia;_category:jazz;_pictures:no;_videos:no;_details:no;_ftindex:yes",\
|
||||
"", \
|
||||
CONTENT_NAME, \
|
||||
"zimfile%26other", \
|
||||
"569344" \
|
||||
)
|
||||
|
||||
#define CHARLES_RAY_CATALOG_ENTRY _CHARLES_RAY_CATALOG_ENTRY("zimfile%26other")
|
||||
|
||||
#define _RAY_CHARLES_CATALOG_ENTRY(CONTENT_NAME) CATALOG_ENTRY(\
|
||||
"raycharles",\
|
||||
"Ray Charles",\
|
||||
"Wikipedia articles about Ray Charles",\
|
||||
"eng",\
|
||||
"wikipedia_en_ray_charles",\
|
||||
"wikipedia",\
|
||||
"public_tag_without_a_value;_private_tag_without_a_value;wikipedia;_category:wikipedia;_pictures:no;_videos:no;_details:no;_ftindex:yes",\
|
||||
"<link rel=\"http://opds-spec.org/image/thumbnail\"\n" \
|
||||
" href=\"/ROOT/catalog/v2/illustration/raycharles/?size=48\"\n" \
|
||||
" type=\"image/png;width=48;height=48;scale=1\"/>\n ", \
|
||||
CONTENT_NAME, \
|
||||
"zimfile", \
|
||||
"569344"\
|
||||
)
|
||||
|
||||
#define RAY_CHARLES_CATALOG_ENTRY _RAY_CHARLES_CATALOG_ENTRY("zimfile")
|
||||
|
||||
#define UNCATEGORIZED_RAY_CHARLES_CATALOG_ENTRY CATALOG_ENTRY(\
|
||||
"raycharles_uncategorized",\
|
||||
"Ray (uncategorized) Charles",\
|
||||
"No category is assigned to this library entry.",\
|
||||
"rus",\
|
||||
"wikipedia_ru_ray_charles",\
|
||||
"",\
|
||||
"public_tag_with_a_value:value_of_a_public_tag;_private_tag_with_a_value:value_of_a_private_tag;wikipedia;_pictures:no;_videos:no;_details:no",\
|
||||
"",\
|
||||
"zimfile", \
|
||||
"zimfile", \
|
||||
"125952"\
|
||||
)
|
||||
|
||||
TEST_F(LibraryServerTest, catalog_root_xml)
|
||||
{
|
||||
@@ -780,4 +783,42 @@ TEST_F(LibraryServerTest, catalog_search_excludes_hidden_tags)
|
||||
#undef EXPECT_ZERO_RESULTS
|
||||
}
|
||||
|
||||
#define NO_MAPPER_CHARLES_RAY_CATALOG_ENTRY _CHARLES_RAY_CATALOG_ENTRY("charlesray")
|
||||
#define NO_MAPPER_RAY_CHARLES_CATALOG_ENTRY _RAY_CHARLES_CATALOG_ENTRY("raycharles")
|
||||
TEST_F(LibraryServerTest, no_name_mapper_returned_catalog_use_uuid_in_link)
|
||||
{
|
||||
resetServer(ZimFileServer::NO_NAME_MAPPER);
|
||||
const auto r = zfs1_->GET("/ROOT/catalog/search?tag=_category:jazz");
|
||||
EXPECT_EQ(r->status, 200);
|
||||
EXPECT_EQ(maskVariableOPDSFeedData(r->body),
|
||||
OPDS_FEED_TAG
|
||||
" <id>12345678-90ab-cdef-1234-567890abcdef</id>\n"
|
||||
" <title>Filtered zims (tag=_category:jazz)</title>\n"
|
||||
" <updated>YYYY-MM-DDThh:mm:ssZ</updated>\n"
|
||||
" <totalResults>1</totalResults>\n"
|
||||
" <startIndex>0</startIndex>\n"
|
||||
" <itemsPerPage>1</itemsPerPage>\n"
|
||||
CATALOG_LINK_TAGS
|
||||
NO_MAPPER_CHARLES_RAY_CATALOG_ENTRY
|
||||
"</feed>\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(LibraryServerTest, no_name_mapper_catalog_v2_individual_entry_access)
|
||||
{
|
||||
resetServer(ZimFileServer::NO_NAME_MAPPER);
|
||||
const auto r = zfs1_->GET("/ROOT/catalog/v2/entry/raycharles");
|
||||
EXPECT_EQ(r->status, 200);
|
||||
EXPECT_EQ(maskVariableOPDSFeedData(r->body),
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
NO_MAPPER_RAY_CHARLES_CATALOG_ENTRY
|
||||
);
|
||||
|
||||
const auto r1 = zfs1_->GET("/ROOT/catalog/v2/entry/non-existent-entry");
|
||||
EXPECT_EQ(r1->status, 404);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#undef EXPECT_SEARCH_RESULTS
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "testing_tools.h"
|
||||
|
||||
TEST(ManagerTest, addBookFromPathAndGetIdTest)
|
||||
{
|
||||
kiwix::Library lib;
|
||||
kiwix::Manager manager = kiwix::Manager(&lib);
|
||||
kiwix::Manager manager = kiwix::Manager(NotOwned<kiwix::Library>(lib));
|
||||
|
||||
auto bookId = manager.addBookFromPathAndGetId("./test/example.zim");
|
||||
ASSERT_NE(bookId, "");
|
||||
@@ -49,7 +51,7 @@ const char sampleLibraryXML[] = R"(
|
||||
TEST(ManagerTest, readXml)
|
||||
{
|
||||
kiwix::Library lib;
|
||||
kiwix::Manager manager = kiwix::Manager(&lib);
|
||||
kiwix::Manager manager = kiwix::Manager(NotOwned<kiwix::Library>(lib));
|
||||
|
||||
EXPECT_EQ(true, manager.readXml(sampleLibraryXML, true, "/data/lib.xml", true));
|
||||
kiwix::Book book = lib.getBookById("0d0bcd57-d3f6-cb22-44cc-a723ccb4e1b2");
|
||||
@@ -71,7 +73,7 @@ TEST(ManagerTest, readXml)
|
||||
TEST(Manager, reload)
|
||||
{
|
||||
kiwix::Library lib;
|
||||
kiwix::Manager manager(&lib);
|
||||
kiwix::Manager manager = kiwix::Manager(NotOwned<kiwix::Library>(lib));
|
||||
|
||||
manager.reload({ "./test/library.xml" });
|
||||
EXPECT_EQ(lib.getBooksIds(), (kiwix::Library::BookIdCollection{
|
||||
|
||||
@@ -4,9 +4,12 @@
|
||||
#include "../include/manager.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "testing_tools.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
|
||||
const char libraryXML[] = R"(
|
||||
<library version="1.0">
|
||||
<book id="01" path="/data/zero_one.zim"> </book>
|
||||
@@ -18,9 +21,13 @@ const char libraryXML[] = R"(
|
||||
)";
|
||||
|
||||
class NameMapperTest : public ::testing::Test {
|
||||
public:
|
||||
explicit NameMapperTest()
|
||||
{}
|
||||
|
||||
protected:
|
||||
void SetUp() override {
|
||||
kiwix::Manager manager(&lib);
|
||||
kiwix::Manager manager{NotOwned<kiwix::Library>(lib)};
|
||||
manager.readXml(libraryXML, false, "./library.xml", true);
|
||||
for ( const std::string& id : lib.getBooksIds() ) {
|
||||
kiwix::Book bookCopy = lib.getBookById(id);
|
||||
@@ -108,7 +115,7 @@ TEST_F(NameMapperTest, HumanReadableNameMapperWithAliases)
|
||||
TEST_F(NameMapperTest, UpdatableNameMapperWithoutAliases)
|
||||
{
|
||||
CapturedStderr stderror;
|
||||
kiwix::UpdatableNameMapper nm(lib, false);
|
||||
kiwix::UpdatableNameMapper nm(NotOwned<kiwix::Library>(lib), false);
|
||||
EXPECT_EQ("", std::string(stderror));
|
||||
|
||||
checkUnaliasedEntriesInNameMapper(nm);
|
||||
@@ -124,7 +131,7 @@ TEST_F(NameMapperTest, UpdatableNameMapperWithoutAliases)
|
||||
TEST_F(NameMapperTest, UpdatableNameMapperWithAliases)
|
||||
{
|
||||
CapturedStderr stderror;
|
||||
kiwix::UpdatableNameMapper nm(lib, true);
|
||||
kiwix::UpdatableNameMapper nm(NotOwned<kiwix::Library>(lib), true);
|
||||
EXPECT_EQ(
|
||||
"Path collision: /data/zero_four_2021-10.zim and"
|
||||
" /data/zero_four_2021-11.zim can't share the same URL path 'zero_four'."
|
||||
|
||||
@@ -131,6 +131,13 @@ TEST_F(ServerTest, 200)
|
||||
EXPECT_EQ(200, zfs1_->GET(res.url)->status) << "res.url: " << res.url;
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, 200_IdNameMapper)
|
||||
{
|
||||
resetServer(ZimFileServer::NO_NAME_MAPPER);
|
||||
EXPECT_EQ(200, zfs1_->GET("/ROOT/content/6f1d19d0-633f-087b-fb55-7ac324ff9baf/A/index")->status);
|
||||
EXPECT_EQ(404, zfs1_->GET("/ROOT/content/zimfile/A/index")->status);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, CompressibleContentIsCompressedIfAcceptable)
|
||||
{
|
||||
for ( const Resource& res : resources200Compressible ) {
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <zim/entry.h>
|
||||
#include <zim/item.h>
|
||||
|
||||
#include "testing_tools.h"
|
||||
|
||||
// Output generated via mustache templates sometimes contains end-of-line
|
||||
// whitespace. This complicates representing the expected output of a unit-test
|
||||
// as C++ raw strings in editors that are configured to delete EOL whitespace.
|
||||
@@ -61,6 +63,7 @@ public: // types
|
||||
WITH_TASKBAR = 1 << 1,
|
||||
WITH_LIBRARY_BUTTON = 1 << 2,
|
||||
BLOCK_EXTERNAL_LINKS = 1 << 3,
|
||||
NO_NAME_MAPPER = 1 << 4,
|
||||
|
||||
WITH_TASKBAR_AND_LIBRARY_BUTTON = WITH_TASKBAR | WITH_LIBRARY_BUTTON,
|
||||
|
||||
@@ -68,7 +71,7 @@ public: // types
|
||||
};
|
||||
|
||||
public: // functions
|
||||
ZimFileServer(int serverPort, std::string libraryFilePath);
|
||||
ZimFileServer(int serverPort, Options options, std::string libraryFilePath);
|
||||
ZimFileServer(int serverPort,
|
||||
Options options,
|
||||
const FilePathCollection& zimpaths,
|
||||
@@ -91,14 +94,15 @@ private:
|
||||
private: // data
|
||||
kiwix::Library library;
|
||||
kiwix::Manager manager;
|
||||
std::unique_ptr<kiwix::HumanReadableNameMapper> nameMapper;
|
||||
std::shared_ptr<kiwix::NameMapper> nameMapper;
|
||||
std::unique_ptr<kiwix::Server> server;
|
||||
std::unique_ptr<httplib::Client> client;
|
||||
const Options options = DEFAULT_OPTIONS;
|
||||
};
|
||||
|
||||
ZimFileServer::ZimFileServer(int serverPort, std::string libraryFilePath)
|
||||
: manager(&this->library)
|
||||
ZimFileServer::ZimFileServer(int serverPort, Options _options, std::string libraryFilePath)
|
||||
: manager(NotOwned<kiwix::Library>(library)),
|
||||
options(_options)
|
||||
{
|
||||
if ( kiwix::isRelativePath(libraryFilePath) )
|
||||
libraryFilePath = kiwix::computeAbsolutePath(kiwix::getCurrentDirectory(), libraryFilePath);
|
||||
@@ -110,8 +114,8 @@ ZimFileServer::ZimFileServer(int serverPort,
|
||||
Options _options,
|
||||
const FilePathCollection& zimpaths,
|
||||
std::string indexTemplateString)
|
||||
: manager(&this->library)
|
||||
, options(_options)
|
||||
: manager(NotOwned<kiwix::Library>(library)),
|
||||
options(_options)
|
||||
{
|
||||
for ( const auto& zimpath : zimpaths ) {
|
||||
if (!manager.addBookFromPath(zimpath, zimpath, "", false))
|
||||
@@ -123,19 +127,25 @@ ZimFileServer::ZimFileServer(int serverPort,
|
||||
void ZimFileServer::run(int serverPort, std::string indexTemplateString)
|
||||
{
|
||||
const std::string address = "127.0.0.1";
|
||||
nameMapper.reset(new kiwix::HumanReadableNameMapper(library, false));
|
||||
server.reset(new kiwix::Server(&library, nameMapper.get()));
|
||||
server->setRoot("ROOT");
|
||||
server->setAddress(address);
|
||||
server->setPort(serverPort);
|
||||
server->setNbThreads(2);
|
||||
server->setVerbose(false);
|
||||
server->setTaskbar(options & WITH_TASKBAR, options & WITH_LIBRARY_BUTTON);
|
||||
server->setBlockExternalLinks(options & BLOCK_EXTERNAL_LINKS);
|
||||
server->setMultiZimSearchLimit(3);
|
||||
if (!indexTemplateString.empty()) {
|
||||
server->setIndexTemplateString(indexTemplateString);
|
||||
if (options & NO_NAME_MAPPER) {
|
||||
nameMapper.reset(new kiwix::IdNameMapper());
|
||||
} else {
|
||||
nameMapper.reset(new kiwix::HumanReadableNameMapper(library, false));
|
||||
}
|
||||
kiwix::Server::Configuration configuration(NotOwned<kiwix::Library>(library), nameMapper);
|
||||
configuration.setRoot("ROOT")
|
||||
.setAddress(address)
|
||||
.setPort(serverPort)
|
||||
.setNbThreads(2)
|
||||
.setVerbose(false)
|
||||
.setTaskbar(options & WITH_TASKBAR, options & WITH_LIBRARY_BUTTON)
|
||||
.setBlockExternalLinks(options & BLOCK_EXTERNAL_LINKS)
|
||||
.setMultiZimSearchLimit(3);
|
||||
|
||||
if (!indexTemplateString.empty()) {
|
||||
configuration.setIndexTemplateString(indexTemplateString);
|
||||
}
|
||||
server.reset(new kiwix::Server(configuration));
|
||||
|
||||
if ( !server->start() )
|
||||
throw std::runtime_error("ZimFileServer failed to start");
|
||||
|
||||
19
test/testing_tools.h
Normal file
19
test/testing_tools.h
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
#ifndef TESTING_TOOLS
|
||||
#define TESTING_TOOLS
|
||||
|
||||
#include <memory>
|
||||
|
||||
struct NoDelete {
|
||||
template<class T> void operator()(T*) {}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class NotOwned : public std::shared_ptr<T> {
|
||||
public:
|
||||
NotOwned(T& object) :
|
||||
std::shared_ptr<T>(&object, NoDelete()) {};
|
||||
};
|
||||
|
||||
|
||||
#endif // TESTING_TOOLS
|
||||
Reference in New Issue
Block a user