From bcd246076540a8353fa55fc0a5e19343c1a2dbc9 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 14 Aug 2015 13:03:08 +0200 Subject: Implement package search service mockup --- brep/buildfile | 28 +++++-- brep/module | 2 + brep/module.cxx | 25 +++--- brep/options.cli | 34 ++++++-- brep/package-search | 32 ++++++++ brep/package-search.cxx | 154 ++++++++++++++++++++++++++++++++++++ brep/package-version-search | 32 ++++++++ brep/package-version-search.cxx | 73 +++++++++++++++++ brep/search | 32 -------- brep/search.cxx | 169 ---------------------------------------- brep/services.cxx | 26 ++++--- brep/shared-database | 4 +- brep/shared-database.cxx | 8 +- brep/view | 32 -------- brep/view.cxx | 131 ------------------------------- 15 files changed, 376 insertions(+), 406 deletions(-) create mode 100644 brep/package-search create mode 100644 brep/package-search.cxx create mode 100644 brep/package-version-search create mode 100644 brep/package-version-search.cxx delete mode 100644 brep/search delete mode 100644 brep/search.cxx delete mode 100644 brep/view delete mode 100644 brep/view.cxx (limited to 'brep') diff --git a/brep/buildfile b/brep/buildfile index 5340d22..9b64ed4 100644 --- a/brep/buildfile +++ b/brep/buildfile @@ -6,20 +6,36 @@ using cli .: libso{brep brep-apache} -import libs += libbpkg%lib{bpkg} -import libs += libodb-pgsql%lib{odb-pgsql} +# brep library build rules. +# import libs += libodb%lib{odb} +import libs += libodb-pgsql%lib{odb-pgsql} +import libs += libbpkg%lib{bpkg} brep = cxx{package package-odb} + libso{brep}: $brep $libs libso{brep}: cxx.export.poptions = -I$out_root -I$src_root -brep = cxx{diagnostics module services search view shared-database} \ - cli.cxx{options} -web = ../web/apache/cxx{request service} +# brep-apache library build rules. +# +import libs += libstudxml%lib{studxml} + +brep = cxx{diagnostics module services package-search package-version-search \ + shared-database} cli.cxx{options} +web = ../web/apache/cxx{request service} ../web/cxx{mime-url-encoding} + libso{brep-apache}: $brep $web libso{brep} $libs +# Set option prefix to the empty value to handle all unknown request parameters +# uniformly with a single catch block. +# +# @@ Adding --option-prefix "" leads to appearing the following warnings +# related to options _parse methed: +# brep/options.cxx:663:33: warning: unused parameter ‘opt_mode’ [-Wunused-parameter] +# ::cli::unknown_mode opt_mode, +# cli.options += -I $src_root --include-with-brackets --include-prefix brep \ ---guard-prefix BREP --generate-file-scanner --suppress-usage +--guard-prefix BREP --generate-file-scanner --suppress-usage --option-prefix "" cli.cxx{options}: cli{options} diff --git a/brep/module b/brep/module index 08fbfea..0743598 100644 --- a/brep/module +++ b/brep/module @@ -92,6 +92,8 @@ namespace brep module (); module (const module& ); + // Can be used by module implementation to parse HTTP request parameters. + // class param_scanner: public cli::scanner { public: diff --git a/brep/module.cxx b/brep/module.cxx index c52d13a..62c70c9 100644 --- a/brep/module.cxx +++ b/brep/module.cxx @@ -22,6 +22,7 @@ using namespace std; using namespace placeholders; // For std::bind's _1, etc. +using namespace cli; namespace brep { @@ -98,22 +99,22 @@ namespace brep { // Read module implementation configuration. // - cli::argv_file_scanner s (0, - argc, - const_cast (argv.data ()), - "conf"); + argv_file_scanner s (0, + argc, + const_cast (argv.data ()), + "conf"); init (s); } // Read brep::module configuration. // - cli::argv_file_scanner s (0, - argc, - const_cast (argv.data ()), - "conf"); + argv_file_scanner s (0, + argc, + const_cast (argv.data ()), + "conf"); - options::module o (s, cli::unknown_mode::skip, cli::unknown_mode::skip); + options::module o (s, unknown_mode::skip, unknown_mode::skip); verb_ = o.verb (); } catch (const server_error& e) @@ -253,7 +254,7 @@ namespace brep if (i_ != name_values_.end ()) return name_ ? i_->name.c_str () : i_->value.c_str (); else - throw cli::eos_reached (); + throw eos_reached (); } const char* module::param_scanner:: @@ -270,7 +271,7 @@ namespace brep return r; } else - throw cli::eos_reached (); + throw eos_reached (); } void module::param_scanner:: @@ -284,6 +285,6 @@ namespace brep name_ = !name_; } else - throw cli::eos_reached (); + throw eos_reached (); } } diff --git a/brep/options.cli b/brep/options.cli index 2894979..8062f59 100644 --- a/brep/options.cli +++ b/brep/options.cli @@ -3,7 +3,7 @@ // license : MIT; see accompanying LICENSE file include ; -include ; +include ; // uint16_t namespace brep { @@ -22,23 +22,43 @@ namespace brep std::uint16_t db-port = 5432; }; - class search: module, db + class package_search: module, db { - size_t results-on-page = 10; + std::uint16_t results-on-page = 10; }; - class view: module, db + class package_version_search: module, db { + std::uint16_t results-on-page = 10; }; } - // Web module request parameters. + // Web module HTTP request parameters. // namespace params { - class search + // Use parameters long names in the C++ code, short aliases in HTTP URL. + // + class package_search { - size_t page = 0; + // Display package search result list starting from this page. + // + std::uint16_t page | p = 0; + + // Package search criteria. + // + std::string query | q = ""; + }; + + class package_version_search + { + // Display package version search result list starting from this page. + // + std::uint16_t page | p = 0; + + // Package version search criteria. + // + std::string query | q = ""; }; } } diff --git a/brep/package-search b/brep/package-search new file mode 100644 index 0000000..156ed68 --- /dev/null +++ b/brep/package-search @@ -0,0 +1,32 @@ +// file : brep/package-search -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef BREP_PACKAGE_SEARCH +#define BREP_PACKAGE_SEARCH + +#include // shared_ptr + +#include // database + +#include +#include + +namespace brep +{ + class package_search: public module + { + private: + virtual void + handle (request&, response&); + + virtual void + init (cli::scanner&); + + private: + std::shared_ptr options_; + std::shared_ptr db_; + }; +} + +#endif // BREP_PACKAGE_SEARCH diff --git a/brep/package-search.cxx b/brep/package-search.cxx new file mode 100644 index 0000000..3317d43 --- /dev/null +++ b/brep/package-search.cxx @@ -0,0 +1,154 @@ +// file : brep/package-search.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include + +#include +#include // make_shared() + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace cli; +using namespace odb::core; + +namespace brep +{ + void package_search:: + init (scanner& s) + { + MODULE_DIAG; + + options_ = make_shared ( + s, unknown_mode::fail, unknown_mode::fail); + + db_ = shared_database (options_->db_host (), options_->db_port ()); + } + + void package_search:: + handle (request& rq, response& rs) + { + using namespace xml; + using namespace web; + using namespace web::xhtml; + + MODULE_DIAG; + + params::package_search pr; + + try + { + param_scanner s (rq.parameters ()); + pr = params::package_search (s, unknown_mode::fail, unknown_mode::fail); + } + catch (const unknown_argument& e) + { + throw invalid_request (400, e.what ()); + } + + // @@ Would be nice to have a manipulator identing string properly + // according to the most nested element identation. + // + const char* ident ("\n "); + const char* title ("Package Search"); + serializer s (rs.content (), title); + + s << HTML + << HEAD + << TITLE << title << ~TITLE + << STYLE(TYPE="text/css") << ident + << ".package {margin: 0 0 0.5em;}" << ident + << ".name a {text-decoration: none;}" << ident + << ".summary {font-size: small;}" + << ~STYLE + << ~HEAD + << BODY; + + string q ( + pr.query ().empty () ? "" : "q=" + mime_url_encode (pr.query ())); + + transaction t (db_->begin ()); + + // @@ Use appropriate view when clarify which package info to be displayed + // and search index structure get implemented. + // + using query = query; + auto r ( + db_->query ( + "ORDER BY" + query::name + + "OFFSET" + to_string (pr.page () * options_->results_on_page ()) + + "LIMIT" + to_string (options_->results_on_page ()))); + + for (const auto& p: r) + { + s << DIV(CLASS="package") + << DIV(CLASS="name") + << A + << HREF + << "/go/" << mime_url_encode (p.name); + + // Propagate search criteria to the package version search url. + // + if (!q.empty ()) + s << "?" << q; + + s << ~HREF + << p.name + << ~A + << ~DIV + << DIV(CLASS="summary") + << p.summary + << ~DIV + << ~DIV; + } + + t.commit (); + + if (pr.page () || r.size () == options_->results_on_page ()) + { + s << DIV; + + if (pr.page ()) + { + s << A + << HREF << "/?p=" << pr.page () - 1 + << (q.empty () ? "" : "&" + q) + << ~HREF + << "Previous" + << ~A + << " "; + } + + // @@ Not ideal as can produce link to an empty page, but easy to fix + // and most likelly will be replaced with something more meaningful + // based on knowing the total number of matched packages. + // + if (r.size () == options_->results_on_page ()) + { + s << A + << HREF << "/?p=" << pr.page () + 1 + << (q.empty () ? "" : "&" + q) + << ~HREF + << "Next" + << ~A; + } + + s << ~DIV; + } + + s << ~BODY + << ~HTML; + } +} diff --git a/brep/package-version-search b/brep/package-version-search new file mode 100644 index 0000000..0292ae0 --- /dev/null +++ b/brep/package-version-search @@ -0,0 +1,32 @@ +// file : brep/package-version-search -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef BREP_PACKAGE_VERSION_SEARCH +#define BREP_PACKAGE_VERSION_SEARCH + +#include // shared_ptr + +#include // database + +#include +#include + +namespace brep +{ + class package_version_search: public module + { + private: + virtual void + handle (request&, response&); + + virtual void + init (cli::scanner&); + + private: + std::shared_ptr options_; + std::shared_ptr db_; + }; +} + +#endif // BREP_PACKAGE_VERSION_SEARCH diff --git a/brep/package-version-search.cxx b/brep/package-version-search.cxx new file mode 100644 index 0000000..a989434 --- /dev/null +++ b/brep/package-version-search.cxx @@ -0,0 +1,73 @@ +// file : brep/package-version-search.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include + +#include +#include // make_shared() + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace cli; +using namespace odb::core; + +namespace brep +{ + void package_version_search:: + init (scanner& s) + { + MODULE_DIAG; + + options_ = make_shared ( + s, unknown_mode::fail, unknown_mode::fail); + + db_ = shared_database (options_->db_host (), options_->db_port ()); + } + + void package_version_search:: + handle (request& rq, response& rs) + { + using namespace xml; + using namespace web; + using namespace web::xhtml; + + MODULE_DIAG; + + const string& name (*rq.path ().rbegin ()); + params::package_version_search pr; + + try + { + param_scanner s (rq.parameters ()); + pr = params::package_version_search ( + s, unknown_mode::fail, unknown_mode::fail); + } + catch (const unknown_argument& e) + { + throw invalid_request (400, e.what ()); + } + + const char* title ("Package"); + serializer s (rs.content (), title); + + s << HTML + << HEAD + << TITLE << title << ~TITLE + << ~HEAD + << BODY << name << ~BODY + << ~HTML; + } +} diff --git a/brep/search b/brep/search deleted file mode 100644 index 0283859..0000000 --- a/brep/search +++ /dev/null @@ -1,32 +0,0 @@ -// file : brep/search -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#ifndef BREP_SEARCH -#define BREP_SEARCH - -#include // shared_ptr - -#include - -#include -#include - -namespace brep -{ - class search: public module - { - private: - virtual void - handle (request&, response&); - - virtual void - init (cli::scanner&); - - private: - std::shared_ptr options_; - std::shared_ptr db_; - }; -} - -#endif // BREP_SEARCH diff --git a/brep/search.cxx b/brep/search.cxx deleted file mode 100644 index 9185aa5..0000000 --- a/brep/search.cxx +++ /dev/null @@ -1,169 +0,0 @@ -// file : brep/search.cxx -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#include - -#include // shared_ptr, make_shared() -#include -#include - -#include -#include -#include - -#include - -#include - -#include -#include -#include - -using namespace std; -using namespace odb::core; - -namespace brep -{ - void search:: - init (cli::scanner& s) - { - MODULE_DIAG; - - options_ = make_shared (s, - cli::unknown_mode::fail, - cli::unknown_mode::fail); - - db_ = shared_database (options_->db_host (), options_->db_port ()); - - if (options_->results_on_page () > 30) - fail << "too many search results on page: " - << options_->results_on_page (); - else if (options_->results_on_page () > 10) - warn << options_->results_on_page () - << " search results on page is quite a lot but will try to cope"; - } - - void search:: - handle (request& rq, response& rs) - { - MODULE_DIAG; - - shared_ptr cli ( - make_shared ("cli", - "CLI is ...", - strings ({"compiler", "c++"}), - string ("This is CLI"), - url (), - url (), - email (), - email ())); - - shared_ptr stable ( - make_shared ( - repository_location ("http://pkg.cpp.org/1/stable"), - "Stable", - dir_path ("/var/pkg/1/stable"))); - - licenses l; - l.comment = "License\"A'"; - l.push_back ("XXX"); - l.push_back ("AAA"); - l.push_back ("BBB"); - l.push_back ("CCC"); - - dependency_alternatives da; - da.push_back ( - {"icl", version_comparison{version ("1.3.3"), comparison::gt}}); - - da.push_back ( - {"ocl", version_comparison{version ("1.5.5"), comparison::lt}}); - - requirement_alternatives ra1; - ra1.push_back ("TAO"); - ra1.push_back ("ORBacus"); - - requirement_alternatives ra2; - ra2.push_back ("Xerces"); - - shared_ptr v ( - make_shared (stable, - cli, - version ("1.1"), - priority (), - license_alternatives ({l}), - "some changes 1\nsome changes 2", - dependencies ({da}), - requirements ({ra1, ra2}))); - - transaction t (db_->begin ()); -// t.tracer (odb::stderr_full_tracer); - - { - db_->persist (cli); - db_->persist (stable); - db_->persist (v); - } - - t.commit (); - - chrono::seconds ma (60); - rs.cookie ("Oh", " Ah\n\n", &ma, "/"); - rs.cookie ("Hm", ";Yes", &ma); - - info << "handling search request from "; // << rq.client_ip (); - - ostream& o (rs.content ()); - - o << ""; - - o << "Options:" - << "
\ntracing verbosity: " << options_->verb () - << "
\ndb endpoint: " << options_->db_host () << ":" - << options_->db_port () - << "
\nsearch results on page: " << options_->results_on_page (); - - o << "

