diff --git a/Builds/VisualStudio2012/RippleD.vcxproj b/Builds/VisualStudio2012/RippleD.vcxproj
index 3ca3b980aa..65a2a23c15 100644
--- a/Builds/VisualStudio2012/RippleD.vcxproj
+++ b/Builds/VisualStudio2012/RippleD.vcxproj
@@ -1621,6 +1621,7 @@
+
diff --git a/Builds/VisualStudio2012/RippleD.vcxproj.filters b/Builds/VisualStudio2012/RippleD.vcxproj.filters
index f96cb148ea..0f34552a5b 100644
--- a/Builds/VisualStudio2012/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2012/RippleD.vcxproj.filters
@@ -2214,6 +2214,9 @@
[1] Ripple\peerfinder\impl
+
+ [1] Ripple\json\api
+
diff --git a/src/beast/Builds/VisualStudio2012/beast.vcxproj b/src/beast/Builds/VisualStudio2012/beast.vcxproj
index 51c503376a..c63d3621da 100644
--- a/src/beast/Builds/VisualStudio2012/beast.vcxproj
+++ b/src/beast/Builds/VisualStudio2012/beast.vcxproj
@@ -184,6 +184,7 @@
+
@@ -569,6 +570,12 @@
true
true
+
+ true
+ true
+ true
+ true
+
true
true
diff --git a/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters b/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters
index e6f5ed48b3..6b718eb5c9 100644
--- a/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters
+++ b/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters
@@ -1245,6 +1245,9 @@
beast
+
+ beast\utility
+
@@ -1793,6 +1796,9 @@
beast\boost
+
+ beast\utility\impl
+
diff --git a/src/beast/beast/Utility.h b/src/beast/beast/Utility.h
index 403f78ee31..952d0c2252 100644
--- a/src/beast/beast/Utility.h
+++ b/src/beast/beast/Utility.h
@@ -25,6 +25,7 @@
#include "utility/Error.h"
#include "utility/Journal.h"
#include "utility/LeakChecked.h"
+#include "utility/PropertyStream.h"
#include "utility/StaticObject.h"
#endif
diff --git a/src/beast/beast/utility/PropertyStream.h b/src/beast/beast/utility/PropertyStream.h
new file mode 100644
index 0000000000..a8fb8956c6
--- /dev/null
+++ b/src/beast/beast/utility/PropertyStream.h
@@ -0,0 +1,263 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ 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 BEAST_UTILITY_PROPERTYSTREAM_H_INCLUDED
+#define BEAST_UTILITY_PROPERTYSTREAM_H_INCLUDED
+
+#include "../CStdInt.h"
+#include "../Uncopyable.h"
+#include "../intrusive/List.h"
+#include "../threads/SharedData.h"
+
+#include
+
+namespace beast {
+
+/** An output stream to procedurally generate an abstract property tree. */
+class PropertyStream
+{
+private:
+ class Proxy;
+
+public:
+ class ScopedArray;
+ class ScopedObject;
+ class Source;
+
+private:
+ class Item : public List - ::Node
+ {
+ public:
+ explicit Item (Source* source);
+ Source& source() const;
+ Source* operator-> () const;
+ Source& operator* () const;
+ private:
+ Source* m_source;
+ };
+
+public:
+ //--------------------------------------------------------------------------
+
+ class Sink : Uncopyable
+ {
+ public:
+ // Object output
+ //
+ // Default implementations convert to string
+ // Json doesn't support 64 bit so we convert these to string
+ // if they are outside the range of the corresponding 32 bit int
+ virtual void begin_object (std::string const& key) = 0;
+ virtual void end_object () = 0;
+ template
+ void lexical_write (std::string const &key, Value value)
+ {
+ std::stringstream ss;
+ ss << value;
+ write (key, ss.str());
+ }
+ virtual void write (std::string const& key, int32 value);
+ virtual void write (std::string const& key, uint32 value);
+ virtual void write (std::string const& key, int64 value);
+ virtual void write (std::string const& key, uint64 value);
+ virtual void write (std::string const& key, std::string const& value) = 0;
+
+ // Array output
+ //
+ virtual void begin_array (std::string const& key) = 0;
+ virtual void end_array () = 0;
+ template
+ void lexical_write (Value value)
+ {
+ std::stringstream ss;
+ ss << value;
+ write (ss.str());
+ }
+ virtual void write ( int32 value);
+ virtual void write (uint32 value);
+ virtual void write ( int64 value);
+ virtual void write (uint64 value);
+ virtual void write (std::string const& value) = 0;
+ };
+
+ //--------------------------------------------------------------------------
+
+ PropertyStream ();
+ PropertyStream (Sink& sink);
+ PropertyStream (PropertyStream const& other);
+ PropertyStream& operator= (PropertyStream const& other);
+
+ /** Object output.
+ */
+ /** @{ */
+ void begin_object (std::string const& key) const;
+ void end_object () const;
+
+ template
+ void write (std::string const& key, Value value) const
+ {
+ m_sink->write (key, value);
+ }
+
+ template
+ void write (Key key, Value value) const
+ {
+ std::stringstream ss;
+ ss << key;
+ write (ss.str(), value);
+ }
+
+ Proxy operator[] (std::string const& key) const;
+
+ template
+ Proxy operator[] (Key key) const;
+
+ /** @} */
+
+ /** Array output.
+ */
+ /** @{ */
+ void begin_array (std::string const& key) const;
+ void end_array () const;
+
+ template
+ void append (Value value) const
+ { m_sink->write (value); }
+
+ template
+ PropertyStream const& operator<< (Value value) const
+ { append (value); return &this; }
+ /** @} */
+
+private:
+ static Sink& nullSink();
+
+ Sink* m_sink;
+};
+
+//------------------------------------------------------------------------------
+
+class PropertyStream::Proxy
+{
+private:
+ PropertyStream m_stream;
+ std::string m_key;
+
+public:
+ Proxy (PropertyStream stream, std::string const& key);
+
+ template
+ Proxy& operator= (Value value)
+ { m_stream.write (m_key, value); return *this; }
+};
+
+//------------------------------------------------------------------------------
+
+template
+PropertyStream::Proxy PropertyStream::operator[] (Key key) const
+{
+ std::stringstream ss;
+ ss << key;
+ return operator[] (ss.str());
+}
+
+//------------------------------------------------------------------------------
+
+class PropertyStream::ScopedObject
+{
+private:
+ PropertyStream m_stream;
+
+public:
+ ScopedObject (std::string const& key, PropertyStream stream);
+ ~ScopedObject ();
+};
+
+//------------------------------------------------------------------------------
+
+class PropertyStream::ScopedArray
+{
+private:
+ PropertyStream m_stream;
+
+public:
+ ScopedArray (std::string const& key, PropertyStream stream);
+ ~ScopedArray ();
+};
+
+//------------------------------------------------------------------------------
+
+/** Subclasses can be called to write to a stream and have children. */
+class PropertyStream::Source : public Uncopyable
+{
+private:
+ struct State
+ {
+ explicit State (Source* source)
+ : item (source)
+ , parent (nullptr)
+ { }
+ Item item;
+ Source* parent;
+ List
- children;
+ };
+
+ typedef SharedData SharedState;
+
+ std::string const m_name;
+ SharedState m_state;
+
+ void remove (SharedState::Access& state, SharedState::Access& childState);
+ void removeAll (SharedState::Access& state);
+
+public:
+ explicit Source (std::string const& name);
+ ~Source ();
+
+ /** Add a child source. */
+ void add (Source& source);
+
+ /** Add a child source by pointer.
+ This returns the passed source so it can be conveniently chained
+ in ctor-initializer lists.
+ */
+ template
+ Derived* add (Derived* child)
+ {
+ add (*static_cast (child));
+ return child;
+ }
+
+ /** Remove a child source. */
+ void remove (Source& child);
+
+ /** Remove all child sources. */
+ void removeAll ();
+
+ void write (PropertyStream stream, bool includeChildren);
+ void write (std::string const& path, PropertyStream stream);
+
+ virtual void onWrite (PropertyStream) { }
+};
+
+//------------------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/src/beast/beast/utility/Utility.cpp b/src/beast/beast/utility/Utility.cpp
index f66ea5a69a..e2b254bfdb 100644
--- a/src/beast/beast/utility/Utility.cpp
+++ b/src/beast/beast/utility/Utility.cpp
@@ -28,3 +28,4 @@
#include "impl/Journal.cpp"
#include "impl/LeakChecked.cpp"
#include "impl/StaticObject.cpp"
+#include "impl/PropertyStream.cpp"
diff --git a/src/beast/beast/utility/impl/PropertyStream.cpp b/src/beast/beast/utility/impl/PropertyStream.cpp
new file mode 100644
index 0000000000..64d1164a1d
--- /dev/null
+++ b/src/beast/beast/utility/impl/PropertyStream.cpp
@@ -0,0 +1,341 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ 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 "../PropertyStream.h"
+
+#include
+
+namespace beast {
+
+PropertyStream::Item::Item (Source* source)
+ : m_source (source)
+{
+}
+
+PropertyStream::Source& PropertyStream::Item::source() const
+{
+ return *m_source;
+}
+
+PropertyStream::Source* PropertyStream::Item::operator-> () const
+{
+ return &source();
+}
+
+PropertyStream::Source& PropertyStream::Item::operator* () const
+{
+ return source();
+}
+
+//------------------------------------------------------------------------------
+
+void PropertyStream::Sink::write (std::string const& key, int32 value)
+{
+ lexical_write (key, value);
+}
+
+void PropertyStream::Sink::write (std::string const& key, uint32 value)
+{
+ lexical_write (key, value);
+}
+
+void PropertyStream::Sink::write (std::string const& key, int64 value)
+{
+ if (value <= std::numeric_limits ::max() &&
+ value >= std::numeric_limits ::min())
+ {
+ write (key, int32(value));
+ }
+ else
+ {
+ lexical_write (key, value);
+ }
+}
+
+void PropertyStream::Sink::write (std::string const& key, uint64 value)
+{
+ if (value <= std::numeric_limits ::max() &&
+ value >= std::numeric_limits ::min())
+ {
+ write (key, uint32(value));
+ }
+ else
+ {
+ lexical_write (key, value);
+ }
+}
+
+void PropertyStream::Sink::write (int32 value)
+{
+ lexical_write (value);
+}
+
+void PropertyStream::Sink::write (uint32 value)
+{
+ lexical_write (value);
+}
+
+void PropertyStream::Sink::write (int64 value)
+{
+ if (value <= std::numeric_limits ::max() &&
+ value >= std::numeric_limits ::min())
+ {
+ write (int32(value));
+ }
+ else
+ {
+ lexical_write (value);
+ }
+}
+
+void PropertyStream::Sink::write (uint64 value)
+{
+ if (value <= std::numeric_limits ::max() &&
+ value >= std::numeric_limits ::min())
+ {
+ write (uint32(value));
+ }
+ else
+ {
+ lexical_write (value);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+PropertyStream::Proxy::Proxy (PropertyStream stream, std::string const& key)
+ : m_stream (stream)
+ , m_key (key)
+{
+}
+
+//------------------------------------------------------------------------------
+
+PropertyStream::ScopedObject::ScopedObject (std::string const& key, PropertyStream stream)
+ : m_stream (stream)
+{
+ m_stream.begin_object (key);
+}
+
+PropertyStream::ScopedObject::~ScopedObject ()
+{
+ m_stream.end_object ();
+}
+
+//------------------------------------------------------------------------------
+
+PropertyStream::Source::Source (std::string const& name)
+ : m_name (name)
+ , m_state (this)
+{
+}
+
+PropertyStream::Source::~Source ()
+{
+ SharedState::Access state (m_state);
+ if (state->parent != nullptr)
+ state->parent->remove (*this);
+ removeAll (state);
+}
+
+void PropertyStream::Source::remove (
+ SharedState::Access& state, SharedState::Access& childState)
+{
+ bassert (childState->parent == this);
+ state->children.erase (
+ state->children.iterator_to (
+ childState->item));
+ childState->parent = nullptr;
+}
+
+void PropertyStream::Source::removeAll (SharedState::Access& state)
+{
+ for (List
- ::iterator iter (state->children.begin());
+ iter != state->children.end();)
+ {
+ SharedState::Access childState ((*iter)->m_state);
+ remove (state, childState);
+ }
+}
+
+void PropertyStream::Source::add (Source& source)
+{
+ SharedState::Access state (m_state);
+ SharedState::Access childState (source.m_state);
+ bassert (childState->parent == nullptr);
+ state->children.push_back (childState->item);
+ childState->parent = this;
+}
+
+void PropertyStream::Source::remove (Source& child)
+{
+ SharedState::Access state (m_state);
+ SharedState::Access childState (child.m_state);
+ remove (state, childState);
+}
+
+void PropertyStream::Source::removeAll ()
+{
+ SharedState::Access state (m_state);
+ removeAll (state);
+}
+
+void PropertyStream::Source::write (PropertyStream stream, bool includeChildren)
+{
+ ScopedObject child (m_name, stream);
+ onWrite (stream);
+
+ if (includeChildren)
+ {
+ SharedState::Access state (m_state);
+ for (List
- ::iterator iter (state->children.begin());
+ iter != state->children.end(); ++iter)
+ {
+ (*iter)->write (stream, true);
+ }
+ }
+}
+
+void PropertyStream::Source::write (std::string const& path, PropertyStream stream)
+{
+ struct Parser
+ {
+ Parser (std::string const& path)
+ : m_first (path.begin())
+ , m_last (path.end())
+ {
+ }
+
+ std::string next ()
+ {
+ std::string::const_iterator pos (
+ std::find (m_first, m_last, '.'));
+ std::string const s (m_first, pos);
+ if (pos != m_last)
+ m_first = pos + 1;
+ else
+ m_first = pos;
+ return s;
+ }
+
+ std::string::const_iterator m_first;
+ std::string::const_iterator m_last;
+ };
+
+ //-----------------------------------------
+
+ if (path.empty ())
+ {
+ write (stream, true);
+ return;
+ }
+
+ Parser p (path);
+ Source* source (this);
+ if (p.next() != source->m_name)
+ return;
+
+ for (;;)
+ {
+ std::string const s (p.next());
+
+ if (s.empty())
+ {
+ source->write (stream, false);
+ break;
+ }
+ else if (s == "*")
+ {
+ source->write (stream, true);
+ break;
+ }
+ else
+ {
+ SharedState::Access state (source->m_state);
+ for (List
- ::iterator iter (state->children.begin());;)
+ {
+ if (iter->source().m_name == s)
+ {
+ source = &iter->source();
+ break;
+ }
+
+ if (++iter == state->children.end())
+ return;
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+PropertyStream::PropertyStream ()
+ : m_sink (&nullSink())
+{
+}
+
+PropertyStream::PropertyStream (Sink& sink)
+ : m_sink (&sink)
+{
+}
+
+PropertyStream::PropertyStream (PropertyStream const& other)
+ : m_sink (other.m_sink)
+{
+}
+
+PropertyStream& PropertyStream::operator= (PropertyStream const& other)
+{
+ m_sink = other.m_sink;
+ return *this;
+}
+
+PropertyStream::Proxy PropertyStream::operator[] (std::string const& key) const
+{
+ return Proxy (*this, key);
+}
+
+void PropertyStream::begin_object (std::string const& key) const
+{
+ m_sink->begin_object (key);
+}
+
+void PropertyStream::end_object () const
+{
+ m_sink->end_object ();
+}
+
+PropertyStream::Sink& PropertyStream::nullSink()
+{
+ struct NullSink : Sink
+ {
+ void begin_object (std::string const&) { }
+ void end_object () { }
+ void write (std::string const&, std::string const&) { }
+ void begin_array (std::string const&) { }
+ void end_array () { }
+ void write (std::string const&) { }
+ };
+
+ static NullSink sink;
+
+ return sink;
+}
+
+}
diff --git a/src/ripple/json/api/JsonPropertyStreamSink.h b/src/ripple/json/api/JsonPropertyStreamSink.h
new file mode 100644
index 0000000000..c0a79bf3bd
--- /dev/null
+++ b/src/ripple/json/api/JsonPropertyStreamSink.h
@@ -0,0 +1,97 @@
+//------------------------------------------------------------------------------
+/*
+ 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_JSONPROPERTYSTREAMSINK_H_INCLUDED
+#define RIPPLE_JSONPROPERTYSTREAMSINK_H_INCLUDED
+
+#include "beast/beast/utility/PropertyStream.h"
+
+//#include "json_value.h" // ??
+
+namespace ripple {
+using namespace beast;
+
+/** A PropertyStream::Sink which produces a Json::Value. */
+class JsonPropertyStreamSink : public PropertyStream::Sink
+{
+public:
+ explicit JsonPropertyStreamSink (Json::Value& root)
+ {
+ m_stack.push_back (&root);
+ }
+
+ void begin_object (std::string const& key)
+ {
+ m_stack.push_back (&((*m_stack.back())[key] = Json::objectValue));
+ }
+
+ void end_object ()
+ {
+ m_stack.pop_back ();
+ }
+
+ void write (std::string const& key, int32 v)
+ {
+ (*m_stack.back())[key] = v;
+ }
+
+ void write (std::string const& key, uint32 v)
+ {
+ (*m_stack.back())[key] = v;
+ }
+
+ void write (std::string const& key, std::string const& v)
+ {
+ (*m_stack.back())[key] = v;
+ }
+
+ void begin_array (std::string const& key)
+ {
+ m_stack.push_back (&((*m_stack.back())[key] = Json::arrayValue));
+ }
+
+ void end_array ()
+ {
+ m_stack.pop_back ();
+ }
+
+ void write (int32 v)
+ {
+ m_stack.back()->append (v);
+ }
+
+ void write (uint32 v)
+ {
+ m_stack.back()->append (v);
+ }
+
+ void write (std::string const& v)
+ {
+ m_stack.back()->append (v);
+ }
+
+private:
+ Json::Value m_value;
+ std::vector m_stack;
+};
+
+}
+
+#endif
+
diff --git a/src/ripple/json/ripple_json.h b/src/ripple/json/ripple_json.h
index f50fc7b69f..3e32f9c402 100644
--- a/src/ripple/json/ripple_json.h
+++ b/src/ripple/json/ripple_json.h
@@ -17,7 +17,6 @@
*/
//==============================================================================
-
#ifndef RIPPLE_JSON_H_INCLUDED
#define RIPPLE_JSON_H_INCLUDED
@@ -46,4 +45,6 @@
#include "api/json_reader.h"
#include "api/json_writer.h"
+#include "api/JsonPropertyStreamSink.h"
+
#endif
diff --git a/src/ripple/peerfinder/api/Manager.h b/src/ripple/peerfinder/api/Manager.h
index 1cd6a22f72..c42d7e8299 100644
--- a/src/ripple/peerfinder/api/Manager.h
+++ b/src/ripple/peerfinder/api/Manager.h
@@ -24,7 +24,9 @@ namespace ripple {
namespace PeerFinder {
/** Maintains a set of IP addresses used for getting into the network. */
-class Manager : public Stoppable
+class Manager
+ : public Stoppable
+ , public PropertyStream::Source
{
protected:
explicit Manager (Stoppable& parent);
diff --git a/src/ripple/peerfinder/impl/Manager.cpp b/src/ripple/peerfinder/impl/Manager.cpp
index d4d1cefa84..dd76d85cd2 100644
--- a/src/ripple/peerfinder/impl/Manager.cpp
+++ b/src/ripple/peerfinder/impl/Manager.cpp
@@ -290,6 +290,23 @@ public:
m_queue.dispatch (bind (&Thread::signalThreadShouldExit, this));
}
+ //--------------------------------------------------------------------------
+ //
+ // PropertyStream
+ //
+
+ void onWrite (PropertyStream stream)
+ {
+ stream ["peers"] = m_logic.m_slots.peerCount;
+ stream ["in"] = m_logic.m_slots.inboundCount;
+ stream ["out"] = m_logic.m_slots.outboundCount;
+ stream ["out_desired"] = m_logic.m_slots.outDesired;
+ stream ["in_avail"] = m_logic.m_slots.inboundSlots;
+ stream ["in_max"] = m_logic.m_slots.inboundSlotsMaximum;
+ stream ["minutes"] = m_logic.m_slots.uptimeMinutes();
+ stream ["round"] = m_logic.m_slots.roundUpwards();
+ }
+
//--------------------------------------------------------------------------
void onDeadlineTimer (DeadlineTimer& timer)
@@ -358,7 +375,8 @@ public:
//------------------------------------------------------------------------------
Manager::Manager (Stoppable& parent)
- : Stoppable ("PeerFinder", parent)
+ : PropertyStream::Source ("peerfinder")
+ , Stoppable ("PeerFinder", parent)
{
}
diff --git a/src/ripple/peerfinder/impl/Slots.cpp b/src/ripple/peerfinder/impl/Slots.cpp
index c2ed4763f7..54b7148f46 100644
--- a/src/ripple/peerfinder/impl/Slots.cpp
+++ b/src/ripple/peerfinder/impl/Slots.cpp
@@ -63,7 +63,7 @@ void Slots::update (Config const& config)
void Slots::addPeer (Config const& config, bool inbound)
{
if (peerCount == 0)
- startTime = Time::getCurrentTime();
+ startTime = RelativeTime::fromStartup();
++peerCount;
if (inbound)
@@ -83,15 +83,15 @@ void Slots::dropPeer (Config const& config, bool inbound)
--outboundCount;
if (peerCount == 0)
- startTime = Time (0);
+ startTime = RelativeTime(0);
update (config);
}
uint32 Slots::uptimeMinutes () const
{
- if (startTime.isNotNull())
- return (Time::getCurrentTime()-startTime).inMinutes();
+ if (startTime.isNotZero())
+ return (RelativeTime::fromStartup()-startTime).inMinutes();
return 0;
}
diff --git a/src/ripple/peerfinder/impl/Slots.h b/src/ripple/peerfinder/impl/Slots.h
index d25f3e993b..f3b1ee14e7 100644
--- a/src/ripple/peerfinder/impl/Slots.h
+++ b/src/ripple/peerfinder/impl/Slots.h
@@ -31,10 +31,9 @@ public:
void update (Config const& config);
void addPeer (Config const& config, bool inbound);
void dropPeer (Config const& config, bool inbound);
- uint32 uptimeMinutes () const;
// Most recent time when we went from 0 to 1 peers
- Time startTime;
+ RelativeTime startTime;
// Current total of connected peers that have HELLOed
int peerCount;
@@ -54,6 +53,16 @@ public:
// The maximum number of incoming slots (calculated)
int inboundSlotsMaximum;
+ // Returns the uptime in minutes
+ // Uptime is measured from the last we transitioned from not
+ // being connected to the network, to being connected.
+ //
+ uint32 uptimeMinutes () const;
+
+ // Returns `true` if we round fractional slot availability upwards
+ bool roundUpwards () const
+ { return m_roundUpwards; }
+
private:
bool m_roundUpwards;
};
diff --git a/src/ripple/validators/api/Manager.h b/src/ripple/validators/api/Manager.h
index 1c92bfdf2b..970865ac53 100644
--- a/src/ripple/validators/api/Manager.h
+++ b/src/ripple/validators/api/Manager.h
@@ -28,14 +28,17 @@ namespace Validators {
the list of chosen validators is critical to the health of the network.
All operations are performed asynchronously on an internal thread.
*/
-class Manager : public RPC::Service
+class Manager : public PropertyStream::Source
{
+protected:
+ Manager();
+
public:
/** Create a new Manager object.
@param parent The parent Stoppable.
@param journal Where to send log output.
*/
- static Manager* New (Stoppable& parent, Journal journal);
+ static Manager* New (Stoppable& stoppableParent, Journal journal);
/** Destroy the object.
Any pending source fetch operations are aborted. This will block
@@ -59,7 +62,7 @@ public:
virtual void addStrings (String name,
StringArray const& stringArray) = 0;
virtual void addFile (File const& file) = 0;
- virtual void addStaticSource (Source* source) = 0;
+ virtual void addStaticSource (Validators::Source* source) = 0;
/** @} */
/** Add a live source of validators from a trusted URL.
@@ -76,7 +79,7 @@ public:
Thread safety:
Can be called from any thread.
*/
- virtual void addSource (Source* source) = 0;
+ virtual void addSource (Validators::Source* source) = 0;
//--------------------------------------------------------------------------
diff --git a/src/ripple/validators/impl/Logic.h b/src/ripple/validators/impl/Logic.h
index 626bb0c882..de5d6d4215 100644
--- a/src/ripple/validators/impl/Logic.h
+++ b/src/ripple/validators/impl/Logic.h
@@ -406,72 +406,6 @@ public:
return n;
}
- //----------------------------------------------------------------------
- //
- // RPC Handlers
- //
-
- // Return the current ChosenList as JSON
- Json::Value rpcPrint (Json::Value const& args, int cpuPercent)
- {
- Json::Value results (Json::objectValue);
-
- Json::Value entries (Json::arrayValue);
- {
- results ["cpu"] = cpuPercent;
- results ["count"] = int(m_validators.size());
- for (ValidatorTable::const_iterator iter (m_validators.begin());
- iter != m_validators.end(); ++iter)
- {
- Validator const& v (iter->second);
- Json::Value entry (Json::objectValue);
- Count const count (v.count ());
-
- entry ["public"] = iter->first.to_string();
- entry ["received"] = int(count.received);
- entry ["expected"] = int(count.expected);
- entry ["closed"] = int(count.closed);
- entry ["percent"] = count.percent();
-
- entries.append (entry);
- }
- }
- results ["validators"] = entries;
-
- return results;
- }
-
- // Returns the list of sources
- Json::Value rpcSources (Json::Value const& arg)
- {
- Json::Value results (Json::objectValue);
-
- Json::Value entries (Json::arrayValue);
- for (SourceTable::const_iterator iter (m_sources.begin());
- iter != m_sources.end(); ++iter)
- {
- Json::Value entry (Json::objectValue);
- SourceDesc const& desc (*iter);
- entry ["name"] = desc.source->name();
- entry ["param"] = desc.source->createParam();
-
- Json::Value results (Json::arrayValue);
- for (int i = 0; i < desc.results.list.size(); ++i)
- {
- Json::Value info (Json::objectValue);
- info ["key"] = "publicKey";
- info ["label"] = desc.results.list[i].label;
- results.append (info);
- }
- entry ["results"] = results;
-
- entries.append (entry);
- }
- results ["sources"] = entries;
-
- return results;
- }
-
//----------------------------------------------------------------------
//
// Ripple interface
diff --git a/src/ripple/validators/impl/Manager.cpp b/src/ripple/validators/impl/Manager.cpp
index d53a32a277..60550b74a8 100644
--- a/src/ripple/validators/impl/Manager.cpp
+++ b/src/ripple/validators/impl/Manager.cpp
@@ -167,42 +167,6 @@ public:
stopThread ();
}
- //--------------------------------------------------------------------------
- //
- // RPC::Service
- //
-
- Json::Value rpcPrint (Json::Value const& args)
- {
- int const cpuPercent (std::ceil (m_queue.getUtilizaton() * 100));
- return m_logic.rpcPrint (args, cpuPercent);
- }
-
- Json::Value rpcRebuild (Json::Value const& args)
- {
- m_queue.dispatch (bind (&Logic::buildChosen, &m_logic));
- Json::Value result;
- result ["chosen_list"] = "rebuilding";
- return result;
- }
-
- Json::Value rpcSources (Json::Value const& args)
- {
- return m_logic.rpcSources(args);
- }
-
- void addRPCHandlers()
- {
- addRPCHandler ("validators_print", beast::bind (
- &ManagerImp::rpcPrint, this, beast::_1));
-
- addRPCHandler ("validators_rebuild", beast::bind (
- &ManagerImp::rpcRebuild, this, beast::_1));
-
- addRPCHandler ("validators_sources", beast::bind (
- &ManagerImp::rpcSources, this, beast::_1));
- }
-
//--------------------------------------------------------------------------
//
// Manager
@@ -234,7 +198,7 @@ public:
addStaticSource (SourceFile::New (file));
}
- void addStaticSource (Source* source)
+ void addStaticSource (Validators::Source* source)
{
#if RIPPLE_USE_VALIDATORS
m_queue.dispatch (bind (&Logic::addStatic, &m_logic, source));
@@ -248,7 +212,7 @@ public:
addSource (SourceURL::New (url));
}
- void addSource (Source* source)
+ void addSource (Validators::Source* source)
{
#if RIPPLE_USE_VALIDATORS
m_queue.dispatch (bind (&Logic::add, &m_logic, source));
@@ -286,8 +250,6 @@ public:
{
#if RIPPLE_USE_VALIDATORS
m_journal.info << "Validators preparing";
-
- addRPCHandlers();
#endif
}
@@ -402,6 +364,11 @@ public:
//------------------------------------------------------------------------------
+Manager::Manager ()
+ : PropertyStream::Source ("validators")
+{
+}
+
Validators::Manager* Validators::Manager::New (Stoppable& parent, Journal journal)
{
return new Validators::ManagerImp (parent, journal);
diff --git a/src/ripple_app/main/Application.cpp b/src/ripple_app/main/Application.cpp
index 1d0bbcd82f..7d45772aea 100644
--- a/src/ripple_app/main/Application.cpp
+++ b/src/ripple_app/main/Application.cpp
@@ -117,8 +117,8 @@ public:
, m_txQueue (TxQueue::New ())
- , m_validators (Validators::Manager::New (
- *this, LogJournal::get ()))
+ , m_validators (add (Validators::Manager::New (
+ *this, LogJournal::get ())))
, mFeatures (IFeatures::New (2 * 7 * 24 * 60 * 60, 200)) // two weeks, 200/256
@@ -472,7 +472,7 @@ public:
// the creation of the peer SSL context and Peers object into
// the conditional.
//
- m_peers = Peers::New (m_mainIoPool, m_mainIoPool, m_peerSSLContext->get ());
+ m_peers = add (Peers::New (m_mainIoPool, m_mainIoPool, m_peerSSLContext->get ()));
// If we're not in standalone mode,
// prepare ourselves for networking
@@ -642,8 +642,6 @@ public:
void onPrepare ()
{
- m_rpcServiceManager->add (*m_validators);
-
prepareValidators ();
}
@@ -670,7 +668,15 @@ public:
stopped ();
}
+ //------------------------------------------------------------------------------
//
+ // PropertyStream
+ //
+
+ void onWrite (PropertyStream stream)
+ {
+ }
+
//------------------------------------------------------------------------------
void run ()
@@ -1201,6 +1207,11 @@ ApplicationImp* ApplicationImp::s_instance;
//------------------------------------------------------------------------------
+Application::Application ()
+ : PropertyStream::Source ("app")
+{
+}
+
Application* Application::New ()
{
return new ApplicationImp;
diff --git a/src/ripple_app/main/Application.h b/src/ripple_app/main/Application.h
index 0db7b24225..f19ffbcb0f 100644
--- a/src/ripple_app/main/Application.h
+++ b/src/ripple_app/main/Application.h
@@ -49,7 +49,7 @@ class DatabaseCon;
typedef TaggedCacheType NodeCache;
typedef TaggedCacheType SLECache;
-class Application
+class Application : public PropertyStream::Source
{
public:
/* VFALCO NOTE
@@ -68,24 +68,11 @@ public:
virtual LockType& getMasterLock () = 0;
-public:
- struct State
- {
- // Stuff in here is accessed concurrently and requires a Access
- };
-
- typedef SharedData SharedState;
-
- SharedState& getSharedState () noexcept { return m_sharedState; }
-
- SharedState const& getSharedState () const noexcept { return m_sharedState; }
-
-private:
- SharedState m_sharedState;
-
public:
static Application* New ();
+ Application ();
+
virtual ~Application () { }
virtual boost::asio::io_service& getIOService () = 0;
@@ -97,7 +84,7 @@ public:
virtual IFeatures& getFeatureTable () = 0;
virtual IFeeVote& getFeeVote () = 0;
virtual IHashRouter& getHashRouter () = 0;
- virtual LoadFeeTrack& getFeeTrack () = 0;
+ virtual LoadFeeTrack& getFeeTrack () = 0;
virtual LoadManager& getLoadManager () = 0;
virtual Peers& getPeers () = 0;
virtual ProofOfWorkFactory& getProofOfWorkFactory () = 0;
diff --git a/src/ripple_app/peers/Peers.cpp b/src/ripple_app/peers/Peers.cpp
index 015f580196..8581729d47 100644
--- a/src/ripple_app/peers/Peers.cpp
+++ b/src/ripple_app/peers/Peers.cpp
@@ -91,8 +91,8 @@ public:
boost::asio::io_service& io_service,
boost::asio::ssl::context& ssl_context)
: Stoppable ("Peers", parent)
- , m_peerFinder (PeerFinder::Manager::New (
- *this, *this, LogJournal::get ()))
+ , m_peerFinder (add (PeerFinder::Manager::New (
+ *this, *this, LogJournal::get ())))
, m_io_service (io_service)
, m_ssl_context (ssl_context)
, mPeerLock (this, "PeersImp", __FILE__, __LINE__)
@@ -223,6 +223,15 @@ public:
stopped();
}
+ //--------------------------------------------------------------------------
+ //
+ // PropertyStream
+ //
+
+ void onWrite (PropertyStream stream)
+ {
+ }
+
//--------------------------------------------------------------------------
PeerFinder::Manager& getPeerFinder()
@@ -1078,6 +1087,11 @@ void PeersImp::scanRefresh ()
//------------------------------------------------------------------------------
+Peers::Peers ()
+ : PropertyStream::Source ("peers")
+{
+}
+
Peers* Peers::New (Stoppable& parent,
boost::asio::io_service& io_service,
boost::asio::ssl::context& ssl_context)
diff --git a/src/ripple_app/peers/Peers.h b/src/ripple_app/peers/Peers.h
index 3614cf070a..7d38492162 100644
--- a/src/ripple_app/peers/Peers.h
+++ b/src/ripple_app/peers/Peers.h
@@ -25,13 +25,15 @@ class Manager;
}
/** Manages the set of connected peers. */
-class Peers
+class Peers : public PropertyStream::Source
{
public:
static Peers* New (Stoppable& parent,
boost::asio::io_service& io_service,
boost::asio::ssl::context& context);
+ Peers ();
+
virtual ~Peers () { }
virtual PeerFinder::Manager& getPeerFinder() = 0;
diff --git a/src/ripple_app/rpc/RPCHandler.cpp b/src/ripple_app/rpc/RPCHandler.cpp
index 6dacc5b1d7..54215dbdb7 100644
--- a/src/ripple_app/rpc/RPCHandler.cpp
+++ b/src/ripple_app/rpc/RPCHandler.cpp
@@ -810,6 +810,24 @@ Json::Value RPCHandler::doPing (Json::Value, LoadType* loadType, Application::Sc
return Json::Value (Json::objectValue);
}
+Json::Value RPCHandler::doPrint (Json::Value params, LoadType* loadType, Application::ScopedLockType& masterLockHolder)
+{
+ masterLockHolder.unlock ();
+
+ Json::Value result (Json::objectValue);
+ JsonPropertyStreamSink sink (result);
+ if (params.isObject() && params["params"].isArray() && params["params"][0u].isString ())
+ {
+ getApp().write (params["params"][0u].asString(), sink);
+ }
+ else
+ {
+ getApp().write (sink, true);
+ }
+
+ return result;
+}
+
// profile offers [submit]
// profile 0:offers 1:pass_a 2:account_a 3:currency_offer_a 4:account_b 5:currency_offer_b 6: 7:[submit]
// issuer is the offering account
@@ -3822,12 +3840,13 @@ Json::Value RPCHandler::doCommand (const Json::Value& params, int iRole, LoadTyp
{ "ledger_header", &RPCHandler::doLedgerHeader, false, optCurrent },
{ "log_level", &RPCHandler::doLogLevel, true, optNone },
{ "logrotate", &RPCHandler::doLogRotate, true, optNone },
- // { "nickname_info", &RPCHandler::doNicknameInfo, false, optCurrent },
+// { "nickname_info", &RPCHandler::doNicknameInfo, false, optCurrent },
{ "owner_info", &RPCHandler::doOwnerInfo, false, optCurrent },
{ "peers", &RPCHandler::doPeers, true, optNone },
{ "path_find", &RPCHandler::doPathFind, false, optCurrent },
{ "ping", &RPCHandler::doPing, false, optNone },
- // { "profile", &RPCHandler::doProfile, false, optCurrent },
+ { "print", &RPCHandler::doPrint, true, optNone },
+// { "profile", &RPCHandler::doProfile, false, optCurrent },
{ "proof_create", &RPCHandler::doProofCreate, true, optNone },
{ "proof_solve", &RPCHandler::doProofSolve, true, optNone },
{ "proof_verify", &RPCHandler::doProofVerify, true, optNone },
@@ -3842,7 +3861,6 @@ Json::Value RPCHandler::doCommand (const Json::Value& params, int iRole, LoadTyp
{ "transaction_entry", &RPCHandler::doTransactionEntry, false, optCurrent },
{ "tx", &RPCHandler::doTx, false, optNetwork },
{ "tx_history", &RPCHandler::doTxHistory, false, optNone },
-
{ "unl_add", &RPCHandler::doUnlAdd, true, optNone },
{ "unl_delete", &RPCHandler::doUnlDelete, true, optNone },
{ "unl_list", &RPCHandler::doUnlList, true, optNone },
@@ -3850,10 +3868,8 @@ Json::Value RPCHandler::doCommand (const Json::Value& params, int iRole, LoadTyp
{ "unl_network", &RPCHandler::doUnlNetwork, true, optNone },
{ "unl_reset", &RPCHandler::doUnlReset, true, optNone },
{ "unl_score", &RPCHandler::doUnlScore, true, optNone },
-
{ "validation_create", &RPCHandler::doValidationCreate, true, optNone },
{ "validation_seed", &RPCHandler::doValidationSeed, true, optNone },
-
{ "wallet_accounts", &RPCHandler::doWalletAccounts, false, optCurrent },
{ "wallet_propose", &RPCHandler::doWalletPropose, true, optNone },
{ "wallet_seed", &RPCHandler::doWalletSeed, true, optNone },
diff --git a/src/ripple_app/rpc/RPCHandler.h b/src/ripple_app/rpc/RPCHandler.h
index 28818958a3..98341554e8 100644
--- a/src/ripple_app/rpc/RPCHandler.h
+++ b/src/ripple_app/rpc/RPCHandler.h
@@ -122,6 +122,7 @@ private:
Json::Value doPathFind (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doPeers (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doPing (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
+ Json::Value doPrint (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doProfile (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doProofCreate (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doProofSolve (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
diff --git a/src/ripple_net/rpc/RPCCall.cpp b/src/ripple_net/rpc/RPCCall.cpp
index 3db57cdac4..1993cb19c0 100644
--- a/src/ripple_net/rpc/RPCCall.cpp
+++ b/src/ripple_net/rpc/RPCCall.cpp
@@ -849,15 +849,16 @@ public:
{ "ledger_accept", &RPCParser::parseAsIs, 0, 0 },
{ "ledger_closed", &RPCParser::parseAsIs, 0, 0 },
{ "ledger_current", &RPCParser::parseAsIs, 0, 0 },
- // { "ledger_entry", &RPCParser::parseLedgerEntry, -1, -1 },
+ // { "ledger_entry", &RPCParser::parseLedgerEntry, -1, -1 },
{ "ledger_header", &RPCParser::parseLedgerId, 1, 1 },
{ "log_level", &RPCParser::parseLogLevel, 0, 2 },
{ "logrotate", &RPCParser::parseAsIs, 0, 0 },
- // { "nickname_info", &RPCParser::parseNicknameInfo, 1, 1 },
+ // { "nickname_info", &RPCParser::parseNicknameInfo, 1, 1 },
{ "owner_info", &RPCParser::parseAccountItems, 1, 2 },
{ "peers", &RPCParser::parseAsIs, 0, 0 },
{ "ping", &RPCParser::parseAsIs, 0, 0 },
- // { "profile", &RPCParser::parseProfile, 1, 9 },
+ { "print", &RPCParser::parseAsIs, 0, 1 },
+ // { "profile", &RPCParser::parseProfile, 1, 9 },
{ "proof_create", &RPCParser::parseProofCreate, 0, 2 },
{ "proof_solve", &RPCParser::parseProofSolve, 1, 1 },
{ "proof_verify", &RPCParser::parseProofVerify, 2, 4 },
@@ -869,11 +870,10 @@ public:
{ "server_info", &RPCParser::parseAsIs, 0, 0 },
{ "server_state", &RPCParser::parseAsIs, 0, 0 },
{ "stop", &RPCParser::parseAsIs, 0, 0 },
- // { "transaction_entry", &RPCParser::parseTransactionEntry, -1, -1 },
+ // { "transaction_entry", &RPCParser::parseTransactionEntry, -1, -1 },
{ "tx", &RPCParser::parseTx, 1, 2 },
{ "tx_account", &RPCParser::parseTxAccount, 1, 7 },
{ "tx_history", &RPCParser::parseTxHistory, 1, 1 },
-
{ "unl_add", &RPCParser::parseUnlAdd, 1, 2 },
{ "unl_delete", &RPCParser::parseUnlDelete, 1, 1 },
{ "unl_list", &RPCParser::parseAsIs, 0, 0 },
@@ -881,14 +881,11 @@ public:
{ "unl_network", &RPCParser::parseAsIs, 0, 0 },
{ "unl_reset", &RPCParser::parseAsIs, 0, 0 },
{ "unl_score", &RPCParser::parseAsIs, 0, 0 },
-
{ "validation_create", &RPCParser::parseValidationCreate, 0, 1 },
{ "validation_seed", &RPCParser::parseValidationSeed, 0, 1 },
-
{ "wallet_accounts", &RPCParser::parseWalletAccounts, 1, 1 },
{ "wallet_propose", &RPCParser::parseWalletPropose, 0, 1 },
{ "wallet_seed", &RPCParser::parseWalletSeed, 0, 1 },
-
{ "internal", &RPCParser::parseInternal, 1, -1 },
#if ENABLE_INSECURE