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"