From a39fa8ae5fdb272cb8a1d01634a3e6cef36b3f67 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sat, 26 Oct 2013 08:35:46 -0700 Subject: [PATCH] New SiteFiles for fetching and managing ripple.txt files --- Builds/QtCreator/rippled.pro | 1 + Builds/VisualStudio2012/RippleD.vcxproj | 26 ++ .../VisualStudio2012/RippleD.vcxproj.filters | 42 +++ SConstruct | 1 + doc/todo/VFALCO_TODO.txt | 2 + src/ripple/peerfinder/api/Manager.h | 7 +- src/ripple/peerfinder/impl/Manager.cpp | 77 ++++- src/ripple/peerfinder/ripple_peerfinder.h | 2 + src/ripple/sitefiles/api/Listener.h | 45 +++ src/ripple/sitefiles/api/Manager.h | 59 ++++ src/ripple/sitefiles/api/Section.h | 56 ++++ src/ripple/sitefiles/api/SiteFile.h | 49 +++ src/ripple/sitefiles/impl/Logic.h | 298 ++++++++++++++++++ src/ripple/sitefiles/impl/Manager.cpp | 148 +++++++++ src/ripple/sitefiles/impl/Section.cpp | 62 ++++ src/ripple/sitefiles/impl/Site.h | 36 +++ src/ripple/sitefiles/impl/SiteFile.cpp | 49 +++ src/ripple/sitefiles/ripple_sitefiles.cpp | 36 +++ src/ripple/sitefiles/ripple_sitefiles.h | 41 +++ src/ripple_app/main/Application.cpp | 29 +- src/ripple_app/main/Application.h | 6 +- src/ripple_app/peers/Peers.cpp | 17 +- src/ripple_app/peers/Peers.h | 7 +- src/ripple_app/ripple_app.cpp | 1 + 24 files changed, 1075 insertions(+), 22 deletions(-) create mode 100644 src/ripple/sitefiles/api/Listener.h create mode 100644 src/ripple/sitefiles/api/Manager.h create mode 100644 src/ripple/sitefiles/api/Section.h create mode 100644 src/ripple/sitefiles/api/SiteFile.h create mode 100644 src/ripple/sitefiles/impl/Logic.h create mode 100644 src/ripple/sitefiles/impl/Manager.cpp create mode 100644 src/ripple/sitefiles/impl/Section.cpp create mode 100644 src/ripple/sitefiles/impl/Site.h create mode 100644 src/ripple/sitefiles/impl/SiteFile.cpp create mode 100644 src/ripple/sitefiles/ripple_sitefiles.cpp create mode 100644 src/ripple/sitefiles/ripple_sitefiles.h diff --git a/Builds/QtCreator/rippled.pro b/Builds/QtCreator/rippled.pro index 64414a3706..a30ae6c857 100644 --- a/Builds/QtCreator/rippled.pro +++ b/Builds/QtCreator/rippled.pro @@ -70,6 +70,7 @@ SOURCES += \ ../../src/ripple/peerfinder/ripple_peerfinder.cpp \ ../../src/ripple/resource/ripple_resource.cpp \ ../../src/ripple/rpc/ripple_rpc.cpp \ + ../../src/ripple/sitefiles/ripple_sitefiles.cpp \ ../../src/ripple/sophia/ripple_sophia.c \ ../../src/ripple/sslutil/ripple_sslutil.cpp \ ../../src/ripple/testoverlay/ripple_testoverlay.cpp \ diff --git a/Builds/VisualStudio2012/RippleD.vcxproj b/Builds/VisualStudio2012/RippleD.vcxproj index 2c5223d37d..5583a2e1a8 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj +++ b/Builds/VisualStudio2012/RippleD.vcxproj @@ -183,6 +183,25 @@ true + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + true @@ -1727,6 +1746,13 @@ + + + + + + + diff --git a/Builds/VisualStudio2012/RippleD.vcxproj.filters b/Builds/VisualStudio2012/RippleD.vcxproj.filters index a6d761d4f1..6d4cb17665 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2012/RippleD.vcxproj.filters @@ -253,6 +253,15 @@ {548e1020-e083-4e5f-b867-59f76ac02d5a} + + {c7fbf1f8-6a13-434a-b6b6-a621624092db} + + + {5d288f7c-6bce-450f-8f46-b2ab6bb898be} + + + {5609ad93-0654-41db-8ecb-7dfcde58d2e6} + @@ -1131,6 +1140,18 @@ [1] Ripple\peerfinder\impl + + [1] Ripple\sitefiles + + + [1] Ripple\sitefiles\impl + + + [1] Ripple\sitefiles\impl + + + [1] Ripple\sitefiles\impl + @@ -2319,6 +2340,27 @@ [1] Ripple\algorithm\api + + [1] Ripple\sitefiles + + + [1] Ripple\sitefiles\impl + + + [1] Ripple\sitefiles\impl + + + [1] Ripple\sitefiles\api + + + [1] Ripple\sitefiles\api + + + [1] Ripple\sitefiles\api + + + [1] Ripple\sitefiles\api + diff --git a/SConstruct b/SConstruct index 265d38e357..7244e80b45 100644 --- a/SConstruct +++ b/SConstruct @@ -161,6 +161,7 @@ COMPILED_FILES.extend([ 'src/ripple/peerfinder/ripple_peerfinder.cpp', 'src/ripple/resource/ripple_resource.cpp', 'src/ripple/rpc/ripple_rpc.cpp', + 'src/ripple/sitefiles/ripple_sitefiles.cpp', 'src/ripple/sophia/ripple_sophia.c', 'src/ripple/sslutil/ripple_sslutil.cpp', 'src/ripple/testoverlay/ripple_testoverlay.cpp', diff --git a/doc/todo/VFALCO_TODO.txt b/doc/todo/VFALCO_TODO.txt index 4d63ce8bda..bea40b3b2e 100644 --- a/doc/todo/VFALCO_TODO.txt +++ b/doc/todo/VFALCO_TODO.txt @@ -20,6 +20,8 @@ David Features: -------------------------------------------------------------------------------- +- std::priority_queue for DeadlineTimer + - Change ProxyInfo to use IPAddress, get rid of IPv4Address from the parsing code diff --git a/src/ripple/peerfinder/api/Manager.h b/src/ripple/peerfinder/api/Manager.h index e955329e1d..9d455ceb07 100644 --- a/src/ripple/peerfinder/api/Manager.h +++ b/src/ripple/peerfinder/api/Manager.h @@ -33,8 +33,11 @@ protected: public: /** Create a new Manager. */ - static Manager* New (Stoppable& parent, - Callback& callback, Journal journal); + static Manager* New ( + Stoppable& parent, + SiteFiles::Manager& siteFiles, + Callback& callback, + Journal journal); /** Destroy the object. Any pending source fetch operations are aborted. diff --git a/src/ripple/peerfinder/impl/Manager.cpp b/src/ripple/peerfinder/impl/Manager.cpp index b48b975267..1f35fa92e1 100644 --- a/src/ripple/peerfinder/impl/Manager.cpp +++ b/src/ripple/peerfinder/impl/Manager.cpp @@ -217,11 +217,13 @@ namespace PeerFinder { class ManagerImp : public Manager , public Thread + , public SiteFiles::Listener , public DeadlineTimer::Listener , public LeakChecked { public: ServiceQueue m_queue; + SiteFiles::Manager& m_siteFiles; Journal m_journal; StoreSqdb m_store; SerializedContext m_context; @@ -233,9 +235,14 @@ public: //-------------------------------------------------------------------------- - ManagerImp (Stoppable& stoppable, Callback& callback, Journal journal) + ManagerImp ( + Stoppable& stoppable, + SiteFiles::Manager& siteFiles, + Callback& callback, + Journal journal) : Manager (stoppable) , Thread ("PeerFinder") + , m_siteFiles (siteFiles) , m_journal (journal) , m_store (journal) , m_checker (m_context, m_queue) @@ -263,6 +270,7 @@ public: // // PeerFinder // + //-------------------------------------------------------------------------- void setConfig (Config const& config) { @@ -356,10 +364,64 @@ public: id, endpoints)); } + //-------------------------------------------------------------------------- + // + // SiteFiles + // + //-------------------------------------------------------------------------- + + void parseBootstrapIPs (std::string const& name, SiteFiles::Section const& section) + { + std::size_t n (0); + for (SiteFiles::Section::DataType::const_iterator iter ( + section.data().begin()); iter != section.data().end(); ++iter) + { + std::string const& s (*iter); + IPAddress addr (IPAddress::from_string (s)); + if (addr.empty ()) + addr = IPAddress::from_string_altform(s); + if (! addr.empty()) + { + // add IPAddress to bootstrap cache + ++n; + } + } + + m_journal.info << + "Added " << n << + " bootstrap IPs from " << name; + } + + void parseFixedIPs (SiteFiles::Section const& section) + { + for (SiteFiles::Section::DataType::const_iterator iter ( + section.data().begin()); iter != section.data().end(); ++iter) + { + std::string const& s (*iter); + IPAddress addr (IPAddress::from_string (s)); + if (addr.empty ()) + addr = IPAddress::from_string_altform(s); + if (! addr.empty()) + { + // add IPAddress to fixed peers + } + } + } + + void onSiteFileFetch ( + std::string const& name, SiteFiles::SiteFile const& siteFile) + { + parseBootstrapIPs (name, siteFile["ips"]); + + //if (name == "local") + // parseFixedIPs (name, siteFile["ips_fixed"]); + } + //-------------------------------------------------------------------------- // // Stoppable // + //-------------------------------------------------------------------------- void onPrepare () { @@ -387,6 +449,7 @@ public: // // PropertyStream // + //-------------------------------------------------------------------------- void onWrite (PropertyStream::Map& map) { @@ -460,11 +523,15 @@ public: init (); + m_siteFiles.addListener (*this); + while (! this->threadShouldExit()) { m_queue.run_one(); } + m_siteFiles.removeListener (*this); + stopped(); } }; @@ -477,9 +544,13 @@ Manager::Manager (Stoppable& parent) { } -Manager* Manager::New (Stoppable& parent, Callback& callback, Journal journal) +Manager* Manager::New ( + Stoppable& parent, + SiteFiles::Manager& siteFiles, + Callback& callback, + Journal journal) { - return new ManagerImp (parent, callback, journal); + return new ManagerImp (parent, siteFiles, callback, journal); } } diff --git a/src/ripple/peerfinder/ripple_peerfinder.h b/src/ripple/peerfinder/ripple_peerfinder.h index 90f2c89ad9..9c018dfd5a 100644 --- a/src/ripple/peerfinder/ripple_peerfinder.h +++ b/src/ripple/peerfinder/ripple_peerfinder.h @@ -22,6 +22,8 @@ #include "beast/modules/beast_core/beast_core.h" +#include "../sitefiles/ripple_sitefiles.h" + namespace ripple { using namespace beast; } diff --git a/src/ripple/sitefiles/api/Listener.h b/src/ripple/sitefiles/api/Listener.h new file mode 100644 index 0000000000..0102c19549 --- /dev/null +++ b/src/ripple/sitefiles/api/Listener.h @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_SITEFILES_LISTENER_H_INCLUDED +#define RIPPLE_SITEFILES_LISTENER_H_INCLUDED + +namespace ripple { +namespace SiteFiles { + +/** SiteFiles listeners receive notifications on new files and sections. + Calls are made on an implementation-defined, unspecified thread. + Subclasses implementations should not perform blocking i/o or take + a long time. +*/ +class Listener +{ +public: + /** Called every time a new site file is retrieved. + Notifications for Site files retrieved before a listener was added will + be sent at the time the listener is added. + */ + virtual void onSiteFileFetch ( + std::string const& name, SiteFile const& siteFile) = 0; +}; + +} +} + +#endif diff --git a/src/ripple/sitefiles/api/Manager.h b/src/ripple/sitefiles/api/Manager.h new file mode 100644 index 0000000000..555d02ea4e --- /dev/null +++ b/src/ripple/sitefiles/api/Manager.h @@ -0,0 +1,59 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_SITEFILES_MANAGER_H_INCLUDED +#define RIPPLE_SITEFILES_MANAGER_H_INCLUDED + +namespace ripple { +namespace SiteFiles { + +/** Fetches and maintains a collection of ripple.txt files from domains. */ +class Manager + : public Stoppable + , public PropertyStream::Source +{ +protected: + explicit Manager (Stoppable& parent); + +public: + /** Create a new Manager. */ + static Manager* New (Stoppable& parent, Journal journal); + + /** Destroy the object. + Any pending fetch operations are aborted. + */ + virtual ~Manager () { } + + /** Adds a listener. */ + virtual void addListener (Listener& listener) = 0; + + /** Remove a listener. */ + virtual void removeListener (Listener& listener) = 0; + + /** Add a URL leading to a ripple.txt file. + This call does not block. The URL will be fetched asynchronously. + Parsing errors are reported to the journal. + */ + virtual void addURL (std::string const& urlstr) = 0; +}; + +} +} + +#endif diff --git a/src/ripple/sitefiles/api/Section.h b/src/ripple/sitefiles/api/Section.h new file mode 100644 index 0000000000..a777ec2985 --- /dev/null +++ b/src/ripple/sitefiles/api/Section.h @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_SITEFILES_SECTION_H_INCLUDED +#define RIPPLE_SITEFILES_SECTION_H_INCLUDED + +namespace ripple { +namespace SiteFiles { + +/** A Site File section. + Each section has a name, an associative map of key/value pairs, + and a vector of zero or more free-form data strings. +*/ +class Section +{ +public: + typedef boost::unordered_map MapType; + typedef std::vector DataType; + + Section(int = 0); // dummy argument for emplace() + + // Observers + std::string const& get (std::string const& key) const; + std::string const& operator[] (std::string const& key) const; + DataType const& data() const; + + // Modifiers + void set (std::string const& key, std::string const& value); + std::string& operator[] (std::string const& key); + void push_back (std::string const& data); + +private: + MapType m_map; + DataType m_data; +}; + +} +} + +#endif diff --git a/src/ripple/sitefiles/api/SiteFile.h b/src/ripple/sitefiles/api/SiteFile.h new file mode 100644 index 0000000000..421bf642f1 --- /dev/null +++ b/src/ripple/sitefiles/api/SiteFile.h @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_SITEFILES_SITEFILE_H_INCLUDED +#define RIPPLE_SITEFILES_SITEFILE_H_INCLUDED + +namespace ripple { +namespace SiteFiles { + +class SiteFile +{ +public: + SiteFile (int = 0); // dummy argument for emplace + + typedef boost::unordered_map SectionsType; + + /** Retrieve a section by name. */ + /** @{ */ + Section const& get (std::string const& name) const; + Section const& operator[] (std::string const& key) const; + /** @} */ + + /** Retrieve or create a section with the specified name. */ + Section& insert (std::string const& name); + +private: + SectionsType m_sections; +}; + +} +} + +#endif diff --git a/src/ripple/sitefiles/impl/Logic.h b/src/ripple/sitefiles/impl/Logic.h new file mode 100644 index 0000000000..69bc28e3d2 --- /dev/null +++ b/src/ripple/sitefiles/impl/Logic.h @@ -0,0 +1,298 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_SITEFILES_LOGIC_H_INCLUDED +#define RIPPLE_SITEFILES_LOGIC_H_INCLUDED + +namespace ripple { +namespace SiteFiles { + +/* +Config file format: + + Syntactically a series of lines, where line has this format: + [ ] ( OR ) + + Semantically a series of of zero or more sections, where each section + has a name and optional data. Specifically, the format: + ( OR
) + + Data appearing before the first header goes into the section whose + name is the empty string "". + + All lines are valid, errors are not possible. Each line matches one of + the Comment, Header, or Data format: + + Comment: + [ ] [ '#' ] + + Comment lines are ignored; The file is treated as if + the comment lines do not exist. + + Header: + [ ] '[' ']' [ ] + + Data: + Anything not matching a comment or header. + + Lines in a data block are added to the section with the last name parsed, + or the empty string if no header line has been seen yet. +*/ +class Logic +{ +public: + typedef std::set Listeners; + typedef boost::unordered_map SiteFiles; + + struct State + { + State() + { + } + + Listeners listeners; + SiteFiles files; + }; + + typedef SharedData SharedState; + + SharedState m_state; + Journal m_journal; + ScopedPointer m_client; + + explicit Logic (Journal journal) + : m_journal (journal) + , m_client (HTTPClientBase::New (journal)) + { + } + + ~Logic () + { + } + + //-------------------------------------------------------------------------- + // + // Logic + // + //-------------------------------------------------------------------------- + + void addListener (Listener& listener) + { + SharedState::Access state (m_state); + + // Notify the listener for each site file already added + for (SiteFiles::const_iterator iter (state->files.begin()); + iter != state->files.end(); ++iter) + { + listener.onSiteFileFetch (iter->first.to_string(), iter->second); + } + + state->listeners.insert (&listener); + } + + void removeListener (Listener& listener) + { + SharedState::Access state (m_state); + state->listeners.erase (&listener); + } + + void addURL (std::string const& urlstr) + { + ParsedURL const p (urlstr); + + if (p.error()) + { + m_journal.error << + "Error parsing '" << urlstr << "'"; + return; + } + + URL const& url (p.url()); + + HTTPClientBase::result_type const result ( + m_client->get (url)); + + //--- + + boost::system::error_code const error (result.first); + + if (error) + { + m_journal.error + << "HTTP GET '" << url << + "' failed: " << error.message(); + return; + } + + HTTPResponse const& response (*result.second); + + processResponse (url, response); + } + + //-------------------------------------------------------------------------- + // + // Implementation + // + //-------------------------------------------------------------------------- + + void processResponse (URL const& url, HTTPResponse const& response) + { + SharedState::Access state (m_state); + + std::pair result ( + state->files.emplace (url, 0)); + + if (! result.second) + { + m_journal.error << + "Duplicate URL '" << url << "' ignored"; + return; + } + + SiteFile& siteFile (result.first->second); + parse (siteFile, response); + + for (Listeners::iterator iter (state->listeners.begin()); + iter != state->listeners.end(); ++iter) + { + Listener* const listener (*iter); + listener->onSiteFileFetch (url.to_string(), siteFile); + } + } + +#if 0 + static boost::regex const& reHeader () + { + static boost::regex re ( + "(?:\\v*)" // Line break (optional) + "(?:\\h*)" // Horizontal whitespace (optional) + "(?:\\[)" // Open bracket + "([^\\]]*)" // [1] Everything between the brackets + "(?:\\])" // Close bracket + "(?:\\V*)" // Rest of the line + , boost::regex::perl | + boost::regex_constants::match_not_null + ); + + return re; + } + + static boost::regex const& reComment () + { + static boost::regex re ( + "(?:\\v)*" // Line break (optional) + "(?:\\h*)" // Horizontal whitespace (optional) + "(?:#\\V*)*" // Comment + "(?:\\v*)" // Line break (optional) + , boost::regex::perl + | boost::regex_constants::match_not_null + ); + + return re; + } + + static boost::regex const& reData () + { + static boost::regex re ( + "(?:\\v|\\h)*" // Whitespace + "(\\V*)" // [1] Rest of the line + , boost::regex::perl + | boost::regex_constants::match_not_null + ); + + return re; + } +#else + + // regex debugger: + // + // https://www.debuggex.com/r/jwZFkNrqsouaTPHf + // + // (Thanks to J Lynn) + // + static boost::regex const& reHeader () + { + static boost::regex re ( + "(?:\\h*(?:#\\V*)?\\v)*" // Zero or more comments + "(?:\\v*)" // Line break (optional) + "(?:\\h*)" // Horizontal whitespace (optional) + "(?:\\[)" // Open bracket + "([^\\]]*)" // [1] Everything between the brackets + "(?:\\])" // Close bracket + "(?:\\V*)" // Rest of the line + "(?:\\h*(?:#\\V*)?\\v)*" // Zero or more comments + , boost::regex::perl + ); + + return re; + } + + static boost::regex const& reData () + { + static boost::regex re ( + "(?:\\h*(?:#\\V*)?\\v)*" // Zero or more comments + "(\\V*)" // [1] Rest of the line + "(?:\\h*(?:#\\V*)?\\v)*" // Zero or more comments + , boost::regex::perl + ); + + return re; + } +#endif + template + void parse ( + SiteFile& siteFile, + BidirectionalIterator start, + BidirectionalIterator end) + { + Section* section (&siteFile.insert ("")); + + boost::match_results m; + for (;start != end;) + { + if (boost::regex_search (start, end, m, reHeader(), + boost::regex_constants::match_continuous)) + { + std::string const& s (m[1]); + section = &siteFile.insert (s); + } + else + { + boost::regex_search (start, end, m, reData(), + boost::regex_constants::match_continuous); + + std::string const& s (m[1]); + section->push_back (s); + } + + start = m[0].second; + } + } + + void parse (SiteFile& siteFile, HTTPResponse const& response) + { + std::string const s (response.body().to_string()); + parse (siteFile, s.begin(), s.end()); + } +}; + +} +} + +#endif diff --git a/src/ripple/sitefiles/impl/Manager.cpp b/src/ripple/sitefiles/impl/Manager.cpp new file mode 100644 index 0000000000..43b9de02f6 --- /dev/null +++ b/src/ripple/sitefiles/impl/Manager.cpp @@ -0,0 +1,148 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +namespace ripple { +namespace SiteFiles { + +typedef ScopedWrapperContext < + RecursiveMutex, RecursiveMutex::ScopedLockType> SerializedContext; + +class ManagerImp + : public Manager + , public Thread + , public DeadlineTimer::Listener + , public LeakChecked +{ +public: + Logic m_logic; + Journal m_journal; + ServiceQueue m_queue; + + //-------------------------------------------------------------------------- + + ManagerImp (Stoppable& stoppable, Journal journal) + : Manager (stoppable) + , Thread ("PeerFinder") + , m_logic (journal) + , m_journal (journal) + { +#if 1 +#if BEAST_MSVC + if (beast_isRunningUnderDebugger()) + { + m_journal.sink().set_console (true); + m_journal.sink().set_severity (Journal::kLowestSeverity); + } +#endif +#endif + addURL ("https://ripple.com/ripple.txt"); + } + + ~ManagerImp () + { + } + + //-------------------------------------------------------------------------- + // + // Manager + // + //-------------------------------------------------------------------------- + + void addListener (SiteFiles::Listener& listener) + { + m_queue.post (beast::bind ( + &Logic::addListener, &m_logic, beast::ref (listener))); + } + + void removeListener (SiteFiles::Listener& listener) + { + m_queue.post (beast::bind ( + &Logic::removeListener, &m_logic, beast::ref (listener))); + } + + void addURL (std::string const& urlstr) + { + m_queue.post (beast::bind (&Logic::addURL, &m_logic, urlstr)); + } + + //-------------------------------------------------------------------------- + // + // Stoppable + // + //-------------------------------------------------------------------------- + + void onPrepare () + { + } + + void onStart () + { + startThread(); + } + + void onStop () + { + m_journal.debug << "Stopping"; + m_queue.stop (); + } + + //-------------------------------------------------------------------------- + // + // PropertyStream + // + //-------------------------------------------------------------------------- + + void onWrite (PropertyStream::Map& map) + { + //SerializedContext::Scope scope (m_context); + + // ... + } + + //-------------------------------------------------------------------------- + + void onDeadlineTimer (DeadlineTimer& timer) + { + } + + void run () + { + m_journal.debug << "Started"; + m_queue.run(); + m_queue.reset(); + m_queue.poll(); + stopped(); + } +}; + +//------------------------------------------------------------------------------ + +Manager::Manager (Stoppable& parent) + : Stoppable ("PeerFinder", parent) + , PropertyStream::Source ("peerfinder") +{ +} + +Manager* Manager::New (Stoppable& parent, Journal journal) +{ + return new ManagerImp (parent, journal); +} + +} +} diff --git a/src/ripple/sitefiles/impl/Section.cpp b/src/ripple/sitefiles/impl/Section.cpp new file mode 100644 index 0000000000..442310ef69 --- /dev/null +++ b/src/ripple/sitefiles/impl/Section.cpp @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +namespace ripple { +namespace SiteFiles { + +Section::Section(int) +{ +} + +std::string const& Section::get (std::string const& key) const +{ + MapType::const_iterator iter (m_map.find (key)); + if (iter != m_map.end()) + return iter->second; + static std::string const none; + return none; +} + +std::string const& Section::operator[] (std::string const& key) const +{ + return get (key); +} + +std::vector const& Section::data() const +{ + return m_data; +} + +void Section::set (std::string const& key, std::string const& value) +{ + m_map [key] = value; +} + +std::string& Section::operator[] (std::string const& key) +{ + return m_map [key]; +} + +void Section::push_back (std::string const& data) +{ + m_data.push_back (data); +} + +} +} diff --git a/src/ripple/sitefiles/impl/Site.h b/src/ripple/sitefiles/impl/Site.h new file mode 100644 index 0000000000..fe8e5e8264 --- /dev/null +++ b/src/ripple/sitefiles/impl/Site.h @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_SITEFILES_SITE_H_INCLUDED +#define RIPPLE_SITEFILES_SITE_H_INCLUDED + +namespace ripple { +namespace SiteFiles { + +struct Site +{ + Site (int) // dummy argument for emplace() + { + } +}; + +} +} + +#endif diff --git a/src/ripple/sitefiles/impl/SiteFile.cpp b/src/ripple/sitefiles/impl/SiteFile.cpp new file mode 100644 index 0000000000..4d5727c3e1 --- /dev/null +++ b/src/ripple/sitefiles/impl/SiteFile.cpp @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +namespace ripple { +namespace SiteFiles { + +SiteFile::SiteFile (int) +{ +} + +Section const& SiteFile::get (std::string const& name) const +{ + SectionsType::const_iterator iter (m_sections.find (name)); + if (iter != m_sections.end()) + return iter->second; + static Section const none; + return none; +} + +Section const& SiteFile::operator[] (std::string const& key) const +{ + return get (key); +} + +Section& SiteFile::insert (std::string const& name) +{ + std::pair result ( + m_sections.emplace (name, 0)); + return result.first->second; +} + +} +} diff --git a/src/ripple/sitefiles/ripple_sitefiles.cpp b/src/ripple/sitefiles/ripple_sitefiles.cpp new file mode 100644 index 0000000000..74c7372319 --- /dev/null +++ b/src/ripple/sitefiles/ripple_sitefiles.cpp @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "BeastConfig.h" + +#include "ripple_sitefiles.h" + +#include "beast/modules/beast_core/beast_core.h" // for DeadlineTimer, remove ASAP +#include "beast/modules/beast_asio/beast_asio.h" // HTTPClientBase + +#include "beast/modules/beast_core/system/BeforeBoost.h" +#include + +#include + +# include "impl/Site.h" +# include "impl/Logic.h" +#include "impl/Manager.cpp" +#include "impl/Section.cpp" +#include "impl/SiteFile.cpp" diff --git a/src/ripple/sitefiles/ripple_sitefiles.h b/src/ripple/sitefiles/ripple_sitefiles.h new file mode 100644 index 0000000000..d8e0f31c03 --- /dev/null +++ b/src/ripple/sitefiles/ripple_sitefiles.h @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_SITEFILES_H_INCLUDED +#define RIPPLE_SITEFILES_H_INCLUDED + +#include + +#include "beast/modules/beast_core/system/BeforeBoost.h" +#include + +#include "beast/beast/http/URL.h" +#include "beast/beast/Threads.h" +#include "beast/beast/Utility.h" + +namespace ripple { +using namespace beast; +} + +# include "api/Section.h" +# include "api/SiteFile.h" +# include "api/Listener.h" +#include "api/Manager.h" + +#endif diff --git a/src/ripple_app/main/Application.cpp b/src/ripple_app/main/Application.cpp index ed6a2442d4..cfa5da12b2 100644 --- a/src/ripple_app/main/Application.cpp +++ b/src/ripple_app/main/Application.cpp @@ -30,6 +30,8 @@ static bool volatile doShutdown = false; // class ApplicationLog; template <> char const* LogPartition::getPartitionName () { return "Application"; } +class SiteFilesLog; +template <> char const* LogPartition::getPartitionName () { return "SiteFiles"; } class ValidatorsLog; template <> char const* LogPartition::getPartitionName () { return "Validators"; } class JobQueueLog; @@ -72,7 +74,7 @@ public: , m_journal (LogJournal::get ()) , m_tempNodeCache ("NodeCache", 16384, 90) , m_sleCache ("LedgerEntryCache", 4096, 120) - + , m_resourceManager (add (Resource::Manager::New ( LogJournal::get ()))) @@ -93,6 +95,9 @@ public: // Anything which calls addJob must be a descendant of the JobQueue // + , m_siteFiles (SiteFiles::Manager::New ( + *this, LogJournal::get ())) + , m_orderBookDB (*m_jobQueue) , m_ledgerMaster (*m_jobQueue) @@ -163,12 +168,22 @@ public: } //-------------------------------------------------------------------------- - + RPC::Manager& getRPCServiceManager() { return *m_rpcServiceManager; } + JobQueue& getJobQueue () + { + return *m_jobQueue; + } + + SiteFiles::Manager& getSiteFiles() + { + return *m_siteFiles; + } + LocalCredentials& getLocalCredentials () { return m_localCredentials ; @@ -209,11 +224,6 @@ public: return *m_nodeStore; } - JobQueue& getJobQueue () - { - return *m_jobQueue; - } - Application::LockType& getMasterLock () { return m_masterMutex; @@ -477,7 +487,7 @@ public: // the creation of the peer SSL context and Peers object into // the conditional. // - m_peers = add (Peers::New (m_mainIoPool, *m_resourceManager, + m_peers = add (Peers::New (m_mainIoPool, *m_resourceManager, *m_siteFiles, m_mainIoPool, m_peerSSLContext->get ())); // If we're not in standalone mode, @@ -850,13 +860,14 @@ private: SLECache m_sleCache; LocalCredentials m_localCredentials; TransactionMaster m_txMaster; - + ScopedPointer m_resourceManager; ScopedPointer m_rpcServiceManager; // These are Stoppable-related ScopedPointer m_jobQueue; IoServicePool m_mainIoPool; + ScopedPointer m_siteFiles; OrderBookDB m_orderBookDB; LedgerMaster m_ledgerMaster; ScopedPointer m_networkOPs; diff --git a/src/ripple_app/main/Application.h b/src/ripple_app/main/Application.h index f19ffbcb0f..bb60617683 100644 --- a/src/ripple_app/main/Application.h +++ b/src/ripple_app/main/Application.h @@ -21,7 +21,9 @@ #ifndef RIPPLE_APP_APPLICATION_H_INCLUDED #define RIPPLE_APP_APPLICATION_H_INCLUDED +namespace SiteFiles { class Manager; } namespace Validators { class Manager; } +namespace Resource { class Manager; } namespace NodeStore { class Database; } namespace RPC { class Manager; } @@ -78,6 +80,9 @@ public: virtual boost::asio::io_service& getIOService () = 0; virtual RPC::Manager& getRPCServiceManager() = 0; + + virtual JobQueue& getJobQueue () = 0; + virtual SiteFiles::Manager& getSiteFiles () = 0; virtual NodeCache& getTempNodeCache () = 0; virtual SLECache& getSLECache () = 0; virtual Validators::Manager& getValidators () = 0; @@ -91,7 +96,6 @@ public: virtual UniqueNodeList& getUNL () = 0; virtual Validations& getValidations () = 0; virtual NodeStore::Database& getNodeStore () = 0; - virtual JobQueue& getJobQueue () = 0; virtual InboundLedgers& getInboundLedgers () = 0; virtual LedgerMaster& getLedgerMaster () = 0; virtual NetworkOPs& getOPs () = 0; diff --git a/src/ripple_app/peers/Peers.cpp b/src/ripple_app/peers/Peers.cpp index c59f0dc4bf..bd826c6bb3 100644 --- a/src/ripple_app/peers/Peers.cpp +++ b/src/ripple_app/peers/Peers.cpp @@ -90,12 +90,16 @@ public: PeersImp (Stoppable& parent, Resource::Manager& resourceManager, - boost::asio::io_service& io_service, - boost::asio::ssl::context& ssl_context) + SiteFiles::Manager& siteFiles, + boost::asio::io_service& io_service, + boost::asio::ssl::context& ssl_context) : Stoppable ("Peers", parent) , m_resourceManager (resourceManager) , m_peerFinder (add (PeerFinder::Manager::New ( - *this, *this, LogJournal::get ()))) + *this, + siteFiles, + *this, + LogJournal::get ()))) , m_io_service (io_service) , m_ssl_context (ssl_context) , mPeerLock (this, "PeersImp", __FILE__, __LINE__) @@ -1123,9 +1127,10 @@ Peers::Peers () Peers* Peers::New (Stoppable& parent, Resource::Manager& resourceManager, - boost::asio::io_service& io_service, - boost::asio::ssl::context& ssl_context) + SiteFiles::Manager& siteFiles, + boost::asio::io_service& io_service, + boost::asio::ssl::context& ssl_context) { - return new PeersImp (parent, resourceManager, io_service, ssl_context); + return new PeersImp (parent, resourceManager, siteFiles, io_service, ssl_context); } diff --git a/src/ripple_app/peers/Peers.h b/src/ripple_app/peers/Peers.h index ac02f035ac..84fd5108db 100644 --- a/src/ripple_app/peers/Peers.h +++ b/src/ripple_app/peers/Peers.h @@ -20,11 +20,15 @@ #ifndef RIPPLE_PEERS_H_INCLUDED #define RIPPLE_PEERS_H_INCLUDED +namespace PeerFinder { +class Manager; +} + namespace Resource { class Manager; } -namespace PeerFinder { +namespace SiteFiles { class Manager; } @@ -34,6 +38,7 @@ class Peers : public PropertyStream::Source public: static Peers* New (Stoppable& parent, Resource::Manager& resourceManager, + SiteFiles::Manager& siteFiles, boost::asio::io_service& io_service, boost::asio::ssl::context& context); diff --git a/src/ripple_app/ripple_app.cpp b/src/ripple_app/ripple_app.cpp index f79dfeb9fa..4722d510ba 100644 --- a/src/ripple_app/ripple_app.cpp +++ b/src/ripple_app/ripple_app.cpp @@ -38,6 +38,7 @@ #include "../ripple/http/ripple_http.h" #include "../ripple/resource/ripple_resource.h" #include "../ripple/rpc/ripple_rpc.h" +#include "../ripple/sitefiles/ripple_sitefiles.h" #include "../ripple/validators/ripple_validators.h" #include "beast/beast/Asio.h"