mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-22 19:00:01 +08:00
添加完整的服务器用例
This commit is contained in:
parent
49d778af99
commit
2f6773f180
53
3rdpart/jsoncpp/assertions.h
Normal file
53
3rdpart/jsoncpp/assertions.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// Copyright 2007-2010 Baptiste Lepilleur
|
||||||
|
// Distributed under MIT license, or public domain if desired and
|
||||||
|
// recognized in your jurisdiction.
|
||||||
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
|
#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED
|
||||||
|
#define CPPTL_JSON_ASSERTIONS_H_INCLUDED
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
#include "../jsoncpp/config.h"
|
||||||
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
|
||||||
|
/** It should not be possible for a maliciously designed file to
|
||||||
|
* cause an abort() or seg-fault, so these macros are used only
|
||||||
|
* for pre-condition violations and internal logic errors.
|
||||||
|
*/
|
||||||
|
#if JSON_USE_EXCEPTION
|
||||||
|
|
||||||
|
// @todo <= add detail about condition in exception
|
||||||
|
# define JSON_ASSERT(condition) \
|
||||||
|
{if (!(condition)) {Json::throwLogicError( "assert json failed" );}}
|
||||||
|
|
||||||
|
# define JSON_FAIL_MESSAGE(message) \
|
||||||
|
{ \
|
||||||
|
std::ostringstream oss; oss << message; \
|
||||||
|
Json::throwLogicError(oss.str()); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // JSON_USE_EXCEPTION
|
||||||
|
|
||||||
|
# define JSON_ASSERT(condition) assert(condition)
|
||||||
|
|
||||||
|
// The call to assert() will show the failure message in debug builds. In
|
||||||
|
// release builds we abort, for a core-dump or debugger.
|
||||||
|
# define JSON_FAIL_MESSAGE(message) \
|
||||||
|
{ \
|
||||||
|
std::ostringstream oss; oss << message; \
|
||||||
|
assert(false && oss.str().c_str()); \
|
||||||
|
abort(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define JSON_ASSERT_MESSAGE(condition, message) \
|
||||||
|
if (!(condition)) { \
|
||||||
|
JSON_FAIL_MESSAGE(message); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED
|
25
3rdpart/jsoncpp/autolink.h
Normal file
25
3rdpart/jsoncpp/autolink.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2007-2010 Baptiste Lepilleur
|
||||||
|
// Distributed under MIT license, or public domain if desired and
|
||||||
|
// recognized in your jurisdiction.
|
||||||
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
|
#ifndef JSON_AUTOLINK_H_INCLUDED
|
||||||
|
#define JSON_AUTOLINK_H_INCLUDED
|
||||||
|
|
||||||
|
#include "../jsoncpp/config.h"
|
||||||
|
|
||||||
|
#ifdef JSON_IN_CPPTL
|
||||||
|
#include <cpptl/cpptl_autolink.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && \
|
||||||
|
!defined(JSON_IN_CPPTL)
|
||||||
|
#define CPPTL_AUTOLINK_NAME "json"
|
||||||
|
#undef CPPTL_AUTOLINK_DLL
|
||||||
|
#ifdef JSON_DLL
|
||||||
|
#define CPPTL_AUTOLINK_DLL
|
||||||
|
#endif
|
||||||
|
#include "autolink.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // JSON_AUTOLINK_H_INCLUDED
|
109
3rdpart/jsoncpp/config.h
Normal file
109
3rdpart/jsoncpp/config.h
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
// Copyright 2007-2010 Baptiste Lepilleur
|
||||||
|
// Distributed under MIT license, or public domain if desired and
|
||||||
|
// recognized in your jurisdiction.
|
||||||
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
|
#ifndef JSON_CONFIG_H_INCLUDED
|
||||||
|
#define JSON_CONFIG_H_INCLUDED
|
||||||
|
|
||||||
|
/// If defined, indicates that json library is embedded in CppTL library.
|
||||||
|
//# define JSON_IN_CPPTL 1
|
||||||
|
|
||||||
|
/// If defined, indicates that json may leverage CppTL library
|
||||||
|
//# define JSON_USE_CPPTL 1
|
||||||
|
/// If defined, indicates that cpptl vector based map should be used instead of
|
||||||
|
/// std::map
|
||||||
|
/// as Value container.
|
||||||
|
//# define JSON_USE_CPPTL_SMALLMAP 1
|
||||||
|
|
||||||
|
// If non-zero, the library uses exceptions to report bad input instead of C
|
||||||
|
// assertion macros. The default is to use exceptions.
|
||||||
|
#ifndef JSON_USE_EXCEPTION
|
||||||
|
#define JSON_USE_EXCEPTION 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// If defined, indicates that the source file is amalgated
|
||||||
|
/// to prevent private header inclusion.
|
||||||
|
/// Remarks: it is automatically defined in the generated amalgated header.
|
||||||
|
// #define JSON_IS_AMALGAMATION
|
||||||
|
|
||||||
|
#ifdef JSON_IN_CPPTL
|
||||||
|
#include <cpptl/config.h>
|
||||||
|
#ifndef JSON_USE_CPPTL
|
||||||
|
#define JSON_USE_CPPTL 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JSON_IN_CPPTL
|
||||||
|
#define JSON_API CPPTL_API
|
||||||
|
#elif defined(JSON_DLL_BUILD)
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#define JSON_API __declspec(dllexport)
|
||||||
|
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
||||||
|
#endif // if defined(_MSC_VER)
|
||||||
|
#elif defined(JSON_DLL)
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#define JSON_API __declspec(dllimport)
|
||||||
|
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
|
||||||
|
#endif // if defined(_MSC_VER)
|
||||||
|
#endif // ifdef JSON_IN_CPPTL
|
||||||
|
#if !defined(JSON_API)
|
||||||
|
#define JSON_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
|
||||||
|
// integer
|
||||||
|
// Storages, and 64 bits integer support is disabled.
|
||||||
|
// #define JSON_NO_INT64 1
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6
|
||||||
|
// Microsoft Visual Studio 6 only support conversion from __int64 to double
|
||||||
|
// (no conversion from unsigned __int64).
|
||||||
|
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
|
||||||
|
// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
|
||||||
|
// characters in the debug information)
|
||||||
|
// All projects I've ever seen with VS6 were using this globally (not bothering
|
||||||
|
// with pragma push/pop).
|
||||||
|
#pragma warning(disable : 4786)
|
||||||
|
#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008
|
||||||
|
/// Indicates that the following function is deprecated.
|
||||||
|
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
|
||||||
|
#elif defined(__clang__) && defined(__has_feature)
|
||||||
|
#if __has_feature(attribute_deprecated_with_message)
|
||||||
|
#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message)))
|
||||||
|
#endif
|
||||||
|
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
|
||||||
|
#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message)))
|
||||||
|
#elif defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||||
|
#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(JSONCPP_DEPRECATED)
|
||||||
|
#define JSONCPP_DEPRECATED(message)
|
||||||
|
#endif // if !defined(JSONCPP_DEPRECATED)
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
typedef int Int;
|
||||||
|
typedef unsigned int UInt;
|
||||||
|
#if defined(JSON_NO_INT64)
|
||||||
|
typedef int LargestInt;
|
||||||
|
typedef unsigned int LargestUInt;
|
||||||
|
#undef JSON_HAS_INT64
|
||||||
|
#else // if defined(JSON_NO_INT64)
|
||||||
|
// For Microsoft Visual use specific types as long long is not supported
|
||||||
|
#if defined(_MSC_VER) // Microsoft Visual Studio
|
||||||
|
typedef __int64 Int64;
|
||||||
|
typedef unsigned __int64 UInt64;
|
||||||
|
#else // if defined(_MSC_VER) // Other platforms, use long long
|
||||||
|
typedef long long int Int64;
|
||||||
|
typedef unsigned long long int UInt64;
|
||||||
|
#endif // if defined(_MSC_VER)
|
||||||
|
typedef Int64 LargestInt;
|
||||||
|
typedef UInt64 LargestUInt;
|
||||||
|
#define JSON_HAS_INT64
|
||||||
|
#endif // if defined(JSON_NO_INT64)
|
||||||
|
} // end namespace Json
|
||||||
|
|
||||||
|
#endif // JSON_CONFIG_H_INCLUDED
|
57
3rdpart/jsoncpp/features.h
Normal file
57
3rdpart/jsoncpp/features.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2007-2010 Baptiste Lepilleur
|
||||||
|
// Distributed under MIT license, or public domain if desired and
|
||||||
|
// recognized in your jurisdiction.
|
||||||
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
|
#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
|
||||||
|
#define CPPTL_JSON_FEATURES_H_INCLUDED
|
||||||
|
|
||||||
|
#if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
#include "../jsoncpp/forwards.h"
|
||||||
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
/** \brief Configuration passed to reader and writer.
|
||||||
|
* This configuration object can be used to force the Reader or Writer
|
||||||
|
* to behave in a standard conforming way.
|
||||||
|
*/
|
||||||
|
class JSON_API Features {
|
||||||
|
public:
|
||||||
|
/** \brief A configuration that allows all features and assumes all strings
|
||||||
|
* are UTF-8.
|
||||||
|
* - C & C++ comments are allowed
|
||||||
|
* - Root object can be any JSON value
|
||||||
|
* - Assumes Value strings are encoded in UTF-8
|
||||||
|
*/
|
||||||
|
static Features all();
|
||||||
|
|
||||||
|
/** \brief A configuration that is strictly compatible with the JSON
|
||||||
|
* specification.
|
||||||
|
* - Comments are forbidden.
|
||||||
|
* - Root object must be either an array or an object value.
|
||||||
|
* - Assumes Value strings are encoded in UTF-8
|
||||||
|
*/
|
||||||
|
static Features strictMode();
|
||||||
|
|
||||||
|
/** \brief Initialize the configuration like JsonConfig::allFeatures;
|
||||||
|
*/
|
||||||
|
Features();
|
||||||
|
|
||||||
|
/// \c true if comments are allowed. Default: \c true.
|
||||||
|
bool allowComments_;
|
||||||
|
|
||||||
|
/// \c true if root must be either an array or an object value. Default: \c
|
||||||
|
/// false.
|
||||||
|
bool strictRoot_;
|
||||||
|
|
||||||
|
/// \c true if dropped null placeholders are allowed. Default: \c false.
|
||||||
|
bool allowDroppedNullPlaceholders_;
|
||||||
|
|
||||||
|
/// \c true if numeric object key are allowed. Default: \c false.
|
||||||
|
bool allowNumericKeys_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Json
|
||||||
|
|
||||||
|
#endif // CPPTL_JSON_FEATURES_H_INCLUDED
|
37
3rdpart/jsoncpp/forwards.h
Normal file
37
3rdpart/jsoncpp/forwards.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2007-2010 Baptiste Lepilleur
|
||||||
|
// Distributed under MIT license, or public domain if desired and
|
||||||
|
// recognized in your jurisdiction.
|
||||||
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
|
#ifndef JSON_FORWARDS_H_INCLUDED
|
||||||
|
#define JSON_FORWARDS_H_INCLUDED
|
||||||
|
|
||||||
|
#if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
#include "config.h"
|
||||||
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
// writer.h
|
||||||
|
class FastWriter;
|
||||||
|
class StyledWriter;
|
||||||
|
|
||||||
|
// reader.h
|
||||||
|
class Reader;
|
||||||
|
|
||||||
|
// features.h
|
||||||
|
class Features;
|
||||||
|
|
||||||
|
// value.h
|
||||||
|
typedef unsigned int ArrayIndex;
|
||||||
|
class StaticString;
|
||||||
|
class Path;
|
||||||
|
class PathArgument;
|
||||||
|
class Value;
|
||||||
|
class ValueIteratorBase;
|
||||||
|
class ValueIterator;
|
||||||
|
class ValueConstIterator;
|
||||||
|
|
||||||
|
} // namespace Json
|
||||||
|
|
||||||
|
#endif // JSON_FORWARDS_H_INCLUDED
|
15
3rdpart/jsoncpp/json.h
Normal file
15
3rdpart/jsoncpp/json.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2007-2010 Baptiste Lepilleur
|
||||||
|
// Distributed under MIT license, or public domain if desired and
|
||||||
|
// recognized in your jurisdiction.
|
||||||
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
|
#ifndef JSON_JSON_H_INCLUDED
|
||||||
|
#define JSON_JSON_H_INCLUDED
|
||||||
|
|
||||||
|
#include "autolink.h"
|
||||||
|
#include "features.h"
|
||||||
|
#include "reader.h"
|
||||||
|
#include "writer.h"
|
||||||
|
#include "value.h"
|
||||||
|
|
||||||
|
#endif // JSON_JSON_H_INCLUDED
|
1979
3rdpart/jsoncpp/json_reader.cpp
Normal file
1979
3rdpart/jsoncpp/json_reader.cpp
Normal file
File diff suppressed because it is too large
Load Diff
87
3rdpart/jsoncpp/json_tool.h
Normal file
87
3rdpart/jsoncpp/json_tool.h
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// Copyright 2007-2010 Baptiste Lepilleur
|
||||||
|
// Distributed under MIT license, or public domain if desired and
|
||||||
|
// recognized in your jurisdiction.
|
||||||
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
|
#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
||||||
|
#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
||||||
|
|
||||||
|
/* This header provides common string manipulation support, such as UTF-8,
|
||||||
|
* portable conversion from/to string...
|
||||||
|
*
|
||||||
|
* It is an internal header that must not be exposed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
/// Converts a unicode code-point to UTF-8.
|
||||||
|
static inline std::string codePointToUTF8(unsigned int cp) {
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
// based on description from http://en.wikipedia.org/wiki/UTF-8
|
||||||
|
|
||||||
|
if (cp <= 0x7f) {
|
||||||
|
result.resize(1);
|
||||||
|
result[0] = static_cast<char>(cp);
|
||||||
|
} else if (cp <= 0x7FF) {
|
||||||
|
result.resize(2);
|
||||||
|
result[1] = static_cast<char>(0x80 | (0x3f & cp));
|
||||||
|
result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
|
||||||
|
} else if (cp <= 0xFFFF) {
|
||||||
|
result.resize(3);
|
||||||
|
result[2] = static_cast<char>(0x80 | (0x3f & cp));
|
||||||
|
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
|
||||||
|
result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));
|
||||||
|
} else if (cp <= 0x10FFFF) {
|
||||||
|
result.resize(4);
|
||||||
|
result[3] = static_cast<char>(0x80 | (0x3f & cp));
|
||||||
|
result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
|
||||||
|
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
|
||||||
|
result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if ch is a control character (in range [1,31]).
|
||||||
|
static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; }
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/// Constant that specify the size of the buffer that must be passed to
|
||||||
|
/// uintToString.
|
||||||
|
uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
|
||||||
|
};
|
||||||
|
|
||||||
|
// Defines a char buffer for use with uintToString().
|
||||||
|
typedef char UIntToStringBuffer[uintToStringBufferSize];
|
||||||
|
|
||||||
|
/** Converts an unsigned integer to string.
|
||||||
|
* @param value Unsigned interger to convert to string
|
||||||
|
* @param current Input/Output string buffer.
|
||||||
|
* Must have at least uintToStringBufferSize chars free.
|
||||||
|
*/
|
||||||
|
static inline void uintToString(LargestUInt value, char*& current) {
|
||||||
|
*--current = 0;
|
||||||
|
do {
|
||||||
|
*--current = static_cast<signed char>(value % 10U + static_cast<unsigned>('0'));
|
||||||
|
value /= 10;
|
||||||
|
} while (value != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Change ',' to '.' everywhere in buffer.
|
||||||
|
*
|
||||||
|
* We had a sophisticated way, but it did not work in WinCE.
|
||||||
|
* @see https://github.com/open-source-parsers/jsoncpp/pull/9
|
||||||
|
*/
|
||||||
|
static inline void fixNumericLocale(char* begin, char* end) {
|
||||||
|
while (begin < end) {
|
||||||
|
if (*begin == ',') {
|
||||||
|
*begin = '.';
|
||||||
|
}
|
||||||
|
++begin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Json {
|
||||||
|
|
||||||
|
#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
1594
3rdpart/jsoncpp/json_value.cpp
Normal file
1594
3rdpart/jsoncpp/json_value.cpp
Normal file
File diff suppressed because it is too large
Load Diff
162
3rdpart/jsoncpp/json_valueiterator.inl
Normal file
162
3rdpart/jsoncpp/json_valueiterator.inl
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
// Copyright 2007-2010 Baptiste Lepilleur
|
||||||
|
// Distributed under MIT license, or public domain if desired and
|
||||||
|
// recognized in your jurisdiction.
|
||||||
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
|
// included by json_value.cpp
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// class ValueIteratorBase
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ValueIteratorBase::ValueIteratorBase()
|
||||||
|
: current_(), isNull_(true) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueIteratorBase::ValueIteratorBase(
|
||||||
|
const Value::ObjectValues::iterator& current)
|
||||||
|
: current_(current), isNull_(false) {}
|
||||||
|
|
||||||
|
Value& ValueIteratorBase::deref() const {
|
||||||
|
return current_->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueIteratorBase::increment() {
|
||||||
|
++current_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueIteratorBase::decrement() {
|
||||||
|
--current_;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueIteratorBase::difference_type
|
||||||
|
ValueIteratorBase::computeDistance(const SelfType& other) const {
|
||||||
|
#ifdef JSON_USE_CPPTL_SMALLMAP
|
||||||
|
return other.current_ - current_;
|
||||||
|
#else
|
||||||
|
// Iterator for null value are initialized using the default
|
||||||
|
// constructor, which initialize current_ to the default
|
||||||
|
// std::map::iterator. As begin() and end() are two instance
|
||||||
|
// of the default std::map::iterator, they can not be compared.
|
||||||
|
// To allow this, we handle this comparison specifically.
|
||||||
|
if (isNull_ && other.isNull_) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage of std::distance is not portable (does not compile with Sun Studio 12
|
||||||
|
// RogueWave STL,
|
||||||
|
// which is the one used by default).
|
||||||
|
// Using a portable hand-made version for non random iterator instead:
|
||||||
|
// return difference_type( std::distance( current_, other.current_ ) );
|
||||||
|
difference_type myDistance = 0;
|
||||||
|
for (Value::ObjectValues::iterator it = current_; it != other.current_;
|
||||||
|
++it) {
|
||||||
|
++myDistance;
|
||||||
|
}
|
||||||
|
return myDistance;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ValueIteratorBase::isEqual(const SelfType& other) const {
|
||||||
|
if (isNull_) {
|
||||||
|
return other.isNull_;
|
||||||
|
}
|
||||||
|
return current_ == other.current_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueIteratorBase::copy(const SelfType& other) {
|
||||||
|
current_ = other.current_;
|
||||||
|
isNull_ = other.isNull_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value ValueIteratorBase::key() const {
|
||||||
|
const Value::CZString czstring = (*current_).first;
|
||||||
|
if (czstring.data()) {
|
||||||
|
if (czstring.isStaticString())
|
||||||
|
return Value(StaticString(czstring.data()));
|
||||||
|
return Value(czstring.data(), czstring.data() + czstring.length());
|
||||||
|
}
|
||||||
|
return Value(czstring.index());
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt ValueIteratorBase::index() const {
|
||||||
|
const Value::CZString czstring = (*current_).first;
|
||||||
|
if (!czstring.data())
|
||||||
|
return czstring.index();
|
||||||
|
return Value::UInt(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ValueIteratorBase::name() const {
|
||||||
|
char const* keey;
|
||||||
|
char const* end;
|
||||||
|
keey = memberName(&end);
|
||||||
|
if (!keey) return std::string();
|
||||||
|
return std::string(keey, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
char const* ValueIteratorBase::memberName() const {
|
||||||
|
const char* cname = (*current_).first.data();
|
||||||
|
return cname ? cname : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
char const* ValueIteratorBase::memberName(char const** end) const {
|
||||||
|
const char* cname = (*current_).first.data();
|
||||||
|
if (!cname) {
|
||||||
|
*end = NULL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*end = cname + (*current_).first.length();
|
||||||
|
return cname;
|
||||||
|
}
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// class ValueConstIterator
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ValueConstIterator::ValueConstIterator() {}
|
||||||
|
|
||||||
|
ValueConstIterator::ValueConstIterator(
|
||||||
|
const Value::ObjectValues::iterator& current)
|
||||||
|
: ValueIteratorBase(current) {}
|
||||||
|
|
||||||
|
ValueConstIterator& ValueConstIterator::
|
||||||
|
operator=(const ValueIteratorBase& other) {
|
||||||
|
copy(other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// class ValueIterator
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ValueIterator::ValueIterator() {}
|
||||||
|
|
||||||
|
ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
|
||||||
|
: ValueIteratorBase(current) {}
|
||||||
|
|
||||||
|
ValueIterator::ValueIterator(const ValueConstIterator& other)
|
||||||
|
: ValueIteratorBase(other) {}
|
||||||
|
|
||||||
|
ValueIterator::ValueIterator(const ValueIterator& other)
|
||||||
|
: ValueIteratorBase(other) {}
|
||||||
|
|
||||||
|
ValueIterator& ValueIterator::operator=(const SelfType& other) {
|
||||||
|
copy(other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Json
|
1182
3rdpart/jsoncpp/json_writer.cpp
Normal file
1182
3rdpart/jsoncpp/json_writer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
401
3rdpart/jsoncpp/reader.h
Normal file
401
3rdpart/jsoncpp/reader.h
Normal file
@ -0,0 +1,401 @@
|
|||||||
|
// Copyright 2007-2010 Baptiste Lepilleur
|
||||||
|
// Distributed under MIT license, or public domain if desired and
|
||||||
|
// recognized in your jurisdiction.
|
||||||
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
|
#ifndef CPPTL_JSON_READER_H_INCLUDED
|
||||||
|
#define CPPTL_JSON_READER_H_INCLUDED
|
||||||
|
|
||||||
|
#if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
#include "../jsoncpp/features.h"
|
||||||
|
#include "../jsoncpp/value.h"
|
||||||
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
#include <deque>
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <stack>
|
||||||
|
#include <string>
|
||||||
|
#include <istream>
|
||||||
|
|
||||||
|
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
||||||
|
// be used by...
|
||||||
|
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4251)
|
||||||
|
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
|
||||||
|
*Value.
|
||||||
|
*
|
||||||
|
* \deprecated Use CharReader and CharReaderBuilder.
|
||||||
|
*/
|
||||||
|
class JSON_API Reader {
|
||||||
|
public:
|
||||||
|
typedef char Char;
|
||||||
|
typedef const Char* Location;
|
||||||
|
|
||||||
|
/** \brief An error tagged with where in the JSON text it was encountered.
|
||||||
|
*
|
||||||
|
* The offsets give the [start, limit) range of bytes within the text. Note
|
||||||
|
* that this is bytes, not codepoints.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct StructuredError {
|
||||||
|
size_t offset_start;
|
||||||
|
size_t offset_limit;
|
||||||
|
std::string message;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Constructs a Reader allowing all features
|
||||||
|
* for parsing.
|
||||||
|
*/
|
||||||
|
Reader();
|
||||||
|
|
||||||
|
/** \brief Constructs a Reader allowing the specified feature set
|
||||||
|
* for parsing.
|
||||||
|
*/
|
||||||
|
Reader(const Features& features);
|
||||||
|
|
||||||
|
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||||
|
* document.
|
||||||
|
* \param document UTF-8 encoded string containing the document to read.
|
||||||
|
* \param root [out] Contains the root value of the document if it was
|
||||||
|
* successfully parsed.
|
||||||
|
* \param collectComments \c true to collect comment and allow writing them
|
||||||
|
* back during
|
||||||
|
* serialization, \c false to discard comments.
|
||||||
|
* This parameter is ignored if
|
||||||
|
* Features::allowComments_
|
||||||
|
* is \c false.
|
||||||
|
* \return \c true if the document was successfully parsed, \c false if an
|
||||||
|
* error occurred.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
parse(const std::string& document, Value& root, bool collectComments = true);
|
||||||
|
|
||||||
|
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||||
|
document.
|
||||||
|
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
|
||||||
|
document to read.
|
||||||
|
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
|
||||||
|
document to read.
|
||||||
|
* Must be >= beginDoc.
|
||||||
|
* \param root [out] Contains the root value of the document if it was
|
||||||
|
* successfully parsed.
|
||||||
|
* \param collectComments \c true to collect comment and allow writing them
|
||||||
|
back during
|
||||||
|
* serialization, \c false to discard comments.
|
||||||
|
* This parameter is ignored if
|
||||||
|
Features::allowComments_
|
||||||
|
* is \c false.
|
||||||
|
* \return \c true if the document was successfully parsed, \c false if an
|
||||||
|
error occurred.
|
||||||
|
*/
|
||||||
|
bool parse(const char* beginDoc,
|
||||||
|
const char* endDoc,
|
||||||
|
Value& root,
|
||||||
|
bool collectComments = true);
|
||||||
|
|
||||||
|
/// \brief Parse from input stream.
|
||||||
|
/// \see Json::operator>>(std::istream&, Json::Value&).
|
||||||
|
bool parse(std::istream& is, Value& root, bool collectComments = true);
|
||||||
|
|
||||||
|
/** \brief Returns a user friendly string that list errors in the parsed
|
||||||
|
* document.
|
||||||
|
* \return Formatted error message with the list of errors with their location
|
||||||
|
* in
|
||||||
|
* the parsed document. An empty string is returned if no error
|
||||||
|
* occurred
|
||||||
|
* during parsing.
|
||||||
|
* \deprecated Use getFormattedErrorMessages() instead (typo fix).
|
||||||
|
*/
|
||||||
|
JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.")
|
||||||
|
std::string getFormatedErrorMessages() const;
|
||||||
|
|
||||||
|
/** \brief Returns a user friendly string that list errors in the parsed
|
||||||
|
* document.
|
||||||
|
* \return Formatted error message with the list of errors with their location
|
||||||
|
* in
|
||||||
|
* the parsed document. An empty string is returned if no error
|
||||||
|
* occurred
|
||||||
|
* during parsing.
|
||||||
|
*/
|
||||||
|
std::string getFormattedErrorMessages() const;
|
||||||
|
|
||||||
|
/** \brief Returns a vector of structured erros encounted while parsing.
|
||||||
|
* \return A (possibly empty) vector of StructuredError objects. Currently
|
||||||
|
* only one error can be returned, but the caller should tolerate
|
||||||
|
* multiple
|
||||||
|
* errors. This can occur if the parser recovers from a non-fatal
|
||||||
|
* parse error and then encounters additional errors.
|
||||||
|
*/
|
||||||
|
std::vector<StructuredError> getStructuredErrors() const;
|
||||||
|
|
||||||
|
/** \brief Add a semantic error message.
|
||||||
|
* \param value JSON Value location associated with the error
|
||||||
|
* \param message The error message.
|
||||||
|
* \return \c true if the error was successfully added, \c false if the
|
||||||
|
* Value offset exceeds the document size.
|
||||||
|
*/
|
||||||
|
bool pushError(const Value& value, const std::string& message);
|
||||||
|
|
||||||
|
/** \brief Add a semantic error message with extra context.
|
||||||
|
* \param value JSON Value location associated with the error
|
||||||
|
* \param message The error message.
|
||||||
|
* \param extra Additional JSON Value location to contextualize the error
|
||||||
|
* \return \c true if the error was successfully added, \c false if either
|
||||||
|
* Value offset exceeds the document size.
|
||||||
|
*/
|
||||||
|
bool pushError(const Value& value, const std::string& message, const Value& extra);
|
||||||
|
|
||||||
|
/** \brief Return whether there are any errors.
|
||||||
|
* \return \c true if there are no errors to report \c false if
|
||||||
|
* errors have occurred.
|
||||||
|
*/
|
||||||
|
bool good() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum TokenType {
|
||||||
|
tokenEndOfStream = 0,
|
||||||
|
tokenObjectBegin,
|
||||||
|
tokenObjectEnd,
|
||||||
|
tokenArrayBegin,
|
||||||
|
tokenArrayEnd,
|
||||||
|
tokenString,
|
||||||
|
tokenNumber,
|
||||||
|
tokenTrue,
|
||||||
|
tokenFalse,
|
||||||
|
tokenNull,
|
||||||
|
tokenArraySeparator,
|
||||||
|
tokenMemberSeparator,
|
||||||
|
tokenComment,
|
||||||
|
tokenError
|
||||||
|
};
|
||||||
|
|
||||||
|
class Token {
|
||||||
|
public:
|
||||||
|
TokenType type_;
|
||||||
|
Location start_;
|
||||||
|
Location end_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ErrorInfo {
|
||||||
|
public:
|
||||||
|
Token token_;
|
||||||
|
std::string message_;
|
||||||
|
Location extra_;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::deque<ErrorInfo> Errors;
|
||||||
|
|
||||||
|
bool readToken(Token& token);
|
||||||
|
void skipSpaces();
|
||||||
|
bool match(Location pattern, int patternLength);
|
||||||
|
bool readComment();
|
||||||
|
bool readCStyleComment();
|
||||||
|
bool readCppStyleComment();
|
||||||
|
bool readString();
|
||||||
|
void readNumber();
|
||||||
|
bool readValue();
|
||||||
|
bool readObject(Token& token);
|
||||||
|
bool readArray(Token& token);
|
||||||
|
bool decodeNumber(Token& token);
|
||||||
|
bool decodeNumber(Token& token, Value& decoded);
|
||||||
|
bool decodeString(Token& token);
|
||||||
|
bool decodeString(Token& token, std::string& decoded);
|
||||||
|
bool decodeDouble(Token& token);
|
||||||
|
bool decodeDouble(Token& token, Value& decoded);
|
||||||
|
bool decodeUnicodeCodePoint(Token& token,
|
||||||
|
Location& current,
|
||||||
|
Location end,
|
||||||
|
unsigned int& unicode);
|
||||||
|
bool decodeUnicodeEscapeSequence(Token& token,
|
||||||
|
Location& current,
|
||||||
|
Location end,
|
||||||
|
unsigned int& unicode);
|
||||||
|
bool addError(const std::string& message, Token& token, Location extra = 0);
|
||||||
|
bool recoverFromError(TokenType skipUntilToken);
|
||||||
|
bool addErrorAndRecover(const std::string& message,
|
||||||
|
Token& token,
|
||||||
|
TokenType skipUntilToken);
|
||||||
|
void skipUntilSpace();
|
||||||
|
Value& currentValue();
|
||||||
|
Char getNextChar();
|
||||||
|
void
|
||||||
|
getLocationLineAndColumn(Location location, int& line, int& column) const;
|
||||||
|
std::string getLocationLineAndColumn(Location location) const;
|
||||||
|
void addComment(Location begin, Location end, CommentPlacement placement);
|
||||||
|
void skipCommentTokens(Token& token);
|
||||||
|
|
||||||
|
typedef std::stack<Value*> Nodes;
|
||||||
|
Nodes nodes_;
|
||||||
|
Errors errors_;
|
||||||
|
std::string document_;
|
||||||
|
Location begin_;
|
||||||
|
Location end_;
|
||||||
|
Location current_;
|
||||||
|
Location lastValueEnd_;
|
||||||
|
Value* lastValue_;
|
||||||
|
std::string commentsBefore_;
|
||||||
|
Features features_;
|
||||||
|
bool collectComments_;
|
||||||
|
}; // Reader
|
||||||
|
|
||||||
|
/** Interface for reading JSON from a char array.
|
||||||
|
*/
|
||||||
|
class JSON_API CharReader {
|
||||||
|
public:
|
||||||
|
virtual ~CharReader() {}
|
||||||
|
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||||
|
document.
|
||||||
|
* The document must be a UTF-8 encoded string containing the document to read.
|
||||||
|
*
|
||||||
|
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
|
||||||
|
document to read.
|
||||||
|
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
|
||||||
|
document to read.
|
||||||
|
* Must be >= beginDoc.
|
||||||
|
* \param root [out] Contains the root value of the document if it was
|
||||||
|
* successfully parsed.
|
||||||
|
* \param errs [out] Formatted error messages (if not NULL)
|
||||||
|
* a user friendly string that lists errors in the parsed
|
||||||
|
* document.
|
||||||
|
* \return \c true if the document was successfully parsed, \c false if an
|
||||||
|
error occurred.
|
||||||
|
*/
|
||||||
|
virtual bool parse(
|
||||||
|
char const* beginDoc, char const* endDoc,
|
||||||
|
Value* root, std::string* errs) = 0;
|
||||||
|
|
||||||
|
class Factory {
|
||||||
|
public:
|
||||||
|
virtual ~Factory() {}
|
||||||
|
/** \brief Allocate a CharReader via operator new().
|
||||||
|
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
||||||
|
*/
|
||||||
|
virtual CharReader* newCharReader() const = 0;
|
||||||
|
}; // Factory
|
||||||
|
}; // CharReader
|
||||||
|
|
||||||
|
/** \brief Build a CharReader implementation.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
\code
|
||||||
|
using namespace Json;
|
||||||
|
CharReaderBuilder builder;
|
||||||
|
builder["collectComments"] = false;
|
||||||
|
Value value;
|
||||||
|
std::string errs;
|
||||||
|
bool ok = parseFromStream(builder, std::cin, &value, &errs);
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
class JSON_API CharReaderBuilder : public CharReader::Factory {
|
||||||
|
public:
|
||||||
|
// Note: We use a Json::Value so that we can add data-members to this class
|
||||||
|
// without a major version bump.
|
||||||
|
/** Configuration of this builder.
|
||||||
|
These are case-sensitive.
|
||||||
|
Available settings (case-sensitive):
|
||||||
|
- `"collectComments": false or true`
|
||||||
|
- true to collect comment and allow writing them
|
||||||
|
back during serialization, false to discard comments.
|
||||||
|
This parameter is ignored if allowComments is false.
|
||||||
|
- `"allowComments": false or true`
|
||||||
|
- true if comments are allowed.
|
||||||
|
- `"strictRoot": false or true`
|
||||||
|
- true if root must be either an array or an object value
|
||||||
|
- `"allowDroppedNullPlaceholders": false or true`
|
||||||
|
- true if dropped null placeholders are allowed. (See StreamWriterBuilder.)
|
||||||
|
- `"allowNumericKeys": false or true`
|
||||||
|
- true if numeric object keys are allowed.
|
||||||
|
- `"allowSingleQuotes": false or true`
|
||||||
|
- true if '' are allowed for strings (both keys and values)
|
||||||
|
- `"stackLimit": integer`
|
||||||
|
- Exceeding stackLimit (recursive depth of `readValue()`) will
|
||||||
|
cause an exception.
|
||||||
|
- This is a security issue (seg-faults caused by deeply nested JSON),
|
||||||
|
so the default is low.
|
||||||
|
- `"failIfExtra": false or true`
|
||||||
|
- If true, `parse()` returns false when extra non-whitespace trails
|
||||||
|
the JSON value in the input string.
|
||||||
|
- `"rejectDupKeys": false or true`
|
||||||
|
- If true, `parse()` returns false when a key is duplicated within an object.
|
||||||
|
|
||||||
|
You can examine 'settings_` yourself
|
||||||
|
to see the defaults. You can also write and read them just like any
|
||||||
|
JSON Value.
|
||||||
|
\sa setDefaults()
|
||||||
|
*/
|
||||||
|
Json::Value settings_;
|
||||||
|
|
||||||
|
CharReaderBuilder();
|
||||||
|
virtual ~CharReaderBuilder();
|
||||||
|
|
||||||
|
virtual CharReader* newCharReader() const;
|
||||||
|
|
||||||
|
/** \return true if 'settings' are legal and consistent;
|
||||||
|
* otherwise, indicate bad settings via 'invalid'.
|
||||||
|
*/
|
||||||
|
bool validate(Json::Value* invalid) const;
|
||||||
|
|
||||||
|
/** A simple way to update a specific setting.
|
||||||
|
*/
|
||||||
|
Value& operator[](std::string key);
|
||||||
|
|
||||||
|
/** Called by ctor, but you can use this to reset settings_.
|
||||||
|
* \pre 'settings' != NULL (but Json::null is fine)
|
||||||
|
* \remark Defaults:
|
||||||
|
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults
|
||||||
|
*/
|
||||||
|
static void setDefaults(Json::Value* settings);
|
||||||
|
/** Same as old Features::strictMode().
|
||||||
|
* \pre 'settings' != NULL (but Json::null is fine)
|
||||||
|
* \remark Defaults:
|
||||||
|
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
|
||||||
|
*/
|
||||||
|
static void strictMode(Json::Value* settings);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Consume entire stream and use its begin/end.
|
||||||
|
* Someday we might have a real StreamReader, but for now this
|
||||||
|
* is convenient.
|
||||||
|
*/
|
||||||
|
bool JSON_API parseFromStream(
|
||||||
|
CharReader::Factory const&,
|
||||||
|
std::istream&,
|
||||||
|
Value* root, std::string* errs);
|
||||||
|
|
||||||
|
/** \brief Read from 'sin' into 'root'.
|
||||||
|
|
||||||
|
Always keep comments from the input JSON.
|
||||||
|
|
||||||
|
This can be used to read a file into a particular sub-object.
|
||||||
|
For example:
|
||||||
|
\code
|
||||||
|
Json::Value root;
|
||||||
|
cin >> root["dir"]["file"];
|
||||||
|
cout << root;
|
||||||
|
\endcode
|
||||||
|
Result:
|
||||||
|
\verbatim
|
||||||
|
{
|
||||||
|
"dir": {
|
||||||
|
"file": {
|
||||||
|
// The input stream JSON would be nested here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\endverbatim
|
||||||
|
\throw std::exception on parse error.
|
||||||
|
\see Json::operator<<()
|
||||||
|
*/
|
||||||
|
JSON_API std::istream& operator>>(std::istream&, Value&);
|
||||||
|
|
||||||
|
} // namespace Json
|
||||||
|
|
||||||
|
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
|
||||||
|
#endif // CPPTL_JSON_READER_H_INCLUDED
|
841
3rdpart/jsoncpp/value.h
Normal file
841
3rdpart/jsoncpp/value.h
Normal file
@ -0,0 +1,841 @@
|
|||||||
|
// Copyright 2007-2010 Baptiste Lepilleur
|
||||||
|
// Distributed under MIT license, or public domain if desired and
|
||||||
|
// recognized in your jurisdiction.
|
||||||
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
|
#ifndef CPPTL_JSON_H_INCLUDED
|
||||||
|
#define CPPTL_JSON_H_INCLUDED
|
||||||
|
|
||||||
|
#if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
#include "forwards.h"
|
||||||
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
#ifndef JSON_USE_CPPTL_SMALLMAP
|
||||||
|
#include <map>
|
||||||
|
#else
|
||||||
|
#include <cpptl/smallmap.h>
|
||||||
|
#endif
|
||||||
|
#ifdef JSON_USE_CPPTL
|
||||||
|
#include <cpptl/forwards.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
||||||
|
// be used by...
|
||||||
|
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4251)
|
||||||
|
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
|
||||||
|
/** \brief JSON (JavaScript Object Notation).
|
||||||
|
*/
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
/** Base class for all exceptions we throw.
|
||||||
|
*
|
||||||
|
* We use nothing but these internally. Of course, STL can throw others.
|
||||||
|
*/
|
||||||
|
class JSON_API Exception : public std::exception {
|
||||||
|
public:
|
||||||
|
Exception(std::string const& msg);
|
||||||
|
virtual ~Exception() throw();
|
||||||
|
virtual char const* what() const throw();
|
||||||
|
protected:
|
||||||
|
std::string const msg_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Exceptions which the user cannot easily avoid.
|
||||||
|
*
|
||||||
|
* E.g. out-of-memory (when we use malloc), stack-overflow, malicious input
|
||||||
|
*
|
||||||
|
* \remark derived from Json::Exception
|
||||||
|
*/
|
||||||
|
class JSON_API RuntimeError : public Exception {
|
||||||
|
public:
|
||||||
|
RuntimeError(std::string const& msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros.
|
||||||
|
*
|
||||||
|
* These are precondition-violations (user bugs) and internal errors (our bugs).
|
||||||
|
*
|
||||||
|
* \remark derived from Json::Exception
|
||||||
|
*/
|
||||||
|
class JSON_API LogicError : public Exception {
|
||||||
|
public:
|
||||||
|
LogicError(std::string const& msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// used internally
|
||||||
|
void throwRuntimeError(std::string const& msg);
|
||||||
|
/// used internally
|
||||||
|
void throwLogicError(std::string const& msg);
|
||||||
|
|
||||||
|
/** \brief Type of the value held by a Value object.
|
||||||
|
*/
|
||||||
|
enum ValueType {
|
||||||
|
nullValue = 0, ///< 'null' value
|
||||||
|
intValue, ///< signed integer value
|
||||||
|
uintValue, ///< unsigned integer value
|
||||||
|
realValue, ///< double value
|
||||||
|
stringValue, ///< UTF-8 string value
|
||||||
|
booleanValue, ///< bool value
|
||||||
|
arrayValue, ///< array value (ordered list)
|
||||||
|
objectValue ///< object value (collection of name/value pairs).
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CommentPlacement {
|
||||||
|
commentBefore = 0, ///< a comment placed on the line before a value
|
||||||
|
commentAfterOnSameLine, ///< a comment just after a value on the same line
|
||||||
|
commentAfter, ///< a comment on the line after a value (only make sense for
|
||||||
|
/// root value)
|
||||||
|
numberOfCommentPlacement
|
||||||
|
};
|
||||||
|
|
||||||
|
//# ifdef JSON_USE_CPPTL
|
||||||
|
// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
|
||||||
|
// typedef CppTL::AnyEnumerator<const Value &> EnumValues;
|
||||||
|
//# endif
|
||||||
|
|
||||||
|
/** \brief Lightweight wrapper to tag static string.
|
||||||
|
*
|
||||||
|
* Value constructor and objectValue member assignement takes advantage of the
|
||||||
|
* StaticString and avoid the cost of string duplication when storing the
|
||||||
|
* string or the member name.
|
||||||
|
*
|
||||||
|
* Example of usage:
|
||||||
|
* \code
|
||||||
|
* Json::Value aValue( StaticString("some text") );
|
||||||
|
* Json::Value object;
|
||||||
|
* static const StaticString code("code");
|
||||||
|
* object[code] = 1234;
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
|
class JSON_API StaticString {
|
||||||
|
public:
|
||||||
|
explicit StaticString(const char* czstring) : c_str_(czstring) {}
|
||||||
|
|
||||||
|
operator const char*() const { return c_str_; }
|
||||||
|
|
||||||
|
const char* c_str() const { return c_str_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* c_str_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
|
||||||
|
*
|
||||||
|
* This class is a discriminated union wrapper that can represents a:
|
||||||
|
* - signed integer [range: Value::minInt - Value::maxInt]
|
||||||
|
* - unsigned integer (range: 0 - Value::maxUInt)
|
||||||
|
* - double
|
||||||
|
* - UTF-8 string
|
||||||
|
* - boolean
|
||||||
|
* - 'null'
|
||||||
|
* - an ordered list of Value
|
||||||
|
* - collection of name/value pairs (javascript object)
|
||||||
|
*
|
||||||
|
* The type of the held value is represented by a #ValueType and
|
||||||
|
* can be obtained using type().
|
||||||
|
*
|
||||||
|
* Values of an #objectValue or #arrayValue can be accessed using operator[]()
|
||||||
|
* methods.
|
||||||
|
* Non-const methods will automatically create the a #nullValue element
|
||||||
|
* if it does not exist.
|
||||||
|
* The sequence of an #arrayValue will be automatically resized and initialized
|
||||||
|
* with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
|
||||||
|
*
|
||||||
|
* The get() methods can be used to obtain default value in the case the
|
||||||
|
* required element does not exist.
|
||||||
|
*
|
||||||
|
* It is possible to iterate over the list of a #objectValue values using
|
||||||
|
* the getMemberNames() method.
|
||||||
|
*
|
||||||
|
* \note #Value string-length fit in size_t, but keys must be < 2^30.
|
||||||
|
* (The reason is an implementation detail.) A #CharReader will raise an
|
||||||
|
* exception if a bound is exceeded to avoid security holes in your app,
|
||||||
|
* but the Value API does *not* check bounds. That is the responsibility
|
||||||
|
* of the caller.
|
||||||
|
*/
|
||||||
|
class JSON_API Value {
|
||||||
|
friend class ValueIteratorBase;
|
||||||
|
public:
|
||||||
|
typedef std::vector<std::string> Members;
|
||||||
|
typedef ValueIterator iterator;
|
||||||
|
typedef ValueConstIterator const_iterator;
|
||||||
|
typedef Json::UInt UInt;
|
||||||
|
typedef Json::Int Int;
|
||||||
|
#if defined(JSON_HAS_INT64)
|
||||||
|
typedef Json::UInt64 UInt64;
|
||||||
|
typedef Json::Int64 Int64;
|
||||||
|
#endif // defined(JSON_HAS_INT64)
|
||||||
|
typedef Json::LargestInt LargestInt;
|
||||||
|
typedef Json::LargestUInt LargestUInt;
|
||||||
|
typedef Json::ArrayIndex ArrayIndex;
|
||||||
|
|
||||||
|
static const Value& null; ///< We regret this reference to a global instance; prefer the simpler Value().
|
||||||
|
static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null
|
||||||
|
/// Minimum signed integer value that can be stored in a Json::Value.
|
||||||
|
static const LargestInt minLargestInt;
|
||||||
|
/// Maximum signed integer value that can be stored in a Json::Value.
|
||||||
|
static const LargestInt maxLargestInt;
|
||||||
|
/// Maximum unsigned integer value that can be stored in a Json::Value.
|
||||||
|
static const LargestUInt maxLargestUInt;
|
||||||
|
|
||||||
|
/// Minimum signed int value that can be stored in a Json::Value.
|
||||||
|
static const Int minInt;
|
||||||
|
/// Maximum signed int value that can be stored in a Json::Value.
|
||||||
|
static const Int maxInt;
|
||||||
|
/// Maximum unsigned int value that can be stored in a Json::Value.
|
||||||
|
static const UInt maxUInt;
|
||||||
|
|
||||||
|
#if defined(JSON_HAS_INT64)
|
||||||
|
/// Minimum signed 64 bits int value that can be stored in a Json::Value.
|
||||||
|
static const Int64 minInt64;
|
||||||
|
/// Maximum signed 64 bits int value that can be stored in a Json::Value.
|
||||||
|
static const Int64 maxInt64;
|
||||||
|
/// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
|
||||||
|
static const UInt64 maxUInt64;
|
||||||
|
#endif // defined(JSON_HAS_INT64)
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||||
|
class CZString {
|
||||||
|
public:
|
||||||
|
enum DuplicationPolicy {
|
||||||
|
noDuplication = 0,
|
||||||
|
duplicate,
|
||||||
|
duplicateOnCopy
|
||||||
|
};
|
||||||
|
CZString(ArrayIndex index);
|
||||||
|
CZString(char const* str, unsigned length, DuplicationPolicy allocate);
|
||||||
|
CZString(CZString const& other);
|
||||||
|
~CZString();
|
||||||
|
CZString& operator=(CZString other);
|
||||||
|
bool operator<(CZString const& other) const;
|
||||||
|
bool operator==(CZString const& other) const;
|
||||||
|
ArrayIndex index() const;
|
||||||
|
//const char* c_str() const; ///< \deprecated
|
||||||
|
char const* data() const;
|
||||||
|
unsigned length() const;
|
||||||
|
bool isStaticString() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void swap(CZString& other);
|
||||||
|
|
||||||
|
struct StringStorage {
|
||||||
|
unsigned policy_: 2;
|
||||||
|
unsigned length_: 30; // 1GB max
|
||||||
|
};
|
||||||
|
|
||||||
|
char const* cstr_; // actually, a prefixed string, unless policy is noDup
|
||||||
|
union {
|
||||||
|
ArrayIndex index_;
|
||||||
|
StringStorage storage_;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
#ifndef JSON_USE_CPPTL_SMALLMAP
|
||||||
|
typedef std::map<CZString, Value> ObjectValues;
|
||||||
|
#else
|
||||||
|
typedef CppTL::SmallMap<CZString, Value> ObjectValues;
|
||||||
|
#endif // ifndef JSON_USE_CPPTL_SMALLMAP
|
||||||
|
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** \brief Create a default Value of the given type.
|
||||||
|
|
||||||
|
This is a very useful constructor.
|
||||||
|
To create an empty array, pass arrayValue.
|
||||||
|
To create an empty object, pass objectValue.
|
||||||
|
Another Value can then be set to this one by assignment.
|
||||||
|
This is useful since clear() and resize() will not alter types.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
\code
|
||||||
|
Json::Value null_value; // null
|
||||||
|
Json::Value arr_value(Json::arrayValue); // []
|
||||||
|
Json::Value obj_value(Json::objectValue); // {}
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
Value(ValueType type = nullValue);
|
||||||
|
Value(Int value);
|
||||||
|
Value(UInt value);
|
||||||
|
#if defined(JSON_HAS_INT64)
|
||||||
|
Value(Int64 value);
|
||||||
|
Value(UInt64 value);
|
||||||
|
#endif // if defined(JSON_HAS_INT64)
|
||||||
|
Value(double value);
|
||||||
|
Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.)
|
||||||
|
Value(const char* begin, const char* end); ///< Copy all, incl zeroes.
|
||||||
|
/** \brief Constructs a value from a static string.
|
||||||
|
|
||||||
|
* Like other value string constructor but do not duplicate the string for
|
||||||
|
* internal storage. The given string must remain alive after the call to this
|
||||||
|
* constructor.
|
||||||
|
* \note This works only for null-terminated strings. (We cannot change the
|
||||||
|
* size of this class, so we have nowhere to store the length,
|
||||||
|
* which might be computed later for various operations.)
|
||||||
|
*
|
||||||
|
* Example of usage:
|
||||||
|
* \code
|
||||||
|
* static StaticString foo("some text");
|
||||||
|
* Json::Value aValue(foo);
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
|
Value(const StaticString& value);
|
||||||
|
Value(const std::string& value); ///< Copy data() til size(). Embedded zeroes too.
|
||||||
|
#ifdef JSON_USE_CPPTL
|
||||||
|
Value(const CppTL::ConstString& value);
|
||||||
|
#endif
|
||||||
|
Value(bool value);
|
||||||
|
/// Deep copy.
|
||||||
|
Value(const Value& other);
|
||||||
|
~Value();
|
||||||
|
|
||||||
|
/// Deep copy, then swap(other).
|
||||||
|
/// \note Over-write existing comments. To preserve comments, use #swapPayload().
|
||||||
|
Value& operator=(Value other);
|
||||||
|
/// Swap everything.
|
||||||
|
void swap(Value& other);
|
||||||
|
/// Swap values but leave comments and source offsets in place.
|
||||||
|
void swapPayload(Value& other);
|
||||||
|
|
||||||
|
ValueType type() const;
|
||||||
|
|
||||||
|
/// Compare payload only, not comments etc.
|
||||||
|
bool operator<(const Value& other) const;
|
||||||
|
bool operator<=(const Value& other) const;
|
||||||
|
bool operator>=(const Value& other) const;
|
||||||
|
bool operator>(const Value& other) const;
|
||||||
|
bool operator==(const Value& other) const;
|
||||||
|
bool operator!=(const Value& other) const;
|
||||||
|
int compare(const Value& other) const;
|
||||||
|
|
||||||
|
const char* asCString() const; ///< Embedded zeroes could cause you trouble!
|
||||||
|
std::string asString() const; ///< Embedded zeroes are possible.
|
||||||
|
/** Get raw char* of string-value.
|
||||||
|
* \return false if !string. (Seg-fault if str or end are NULL.)
|
||||||
|
*/
|
||||||
|
bool getString(
|
||||||
|
char const** begin, char const** end) const;
|
||||||
|
#ifdef JSON_USE_CPPTL
|
||||||
|
CppTL::ConstString asConstString() const;
|
||||||
|
#endif
|
||||||
|
Int asInt() const;
|
||||||
|
UInt asUInt() const;
|
||||||
|
#if defined(JSON_HAS_INT64)
|
||||||
|
Int64 asInt64() const;
|
||||||
|
UInt64 asUInt64() const;
|
||||||
|
#endif // if defined(JSON_HAS_INT64)
|
||||||
|
LargestInt asLargestInt() const;
|
||||||
|
LargestUInt asLargestUInt() const;
|
||||||
|
float asFloat() const;
|
||||||
|
double asDouble() const;
|
||||||
|
bool asBool() const;
|
||||||
|
|
||||||
|
bool isNull() const;
|
||||||
|
bool isBool() const;
|
||||||
|
bool isInt() const;
|
||||||
|
bool isInt64() const;
|
||||||
|
bool isUInt() const;
|
||||||
|
bool isUInt64() const;
|
||||||
|
bool isIntegral() const;
|
||||||
|
bool isDouble() const;
|
||||||
|
bool isNumeric() const;
|
||||||
|
bool isString() const;
|
||||||
|
bool isArray() const;
|
||||||
|
bool isObject() const;
|
||||||
|
|
||||||
|
bool isConvertibleTo(ValueType other) const;
|
||||||
|
|
||||||
|
/// Number of values in array or object
|
||||||
|
ArrayIndex size() const;
|
||||||
|
|
||||||
|
/// \brief Return true if empty array, empty object, or null;
|
||||||
|
/// otherwise, false.
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
|
/// Return isNull()
|
||||||
|
bool operator!() const;
|
||||||
|
|
||||||
|
/// Remove all object members and array elements.
|
||||||
|
/// \pre type() is arrayValue, objectValue, or nullValue
|
||||||
|
/// \post type() is unchanged
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/// Resize the array to size elements.
|
||||||
|
/// New elements are initialized to null.
|
||||||
|
/// May only be called on nullValue or arrayValue.
|
||||||
|
/// \pre type() is arrayValue or nullValue
|
||||||
|
/// \post type() is arrayValue
|
||||||
|
void resize(ArrayIndex size);
|
||||||
|
|
||||||
|
/// Access an array element (zero based index ).
|
||||||
|
/// If the array contains less than index element, then null value are
|
||||||
|
/// inserted
|
||||||
|
/// in the array so that its size is index+1.
|
||||||
|
/// (You may need to say 'value[0u]' to get your compiler to distinguish
|
||||||
|
/// this from the operator[] which takes a string.)
|
||||||
|
Value& operator[](ArrayIndex index);
|
||||||
|
|
||||||
|
/// Access an array element (zero based index ).
|
||||||
|
/// If the array contains less than index element, then null value are
|
||||||
|
/// inserted
|
||||||
|
/// in the array so that its size is index+1.
|
||||||
|
/// (You may need to say 'value[0u]' to get your compiler to distinguish
|
||||||
|
/// this from the operator[] which takes a string.)
|
||||||
|
Value& operator[](int index);
|
||||||
|
|
||||||
|
/// Access an array element (zero based index )
|
||||||
|
/// (You may need to say 'value[0u]' to get your compiler to distinguish
|
||||||
|
/// this from the operator[] which takes a string.)
|
||||||
|
const Value& operator[](ArrayIndex index) const;
|
||||||
|
|
||||||
|
/// Access an array element (zero based index )
|
||||||
|
/// (You may need to say 'value[0u]' to get your compiler to distinguish
|
||||||
|
/// this from the operator[] which takes a string.)
|
||||||
|
const Value& operator[](int index) const;
|
||||||
|
|
||||||
|
/// If the array contains at least index+1 elements, returns the element
|
||||||
|
/// value,
|
||||||
|
/// otherwise returns defaultValue.
|
||||||
|
Value get(ArrayIndex index, const Value& defaultValue) const;
|
||||||
|
/// Return true if index < size().
|
||||||
|
bool isValidIndex(ArrayIndex index) const;
|
||||||
|
/// \brief Append value to array at the end.
|
||||||
|
///
|
||||||
|
/// Equivalent to jsonvalue[jsonvalue.size()] = value;
|
||||||
|
Value& append(const Value& value);
|
||||||
|
|
||||||
|
/// Access an object value by name, create a null member if it does not exist.
|
||||||
|
/// \note Because of our implementation, keys are limited to 2^30 -1 chars.
|
||||||
|
/// Exceeding that will cause an exception.
|
||||||
|
Value& operator[](const char* key);
|
||||||
|
/// Access an object value by name, returns null if there is no member with
|
||||||
|
/// that name.
|
||||||
|
const Value& operator[](const char* key) const;
|
||||||
|
/// Access an object value by name, create a null member if it does not exist.
|
||||||
|
/// \param key may contain embedded nulls.
|
||||||
|
Value& operator[](const std::string& key);
|
||||||
|
/// Access an object value by name, returns null if there is no member with
|
||||||
|
/// that name.
|
||||||
|
/// \param key may contain embedded nulls.
|
||||||
|
const Value& operator[](const std::string& key) const;
|
||||||
|
/** \brief Access an object value by name, create a null member if it does not
|
||||||
|
exist.
|
||||||
|
|
||||||
|
* If the object has no entry for that name, then the member name used to store
|
||||||
|
* the new entry is not duplicated.
|
||||||
|
* Example of use:
|
||||||
|
* \code
|
||||||
|
* Json::Value object;
|
||||||
|
* static const StaticString code("code");
|
||||||
|
* object[code] = 1234;
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
|
Value& operator[](const StaticString& key);
|
||||||
|
#ifdef JSON_USE_CPPTL
|
||||||
|
/// Access an object value by name, create a null member if it does not exist.
|
||||||
|
Value& operator[](const CppTL::ConstString& key);
|
||||||
|
/// Access an object value by name, returns null if there is no member with
|
||||||
|
/// that name.
|
||||||
|
const Value& operator[](const CppTL::ConstString& key) const;
|
||||||
|
#endif
|
||||||
|
/// Return the member named key if it exist, defaultValue otherwise.
|
||||||
|
/// \note deep copy
|
||||||
|
Value get(const char* key, const Value& defaultValue) const;
|
||||||
|
/// Return the member named key if it exist, defaultValue otherwise.
|
||||||
|
/// \note deep copy
|
||||||
|
/// \note key may contain embedded nulls.
|
||||||
|
Value get(const char* begin, const char* end, const Value& defaultValue) const;
|
||||||
|
/// Return the member named key if it exist, defaultValue otherwise.
|
||||||
|
/// \note deep copy
|
||||||
|
/// \param key may contain embedded nulls.
|
||||||
|
Value get(const std::string& key, const Value& defaultValue) const;
|
||||||
|
#ifdef JSON_USE_CPPTL
|
||||||
|
/// Return the member named key if it exist, defaultValue otherwise.
|
||||||
|
/// \note deep copy
|
||||||
|
Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
|
||||||
|
#endif
|
||||||
|
/// Most general and efficient version of isMember()const, get()const,
|
||||||
|
/// and operator[]const
|
||||||
|
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
|
||||||
|
Value const* find(char const* begin, char const* end) const;
|
||||||
|
/// Most general and efficient version of object-mutators.
|
||||||
|
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
|
||||||
|
/// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
|
||||||
|
Value const* demand(char const* begin, char const* end);
|
||||||
|
/// \brief Remove and return the named member.
|
||||||
|
///
|
||||||
|
/// Do nothing if it did not exist.
|
||||||
|
/// \return the removed Value, or null.
|
||||||
|
/// \pre type() is objectValue or nullValue
|
||||||
|
/// \post type() is unchanged
|
||||||
|
/// \deprecated
|
||||||
|
Value removeMember(const char* key);
|
||||||
|
/// Same as removeMember(const char*)
|
||||||
|
/// \param key may contain embedded nulls.
|
||||||
|
/// \deprecated
|
||||||
|
Value removeMember(const std::string& key);
|
||||||
|
/// Same as removeMember(const char* begin, const char* end, Value* removed),
|
||||||
|
/// but 'key' is null-terminated.
|
||||||
|
bool removeMember(const char* key, Value* removed);
|
||||||
|
/** \brief Remove the named map member.
|
||||||
|
|
||||||
|
Update 'removed' iff removed.
|
||||||
|
\param key may contain embedded nulls.
|
||||||
|
\return true iff removed (no exceptions)
|
||||||
|
*/
|
||||||
|
bool removeMember(std::string const& key, Value* removed);
|
||||||
|
/// Same as removeMember(std::string const& key, Value* removed)
|
||||||
|
bool removeMember(const char* begin, const char* end, Value* removed);
|
||||||
|
/** \brief Remove the indexed array element.
|
||||||
|
|
||||||
|
O(n) expensive operations.
|
||||||
|
Update 'removed' iff removed.
|
||||||
|
\return true iff removed (no exceptions)
|
||||||
|
*/
|
||||||
|
bool removeIndex(ArrayIndex i, Value* removed);
|
||||||
|
|
||||||
|
/// Return true if the object has a member named key.
|
||||||
|
/// \note 'key' must be null-terminated.
|
||||||
|
bool isMember(const char* key) const;
|
||||||
|
/// Return true if the object has a member named key.
|
||||||
|
/// \param key may contain embedded nulls.
|
||||||
|
bool isMember(const std::string& key) const;
|
||||||
|
/// Same as isMember(std::string const& key)const
|
||||||
|
bool isMember(const char* begin, const char* end) const;
|
||||||
|
#ifdef JSON_USE_CPPTL
|
||||||
|
/// Return true if the object has a member named key.
|
||||||
|
bool isMember(const CppTL::ConstString& key) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// \brief Return a list of the member names.
|
||||||
|
///
|
||||||
|
/// If null, return an empty list.
|
||||||
|
/// \pre type() is objectValue or nullValue
|
||||||
|
/// \post if type() was nullValue, it remains nullValue
|
||||||
|
Members getMemberNames() const;
|
||||||
|
|
||||||
|
//# ifdef JSON_USE_CPPTL
|
||||||
|
// EnumMemberNames enumMemberNames() const;
|
||||||
|
// EnumValues enumValues() const;
|
||||||
|
//# endif
|
||||||
|
|
||||||
|
/// \deprecated Always pass len.
|
||||||
|
JSONCPP_DEPRECATED("Use setComment(std::string const&) instead.")
|
||||||
|
void setComment(const char* comment, CommentPlacement placement);
|
||||||
|
/// Comments must be //... or /* ... */
|
||||||
|
void setComment(const char* comment, size_t len, CommentPlacement placement);
|
||||||
|
/// Comments must be //... or /* ... */
|
||||||
|
void setComment(const std::string& comment, CommentPlacement placement);
|
||||||
|
bool hasComment(CommentPlacement placement) const;
|
||||||
|
/// Include delimiters and embedded newlines.
|
||||||
|
std::string getComment(CommentPlacement placement) const;
|
||||||
|
|
||||||
|
std::string toStyledString() const;
|
||||||
|
|
||||||
|
const_iterator begin() const;
|
||||||
|
const_iterator end() const;
|
||||||
|
|
||||||
|
iterator begin();
|
||||||
|
iterator end();
|
||||||
|
|
||||||
|
// Accessors for the [start, limit) range of bytes within the JSON text from
|
||||||
|
// which this value was parsed, if any.
|
||||||
|
void setOffsetStart(size_t start);
|
||||||
|
void setOffsetLimit(size_t limit);
|
||||||
|
size_t getOffsetStart() const;
|
||||||
|
size_t getOffsetLimit() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void initBasic(ValueType type, bool allocated = false);
|
||||||
|
|
||||||
|
Value& resolveReference(const char* key);
|
||||||
|
Value& resolveReference(const char* key, const char* end);
|
||||||
|
|
||||||
|
struct CommentInfo {
|
||||||
|
CommentInfo();
|
||||||
|
~CommentInfo();
|
||||||
|
|
||||||
|
void setComment(const char* text, size_t len);
|
||||||
|
|
||||||
|
char* comment_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// struct MemberNamesTransform
|
||||||
|
//{
|
||||||
|
// typedef const char *result_type;
|
||||||
|
// const char *operator()( const CZString &name ) const
|
||||||
|
// {
|
||||||
|
// return name.c_str();
|
||||||
|
// }
|
||||||
|
//};
|
||||||
|
|
||||||
|
union ValueHolder {
|
||||||
|
LargestInt int_;
|
||||||
|
LargestUInt uint_;
|
||||||
|
double real_;
|
||||||
|
bool bool_;
|
||||||
|
char* string_; // actually ptr to unsigned, followed by str, unless !allocated_
|
||||||
|
ObjectValues* map_;
|
||||||
|
} value_;
|
||||||
|
ValueType type_ : 8;
|
||||||
|
unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
|
||||||
|
// If not allocated_, string_ must be null-terminated.
|
||||||
|
CommentInfo* comments_;
|
||||||
|
|
||||||
|
// [start, limit) byte offsets in the source JSON text from which this Value
|
||||||
|
// was extracted.
|
||||||
|
size_t start_;
|
||||||
|
size_t limit_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Experimental and untested: represents an element of the "path" to
|
||||||
|
* access a node.
|
||||||
|
*/
|
||||||
|
class JSON_API PathArgument {
|
||||||
|
public:
|
||||||
|
friend class Path;
|
||||||
|
|
||||||
|
PathArgument();
|
||||||
|
PathArgument(ArrayIndex index);
|
||||||
|
PathArgument(const char* key);
|
||||||
|
PathArgument(const std::string& key);
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum Kind {
|
||||||
|
kindNone = 0,
|
||||||
|
kindIndex,
|
||||||
|
kindKey
|
||||||
|
};
|
||||||
|
std::string key_;
|
||||||
|
ArrayIndex index_;
|
||||||
|
Kind kind_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Experimental and untested: represents a "path" to access a node.
|
||||||
|
*
|
||||||
|
* Syntax:
|
||||||
|
* - "." => root node
|
||||||
|
* - ".[n]" => elements at index 'n' of root node (an array value)
|
||||||
|
* - ".name" => member named 'name' of root node (an object value)
|
||||||
|
* - ".name1.name2.name3"
|
||||||
|
* - ".[0][1][2].name1[3]"
|
||||||
|
* - ".%" => member name is provided as parameter
|
||||||
|
* - ".[%]" => index is provied as parameter
|
||||||
|
*/
|
||||||
|
class JSON_API Path {
|
||||||
|
public:
|
||||||
|
Path(const std::string& path,
|
||||||
|
const PathArgument& a1 = PathArgument(),
|
||||||
|
const PathArgument& a2 = PathArgument(),
|
||||||
|
const PathArgument& a3 = PathArgument(),
|
||||||
|
const PathArgument& a4 = PathArgument(),
|
||||||
|
const PathArgument& a5 = PathArgument());
|
||||||
|
|
||||||
|
const Value& resolve(const Value& root) const;
|
||||||
|
Value resolve(const Value& root, const Value& defaultValue) const;
|
||||||
|
/// Creates the "path" to access the specified node and returns a reference on
|
||||||
|
/// the node.
|
||||||
|
Value& make(Value& root) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::vector<const PathArgument*> InArgs;
|
||||||
|
typedef std::vector<PathArgument> Args;
|
||||||
|
|
||||||
|
void makePath(const std::string& path, const InArgs& in);
|
||||||
|
void addPathInArg(const std::string& path,
|
||||||
|
const InArgs& in,
|
||||||
|
InArgs::const_iterator& itInArg,
|
||||||
|
PathArgument::Kind kind);
|
||||||
|
void invalidPath(const std::string& path, int location);
|
||||||
|
|
||||||
|
Args args_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief base class for Value iterators.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class JSON_API ValueIteratorBase {
|
||||||
|
public:
|
||||||
|
typedef std::bidirectional_iterator_tag iterator_category;
|
||||||
|
typedef unsigned int size_t;
|
||||||
|
typedef int difference_type;
|
||||||
|
typedef ValueIteratorBase SelfType;
|
||||||
|
|
||||||
|
bool operator==(const SelfType& other) const { return isEqual(other); }
|
||||||
|
|
||||||
|
bool operator!=(const SelfType& other) const { return !isEqual(other); }
|
||||||
|
|
||||||
|
difference_type operator-(const SelfType& other) const {
|
||||||
|
return other.computeDistance(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return either the index or the member name of the referenced value as a
|
||||||
|
/// Value.
|
||||||
|
Value key() const;
|
||||||
|
|
||||||
|
/// Return the index of the referenced Value, or -1 if it is not an arrayValue.
|
||||||
|
UInt index() const;
|
||||||
|
|
||||||
|
/// Return the member name of the referenced Value, or "" if it is not an
|
||||||
|
/// objectValue.
|
||||||
|
/// \note Avoid `c_str()` on result, as embedded zeroes are possible.
|
||||||
|
std::string name() const;
|
||||||
|
|
||||||
|
/// Return the member name of the referenced Value. "" if it is not an
|
||||||
|
/// objectValue.
|
||||||
|
/// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls.
|
||||||
|
JSONCPP_DEPRECATED("Use `key = name();` instead.")
|
||||||
|
char const* memberName() const;
|
||||||
|
/// Return the member name of the referenced Value, or NULL if it is not an
|
||||||
|
/// objectValue.
|
||||||
|
/// \note Better version than memberName(). Allows embedded nulls.
|
||||||
|
char const* memberName(char const** end) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Value& deref() const;
|
||||||
|
|
||||||
|
void increment();
|
||||||
|
|
||||||
|
void decrement();
|
||||||
|
|
||||||
|
difference_type computeDistance(const SelfType& other) const;
|
||||||
|
|
||||||
|
bool isEqual(const SelfType& other) const;
|
||||||
|
|
||||||
|
void copy(const SelfType& other);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Value::ObjectValues::iterator current_;
|
||||||
|
// Indicates that iterator is for a null value.
|
||||||
|
bool isNull_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// For some reason, BORLAND needs these at the end, rather
|
||||||
|
// than earlier. No idea why.
|
||||||
|
ValueIteratorBase();
|
||||||
|
explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief const iterator for object and array value.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class JSON_API ValueConstIterator : public ValueIteratorBase {
|
||||||
|
friend class Value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef const Value value_type;
|
||||||
|
//typedef unsigned int size_t;
|
||||||
|
//typedef int difference_type;
|
||||||
|
typedef const Value& reference;
|
||||||
|
typedef const Value* pointer;
|
||||||
|
typedef ValueConstIterator SelfType;
|
||||||
|
|
||||||
|
ValueConstIterator();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*! \internal Use by Value to create an iterator.
|
||||||
|
*/
|
||||||
|
explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
|
||||||
|
public:
|
||||||
|
SelfType& operator=(const ValueIteratorBase& other);
|
||||||
|
|
||||||
|
SelfType operator++(int) {
|
||||||
|
SelfType temp(*this);
|
||||||
|
++*this;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelfType operator--(int) {
|
||||||
|
SelfType temp(*this);
|
||||||
|
--*this;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelfType& operator--() {
|
||||||
|
decrement();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelfType& operator++() {
|
||||||
|
increment();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
reference operator*() const { return deref(); }
|
||||||
|
|
||||||
|
pointer operator->() const { return &deref(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Iterator for object and array value.
|
||||||
|
*/
|
||||||
|
class JSON_API ValueIterator : public ValueIteratorBase {
|
||||||
|
friend class Value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef Value value_type;
|
||||||
|
typedef unsigned int size_t;
|
||||||
|
typedef int difference_type;
|
||||||
|
typedef Value& reference;
|
||||||
|
typedef Value* pointer;
|
||||||
|
typedef ValueIterator SelfType;
|
||||||
|
|
||||||
|
ValueIterator();
|
||||||
|
ValueIterator(const ValueConstIterator& other);
|
||||||
|
ValueIterator(const ValueIterator& other);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*! \internal Use by Value to create an iterator.
|
||||||
|
*/
|
||||||
|
explicit ValueIterator(const Value::ObjectValues::iterator& current);
|
||||||
|
public:
|
||||||
|
SelfType& operator=(const SelfType& other);
|
||||||
|
|
||||||
|
SelfType operator++(int) {
|
||||||
|
SelfType temp(*this);
|
||||||
|
++*this;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelfType operator--(int) {
|
||||||
|
SelfType temp(*this);
|
||||||
|
--*this;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelfType& operator--() {
|
||||||
|
decrement();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelfType& operator++() {
|
||||||
|
increment();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
reference operator*() const { return deref(); }
|
||||||
|
|
||||||
|
pointer operator->() const { return &deref(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Json
|
||||||
|
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
/// Specialize std::swap() for Json::Value.
|
||||||
|
template<>
|
||||||
|
inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
|
||||||
|
#endif // CPPTL_JSON_H_INCLUDED
|
13
3rdpart/jsoncpp/version.h
Normal file
13
3rdpart/jsoncpp/version.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// DO NOT EDIT. This file (and "version") is generated by CMake.
|
||||||
|
// Run CMake configure step to update it.
|
||||||
|
#ifndef JSON_VERSION_H_INCLUDED
|
||||||
|
# define JSON_VERSION_H_INCLUDED
|
||||||
|
|
||||||
|
# define JSONCPP_VERSION_STRING "1.6.5"
|
||||||
|
# define JSONCPP_VERSION_MAJOR 1
|
||||||
|
# define JSONCPP_VERSION_MINOR 6
|
||||||
|
# define JSONCPP_VERSION_PATCH 5
|
||||||
|
# define JSONCPP_VERSION_QUALIFIER
|
||||||
|
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
|
||||||
|
|
||||||
|
#endif // JSON_VERSION_H_INCLUDED
|
13
3rdpart/jsoncpp/version.h.in
Normal file
13
3rdpart/jsoncpp/version.h.in
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// DO NOT EDIT. This file (and "version") is generated by CMake.
|
||||||
|
// Run CMake configure step to update it.
|
||||||
|
#ifndef JSON_VERSION_H_INCLUDED
|
||||||
|
# define JSON_VERSION_H_INCLUDED
|
||||||
|
|
||||||
|
# define JSONCPP_VERSION_STRING "@JSONCPP_VERSION@"
|
||||||
|
# define JSONCPP_VERSION_MAJOR @JSONCPP_VERSION_MAJOR@
|
||||||
|
# define JSONCPP_VERSION_MINOR @JSONCPP_VERSION_MINOR@
|
||||||
|
# define JSONCPP_VERSION_PATCH @JSONCPP_VERSION_PATCH@
|
||||||
|
# define JSONCPP_VERSION_QUALIFIER
|
||||||
|
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
|
||||||
|
|
||||||
|
#endif // JSON_VERSION_H_INCLUDED
|
327
3rdpart/jsoncpp/writer.h
Normal file
327
3rdpart/jsoncpp/writer.h
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
// Copyright 2007-2010 Baptiste Lepilleur
|
||||||
|
// Distributed under MIT license, or public domain if desired and
|
||||||
|
// recognized in your jurisdiction.
|
||||||
|
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||||
|
|
||||||
|
#ifndef JSON_WRITER_H_INCLUDED
|
||||||
|
#define JSON_WRITER_H_INCLUDED
|
||||||
|
|
||||||
|
#if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
#include "value.h"
|
||||||
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
||||||
|
// be used by...
|
||||||
|
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4251)
|
||||||
|
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
class Value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
\code
|
||||||
|
using namespace Json;
|
||||||
|
void writeToStdout(StreamWriter::Factory const& factory, Value const& value) {
|
||||||
|
std::unique_ptr<StreamWriter> const writer(
|
||||||
|
factory.newStreamWriter());
|
||||||
|
writer->write(value, &std::cout);
|
||||||
|
std::cout << std::endl; // add lf and flush
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
class JSON_API StreamWriter {
|
||||||
|
protected:
|
||||||
|
std::ostream* sout_; // not owned; will not delete
|
||||||
|
public:
|
||||||
|
StreamWriter();
|
||||||
|
virtual ~StreamWriter();
|
||||||
|
/** Write Value into document as configured in sub-class.
|
||||||
|
Do not take ownership of sout, but maintain a reference during function.
|
||||||
|
\pre sout != NULL
|
||||||
|
\return zero on success (For now, we always return zero, so check the stream instead.)
|
||||||
|
\throw std::exception possibly, depending on configuration
|
||||||
|
*/
|
||||||
|
virtual int write(Value const& root, std::ostream* sout) = 0;
|
||||||
|
|
||||||
|
/** \brief A simple abstract factory.
|
||||||
|
*/
|
||||||
|
class JSON_API Factory {
|
||||||
|
public:
|
||||||
|
virtual ~Factory();
|
||||||
|
/** \brief Allocate a CharReader via operator new().
|
||||||
|
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
||||||
|
*/
|
||||||
|
virtual StreamWriter* newStreamWriter() const = 0;
|
||||||
|
}; // Factory
|
||||||
|
}; // StreamWriter
|
||||||
|
|
||||||
|
/** \brief Write into stringstream, then return string, for convenience.
|
||||||
|
* A StreamWriter will be created from the factory, used, and then deleted.
|
||||||
|
*/
|
||||||
|
std::string JSON_API writeString(StreamWriter::Factory const& factory, Value const& root);
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Build a StreamWriter implementation.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
\code
|
||||||
|
using namespace Json;
|
||||||
|
Value value = ...;
|
||||||
|
StreamWriterBuilder builder;
|
||||||
|
builder["commentStyle"] = "None";
|
||||||
|
builder["indentation"] = " "; // or whatever you like
|
||||||
|
std::unique_ptr<Json::StreamWriter> writer(
|
||||||
|
builder.newStreamWriter());
|
||||||
|
writer->write(value, &std::cout);
|
||||||
|
std::cout << std::endl; // add lf and flush
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
class JSON_API StreamWriterBuilder : public StreamWriter::Factory {
|
||||||
|
public:
|
||||||
|
// Note: We use a Json::Value so that we can add data-members to this class
|
||||||
|
// without a major version bump.
|
||||||
|
/** Configuration of this builder.
|
||||||
|
Available settings (case-sensitive):
|
||||||
|
- "commentStyle": "None" or "All"
|
||||||
|
- "indentation": "<anything>"
|
||||||
|
- "enableYAMLCompatibility": false or true
|
||||||
|
- slightly change the whitespace around colons
|
||||||
|
- "dropNullPlaceholders": false or true
|
||||||
|
- Drop the "null" string from the writer's output for nullValues.
|
||||||
|
Strictly speaking, this is not valid JSON. But when the output is being
|
||||||
|
fed to a browser's Javascript, it makes for smaller output and the
|
||||||
|
browser can handle the output just fine.
|
||||||
|
|
||||||
|
You can examine 'settings_` yourself
|
||||||
|
to see the defaults. You can also write and read them just like any
|
||||||
|
JSON Value.
|
||||||
|
\sa setDefaults()
|
||||||
|
*/
|
||||||
|
Json::Value settings_;
|
||||||
|
|
||||||
|
StreamWriterBuilder();
|
||||||
|
virtual ~StreamWriterBuilder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
||||||
|
*/
|
||||||
|
virtual StreamWriter* newStreamWriter() const;
|
||||||
|
|
||||||
|
/** \return true if 'settings' are legal and consistent;
|
||||||
|
* otherwise, indicate bad settings via 'invalid'.
|
||||||
|
*/
|
||||||
|
bool validate(Json::Value* invalid) const;
|
||||||
|
/** A simple way to update a specific setting.
|
||||||
|
*/
|
||||||
|
Value& operator[](std::string key);
|
||||||
|
|
||||||
|
/** Called by ctor, but you can use this to reset settings_.
|
||||||
|
* \pre 'settings' != NULL (but Json::null is fine)
|
||||||
|
* \remark Defaults:
|
||||||
|
* \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults
|
||||||
|
*/
|
||||||
|
static void setDefaults(Json::Value* settings);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Abstract class for writers.
|
||||||
|
* \deprecated Use StreamWriter. (And really, this is an implementation detail.)
|
||||||
|
*/
|
||||||
|
class JSON_API Writer {
|
||||||
|
public:
|
||||||
|
virtual ~Writer();
|
||||||
|
|
||||||
|
virtual std::string write(const Value& root) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format
|
||||||
|
*without formatting (not human friendly).
|
||||||
|
*
|
||||||
|
* The JSON document is written in a single line. It is not intended for 'human'
|
||||||
|
*consumption,
|
||||||
|
* but may be usefull to support feature such as RPC where bandwith is limited.
|
||||||
|
* \sa Reader, Value
|
||||||
|
* \deprecated Use StreamWriterBuilder.
|
||||||
|
*/
|
||||||
|
class JSON_API FastWriter : public Writer {
|
||||||
|
|
||||||
|
public:
|
||||||
|
FastWriter();
|
||||||
|
virtual ~FastWriter() {}
|
||||||
|
|
||||||
|
void enableYAMLCompatibility();
|
||||||
|
|
||||||
|
/** \brief Drop the "null" string from the writer's output for nullValues.
|
||||||
|
* Strictly speaking, this is not valid JSON. But when the output is being
|
||||||
|
* fed to a browser's Javascript, it makes for smaller output and the
|
||||||
|
* browser can handle the output just fine.
|
||||||
|
*/
|
||||||
|
void dropNullPlaceholders();
|
||||||
|
|
||||||
|
void omitEndingLineFeed();
|
||||||
|
|
||||||
|
public: // overridden from Writer
|
||||||
|
virtual std::string write(const Value& root);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void writeValue(const Value& value);
|
||||||
|
|
||||||
|
std::string document_;
|
||||||
|
bool yamlCompatiblityEnabled_;
|
||||||
|
bool dropNullPlaceholders_;
|
||||||
|
bool omitEndingLineFeed_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
|
||||||
|
*human friendly way.
|
||||||
|
*
|
||||||
|
* The rules for line break and indent are as follow:
|
||||||
|
* - Object value:
|
||||||
|
* - if empty then print {} without indent and line break
|
||||||
|
* - if not empty the print '{', line break & indent, print one value per
|
||||||
|
*line
|
||||||
|
* and then unindent and line break and print '}'.
|
||||||
|
* - Array value:
|
||||||
|
* - if empty then print [] without indent and line break
|
||||||
|
* - if the array contains no object value, empty array or some other value
|
||||||
|
*types,
|
||||||
|
* and all the values fit on one lines, then print the array on a single
|
||||||
|
*line.
|
||||||
|
* - otherwise, it the values do not fit on one line, or the array contains
|
||||||
|
* object or non empty array, then print one value per line.
|
||||||
|
*
|
||||||
|
* If the Value have comments then they are outputed according to their
|
||||||
|
*#CommentPlacement.
|
||||||
|
*
|
||||||
|
* \sa Reader, Value, Value::setComment()
|
||||||
|
* \deprecated Use StreamWriterBuilder.
|
||||||
|
*/
|
||||||
|
class JSON_API StyledWriter : public Writer {
|
||||||
|
public:
|
||||||
|
StyledWriter();
|
||||||
|
virtual ~StyledWriter() {}
|
||||||
|
|
||||||
|
public: // overridden from Writer
|
||||||
|
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||||
|
* \param root Value to serialize.
|
||||||
|
* \return String containing the JSON document that represents the root value.
|
||||||
|
*/
|
||||||
|
virtual std::string write(const Value& root);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void writeValue(const Value& value);
|
||||||
|
void writeArrayValue(const Value& value);
|
||||||
|
bool isMultineArray(const Value& value);
|
||||||
|
void pushValue(const std::string& value);
|
||||||
|
void writeIndent();
|
||||||
|
void writeWithIndent(const std::string& value);
|
||||||
|
void indent();
|
||||||
|
void unindent();
|
||||||
|
void writeCommentBeforeValue(const Value& root);
|
||||||
|
void writeCommentAfterValueOnSameLine(const Value& root);
|
||||||
|
bool hasCommentForValue(const Value& value);
|
||||||
|
static std::string normalizeEOL(const std::string& text);
|
||||||
|
|
||||||
|
typedef std::vector<std::string> ChildValues;
|
||||||
|
|
||||||
|
ChildValues childValues_;
|
||||||
|
std::string document_;
|
||||||
|
std::string indentString_;
|
||||||
|
int rightMargin_;
|
||||||
|
int indentSize_;
|
||||||
|
bool addChildValues_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
|
||||||
|
human friendly way,
|
||||||
|
to a stream rather than to a string.
|
||||||
|
*
|
||||||
|
* The rules for line break and indent are as follow:
|
||||||
|
* - Object value:
|
||||||
|
* - if empty then print {} without indent and line break
|
||||||
|
* - if not empty the print '{', line break & indent, print one value per
|
||||||
|
line
|
||||||
|
* and then unindent and line break and print '}'.
|
||||||
|
* - Array value:
|
||||||
|
* - if empty then print [] without indent and line break
|
||||||
|
* - if the array contains no object value, empty array or some other value
|
||||||
|
types,
|
||||||
|
* and all the values fit on one lines, then print the array on a single
|
||||||
|
line.
|
||||||
|
* - otherwise, it the values do not fit on one line, or the array contains
|
||||||
|
* object or non empty array, then print one value per line.
|
||||||
|
*
|
||||||
|
* If the Value have comments then they are outputed according to their
|
||||||
|
#CommentPlacement.
|
||||||
|
*
|
||||||
|
* \param indentation Each level will be indented by this amount extra.
|
||||||
|
* \sa Reader, Value, Value::setComment()
|
||||||
|
* \deprecated Use StreamWriterBuilder.
|
||||||
|
*/
|
||||||
|
class JSON_API StyledStreamWriter {
|
||||||
|
public:
|
||||||
|
StyledStreamWriter(std::string indentation = "\t");
|
||||||
|
~StyledStreamWriter() {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||||
|
* \param out Stream to write to. (Can be ostringstream, e.g.)
|
||||||
|
* \param root Value to serialize.
|
||||||
|
* \note There is no point in deriving from Writer, since write() should not
|
||||||
|
* return a value.
|
||||||
|
*/
|
||||||
|
void write(std::ostream& out, const Value& root);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void writeValue(const Value& value);
|
||||||
|
void writeArrayValue(const Value& value);
|
||||||
|
bool isMultineArray(const Value& value);
|
||||||
|
void pushValue(const std::string& value);
|
||||||
|
void writeIndent();
|
||||||
|
void writeWithIndent(const std::string& value);
|
||||||
|
void indent();
|
||||||
|
void unindent();
|
||||||
|
void writeCommentBeforeValue(const Value& root);
|
||||||
|
void writeCommentAfterValueOnSameLine(const Value& root);
|
||||||
|
bool hasCommentForValue(const Value& value);
|
||||||
|
static std::string normalizeEOL(const std::string& text);
|
||||||
|
|
||||||
|
typedef std::vector<std::string> ChildValues;
|
||||||
|
|
||||||
|
ChildValues childValues_;
|
||||||
|
std::ostream* document_;
|
||||||
|
std::string indentString_;
|
||||||
|
int rightMargin_;
|
||||||
|
std::string indentation_;
|
||||||
|
bool addChildValues_ : 1;
|
||||||
|
bool indented_ : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(JSON_HAS_INT64)
|
||||||
|
std::string JSON_API valueToString(Int value);
|
||||||
|
std::string JSON_API valueToString(UInt value);
|
||||||
|
#endif // if defined(JSON_HAS_INT64)
|
||||||
|
std::string JSON_API valueToString(LargestInt value);
|
||||||
|
std::string JSON_API valueToString(LargestUInt value);
|
||||||
|
std::string JSON_API valueToString(double value);
|
||||||
|
std::string JSON_API valueToString(bool value);
|
||||||
|
std::string JSON_API valueToQuotedString(const char* value);
|
||||||
|
|
||||||
|
/// \brief Output using the StyledStreamWriter.
|
||||||
|
/// \see Json::operator>>()
|
||||||
|
JSON_API std::ostream& operator<<(std::ostream&, const Value& root);
|
||||||
|
|
||||||
|
} // namespace Json
|
||||||
|
|
||||||
|
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||||
|
|
||||||
|
#endif // JSON_WRITER_H_INCLUDED
|
@ -113,7 +113,12 @@ endif ()
|
|||||||
#测试程序
|
#测试程序
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
|
|
||||||
|
#主服务器
|
||||||
|
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||||
|
add_subdirectory(server)
|
||||||
|
elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||||
|
add_subdirectory(server)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
9
server/CMakeLists.txt
Normal file
9
server/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
include_directories(../3rdpart)
|
||||||
|
file(GLOB jsoncpp_src_list ../3rdpart/jsoncpp/*.cpp ../3rdpart/jsoncpp/*.h )
|
||||||
|
add_library(jsoncpp STATIC ${jsoncpp_src_list})
|
||||||
|
|
||||||
|
file(GLOB MediaServer_src_list ./*.cpp ./*.h)
|
||||||
|
add_executable(MediaServer ${MediaServer_src_list})
|
||||||
|
target_link_libraries(MediaServer jsoncpp ${LINK_LIB_LIST})
|
||||||
|
|
||||||
|
|
132
server/Process.cpp
Normal file
132
server/Process.cpp
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
//
|
||||||
|
// Created by xzl on 2018/5/24.
|
||||||
|
//
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <signal.h>
|
||||||
|
#include "Util/util.h"
|
||||||
|
#include "Util/File.h"
|
||||||
|
#include "Util/logger.h"
|
||||||
|
#include "Util/uv_errno.h"
|
||||||
|
#include "Util/TimeTicker.h"
|
||||||
|
#include "Process.h"
|
||||||
|
#include "Poller/Timer.h"
|
||||||
|
using namespace toolkit;
|
||||||
|
|
||||||
|
void Process::run(const string &cmd, const string &log_file_tmp) {
|
||||||
|
kill(2000);
|
||||||
|
_pid = fork();
|
||||||
|
if (_pid < 0) {
|
||||||
|
throw std::runtime_error(StrPrinter << "fork child process falied,err:" << get_uv_errmsg());
|
||||||
|
}
|
||||||
|
if (_pid == 0) {
|
||||||
|
//子进程
|
||||||
|
// ignore the SIGINT and SIGTERM
|
||||||
|
signal(SIGINT, SIG_IGN);
|
||||||
|
signal(SIGTERM, SIG_IGN);
|
||||||
|
|
||||||
|
string log_file ;
|
||||||
|
if(log_file_tmp.empty()){
|
||||||
|
log_file = "/dev/null";
|
||||||
|
}else{
|
||||||
|
log_file = StrPrinter << log_file_tmp << "." << getpid();
|
||||||
|
}
|
||||||
|
|
||||||
|
int log_fd = -1;
|
||||||
|
int flags = O_CREAT | O_WRONLY | O_APPEND;
|
||||||
|
mode_t mode = S_IRWXO | S_IRWXG | S_IRWXU;// S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
|
||||||
|
File::createfile_path(log_file.data(), mode);
|
||||||
|
if ((log_fd = ::open(log_file.c_str(), flags, mode)) < 0) {
|
||||||
|
fprintf(stderr, "open log file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno));
|
||||||
|
} else {
|
||||||
|
// dup to stdout and stderr.
|
||||||
|
if (dup2(log_fd, STDOUT_FILENO) < 0) {
|
||||||
|
fprintf(stderr, "dup2 stdout file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno));
|
||||||
|
}
|
||||||
|
if (dup2(log_fd, STDERR_FILENO) < 0) {
|
||||||
|
fprintf(stderr, "dup2 stderr file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno));
|
||||||
|
}
|
||||||
|
// close log fd
|
||||||
|
::close(log_fd);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\r\n\r\n#### pid=%d,cmd=%s #####\r\n\r\n", getpid(), cmd.data());
|
||||||
|
|
||||||
|
// close other fds
|
||||||
|
// TODO: do in right way.
|
||||||
|
for (int i = 3; i < 1024; i++) {
|
||||||
|
::close(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto params = split(cmd, " ");
|
||||||
|
// memory leak in child process, it's ok.
|
||||||
|
char **charpv_params = new char *[params.size() + 1];
|
||||||
|
for (int i = 0; i < (int) params.size(); i++) {
|
||||||
|
std::string &p = params[i];
|
||||||
|
charpv_params[i] = (char *) p.data();
|
||||||
|
}
|
||||||
|
// EOF: NULL
|
||||||
|
charpv_params[params.size()] = NULL;
|
||||||
|
|
||||||
|
// TODO: execv or execvp
|
||||||
|
auto ret = execv(params[0].c_str(), charpv_params);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "fork process failed, errno=%d(%s)\r\n", errno, strerror(errno));
|
||||||
|
}
|
||||||
|
exit(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoL << "start child proces " << _pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::kill(int max_delay) {
|
||||||
|
if (_pid <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (::kill(_pid, SIGTERM) == -1) {
|
||||||
|
WarnL << "kill process " << _pid << " falied,err:" << get_uv_errmsg();
|
||||||
|
} else {
|
||||||
|
//等待子进程退出
|
||||||
|
auto pid = _pid;
|
||||||
|
EventPollerPool::Instance().getPoller()->doDelayTask(max_delay,[pid](){
|
||||||
|
//最多等待2秒,2秒后强制杀掉程序
|
||||||
|
if (waitpid(pid, NULL, WNOHANG) == 0) {
|
||||||
|
::kill(pid, SIGKILL);
|
||||||
|
WarnL << "force kill process " << pid;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_pid = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Process::~Process() {
|
||||||
|
kill(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Process::Process() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Process::wait(bool block) {
|
||||||
|
if (_pid <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int status = 0;
|
||||||
|
pid_t p = waitpid(_pid, &status, block ? 0 : WNOHANG);
|
||||||
|
|
||||||
|
_exit_code = (status & 0xFF00) >> 8;
|
||||||
|
if (p < 0) {
|
||||||
|
WarnL << "waitpid failed, pid=" << _pid << ", err=" << get_uv_errmsg();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (p > 0) {
|
||||||
|
InfoL << "process terminated, pid=" << _pid << ", exit code=" << _exit_code;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//WarnL << "process is running, pid=" << _pid;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Process::exit_code() {
|
||||||
|
return _exit_code;
|
||||||
|
}
|
27
server/Process.h
Normal file
27
server/Process.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// Created by xzl on 2018/5/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef IPTV_PROCESS_H
|
||||||
|
#define IPTV_PROCESS_H
|
||||||
|
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <string>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class Process {
|
||||||
|
public:
|
||||||
|
Process();
|
||||||
|
~Process();
|
||||||
|
void run(const string &cmd,const string &log_file);
|
||||||
|
void kill(int max_delay);
|
||||||
|
bool wait(bool block = true);
|
||||||
|
int exit_code();
|
||||||
|
private:
|
||||||
|
pid_t _pid = -1;
|
||||||
|
int _exit_code = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //IPTV_PROCESS_H
|
377
server/System.cpp
Normal file
377
server/System.cpp
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
//
|
||||||
|
// Created by xzl on 2018/9/5.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "System.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <execinfo.h>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include "Util/mini.h"
|
||||||
|
#include "Util/util.h"
|
||||||
|
#include "Util/logger.h"
|
||||||
|
#include "Util/onceToken.h"
|
||||||
|
#include "Util/NoticeCenter.h"
|
||||||
|
#include "System.h"
|
||||||
|
#include "Util/uv_errno.h"
|
||||||
|
#include "Util/CMD.h"
|
||||||
|
#include "Util/MD5.h"
|
||||||
|
using namespace toolkit;
|
||||||
|
|
||||||
|
const int MAX_STACK_FRAMES = 128;
|
||||||
|
#define BroadcastOnCrashDumpArgs int &sig,const vector<vector<string> > &stack
|
||||||
|
const char kBroadcastOnCrashDump[] = "kBroadcastOnCrashDump";
|
||||||
|
|
||||||
|
//#if defined(__MACH__) || defined(__APPLE__)
|
||||||
|
//#define TEST_LINUX
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
vector<string> splitWithEmptyLine(const string &s, const char *delim) {
|
||||||
|
vector<string> ret;
|
||||||
|
int last = 0;
|
||||||
|
int index = s.find(delim, last);
|
||||||
|
while (index != string::npos) {
|
||||||
|
ret.push_back(s.substr(last, index - last));
|
||||||
|
last = index + strlen(delim);
|
||||||
|
index = s.find(delim, last);
|
||||||
|
}
|
||||||
|
if (s.size() - last > 0) {
|
||||||
|
ret.push_back(s.substr(last));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
map<string, mINI> splitTopStr(const string &cmd_str) {
|
||||||
|
map<string, mINI> ret;
|
||||||
|
auto lines = splitWithEmptyLine(cmd_str, "\n");
|
||||||
|
int i = 0;
|
||||||
|
for (auto &line : lines) {
|
||||||
|
if(i++ < 1 && line.empty()){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (line.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto line_vec = split(line, ":");
|
||||||
|
|
||||||
|
if (line_vec.size() < 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
trim(line_vec[0], " \r\n\t");
|
||||||
|
auto args_vec = split(line_vec[1], ",");
|
||||||
|
for (auto &arg : args_vec) {
|
||||||
|
auto arg_vec = split(trim(arg, " \r\n\t."), " ");
|
||||||
|
if (arg_vec.size() < 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ret[line_vec[0]].emplace(arg_vec[1], arg_vec[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool System::getSystemUsage(SystemUsage &usage) {
|
||||||
|
try {
|
||||||
|
#if defined(__linux) || defined(__linux__) || defined(TEST_LINUX)
|
||||||
|
string cmd_str;
|
||||||
|
#if !defined(TEST_LINUX)
|
||||||
|
cmd_str = System::execute("top -b -n 1");
|
||||||
|
#else
|
||||||
|
cmd_str = "top - 07:21:31 up 5:48, 2 users, load average: 0.03, 0.62, 0.54\n"
|
||||||
|
"Tasks: 80 total, 1 running, 78 sleeping, 0 stopped, 1 zombie\n"
|
||||||
|
"%Cpu(s): 0.8 us, 0.4 sy, 0.0 ni, 98.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st\n"
|
||||||
|
"KiB Mem: 2058500 total, 249100 used, 1809400 free, 19816 buffers\n"
|
||||||
|
"KiB Swap: 1046524 total, 0 used, 1046524 free. 153012 cached Mem\n"
|
||||||
|
"\n";
|
||||||
|
#endif
|
||||||
|
if (cmd_str.empty()) {
|
||||||
|
WarnL << "System::execute(\"top -b -n 1\") return empty";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto topMap = splitTopStr(cmd_str);
|
||||||
|
|
||||||
|
usage.task_total = topMap["Tasks"]["total"];
|
||||||
|
usage.task_running = topMap["Tasks"]["running"];
|
||||||
|
usage.task_sleeping = topMap["Tasks"]["sleeping"];
|
||||||
|
usage.task_stopped = topMap["Tasks"]["stopped"];
|
||||||
|
|
||||||
|
usage.cpu_user = topMap["%Cpu(s)"]["us"];
|
||||||
|
usage.cpu_sys = topMap["%Cpu(s)"]["sy"];
|
||||||
|
usage.cpu_idle = topMap["%Cpu(s)"]["id"];
|
||||||
|
|
||||||
|
usage.mem_total = topMap["KiB Mem"]["total"];
|
||||||
|
usage.mem_free = topMap["KiB Mem"]["free"];
|
||||||
|
usage.mem_used = topMap["KiB Mem"]["used"];
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#elif defined(__MACH__) || defined(__APPLE__)
|
||||||
|
/*
|
||||||
|
"Processes: 275 total, 2 running, 1 stuck, 272 sleeping, 1258 threads \n"
|
||||||
|
"2018/09/12 10:41:32\n"
|
||||||
|
"Load Avg: 2.06, 2.88, 2.86 \n"
|
||||||
|
"CPU usage: 14.54% user, 25.45% sys, 60.0% idle \n"
|
||||||
|
"SharedLibs: 117M resident, 37M data, 15M linkedit.\n"
|
||||||
|
"MemRegions: 46648 total, 3654M resident, 62M private, 714M shared.\n"
|
||||||
|
"PhysMem: 7809M used (1906M wired), 381M unused.\n"
|
||||||
|
"VM: 751G vsize, 614M framework vsize, 0(0) swapins, 0(0) swapouts.\n"
|
||||||
|
"Networks: packets: 502366/248M in, 408957/87M out.\n"
|
||||||
|
"Disks: 349435/6037M read, 78622/2577M written.";
|
||||||
|
*/
|
||||||
|
|
||||||
|
string cmd_str = System::execute("top -l 1");
|
||||||
|
if(cmd_str.empty()){
|
||||||
|
WarnL << "System::execute(\"top -n 1\") return empty";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto topMap = splitTopStr(cmd_str);
|
||||||
|
usage.task_total = topMap["Processes"]["total"];
|
||||||
|
usage.task_running = topMap["Processes"]["running"];
|
||||||
|
usage.task_sleeping = topMap["Processes"]["sleeping"];
|
||||||
|
usage.task_stopped = topMap["Processes"]["stuck"];
|
||||||
|
|
||||||
|
usage.cpu_user = topMap["CPU usage"]["user"];
|
||||||
|
usage.cpu_sys = topMap["CPU usage"]["sys"];
|
||||||
|
usage.cpu_idle = topMap["CPU usage"]["idle"];
|
||||||
|
|
||||||
|
usage.mem_free = topMap["PhysMem"]["unused"].as<uint32_t>() * 1024 * 1024;
|
||||||
|
usage.mem_used = topMap["PhysMem"]["used"].as<uint32_t>() * 1024 * 1024;
|
||||||
|
usage.mem_total = usage.mem_free + usage.mem_used;
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
WarnL << "System not supported";
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
} catch (std::exception &ex) {
|
||||||
|
WarnL << ex.what();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool System::getNetworkUsage(vector<NetworkUsage> &usage) {
|
||||||
|
try {
|
||||||
|
#if defined(__linux) || defined(__linux__) || defined(TEST_LINUX)
|
||||||
|
string cmd_str;
|
||||||
|
#if !defined(TEST_LINUX)
|
||||||
|
cmd_str = System::execute("cat /proc/net/dev");
|
||||||
|
#else
|
||||||
|
cmd_str =
|
||||||
|
"Inter-| Receive | Transmit\n"
|
||||||
|
" face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n"
|
||||||
|
" lo: 475978 7546 0 0 0 0 0 0 475978 7546 0 0 0 0 0 0\n"
|
||||||
|
"enp3s0: 151747818 315136 0 0 0 0 0 145 1590783447 1124616 0 0 0 0 0 0";
|
||||||
|
#endif
|
||||||
|
if (cmd_str.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto lines = split(cmd_str, "\n");
|
||||||
|
int i = 0;
|
||||||
|
vector<string> column_name_vec;
|
||||||
|
vector<string> category_prefix_vec;
|
||||||
|
for (auto &line : lines) {
|
||||||
|
switch (i++) {
|
||||||
|
case 0: {
|
||||||
|
category_prefix_vec = split(line, "|");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1: {
|
||||||
|
auto category_suffix_vec = split(line, "|");
|
||||||
|
int j = 0;
|
||||||
|
for (auto &category_suffix : category_suffix_vec) {
|
||||||
|
auto column_suffix_vec = split(category_suffix, " ");
|
||||||
|
for (auto &column_suffix : column_suffix_vec) {
|
||||||
|
column_name_vec.emplace_back(trim(category_prefix_vec[j]) + "-" + trim(column_suffix));
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
mINI valMap;
|
||||||
|
auto vals = split(line, " ");
|
||||||
|
int j = 0;
|
||||||
|
for (auto &val : vals) {
|
||||||
|
valMap[column_name_vec[j++]] = trim(val, " \r\n\t:");
|
||||||
|
}
|
||||||
|
usage.emplace_back(NetworkUsage());
|
||||||
|
auto &ifrUsage = usage.back();
|
||||||
|
ifrUsage.interface = valMap["Inter--face"];
|
||||||
|
ifrUsage.recv_bytes = valMap["Receive-bytes"];
|
||||||
|
ifrUsage.recv_packets = valMap["Receive-packets"];
|
||||||
|
ifrUsage.snd_bytes = valMap["Transmit-bytes"];
|
||||||
|
ifrUsage.snd_packets = valMap["Transmit-packets"];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
WarnL << "System not supported";
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
} catch (std::exception &ex) {
|
||||||
|
WarnL << ex.what();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool System::getTcpUsage(System::TcpUsage &usage) {
|
||||||
|
usage.established = atoi(trim(System::execute("netstat -na|grep ESTABLISHED|wc -l")).data());
|
||||||
|
usage.syn_recv = atoi(trim(System::execute("netstat -na|grep SYN_RECV|wc -l")).data());
|
||||||
|
usage.time_wait = atoi(trim(System::execute("netstat -na|grep TIME_WAIT|wc -l")).data());
|
||||||
|
usage.close_wait = atoi(trim(System::execute("netstat -na|grep CLOSE_WAIT|wc -l")).data());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string System::execute(const string &cmd) {
|
||||||
|
// DebugL << cmd;
|
||||||
|
FILE *fPipe = popen(cmd.data(), "r");
|
||||||
|
if(!fPipe){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
string ret;
|
||||||
|
char buff[1024] = {0};
|
||||||
|
while(fgets(buff, sizeof(buff), fPipe)){
|
||||||
|
ret.append(buff);
|
||||||
|
}
|
||||||
|
pclose(fPipe);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static string addr2line(const string &address) {
|
||||||
|
string cmd = StrPrinter << "addr2line -e " << exePath() << " " << address;
|
||||||
|
return System::execute(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sig_crash(int sig) {
|
||||||
|
signal(sig, SIG_DFL);
|
||||||
|
void *array[MAX_STACK_FRAMES];
|
||||||
|
int size = backtrace(array, MAX_STACK_FRAMES);
|
||||||
|
char ** strings = backtrace_symbols(array, size);
|
||||||
|
vector<vector<string> > stack(size);
|
||||||
|
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
auto &ref = stack[i];
|
||||||
|
std::string symbol(strings[i]);
|
||||||
|
ref.emplace_back(symbol);
|
||||||
|
#if defined(__linux) || defined(__linux__)
|
||||||
|
size_t pos1 = symbol.find_first_of("[");
|
||||||
|
size_t pos2 = symbol.find_last_of("]");
|
||||||
|
std::string address = symbol.substr(pos1 + 1, pos2 - pos1 - 1);
|
||||||
|
ref.emplace_back(addr2line(address));
|
||||||
|
#endif//__linux
|
||||||
|
}
|
||||||
|
free(strings);
|
||||||
|
|
||||||
|
NoticeCenter::Instance().emitEvent(kBroadcastOnCrashDump,sig,stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void System::startDaemon() {
|
||||||
|
signal(SIGTTOU,SIG_IGN);
|
||||||
|
signal(SIGTTIN,SIG_IGN);
|
||||||
|
signal(SIGHUP,SIG_IGN);
|
||||||
|
signal(SIGINT, [](int) {
|
||||||
|
InfoL << "SIGINT:exit";
|
||||||
|
signal(SIGINT,SIG_IGN);
|
||||||
|
throw ExitException();
|
||||||
|
});
|
||||||
|
|
||||||
|
do{
|
||||||
|
auto pid = fork();
|
||||||
|
if(pid == -1){
|
||||||
|
WarnL << "fork失败:" << get_uv_errmsg();
|
||||||
|
//休眠1秒再试
|
||||||
|
sleep(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(pid == 0){
|
||||||
|
//子进程
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//父进程,监视子进程是否退出
|
||||||
|
DebugL << "启动子进程:" << pid;
|
||||||
|
do{
|
||||||
|
try {
|
||||||
|
int status = 0;
|
||||||
|
if(waitpid(pid, &status, 0) >= 0) {
|
||||||
|
WarnL << "子进程退出";
|
||||||
|
//休眠1秒再启动子进程
|
||||||
|
sleep(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DebugL << "waitpid被中断:" << get_uv_errmsg();
|
||||||
|
}catch (ExitException &ex){
|
||||||
|
WarnL << "收到主动退出信号,关闭父进程与子进程";
|
||||||
|
//通知子进程主动退出
|
||||||
|
kill(pid,SIGINT);
|
||||||
|
//父进程主动退出
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}while (true);
|
||||||
|
}while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static string currentDateTime(){
|
||||||
|
time_t ts = time(NULL);
|
||||||
|
std::tm tm_snapshot;
|
||||||
|
localtime_r(&ts, &tm_snapshot);
|
||||||
|
|
||||||
|
char buffer[1024] = {0};
|
||||||
|
std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm_snapshot);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void System::systemSetup(){
|
||||||
|
struct rlimit rlim,rlim_new;
|
||||||
|
if (getrlimit(RLIMIT_CORE, &rlim)==0) {
|
||||||
|
rlim_new.rlim_cur = rlim_new.rlim_max = RLIM_INFINITY;
|
||||||
|
if (setrlimit(RLIMIT_CORE, &rlim_new)!=0) {
|
||||||
|
rlim_new.rlim_cur = rlim_new.rlim_max = rlim.rlim_max;
|
||||||
|
setrlimit(RLIMIT_CORE, &rlim_new);
|
||||||
|
}
|
||||||
|
InfoL << "core文件大小设置为:" << rlim_new.rlim_cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getrlimit(RLIMIT_NOFILE, &rlim)==0) {
|
||||||
|
rlim_new.rlim_cur = rlim_new.rlim_max = RLIM_INFINITY;
|
||||||
|
if (setrlimit(RLIMIT_NOFILE, &rlim_new)!=0) {
|
||||||
|
rlim_new.rlim_cur = rlim_new.rlim_max = rlim.rlim_max;
|
||||||
|
setrlimit(RLIMIT_NOFILE, &rlim_new);
|
||||||
|
}
|
||||||
|
InfoL << "文件最大描述符个数设置为:" << rlim_new.rlim_cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
signal(SIGSEGV, sig_crash);
|
||||||
|
signal(SIGABRT, sig_crash);
|
||||||
|
NoticeCenter::Instance().addListener(nullptr,kBroadcastOnCrashDump,[](BroadcastOnCrashDumpArgs){
|
||||||
|
stringstream ss;
|
||||||
|
ss << "## crash date:" << currentDateTime() << endl;
|
||||||
|
ss << "## exe: " << exeName() << endl;
|
||||||
|
ss << "## signal: " << sig << endl;
|
||||||
|
ss << "## stack: " << endl;
|
||||||
|
for (int i = 0; i < stack.size(); ++i) {
|
||||||
|
ss << "[" << i << "]: ";
|
||||||
|
for (auto &str : stack[i]){
|
||||||
|
ss << str << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string stack_info = ss.str();
|
||||||
|
ofstream out(StrPrinter << exeDir() << "/crash." << getpid(), ios::out | ios::binary | ios::trunc);
|
||||||
|
out << stack_info;
|
||||||
|
out.flush();
|
||||||
|
|
||||||
|
cerr << stack_info << endl;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
68
server/System.h
Normal file
68
server/System.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
//
|
||||||
|
// Created by xzl on 2018/9/5.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef IPTV_BASH_H
|
||||||
|
#define IPTV_BASH_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include "Util/NoticeCenter.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace toolkit;
|
||||||
|
|
||||||
|
class System {
|
||||||
|
public:
|
||||||
|
typedef struct {
|
||||||
|
uint32_t task_total;
|
||||||
|
uint32_t task_running;
|
||||||
|
uint32_t task_sleeping;
|
||||||
|
uint32_t task_stopped;
|
||||||
|
|
||||||
|
uint64_t mem_total;
|
||||||
|
uint64_t mem_free;
|
||||||
|
uint64_t mem_used;
|
||||||
|
|
||||||
|
float cpu_user;
|
||||||
|
float cpu_sys;
|
||||||
|
float cpu_idle;
|
||||||
|
} SystemUsage;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t recv_bytes;
|
||||||
|
uint64_t recv_packets;
|
||||||
|
uint64_t snd_bytes;
|
||||||
|
uint64_t snd_packets;
|
||||||
|
string interface;
|
||||||
|
} NetworkUsage;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t available;
|
||||||
|
uint64_t used;
|
||||||
|
float used_per;
|
||||||
|
string mounted_on;
|
||||||
|
string filesystem;
|
||||||
|
bool mounted;
|
||||||
|
} DiskUsage;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t established;
|
||||||
|
uint32_t syn_recv;
|
||||||
|
uint32_t time_wait;
|
||||||
|
uint32_t close_wait;
|
||||||
|
} TcpUsage;
|
||||||
|
|
||||||
|
static bool getSystemUsage(SystemUsage &usage);
|
||||||
|
static bool getNetworkUsage(vector<NetworkUsage> &usage);
|
||||||
|
static bool getTcpUsage(TcpUsage &usage);
|
||||||
|
static string execute(const string &cmd);
|
||||||
|
static void startDaemon();
|
||||||
|
static void systemSetup();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //IPTV_BASH_H
|
324
server/WebApi.cpp
Normal file
324
server/WebApi.cpp
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
#include <signal.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <sstream>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include "jsoncpp/json.h"
|
||||||
|
#include "Util/util.h"
|
||||||
|
#include "Util/logger.h"
|
||||||
|
#include "Util/onceToken.h"
|
||||||
|
#include "Util/NoticeCenter.h"
|
||||||
|
#include "Util/SqlPool.h"
|
||||||
|
#include "Common/config.h"
|
||||||
|
#include "Common/MediaSource.h"
|
||||||
|
#include "Http/HttpRequester.h"
|
||||||
|
#include "Http/HttpSession.h"
|
||||||
|
#include "Network/TcpServer.h"
|
||||||
|
|
||||||
|
using namespace Json;
|
||||||
|
using namespace toolkit;
|
||||||
|
using namespace mediakit;
|
||||||
|
|
||||||
|
#define API_ARGS HttpSession::KeyValue &headerIn, \
|
||||||
|
HttpSession::KeyValue &headerOut, \
|
||||||
|
HttpSession::KeyValue &allArgs, \
|
||||||
|
Json::Value &val
|
||||||
|
|
||||||
|
#define API_REGIST(field, name, ...) \
|
||||||
|
s_map_api.emplace("/index/"#field"/"#name,[](API_ARGS,const HttpSession::HttpResponseInvoker &invoker){ \
|
||||||
|
static auto lam = [&](API_ARGS) __VA_ARGS__ ; \
|
||||||
|
lam(headerIn, headerOut, allArgs, val); \
|
||||||
|
invoker("200 OK", headerOut, val.toStyledString()); \
|
||||||
|
});
|
||||||
|
|
||||||
|
#define API_REGIST_INVOKER(field, name, ...) \
|
||||||
|
s_map_api.emplace("/index/"#field"/"#name,[](API_ARGS,const HttpSession::HttpResponseInvoker &invoker) __VA_ARGS__);
|
||||||
|
|
||||||
|
//异步http api lambad定义
|
||||||
|
typedef std::function<void(API_ARGS,const HttpSession::HttpResponseInvoker &invoker)> AsyncHttpApi;
|
||||||
|
//api列表
|
||||||
|
static map<string, AsyncHttpApi> s_map_api;
|
||||||
|
|
||||||
|
namespace API {
|
||||||
|
typedef enum {
|
||||||
|
SqlFailed = -200,
|
||||||
|
AuthFailed = -100,
|
||||||
|
OtherFailed = -1,
|
||||||
|
Success = 0
|
||||||
|
} ApiErr;
|
||||||
|
|
||||||
|
#define API_FIELD "api."
|
||||||
|
const char kApiDebug[] = API_FIELD"apiDebug";
|
||||||
|
static onceToken token([]() {
|
||||||
|
mINI::Instance()[kApiDebug] = "0";
|
||||||
|
});
|
||||||
|
}//namespace API
|
||||||
|
|
||||||
|
class ApiRetException: public std::runtime_error {
|
||||||
|
public:
|
||||||
|
ApiRetException(const char *str = "success" ,int code = API::Success):runtime_error(str){
|
||||||
|
_code = code;
|
||||||
|
}
|
||||||
|
~ApiRetException() = default;
|
||||||
|
int code(){ return _code; }
|
||||||
|
private:
|
||||||
|
int _code;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AuthException : public ApiRetException {
|
||||||
|
public:
|
||||||
|
AuthException(const char *str):ApiRetException(str,API::AuthFailed){}
|
||||||
|
~AuthException() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//获取HTTP请求中url参数、content参数
|
||||||
|
static HttpSession::KeyValue getAllArgs(const Parser &parser) {
|
||||||
|
HttpSession::KeyValue allArgs;
|
||||||
|
{
|
||||||
|
//TraceL << parser.FullUrl() << "\r\n" << parser.Content();
|
||||||
|
auto &urlArgs = parser.getUrlArgs();
|
||||||
|
auto contentArgs = parser.parseArgs(parser.Content());
|
||||||
|
for (auto &pr : contentArgs) {
|
||||||
|
allArgs.emplace(pr.first, HttpSession::urlDecode(pr.second));
|
||||||
|
}
|
||||||
|
for (auto &pr : urlArgs) {
|
||||||
|
allArgs.emplace(pr.first, HttpSession::urlDecode(pr.second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void addHttpListener(){
|
||||||
|
GET_CONFIG_AND_REGISTER(bool, api_debug, API::kApiDebug);
|
||||||
|
//注册监听kBroadcastHttpRequest事件
|
||||||
|
NoticeCenter::Instance().addListener(nullptr, Broadcast::kBroadcastHttpRequest, [](BroadcastHttpRequestArgs) {
|
||||||
|
auto it = s_map_api.find(parser.Url());
|
||||||
|
if (it == s_map_api.end()) {
|
||||||
|
consumed = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//该api已被消费
|
||||||
|
consumed = true;
|
||||||
|
AsyncHttpApi api = it->second;
|
||||||
|
//异步执行该api,防止阻塞NoticeCenter
|
||||||
|
EventPollerPool::Instance().getExecutor()->async([api, parser, invoker]() {
|
||||||
|
//执行API
|
||||||
|
Json::Value val;
|
||||||
|
val["code"] = API::Success;
|
||||||
|
HttpSession::KeyValue &headerIn = parser.getValues();
|
||||||
|
HttpSession::KeyValue headerOut;
|
||||||
|
HttpSession::KeyValue allArgs = getAllArgs(parser);
|
||||||
|
headerOut["Content-Type"] = "application/json; charset=utf-8";
|
||||||
|
if(api_debug){
|
||||||
|
auto newInvoker = [invoker,parser,allArgs](const string &codeOut,
|
||||||
|
const HttpSession::KeyValue &headerOut,
|
||||||
|
const string &contentOut){
|
||||||
|
stringstream ss;
|
||||||
|
for(auto &pr : allArgs ){
|
||||||
|
ss << pr.first << " : " << pr.second << "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugL << "request:\r\n" << parser.Method() << " " << parser.FullUrl() << "\r\n"
|
||||||
|
<< "content:\r\n" << parser.Content() << "\r\n"
|
||||||
|
<< "args:\r\n" << ss.str()
|
||||||
|
<< "response:\r\n"
|
||||||
|
<< contentOut << "\r\n";
|
||||||
|
|
||||||
|
invoker(codeOut,headerOut,contentOut);
|
||||||
|
};
|
||||||
|
((HttpSession::HttpResponseInvoker &)invoker) = newInvoker;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
api(headerIn, headerOut, allArgs, val, invoker);
|
||||||
|
} catch(AuthException &ex){
|
||||||
|
val["code"] = API::AuthFailed;
|
||||||
|
val["msg"] = ex.what();
|
||||||
|
invoker("200 OK", headerOut, val.toStyledString());
|
||||||
|
} catch(ApiRetException &ex){
|
||||||
|
val["code"] = ex.code();
|
||||||
|
val["msg"] = ex.what();
|
||||||
|
invoker("200 OK", headerOut, val.toStyledString());
|
||||||
|
} catch(SqlException &ex){
|
||||||
|
val["code"] = API::SqlFailed;
|
||||||
|
val["msg"] = StrPrinter << "操作数据库失败:" << ex.what() << ":" << ex.getSql();
|
||||||
|
WarnL << ex.what() << ":" << ex.getSql();
|
||||||
|
invoker("200 OK", headerOut, val.toStyledString());
|
||||||
|
} catch (std::exception &ex) {
|
||||||
|
val["code"] = API::OtherFailed;
|
||||||
|
val["msg"] = ex.what();
|
||||||
|
invoker("200 OK", headerOut, val.toStyledString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//安装api接口
|
||||||
|
void installWebApi() {
|
||||||
|
addHttpListener();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取线程负载
|
||||||
|
*/
|
||||||
|
API_REGIST_INVOKER(api, getThreadsLoad, {
|
||||||
|
EventPollerPool::Instance().getExecutorDelay([invoker, headerOut](const vector<int> &vecDelay) {
|
||||||
|
Value val;
|
||||||
|
auto vec = EventPollerPool::Instance().getExecutorLoad();
|
||||||
|
int i = 0;
|
||||||
|
for (auto load : vec) {
|
||||||
|
Value obj(objectValue);
|
||||||
|
obj["load"] = load;
|
||||||
|
obj["delay"] = vecDelay[i++];
|
||||||
|
val["data"].append(obj);
|
||||||
|
}
|
||||||
|
invoker("200 OK", headerOut, val.toStyledString());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取服务器配置
|
||||||
|
*/
|
||||||
|
API_REGIST(api, getServerConfig, {
|
||||||
|
Value obj;
|
||||||
|
for (auto &pr : mINI::Instance()) {
|
||||||
|
obj[pr.first] = (string &) pr.second;
|
||||||
|
}
|
||||||
|
val["data"].append(obj);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置服务器配置
|
||||||
|
*/
|
||||||
|
API_REGIST(api, setServerConfig, {
|
||||||
|
auto &ini = mINI::Instance();
|
||||||
|
int changed = 0;
|
||||||
|
for (auto &pr : allArgs) {
|
||||||
|
if (ini.find(pr.first) == ini.end()) {
|
||||||
|
//没有这个key
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ini[pr.first] == pr.second) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ini[pr.first] = pr.second;
|
||||||
|
//替换成功
|
||||||
|
++changed;
|
||||||
|
}
|
||||||
|
if (changed > 0) {
|
||||||
|
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastReloadConfig);
|
||||||
|
ini.dumpFile();
|
||||||
|
}
|
||||||
|
val["changed"] = changed;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取服务器api列表
|
||||||
|
*/
|
||||||
|
API_REGIST(api,getApiList,{
|
||||||
|
for(auto &pr : s_map_api){
|
||||||
|
val["data"].append(pr.first);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重启服务器
|
||||||
|
*/
|
||||||
|
API_REGIST(api,restartServer,{
|
||||||
|
EventPollerPool::Instance().getPoller()->doDelayTask(1000,[](){
|
||||||
|
//尝试正常退出
|
||||||
|
::kill(getpid(), SIGINT);
|
||||||
|
|
||||||
|
//3秒后强制退出
|
||||||
|
EventPollerPool::Instance().getPoller()->doDelayTask(3000,[](){
|
||||||
|
exit(0);
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
val["msg"] = "服务器将在一秒后自动重启";
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
API_REGIST(api,getMediaList,{
|
||||||
|
//获取所有MediaSource列表
|
||||||
|
val["code"] = 0;
|
||||||
|
val["msg"] = "success";
|
||||||
|
MediaSource::for_each_media([&](const string &schema,
|
||||||
|
const string &vhost,
|
||||||
|
const string &app,
|
||||||
|
const string &stream,
|
||||||
|
const MediaSource::Ptr &media){
|
||||||
|
if(!allArgs["schema"].empty() && allArgs["schema"] != schema){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!allArgs["vhost"].empty() && allArgs["vhost"] != vhost){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!allArgs["app"].empty() && allArgs["app"] != app){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Value item;
|
||||||
|
item["schema"] = schema;
|
||||||
|
item["vhost"] = vhost;
|
||||||
|
item["app"] = app;
|
||||||
|
item["stream"] = stream;
|
||||||
|
val["data"]["array"].append(item);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
API_REGIST(api,kick_pusher,{
|
||||||
|
//踢掉推流器
|
||||||
|
auto src = MediaSource::find(allArgs["schema"],
|
||||||
|
allArgs["vhost"],
|
||||||
|
allArgs["app"],
|
||||||
|
allArgs["stream"]);
|
||||||
|
if(src){
|
||||||
|
bool flag = src->close();
|
||||||
|
val["code"] = flag ? 0 : -1;
|
||||||
|
val["msg"] = flag ? "success" : "kick failed";
|
||||||
|
}else{
|
||||||
|
val["code"] = -2;
|
||||||
|
val["msg"] = "can not find the pusher";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
API_REGIST(api,kick_session,{
|
||||||
|
//踢掉tcp会话
|
||||||
|
auto id = allArgs["id"];
|
||||||
|
if(id.empty()){
|
||||||
|
val["code"] = -1;
|
||||||
|
val["msg"] = "illegal parameter:id";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto session = SessionMap::Instance().get(id);
|
||||||
|
if(!session){
|
||||||
|
val["code"] = -2;
|
||||||
|
val["msg"] = "can not find the target";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
session->safeShutdown();
|
||||||
|
val["code"] = 0;
|
||||||
|
val["msg"] = "success";
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
////////////以下是注册的Hook API////////////
|
||||||
|
API_REGIST(hook,on_publish,{
|
||||||
|
//开始推流事件
|
||||||
|
val["code"] = 0;
|
||||||
|
val["msg"] = "success";
|
||||||
|
});
|
||||||
|
|
||||||
|
API_REGIST(hook,on_play,{
|
||||||
|
//开始播放事件
|
||||||
|
val["code"] = 0;
|
||||||
|
val["msg"] = "success";
|
||||||
|
});
|
||||||
|
|
||||||
|
API_REGIST(hook,on_flow_report,{
|
||||||
|
//流量统计hook api
|
||||||
|
val["code"] = 0;
|
||||||
|
val["msg"] = "success";
|
||||||
|
});
|
||||||
|
}
|
169
server/WebHook.cpp
Normal file
169
server/WebHook.cpp
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
#include <sstream>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <mutex>
|
||||||
|
#include "System.h"
|
||||||
|
#include "jsoncpp/json.h"
|
||||||
|
#include "Util/logger.h"
|
||||||
|
#include "Util/util.h"
|
||||||
|
#include "Util/onceToken.h"
|
||||||
|
#include "Util/NoticeCenter.h"
|
||||||
|
#include "Common/config.h"
|
||||||
|
#include "Common/MediaSource.h"
|
||||||
|
#include "Http/HttpRequester.h"
|
||||||
|
#include "Network/TcpSession.h"
|
||||||
|
|
||||||
|
using namespace Json;
|
||||||
|
using namespace toolkit;
|
||||||
|
using namespace mediakit;
|
||||||
|
|
||||||
|
namespace Hook {
|
||||||
|
#define HOOK_FIELD "hook."
|
||||||
|
|
||||||
|
const char kEnable[] = HOOK_FIELD"enable";
|
||||||
|
const char kTimeoutSec[] = HOOK_FIELD"timeoutSec";
|
||||||
|
const char kOnPublish[] = HOOK_FIELD"on_publish";
|
||||||
|
const char kOnPlay[] = HOOK_FIELD"on_play";
|
||||||
|
const char kOnFlowReport[] = HOOK_FIELD"on_flow_report";
|
||||||
|
const char kAdminParams[] = HOOK_FIELD"admin_params";
|
||||||
|
|
||||||
|
onceToken token([](){
|
||||||
|
mINI::Instance()[kEnable] = false;
|
||||||
|
mINI::Instance()[kTimeoutSec] = 10;
|
||||||
|
mINI::Instance()[kOnPublish] = "http://127.0.0.1/index/hook/on_publish";
|
||||||
|
mINI::Instance()[kOnPlay] = "http://127.0.0.1/index/hook/on_play";
|
||||||
|
mINI::Instance()[kOnFlowReport] = "http://127.0.0.1/index/hook/on_flow_report";
|
||||||
|
mINI::Instance()[kAdminParams] = "token=035c73f7-bb6b-4889-a715-d9eb2d1925cc";
|
||||||
|
},nullptr);
|
||||||
|
}//namespace Hook
|
||||||
|
|
||||||
|
|
||||||
|
static void parse_http_response(const SockException &ex,
|
||||||
|
const string &status,
|
||||||
|
const HttpClient::HttpHeader &header,
|
||||||
|
const string &strRecvBody,
|
||||||
|
const function<void(const Value &,const string &)> &fun){
|
||||||
|
if(ex){
|
||||||
|
auto errStr = StrPrinter << "[network err]:" << ex.what() << endl;
|
||||||
|
fun(Json::nullValue,errStr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(status != "200"){
|
||||||
|
auto errStr = StrPrinter << "[bad http status code]:" << status << endl;
|
||||||
|
fun(Json::nullValue,errStr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
stringstream ss(strRecvBody);
|
||||||
|
Value result;
|
||||||
|
ss >> result;
|
||||||
|
if(result["code"].asInt() != 0) {
|
||||||
|
auto errStr = StrPrinter << "[json code]:" << "code=" << result["code"] << ",msg=" << result["msg"] << endl;
|
||||||
|
fun(Json::nullValue,errStr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fun(result,"");
|
||||||
|
}catch (std::exception &ex){
|
||||||
|
auto errStr = StrPrinter << "[parse json failed]:" << ex.what() << endl;
|
||||||
|
fun(Json::nullValue,errStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_http_hook(const string &url,const Value &body,const function<void(const Value &,const string &)> &fun){
|
||||||
|
GET_CONFIG_AND_REGISTER(float,hook_timeoutSec,Hook::kTimeoutSec);
|
||||||
|
HttpRequester::Ptr requester(new HttpRequester);
|
||||||
|
requester->setMethod("POST");
|
||||||
|
requester->setBody(body.toStyledString());
|
||||||
|
requester->addHeader("Content-Type","application/json; charset=utf-8");
|
||||||
|
std::shared_ptr<Ticker> pTicker(new Ticker);
|
||||||
|
requester->startRequester(url,[url,fun,body,requester,pTicker](const SockException &ex,
|
||||||
|
const string &status,
|
||||||
|
const HttpClient::HttpHeader &header,
|
||||||
|
const string &strRecvBody){
|
||||||
|
onceToken token(nullptr,[&](){
|
||||||
|
const_cast<HttpRequester::Ptr &>(requester).reset();
|
||||||
|
});
|
||||||
|
parse_http_response(ex,status,header,strRecvBody,[&](const Value &obj,const string &err){
|
||||||
|
if(fun){
|
||||||
|
fun(obj,err);
|
||||||
|
}
|
||||||
|
if(!err.empty()) {
|
||||||
|
WarnL << "hook " << url << " " <<pTicker->elapsedTime() << "ms,failed" << err << ":" << body;
|
||||||
|
}else if(pTicker->elapsedTime() > 500){
|
||||||
|
DebugL << "hook " << url << " " <<pTicker->elapsedTime() << "ms,success:" << body;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},hook_timeoutSec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Value make_json(const MediaInfo &args){
|
||||||
|
Value body;
|
||||||
|
body["schema"] = args._schema;
|
||||||
|
body["vhost"] = args._vhost;
|
||||||
|
body["app"] = args._app;
|
||||||
|
body["stream"] = args._streamid;
|
||||||
|
body["params"] = args._param_strs;
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void installWebHook(){
|
||||||
|
GET_CONFIG_AND_REGISTER(bool,hook_enable,Hook::kEnable);
|
||||||
|
GET_CONFIG_AND_REGISTER(string,hook_publish,Hook::kOnPublish);
|
||||||
|
GET_CONFIG_AND_REGISTER(string,hook_play,Hook::kOnPlay);
|
||||||
|
GET_CONFIG_AND_REGISTER(string,hook_flowreport,Hook::kOnFlowReport);
|
||||||
|
GET_CONFIG_AND_REGISTER(string,hook_adminparams,Hook::kAdminParams);
|
||||||
|
|
||||||
|
NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastRtmpPublish,[](BroadcastRtmpPublishArgs){
|
||||||
|
if(!hook_enable || args._param_strs == hook_adminparams){
|
||||||
|
invoker("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//异步执行该hook api,防止阻塞NoticeCenter
|
||||||
|
Value body = make_json(args);
|
||||||
|
body["ip"] = sender.get_peer_ip();
|
||||||
|
body["port"] = sender.get_peer_port();
|
||||||
|
body["id"] = sender.getIdentifier();
|
||||||
|
EventPollerPool::Instance().getExecutor()->async([body,invoker](){
|
||||||
|
//执行hook
|
||||||
|
do_http_hook(hook_publish,body,[invoker](const Value &obj,const string &err){
|
||||||
|
invoker(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastMediaPlayed,[](BroadcastMediaPlayedArgs){
|
||||||
|
if(!hook_enable || args._param_strs == hook_adminparams){
|
||||||
|
invoker("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Value body = make_json(args);
|
||||||
|
body["ip"] = sender.get_peer_ip();
|
||||||
|
body["port"] = sender.get_peer_port();
|
||||||
|
body["id"] = sender.getIdentifier();
|
||||||
|
//异步执行该hook api,防止阻塞NoticeCenter
|
||||||
|
EventPollerPool::Instance().getExecutor()->async([body,invoker](){
|
||||||
|
//执行hook
|
||||||
|
do_http_hook(hook_play,body,[invoker](const Value &obj,const string &err){
|
||||||
|
invoker(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastFlowReport,[](BroadcastFlowReportArgs){
|
||||||
|
if(!hook_enable || args._param_strs == hook_adminparams){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Value body = make_json(args);
|
||||||
|
body["ip"] = sender.get_peer_ip();
|
||||||
|
body["port"] = sender.get_peer_port();
|
||||||
|
body["id"] = sender.getIdentifier();
|
||||||
|
body["totalBytes"] = (Json::UInt64)totalBytes;
|
||||||
|
body["duration"] = (Json::UInt64)totalDuration;
|
||||||
|
|
||||||
|
//流量统计事件
|
||||||
|
EventPollerPool::Instance().getExecutor()->async([body,totalBytes](){
|
||||||
|
//执行hook
|
||||||
|
do_http_hook(hook_flowreport,body, nullptr);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
282
server/main.cpp
Normal file
282
server/main.cpp
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016-2019 xiongziliang <771730766@qq.com>
|
||||||
|
*
|
||||||
|
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include "Util/MD5.h"
|
||||||
|
#include "Util/File.h"
|
||||||
|
#include "Util/logger.h"
|
||||||
|
#include "Util/SSLBox.h"
|
||||||
|
#include "Util/onceToken.h"
|
||||||
|
#include "Util/CMD.h"
|
||||||
|
#include "Network/TcpServer.h"
|
||||||
|
#include "Poller/EventPoller.h"
|
||||||
|
#include "Common/config.h"
|
||||||
|
#include "Rtsp/UDPServer.h"
|
||||||
|
#include "Rtsp/RtspSession.h"
|
||||||
|
#include "Rtmp/RtmpSession.h"
|
||||||
|
#include "Shell/ShellSession.h"
|
||||||
|
#include "RtmpMuxer/FlvMuxer.h"
|
||||||
|
#include "Player/PlayerProxy.h"
|
||||||
|
#include "Http/WebSocketSession.h"
|
||||||
|
#include "System.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace toolkit;
|
||||||
|
using namespace mediakit;
|
||||||
|
|
||||||
|
namespace mediakit {
|
||||||
|
////////////HTTP配置///////////
|
||||||
|
namespace Http {
|
||||||
|
#define HTTP_FIELD "http."
|
||||||
|
#define HTTP_PORT 80
|
||||||
|
const char kPort[] = HTTP_FIELD"port";
|
||||||
|
#define HTTPS_PORT 443
|
||||||
|
const char kSSLPort[] = HTTP_FIELD"sslport";
|
||||||
|
onceToken token1([](){
|
||||||
|
mINI::Instance()[kPort] = HTTP_PORT;
|
||||||
|
mINI::Instance()[kSSLPort] = HTTPS_PORT;
|
||||||
|
},nullptr);
|
||||||
|
}//namespace Http
|
||||||
|
|
||||||
|
////////////SHELL配置///////////
|
||||||
|
namespace Shell {
|
||||||
|
#define SHELL_FIELD "shell."
|
||||||
|
#define SHELL_PORT 9000
|
||||||
|
const char kPort[] = SHELL_FIELD"port";
|
||||||
|
onceToken token1([](){
|
||||||
|
mINI::Instance()[kPort] = SHELL_PORT;
|
||||||
|
},nullptr);
|
||||||
|
} //namespace Shell
|
||||||
|
|
||||||
|
////////////RTSP服务器配置///////////
|
||||||
|
namespace Rtsp {
|
||||||
|
#define RTSP_FIELD "rtsp."
|
||||||
|
#define RTSP_PORT 554
|
||||||
|
#define RTSPS_PORT 322
|
||||||
|
const char kPort[] = RTSP_FIELD"port";
|
||||||
|
const char kSSLPort[] = RTSP_FIELD"sslport";
|
||||||
|
onceToken token1([](){
|
||||||
|
mINI::Instance()[kPort] = RTSP_PORT;
|
||||||
|
mINI::Instance()[kSSLPort] = RTSPS_PORT;
|
||||||
|
},nullptr);
|
||||||
|
|
||||||
|
} //namespace Rtsp
|
||||||
|
|
||||||
|
////////////RTMP服务器配置///////////
|
||||||
|
namespace Rtmp {
|
||||||
|
#define RTMP_FIELD "rtmp."
|
||||||
|
#define RTMP_PORT 1935
|
||||||
|
const char kPort[] = RTMP_FIELD"port";
|
||||||
|
onceToken token1([](){
|
||||||
|
mINI::Instance()[kPort] = RTMP_PORT;
|
||||||
|
},nullptr);
|
||||||
|
} //namespace RTMP
|
||||||
|
} // namespace mediakit
|
||||||
|
|
||||||
|
|
||||||
|
class CMD_main : public CMD {
|
||||||
|
public:
|
||||||
|
CMD_main() {
|
||||||
|
_parser.reset(new OptionParser(nullptr));
|
||||||
|
|
||||||
|
(*_parser) << Option('d',/*该选项简称,如果是\x00则说明无简称*/
|
||||||
|
"daemon",/*该选项全称,每个选项必须有全称;不得为null或空字符串*/
|
||||||
|
Option::ArgNone,/*该选项后面必须跟值*/
|
||||||
|
nullptr,/*该选项默认值*/
|
||||||
|
false,/*该选项是否必须赋值,如果没有默认值且为ArgRequired时用户必须提供该参数否则将抛异常*/
|
||||||
|
"是否以Daemon方式启动",/*该选项说明文字*/
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
(*_parser) << Option('l',/*该选项简称,如果是\x00则说明无简称*/
|
||||||
|
"level",/*该选项全称,每个选项必须有全称;不得为null或空字符串*/
|
||||||
|
Option::ArgRequired,/*该选项后面必须跟值*/
|
||||||
|
to_string(LTrace).data(),/*该选项默认值*/
|
||||||
|
false,/*该选项是否必须赋值,如果没有默认值且为ArgRequired时用户必须提供该参数否则将抛异常*/
|
||||||
|
"日志等级,LTrace~LError(0~4)",/*该选项说明文字*/
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
(*_parser) << Option('c',/*该选项简称,如果是\x00则说明无简称*/
|
||||||
|
"config",/*该选项全称,每个选项必须有全称;不得为null或空字符串*/
|
||||||
|
Option::ArgRequired,/*该选项后面必须跟值*/
|
||||||
|
(exeDir() + "config.ini").data(),/*该选项默认值*/
|
||||||
|
false,/*该选项是否必须赋值,如果没有默认值且为ArgRequired时用户必须提供该参数否则将抛异常*/
|
||||||
|
"配置文件路径",/*该选项说明文字*/
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
(*_parser) << Option('s',/*该选项简称,如果是\x00则说明无简称*/
|
||||||
|
"ssl",/*该选项全称,每个选项必须有全称;不得为null或空字符串*/
|
||||||
|
Option::ArgRequired,/*该选项后面必须跟值*/
|
||||||
|
(exeDir() + "ssl.p12").data(),/*该选项默认值*/
|
||||||
|
false,/*该选项是否必须赋值,如果没有默认值且为ArgRequired时用户必须提供该参数否则将抛异常*/
|
||||||
|
"ssl证书路径,支持p12/pem类型",/*该选项说明文字*/
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
(*_parser) << Option('t',/*该选项简称,如果是\x00则说明无简称*/
|
||||||
|
"threads",/*该选项全称,每个选项必须有全称;不得为null或空字符串*/
|
||||||
|
Option::ArgRequired,/*该选项后面必须跟值*/
|
||||||
|
to_string(thread::hardware_concurrency()).data(),/*该选项默认值*/
|
||||||
|
false,/*该选项是否必须赋值,如果没有默认值且为ArgRequired时用户必须提供该参数否则将抛异常*/
|
||||||
|
"启动事件触发线程数",/*该选项说明文字*/
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~CMD_main() {}
|
||||||
|
virtual const char *description() const {
|
||||||
|
return "主程序命令参数";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern void installWebApi();
|
||||||
|
extern void installWebHook();
|
||||||
|
|
||||||
|
static void inline listen_shell_input(){
|
||||||
|
cout << "> 欢迎进入命令模式,你可以输入\"help\"命令获取帮助" << endl;
|
||||||
|
cout << "> " << std::flush;
|
||||||
|
SockUtil::setNoBlocked(STDIN_FILENO);
|
||||||
|
auto oninput = [](int event) {
|
||||||
|
if (event & Event_Read) {
|
||||||
|
char buf[1024];
|
||||||
|
int n = read(STDIN_FILENO, buf, sizeof(buf));
|
||||||
|
if (n > 0) {
|
||||||
|
buf[n] = '\0';
|
||||||
|
try {
|
||||||
|
CMDRegister::Instance()(buf);
|
||||||
|
cout << "> " << std::flush;
|
||||||
|
} catch (ExitException &ex) {
|
||||||
|
InfoL << "ExitException";
|
||||||
|
kill(getpid(), SIGINT);
|
||||||
|
} catch (std::exception &ex) {
|
||||||
|
cout << ex.what() << endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DebugL << get_uv_errmsg();
|
||||||
|
EventPollerPool::Instance().getFirstPoller()->delEvent(STDIN_FILENO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event & Event_Error) {
|
||||||
|
WarnL << "Event_Error";
|
||||||
|
EventPollerPool::Instance().getFirstPoller()->delEvent(STDIN_FILENO);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
EventPollerPool::Instance().getFirstPoller()->addEvent(STDIN_FILENO, Event_Read | Event_Error | Event_LT,oninput);
|
||||||
|
}
|
||||||
|
int main(int argc,char *argv[]) {
|
||||||
|
CMD_main cmd_main;
|
||||||
|
try {
|
||||||
|
cmd_main.operator()(argc,argv);
|
||||||
|
} catch (std::exception &ex) {
|
||||||
|
cout << ex.what() << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bDaemon = cmd_main.hasKey("daemon");
|
||||||
|
LogLevel logLevel = (LogLevel)cmd_main["level"].as<int>();
|
||||||
|
logLevel = MIN(MAX(logLevel,LTrace),LError);
|
||||||
|
string ini_file = cmd_main["config"];
|
||||||
|
string ssl_file = cmd_main["ssl"];
|
||||||
|
int threads = cmd_main["threads"];
|
||||||
|
|
||||||
|
//设置日志
|
||||||
|
Logger::Instance().add(std::make_shared<ConsoleChannel>("ConsoleChannel",logLevel));
|
||||||
|
#if defined(__linux__) || defined(__linux)
|
||||||
|
Logger::Instance().add(std::make_shared<SysLogChannel>("SysLogChannel",logLevel));
|
||||||
|
#else
|
||||||
|
Logger::Instance().add(std::make_shared<FileChannel>("FileChannel",exePath() + ".log",logLevel));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(bDaemon){
|
||||||
|
//启动守护进程
|
||||||
|
System::startDaemon();
|
||||||
|
}
|
||||||
|
|
||||||
|
//启动异步日志线程
|
||||||
|
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||||
|
//加载配置文件,如果配置文件不存在就创建一个
|
||||||
|
loadIniConfig(ini_file.data());
|
||||||
|
|
||||||
|
//加载证书,证书包含公钥和私钥
|
||||||
|
SSL_Initor::Instance().loadCertificate(ssl_file.data());
|
||||||
|
//信任某个自签名证书
|
||||||
|
SSL_Initor::Instance().trustCertificate(ssl_file.data());
|
||||||
|
//不忽略无效证书证书(例如自签名或过期证书)
|
||||||
|
SSL_Initor::Instance().ignoreInvalidCertificate(false);
|
||||||
|
|
||||||
|
uint16_t shellPort = mINI::Instance()[Shell::kPort];
|
||||||
|
uint16_t rtspPort = mINI::Instance()[Rtsp::kPort];
|
||||||
|
uint16_t rtspsPort = mINI::Instance()[Rtsp::kSSLPort];
|
||||||
|
uint16_t rtmpPort = mINI::Instance()[Rtmp::kPort];
|
||||||
|
uint16_t httpPort = mINI::Instance()[Http::kPort];
|
||||||
|
uint16_t httpsPort = mINI::Instance()[Http::kSSLPort];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置poller线程数,该函数必须在使用ZLToolKit网络相关对象之前调用才能生效
|
||||||
|
*/
|
||||||
|
EventPollerPool::setPoolSize(threads);
|
||||||
|
|
||||||
|
//简单的telnet服务器,可用于服务器调试,但是不能使用23端口,否则telnet上了莫名其妙的现象
|
||||||
|
//测试方法:telnet 127.0.0.1 9000
|
||||||
|
TcpServer::Ptr shellSrv(new TcpServer());
|
||||||
|
TcpServer::Ptr rtspSrv(new TcpServer());
|
||||||
|
TcpServer::Ptr rtmpSrv(new TcpServer());
|
||||||
|
TcpServer::Ptr httpSrv(new TcpServer());
|
||||||
|
|
||||||
|
shellSrv->start<ShellSession>(shellPort);
|
||||||
|
rtspSrv->start<RtspSession>(rtspPort);//默认554
|
||||||
|
rtmpSrv->start<RtmpSession>(rtmpPort);//默认1935
|
||||||
|
//http服务器,支持websocket
|
||||||
|
httpSrv->start<EchoWebSocketSession>(httpPort);//默认80
|
||||||
|
|
||||||
|
//如果支持ssl,还可以开启https服务器
|
||||||
|
TcpServer::Ptr httpsSrv(new TcpServer());
|
||||||
|
//https服务器,支持websocket
|
||||||
|
httpsSrv->start<SSLEchoWebSocketSession>(httpsPort);//默认443
|
||||||
|
|
||||||
|
//支持ssl加密的rtsp服务器,可用于诸如亚马逊echo show这样的设备访问
|
||||||
|
TcpServer::Ptr rtspSSLSrv(new TcpServer());
|
||||||
|
rtspSSLSrv->start<RtspSessionWithSSL>(rtspsPort);//默认322
|
||||||
|
|
||||||
|
installWebApi();
|
||||||
|
InfoL << "已启动http api 接口";
|
||||||
|
installWebHook();
|
||||||
|
InfoL << "已启动http hook 接口";
|
||||||
|
|
||||||
|
if(!bDaemon) {
|
||||||
|
//交互式shell输入
|
||||||
|
listen_shell_input();
|
||||||
|
}
|
||||||
|
|
||||||
|
//设置退出信号处理函数
|
||||||
|
static semaphore sem;
|
||||||
|
signal(SIGINT, [](int) { InfoL << "SIGINT:exit"; sem.post(); });// 设置退出信号
|
||||||
|
signal(SIGHUP, [](int) { mediakit::loadIniConfig(); });
|
||||||
|
sem.wait();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -37,7 +37,7 @@ namespace mediakit {
|
|||||||
|
|
||||||
bool loadIniConfig(const char *ini_path){
|
bool loadIniConfig(const char *ini_path){
|
||||||
string ini;
|
string ini;
|
||||||
if(ini_path){
|
if(ini_path && ini_path[0] != '\0'){
|
||||||
ini = ini_path;
|
ini = ini_path;
|
||||||
}else{
|
}else{
|
||||||
ini = exePath() + ".ini";
|
ini = exePath() + ".ini";
|
||||||
|
Loading…
Reference in New Issue
Block a user