\nParams:"; - - const name_values& ps (rq.parameters ()); - - if (ps.empty ()) - throw invalid_request (422, "search parameters expected"); - - if (ps.size () > 100) - fail << "too many parameters: " << ps.size () << - info << "are you crazy to specify so many?"; - - level2 ([&]{trace << "search request with " << ps.size () << " params";}); - - for (const auto& p: ps) - { - o << "
\n" << p.name << "=" << p.value; - } - - param_scanner s (ps); - unique_ptr prm; - - try - { - prm.reset (new params::search (s, - cli::unknown_mode::fail, - cli::unknown_mode::fail)); - } - catch (const cli::unknown_argument& e) - { - throw invalid_request (400, e.what ()); - } - - o << "
\nPage num: " << prm->page (); - o << "

\nCookies:"; - - for (const auto& c: rq.cookies ()) - { - o << "
\n" << c.name << "=" << c.value; - } - - o << "

View" - << ""; - } -} diff --git a/brep/services.cxx b/brep/services.cxx index 86b27b7..510a231 100644 --- a/brep/services.cxx +++ b/brep/services.cxx @@ -1,21 +1,25 @@ -// file : services.cxx -*- C++ -*- +// file : brep/services.cxx -*- C++ -*- // copyright : Copyright (c) 2014-2015 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file -#include -#include +#include // AP_MODULE_DECLARE_DATA #include +#include +#include + using namespace brep; using web::apache::service; -static search search_mod; -service AP_MODULE_DECLARE_DATA search_srv ("search", - search_mod, - {"db-host", "db-port", "conf"}); +static package_search package_search_mod; +service AP_MODULE_DECLARE_DATA package_search_srv ( + "package-search", + package_search_mod, + {"db-host", "db-port", "conf"}); -static view view_mod; -service AP_MODULE_DECLARE_DATA view_srv ("view", - view_mod, - {"db-host", "db-port", "conf"}); +static package_version_search package_version_search_mod; +service AP_MODULE_DECLARE_DATA package_version_search_srv ( + "package-version-search", + package_version_search_mod, + {"db-host", "db-port", "conf"}); diff --git a/brep/shared-database b/brep/shared-database index cad526f..36fa0a2 100644 --- a/brep/shared-database +++ b/brep/shared-database @@ -14,8 +14,8 @@ namespace brep { // Returns pointer to the shared database instance, creating one on the // first call. On subsequent calls ensures passed host and port equals - // to ones of the shared database instance throwing runtime_error otherwise. - // Is not thread-safe. + // to ones of the existing database instance throwing runtime_error + // otherwise. Is not thread-safe. // std::shared_ptr shared_database (const std::string& host, unsigned int port); diff --git a/brep/shared-database.cxx b/brep/shared-database.cxx index fb952d8..fc17659 100644 --- a/brep/shared-database.cxx +++ b/brep/shared-database.cxx @@ -10,14 +10,14 @@ #include using namespace std; -using namespace odb; namespace brep { - shared_ptr - shared_database (const string& host, unsigned int port) + shared_ptr + shared_database (const string& h, unsigned int p) { - static weak_ptr db; + using odb::pgsql::database; + static weak_ptr db; // In C++11, function-static variable initialization is // guaranteed to be thread-safe, thought this doesn't diff --git a/brep/view b/brep/view deleted file mode 100644 index 280b9ab..0000000 --- a/brep/view +++ /dev/null @@ -1,32 +0,0 @@ -// file : brep/view -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#ifndef BREP_VIEW -#define BREP_VIEW - -#include // shared_ptr - -#include - -#include -#include - -namespace brep -{ - class view: public module - { - private: - virtual void - handle (request&, response&); - - virtual void - init (cli::scanner&); - - private: - std::shared_ptr options_; - std::shared_ptr db_; - }; -} - -#endif // BREP_VIEW diff --git a/brep/view.cxx b/brep/view.cxx deleted file mode 100644 index 3098e93..0000000 --- a/brep/view.cxx +++ /dev/null @@ -1,131 +0,0 @@ -// file : brep/view.cxx -*- C++ -*- -// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#include - -#include // shared_ptr, make_shared() -#include - -#include -#include -#include - -#include - -#include -#include -#include - -using namespace std; -using namespace odb::core; - -#pragma db namespace session -namespace brep -{ - void view:: - init (cli::scanner& s) - { - options_ = make_shared (s, - cli::unknown_mode::fail, - cli::unknown_mode::fail); - - db_ = shared_database (options_->db_host (), options_->db_port ()); - } - - void view:: - handle (request& rq, response& rs) - { - session s; - transaction t (db_->begin ()); - - shared_ptr p (db_->load ("cli")); - - for (auto& vp: p->versions) - { - shared_ptr v (vp.load ()); - v->repository.load (); - v->package.load (); - } - - t.commit (); - - ostream& o (rs.content (200, "text/html;charset=utf-8", false)); - - o << ""; - - o << "Options:" - << "
\ntracing verbosity: " << options_->verb () - << "
\ndb endpoint: " << options_->db_host () << ":" - << options_->db_port (); - - o << "

\nCookies:"; - - for (const auto& c: rq.cookies ()) - { - o << "
\n" << c.name << "=" << c.value; - } - - o << "

\n" << p->name << ": " << p->versions.size (); - - for (const auto& vp: p->versions) - { - // Just finds package_version object in session cache. - // - shared_ptr v (vp.load ()); - - assert (v != nullptr); - assert (v->repository.get_eager () != nullptr); - assert (v->package.get_eager () != nullptr); - - o << "
version:" << v->version.string () - << "
package:" << v->package->name - << "
repo:" << v->repository->display_name - << "
changes:" << v->changes - << "
licenses:" << v->license_alternatives.size (); - - for (const auto& la: v->license_alternatives) - { - o << "
"; - - for (const auto& l: la) - { - o << " |" << l << "|"; - } - } - - o << "
deps:" << v->dependencies.size (); - - for (const auto& da: v->dependencies) - { - o << "
"; - - for (const auto& d: da) - { - o << " |" << d.package; - - if (d.version) - { - o << "," << d.version->value.string () << "," - << static_cast (d.version->operation) << "|"; - } - } - } - - o << "
requirements:" << v->requirements.size (); - - for (const auto& ra: v->requirements) - { - o << "
"; - - for (const auto& r: ra) - { - o << " |" << r << "|"; - } - } - } - - o << "

Search" - << ""; - } -} -- cgit v1.1