merge JSON-2 into default branch. #close JSON-2
commit
d0d3968346
|
@ -0,0 +1,14 @@
|
|||
#ifndef JSON_ADAPTER_CONTEXT_HH
|
||||
#define JSON_ADAPTER_CONTEXT_HH
|
||||
|
||||
#include <string>
|
||||
|
||||
class Context
|
||||
{
|
||||
public:
|
||||
virtual ~Context() = default;
|
||||
|
||||
virtual bool verify_security_token(const std::string& token) const = 0;
|
||||
};
|
||||
|
||||
#endif // JSON_ADAPTER_CONTEXT_HH
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "json_spirit/json_spirit_value.h"
|
||||
#include "json_spirit/json_spirit_writer.h"
|
||||
|
||||
#include "context.hh"
|
||||
#include <type_traits>
|
||||
|
||||
// Just for debugging:
|
||||
|
@ -12,8 +14,8 @@
|
|||
|
||||
namespace js = json_spirit;
|
||||
|
||||
template<class T> struct In;
|
||||
template<class T> struct Out;
|
||||
template<class T, bool NeedInput> struct In;
|
||||
template<class T, bool NeedInput> struct Out;
|
||||
|
||||
// "params" and "position" might be used to fetch additional parameters from the array.
|
||||
template<class T>
|
||||
|
@ -25,21 +27,21 @@ js::Value to_json(const T& t);
|
|||
|
||||
|
||||
// helper classes to specify in- and out-parameters
|
||||
template<class T>
|
||||
template<class T, bool NeedInput=true>
|
||||
struct In
|
||||
{
|
||||
typedef T c_type; // the according type in C function parameter
|
||||
enum { is_output = false };
|
||||
enum { is_output = false, need_input = NeedInput };
|
||||
|
||||
explicit In(const T& t) : value(t) {}
|
||||
~In();
|
||||
|
||||
In(const In<T>& other) = delete;
|
||||
In(In<T>&& victim) = delete;
|
||||
In<T>& operator=(const In<T>&) = delete;
|
||||
In(const In<T,NeedInput>& other) = delete;
|
||||
In(In<T,NeedInput>&& victim) = delete;
|
||||
In<T,NeedInput>& operator=(const In<T,NeedInput>&) = delete;
|
||||
|
||||
// default implementation:
|
||||
In(const js::Value& v, const js::Array& params, unsigned position)
|
||||
In(const js::Value& v, Context*)
|
||||
: In( from_json<T>(v) )
|
||||
{ }
|
||||
|
||||
|
@ -53,21 +55,21 @@ struct In
|
|||
|
||||
|
||||
// to call functions that operate directly on the JSON data type
|
||||
template<class T>
|
||||
template<class T, bool NeedInput=true>
|
||||
struct InRaw
|
||||
{
|
||||
typedef js::Value c_type; // do not unwrap JSON data type
|
||||
enum { is_output = false };
|
||||
enum { is_output = false, need_input = NeedInput };
|
||||
|
||||
explicit InRaw(const js::Value& t) : value(t) {}
|
||||
~InRaw() = default;
|
||||
|
||||
InRaw(const InRaw<T>& other) = delete;
|
||||
InRaw(InRaw<T>&& victim) = delete;
|
||||
InRaw<T>& operator=(const InRaw<T>&) = delete;
|
||||
InRaw(const InRaw<T,NeedInput>& other) = delete;
|
||||
InRaw(InRaw<T,NeedInput>&& victim) = delete;
|
||||
InRaw<T,NeedInput>& operator=(const InRaw<T,NeedInput>&) = delete;
|
||||
|
||||
// default implementation:
|
||||
InRaw(const js::Value& v, const js::Array& params, unsigned position)
|
||||
InRaw(const js::Value& v, Context*)
|
||||
: InRaw(v)
|
||||
{ }
|
||||
|
||||
|
@ -81,19 +83,19 @@ struct InRaw
|
|||
|
||||
|
||||
// helper classes to specify in- and out-parameters
|
||||
template<class T>
|
||||
struct InOut : public In<T>
|
||||
template<class T, bool NeedInput=true>
|
||||
struct InOut : public In<T,NeedInput>
|
||||
{
|
||||
typedef In<T> Base;
|
||||
enum { is_output = true };
|
||||
typedef In<T,NeedInput> Base;
|
||||
enum { is_output = true, need_input = NeedInput };
|
||||
|
||||
explicit InOut(const T& t) : Base(t) {}
|
||||
~InOut() = default;
|
||||
|
||||
InOut<T>& operator=(const InOut<T>&) = delete;
|
||||
InOut<T,NeedInput>& operator=(const InOut<T,NeedInput>&) = delete;
|
||||
|
||||
// default implementation:
|
||||
InOut(const js::Value& v, const js::Array& params, unsigned position)
|
||||
InOut(const js::Value& v, Context*)
|
||||
: Base( from_json<T>(v) )
|
||||
{ }
|
||||
|
||||
|
@ -104,11 +106,11 @@ struct InOut : public In<T>
|
|||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
template<class T, bool NeedInput = true>
|
||||
struct Out
|
||||
{
|
||||
typedef T* c_type; // the according type in C function parameter
|
||||
enum { is_output = true };
|
||||
enum { is_output = true, need_input = NeedInput }; // if need_input=false it would no longer consume an element in the input parameter array.
|
||||
|
||||
explicit Out() : value{ new T{} }
|
||||
{
|
||||
|
@ -120,14 +122,14 @@ struct Out
|
|||
|
||||
~Out();
|
||||
|
||||
Out(const Out<T>& other) = delete;
|
||||
Out(Out<T>&& victim) = delete;
|
||||
Out(const Out<T,NeedInput>& other) = delete;
|
||||
Out(Out<T,NeedInput>&& victim) = delete;
|
||||
|
||||
// just to be sure they are not implicitly defined:
|
||||
Out<T>& operator=(const Out<T>& other) = delete;
|
||||
Out<T>& operator=(Out<T>&& victim) = delete;
|
||||
Out<T,NeedInput>& operator=(const Out<T,NeedInput>& other) = delete;
|
||||
Out<T,NeedInput>& operator=(Out<T,NeedInput>&& victim) = delete;
|
||||
|
||||
Out(const js::Value& v, const js::Array& params, unsigned position)
|
||||
Out(const js::Value& v, Context*)
|
||||
: Out()
|
||||
{ }
|
||||
|
||||
|
@ -139,7 +141,7 @@ struct Out
|
|||
T* value = nullptr;
|
||||
|
||||
friend
|
||||
std::ostream& operator<<(std::ostream& o, const Out<T>& out)
|
||||
std::ostream& operator<<(std::ostream& o, const Out<T,NeedInput>& out)
|
||||
{
|
||||
o << (const void*)&out;
|
||||
|
||||
|
@ -159,14 +161,14 @@ struct Out
|
|||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
js::Value to_json(const Out<T>& o)
|
||||
template<class T, bool NeedInput>
|
||||
js::Value to_json(const Out<T,NeedInput>& o)
|
||||
{
|
||||
return ::to_json(*o.value);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
js::Value to_json(const InOut<T>& o)
|
||||
template<class T, bool NeedInput>
|
||||
js::Value to_json(const InOut<T,NeedInput>& o)
|
||||
{
|
||||
return ::to_json(o.value);
|
||||
}
|
||||
|
@ -186,7 +188,15 @@ template<class R, unsigned U, class... Args>
|
|||
class helper<R, U, U, Args...>
|
||||
{
|
||||
public:
|
||||
static js::Value call( const std::function<R(typename Args::c_type...)>& fn, js::Array& out_parameters, const js::Array& parameters, const Args&... args)
|
||||
enum { nr_of_output_params = 0 };
|
||||
enum { nr_of_input_params = 0 };
|
||||
|
||||
static void copyParam( js::Array& dest, const js::Array& src, unsigned index )
|
||||
{
|
||||
// do nothing. :-)
|
||||
}
|
||||
|
||||
static js::Value call( const std::function<R(typename Args::c_type...)>& fn, Context*, js::Array& out_parameters, const js::Array& parameters, const Args&... args)
|
||||
{
|
||||
return to_json( fn(args.value...) );
|
||||
}
|
||||
|
@ -198,7 +208,15 @@ template<unsigned U, class... Args>
|
|||
class helper<void, U, U, Args...>
|
||||
{
|
||||
public:
|
||||
static js::Value call( const std::function<void(typename Args::c_type...)>& fn, js::Array& out_parameters, const js::Array& parameters, const Args&... args)
|
||||
enum { nr_of_output_params = 0 };
|
||||
enum { nr_of_input_params = 0 };
|
||||
|
||||
static void copyParam( js::Array& dest, const js::Array& src, unsigned index )
|
||||
{
|
||||
// do nothing. :-)
|
||||
}
|
||||
|
||||
static js::Value call( const std::function<void(typename Args::c_type...)>& fn, Context*, js::Array& out_parameters, const js::Array& parameters, const Args&... args)
|
||||
{
|
||||
fn(args.value...);
|
||||
return js::Value{};
|
||||
|
@ -217,16 +235,29 @@ public:
|
|||
typedef typename std::tuple_element<U, Tuple>::type Element; // The type of the U'th parameter
|
||||
typedef helper<R, U+1, MAX, Args...> NextHelper;
|
||||
|
||||
public:
|
||||
|
||||
enum { nr_of_output_params = int(Element::is_output) + NextHelper::nr_of_output_params };
|
||||
enum { nr_of_input_params = int(Element::need_input) + NextHelper::nr_of_input_params };
|
||||
|
||||
static void copyParam( js::Array& dest, const js::Array& src, unsigned index )
|
||||
{
|
||||
if(Element::need_input)
|
||||
{
|
||||
dest.push_back( src.at(index) );
|
||||
++index;
|
||||
}else{
|
||||
dest.push_back( js::Value{} ); // insert dummy parameter
|
||||
}
|
||||
NextHelper::copyParam( dest, src, index );
|
||||
}
|
||||
|
||||
// A2... a2 are the alredy pealed-off paremeters
|
||||
template<class... A2>
|
||||
static js::Value call( const std::function<R(typename Args::c_type...)>& fn, js::Array& out_parameters, const js::Array& parameters, const A2&... a2)
|
||||
static js::Value call( const std::function<R(typename Args::c_type...)>& fn, Context* ctx, js::Array& out_parameters, const js::Array& parameters, const A2&... a2)
|
||||
{
|
||||
// extract the U'th element of the parameter list
|
||||
const Element element(parameters[U], parameters, U);
|
||||
const Element element(parameters[U], ctx);
|
||||
|
||||
const js::Value ret = NextHelper::call(fn, out_parameters, parameters, a2..., element );
|
||||
const js::Value ret = NextHelper::call(fn, ctx, out_parameters, parameters, a2..., element );
|
||||
if(Element::is_output)
|
||||
{
|
||||
js::Value out = element.to_json();
|
||||
|
@ -247,25 +278,25 @@ struct Type2String
|
|||
};
|
||||
|
||||
template<class T>
|
||||
struct Type2String<In<T>>
|
||||
struct Type2String<In<T, true>>
|
||||
{
|
||||
static js::Value get() { js::Object ret; ret.emplace_back("direction", "In"); ret.emplace_back("type", Type2String<T>::get() ); return ret; }
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct Type2String<InRaw<T>>
|
||||
struct Type2String<InRaw<T, true>>
|
||||
{
|
||||
static js::Value get() { js::Object ret; ret.emplace_back("direction", "In"); ret.emplace_back("type", Type2String<T>::get() ); return ret; }
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct Type2String<Out<T>>
|
||||
struct Type2String<Out<T, true>>
|
||||
{
|
||||
static js::Value get() { js::Object ret; ret.emplace_back("direction", "Out"); ret.emplace_back("type", Type2String<T>::get() ); return ret; }
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct Type2String<InOut<T>>
|
||||
struct Type2String<InOut<T, true>>
|
||||
{
|
||||
static js::Value get() { js::Object ret; ret.emplace_back("direction", "InOut"); ret.emplace_back("type", Type2String<T>::get() ); return ret; }
|
||||
};
|
||||
|
@ -277,7 +308,10 @@ struct Type2Json<T, Args...>
|
|||
{
|
||||
static js::Array& get(js::Array& a)
|
||||
{
|
||||
a.push_back( Type2String<T>::get() );
|
||||
if(T::need_input)
|
||||
{
|
||||
a.push_back( Type2String<T>::get() );
|
||||
}
|
||||
Type2Json<Args...>::get(a);
|
||||
return a;
|
||||
}
|
||||
|
@ -298,7 +332,7 @@ public:
|
|||
virtual ~FuncBase() = default;
|
||||
virtual bool isSeparator() const = 0;
|
||||
virtual void setJavaScriptSignature(js::Object& o) const = 0;
|
||||
virtual js::Value call(const js::Array& params) const = 0;
|
||||
virtual js::Value call(const js::Array& params, Context* context) const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -306,9 +340,6 @@ template<class R, class... Args>
|
|||
class Func : public FuncBase
|
||||
{
|
||||
public:
|
||||
// typedef std::tuple<Args...> arg_t;
|
||||
enum { Size = sizeof...(Args) };
|
||||
|
||||
virtual ~Func() = default;
|
||||
virtual bool isSeparator() const override
|
||||
{
|
||||
|
@ -323,21 +354,34 @@ public:
|
|||
|
||||
std::function<R(typename Args::c_type ...)> fn;
|
||||
|
||||
js::Value call(const js::Array& parameters) const override
|
||||
js::Value call(const js::Array& parameters, Context* context) const override
|
||||
{
|
||||
if(parameters.size() != sizeof...(Args))
|
||||
typedef helper<R, 0, sizeof...(Args), Args...> Helper;
|
||||
|
||||
if(parameters.size() != Helper::nr_of_input_params)
|
||||
throw std::runtime_error("Size mismatch: "
|
||||
"Array has " + std::to_string( parameters.size() ) + " element(s), "
|
||||
"but I expect " + std::to_string( sizeof...(Args) ) + " element(s)! "
|
||||
"but I expect " + std::to_string( Helper::nr_of_input_params) + " element(s)! "
|
||||
);
|
||||
|
||||
const js::Array* p_params = ¶meters;
|
||||
|
||||
// create a copy of the parameters only if necessary
|
||||
js::Array param_copy;
|
||||
if( Helper::nr_of_input_params != sizeof...(Args) )
|
||||
{
|
||||
param_copy.reserve( Helper::nr_of_input_params );
|
||||
Helper::copyParam( param_copy, parameters, 0u );
|
||||
p_params = ¶m_copy; // use the copy instead of 'parameters'
|
||||
}
|
||||
|
||||
// recursive template magic breaks loose:
|
||||
// recursively extract the JSON parameters, call 'fn' and collect its return value
|
||||
// and all output parameters into a tuple<> and return it as JSON array
|
||||
js::Array out_params;
|
||||
out_params.reserve( 1 + sizeof...(Args) ); // too big, but who cares?
|
||||
out_params.reserve( 1 + Helper::nr_of_output_params );
|
||||
|
||||
js::Value ret = helper<R, 0, sizeof...(Args), Args...>::call(fn, out_params, parameters);
|
||||
js::Value ret = Helper::call(fn, context, out_params, *p_params);
|
||||
out_params.push_back( ret );
|
||||
return out_params;
|
||||
}
|
||||
|
@ -348,7 +392,7 @@ public:
|
|||
Type2Json<Args...>::get(params);
|
||||
|
||||
o.emplace_back( "return", Type2String<R>::get() );
|
||||
o.emplace_back( "params", params );
|
||||
o.emplace_back( "params", std::move(params) );
|
||||
o.emplace_back( "separator", false );
|
||||
}
|
||||
};
|
||||
|
@ -359,9 +403,9 @@ class Separator : public FuncBase
|
|||
{
|
||||
public:
|
||||
Separator() = default;
|
||||
virtual bool isSeparator() const override { return true; }
|
||||
virtual void setJavaScriptSignature(js::Object& o) const override { o.emplace_back("separator", true); }
|
||||
virtual js::Value call(const js::Array& params) const override { return js::Value{}; }
|
||||
virtual bool isSeparator() const override { return true; }
|
||||
virtual void setJavaScriptSignature(js::Object& o) const override { o.emplace_back("separator", true); }
|
||||
virtual js::Value call(const js::Array&, Context*) const override { return js::Value{}; }
|
||||
};
|
||||
|
||||
//typedef std::map< std::string, FuncBase* > FunctionMap;
|
||||
|
|
|
@ -27,6 +27,21 @@
|
|||
#include "json_spirit/json_spirit_utils.h"
|
||||
|
||||
|
||||
template<>
|
||||
In<Context*, false>::~In()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
template<>
|
||||
In<Context*, false>::In(const js::Value&, Context* ctx)
|
||||
: value( ctx )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
static const unsigned API_VERSION = 0x0002;
|
||||
|
@ -79,15 +94,28 @@ PEP_STATUS get_gpg_path(const char** path)
|
|||
}
|
||||
|
||||
|
||||
PEP_STATUS registerEventListener(std::string address, unsigned port, std::string securityContext)
|
||||
|
||||
PEP_STATUS registerEventListener(Context* ctx, std::string address, unsigned port, std::string securityContext)
|
||||
{
|
||||
// TODO: implement it!
|
||||
JsonAdapter* ja = dynamic_cast<JsonAdapter*>(ctx);
|
||||
if(!ja)
|
||||
{
|
||||
return PEP_STATUS(-42);
|
||||
}
|
||||
|
||||
ja->registerEventListener(address, port, securityContext);
|
||||
return PEP_STATUS_OK;
|
||||
}
|
||||
|
||||
PEP_STATUS unregisterEventListener(std::string address, unsigned port, std::string securityContext)
|
||||
PEP_STATUS unregisterEventListener(Context* ctx, std::string address, unsigned port, std::string securityContext)
|
||||
{
|
||||
// TODO: implement it!
|
||||
JsonAdapter* ja = dynamic_cast<JsonAdapter*>(ctx);
|
||||
if(!ja)
|
||||
{
|
||||
return PEP_STATUS(-42);
|
||||
}
|
||||
|
||||
ja->unregisterEventListener(address, port, securityContext);
|
||||
return PEP_STATUS_OK;
|
||||
}
|
||||
|
||||
|
@ -98,44 +126,44 @@ const FunctionMap functions = {
|
|||
|
||||
// from message_api.h
|
||||
FP( "—— Message API ——", new Separator ),
|
||||
FP( "encrypt_message", new Func<PEP_STATUS, In<PEP_SESSION>, In<message*>, In<stringlist_t*>, Out<message*>, In<PEP_enc_format>>( &encrypt_message ) ),
|
||||
FP( "decrypt_message", new Func<PEP_STATUS, In<PEP_SESSION>, In<message*>, Out<message*>, Out<stringlist_t*>, Out<PEP_color>, Out<PEP_decrypt_flags_t>>( &decrypt_message ) ),
|
||||
FP( "outgoing_message_color", new Func<PEP_STATUS, In<PEP_SESSION>, In<message*>, Out<PEP_color>>( &outgoing_message_color ) ),
|
||||
FP( "identity_color" , new Func<PEP_STATUS, In<PEP_SESSION>, In<pEp_identity*>, Out<PEP_color>>( &identity_color) ),
|
||||
FP( "encrypt_message", new Func<PEP_STATUS, In<PEP_SESSION, false>, In<message*>, In<stringlist_t*>, Out<message*>, In<PEP_enc_format>>( &encrypt_message ) ),
|
||||
FP( "decrypt_message", new Func<PEP_STATUS, In<PEP_SESSION, false>, In<message*>, Out<message*>, Out<stringlist_t*>, Out<PEP_color>, Out<PEP_decrypt_flags_t>>( &decrypt_message ) ),
|
||||
FP( "outgoing_message_color", new Func<PEP_STATUS, In<PEP_SESSION,false>, In<message*>, Out<PEP_color>>( &outgoing_message_color ) ),
|
||||
FP( "identity_color" , new Func<PEP_STATUS, In<PEP_SESSION,false>, In<pEp_identity*>, Out<PEP_color>>( &identity_color) ),
|
||||
FP( "get_gpg_path", new Func<PEP_STATUS, Out<const char*>>(&get_gpg_path) ),
|
||||
|
||||
FP( "—— pEp Engine Core API ——", new Separator),
|
||||
FP( "log_event", new Func<PEP_STATUS, In<PEP_SESSION>, In<const char*>, In<const char*>, In<const char*>, In<const char*>>( &log_event) ),
|
||||
FP( "trustwords", new Func<PEP_STATUS, In<PEP_SESSION>, In<const char*>, In<const char*>, Out<char*>, Out<size_t>, In<int>>( &trustwords) ),
|
||||
FP( "get_languagelist", new Func<PEP_STATUS, In<PEP_SESSION>, Out<char*>>( &get_languagelist) ),
|
||||
FP( "get_phrase" , new Func<PEP_STATUS, In<PEP_SESSION>, In<const char*>, In<int>, Out<char*>> ( &get_phrase) ),
|
||||
FP( "log_event", new Func<PEP_STATUS, In<PEP_SESSION,false>, In<const char*>, In<const char*>, In<const char*>, In<const char*>>( &log_event) ),
|
||||
FP( "trustwords", new Func<PEP_STATUS, In<PEP_SESSION,false>, In<const char*>, In<const char*>, Out<char*>, Out<size_t>, In<int>>( &trustwords) ),
|
||||
FP( "get_languagelist", new Func<PEP_STATUS, In<PEP_SESSION,false>, Out<char*>>( &get_languagelist) ),
|
||||
FP( "get_phrase" , new Func<PEP_STATUS, In<PEP_SESSION,false>, In<const char*>, In<int>, Out<char*>> ( &get_phrase) ),
|
||||
FP( "get_engine_version", new Func<const char*> ( &get_engine_version) ),
|
||||
|
||||
FP( "—— Identity Management API ——", new Separator),
|
||||
FP( "get_identity" , new Func<PEP_STATUS, In<PEP_SESSION>, In<const char*>, In<const char*>, Out<pEp_identity*>>( &get_identity) ),
|
||||
FP( "set_identity" , new Func<PEP_STATUS, In<PEP_SESSION>, In<pEp_identity*>> ( &set_identity) ),
|
||||
FP( "mark_as_comprimized", new Func<PEP_STATUS, In<PEP_SESSION>, In<const char*>> ( &mark_as_compromized) ),
|
||||
FP( "get_identity" , new Func<PEP_STATUS, In<PEP_SESSION,false>, In<const char*>, In<const char*>, Out<pEp_identity*>>( &get_identity) ),
|
||||
FP( "set_identity" , new Func<PEP_STATUS, In<PEP_SESSION,false>, In<pEp_identity*>> ( &set_identity) ),
|
||||
FP( "mark_as_comprimized", new Func<PEP_STATUS, In<PEP_SESSION,false>, In<const char*>> ( &mark_as_compromized) ),
|
||||
|
||||
FP( "—— Low level Key Management API ——", new Separator),
|
||||
FP( "generate_keypair", new Func<PEP_STATUS, In<PEP_SESSION>, InOut<pEp_identity*>> ( &generate_keypair) ),
|
||||
FP( "delete_keypair", new Func<PEP_STATUS, In<PEP_SESSION>, In<const char*>> ( &delete_keypair) ),
|
||||
FP( "import_key" , new Func<PEP_STATUS, In<PEP_SESSION>, In<const char*>, In<std::size_t>, Out<identity_list*>> ( &import_key) ),
|
||||
FP( "export_key" , new Func<PEP_STATUS, In<PEP_SESSION>, In<const char*>, Out<char*>, Out<std::size_t>> ( &export_key) ),
|
||||
FP( "find_keys" , new Func<PEP_STATUS, In<PEP_SESSION>, In<const char*>, Out<stringlist_t*>> ( &find_keys) ),
|
||||
FP( "get_trust" , new Func<PEP_STATUS, In<PEP_SESSION>, InOut<pEp_identity*>> ( &get_trust) ),
|
||||
FP( "own_key_is_listed", new Func<PEP_STATUS, In<PEP_SESSION>, In<const char*>, Out<bool>> ( &own_key_is_listed) ),
|
||||
FP( "own_key_retrieve" , new Func<PEP_STATUS, In<PEP_SESSION>, Out<stringlist_t*>> ( &own_key_retrieve) ),
|
||||
FP( "generate_keypair", new Func<PEP_STATUS, In<PEP_SESSION,false>, InOut<pEp_identity*>> ( &generate_keypair) ),
|
||||
FP( "delete_keypair", new Func<PEP_STATUS, In<PEP_SESSION,false>, In<const char*>> ( &delete_keypair) ),
|
||||
FP( "import_key" , new Func<PEP_STATUS, In<PEP_SESSION,false>, In<const char*>, In<std::size_t>, Out<identity_list*>> ( &import_key) ),
|
||||
FP( "export_key" , new Func<PEP_STATUS, In<PEP_SESSION,false>, In<const char*>, Out<char*>, Out<std::size_t>> ( &export_key) ),
|
||||
FP( "find_keys" , new Func<PEP_STATUS, In<PEP_SESSION,false>, In<const char*>, Out<stringlist_t*>> ( &find_keys) ),
|
||||
FP( "get_trust" , new Func<PEP_STATUS, In<PEP_SESSION,false>, InOut<pEp_identity*>> ( &get_trust) ),
|
||||
FP( "own_key_is_listed", new Func<PEP_STATUS, In<PEP_SESSION,false>, In<const char*>, Out<bool>> ( &own_key_is_listed) ),
|
||||
FP( "own_key_retrieve" , new Func<PEP_STATUS, In<PEP_SESSION,false>, Out<stringlist_t*>> ( &own_key_retrieve) ),
|
||||
|
||||
FP( "least_trust" , new Func<PEP_STATUS, In<PEP_SESSION>, In<const char*>, Out<PEP_comm_type>> ( &least_trust) ),
|
||||
FP( "get_key_rating", new Func<PEP_STATUS, In<PEP_SESSION>, In<const char*>, Out<PEP_comm_type>> ( &get_key_rating) ),
|
||||
FP( "renew_key" , new Func<PEP_STATUS, In<PEP_SESSION>, In<const char*>, In<const timestamp*>> ( &renew_key) ),
|
||||
FP( "revoke" , new Func<PEP_STATUS, In<PEP_SESSION>, In<const char*>, In<const char*>> ( &revoke_key) ),
|
||||
FP( "key_expired" , new Func<PEP_STATUS, In<PEP_SESSION>, In<const char*>, In<time_t>, Out<bool>> ( &key_expired) ),
|
||||
FP( "least_trust" , new Func<PEP_STATUS, In<PEP_SESSION,false>, In<const char*>, Out<PEP_comm_type>> ( &least_trust) ),
|
||||
FP( "get_key_rating", new Func<PEP_STATUS, In<PEP_SESSION,false>, In<const char*>, Out<PEP_comm_type>> ( &get_key_rating) ),
|
||||
FP( "renew_key" , new Func<PEP_STATUS, In<PEP_SESSION,false>, In<const char*>, In<const timestamp*>> ( &renew_key) ),
|
||||
FP( "revoke" , new Func<PEP_STATUS, In<PEP_SESSION,false>, In<const char*>, In<const char*>> ( &revoke_key) ),
|
||||
FP( "key_expired" , new Func<PEP_STATUS, In<PEP_SESSION,false>, In<const char*>, In<time_t>, Out<bool>> ( &key_expired) ),
|
||||
|
||||
FP( "-- Event Listener & Results", new Separator ),
|
||||
FP( "registerEventListener" , new Func<PEP_STATUS, In<std::string>, In<unsigned>, In<std::string>> ( ®isterEventListener) ),
|
||||
FP( "unregisterEventListener", new Func<PEP_STATUS, In<std::string>, In<unsigned>, In<std::string>> ( &unregisterEventListener) ),
|
||||
FP( "deliverHandshakeResult" , new Func<PEP_STATUS, In<PEP_SESSION>, In<sync_handshake_result>> (&deliverHandshakeResult) ),
|
||||
FP( "registerEventListener" , new Func<PEP_STATUS, In<Context*, false>, In<std::string>, In<unsigned>, In<std::string>> ( ®isterEventListener) ),
|
||||
FP( "unregisterEventListener", new Func<PEP_STATUS, In<Context*, false>, In<std::string>, In<unsigned>, In<std::string>> ( &unregisterEventListener) ),
|
||||
FP( "deliverHandshakeResult" , new Func<PEP_STATUS, In<PEP_SESSION,false>, In<sync_handshake_result>> (&deliverHandshakeResult) ),
|
||||
|
||||
// my own example function that does something useful. :-)
|
||||
FP( "—— Other ——", new Separator ),
|
||||
|
@ -279,7 +307,7 @@ void OnApiRequest(evhttp_request* req, void* obj)
|
|||
try
|
||||
{
|
||||
|
||||
const JsonAdapter* ja = static_cast<const JsonAdapter*>(obj);
|
||||
JsonAdapter* ja = static_cast<JsonAdapter*>(obj);
|
||||
|
||||
std::vector<char> data(length);
|
||||
ssize_t nr = evbuffer_copyout(inbuf, data.data(), data.size());
|
||||
|
@ -291,7 +319,7 @@ void OnApiRequest(evhttp_request* req, void* obj)
|
|||
if(p.type() == js::obj_type)
|
||||
{
|
||||
const js::Object& request = p.get_obj();
|
||||
answer = call( functions, request, ja->sec_token() );
|
||||
answer = call( functions, request, ja );
|
||||
}else{
|
||||
answer = make_error( JSON_RPC::PARSE_ERROR, "evbuffer_copyout does not return a JSON string. b=" + std::to_string(b), js::Value{data_string}, 42 );
|
||||
}
|
||||
|
@ -382,6 +410,13 @@ auto ThreadDeleter = [](std::thread *t)
|
|||
typedef std::unique_ptr<std::thread, decltype(ThreadDeleter)> ThreadPtr;
|
||||
typedef std::vector<ThreadPtr> ThreadPool;
|
||||
|
||||
typedef std::pair<std::string, unsigned> EventListenerKey;
|
||||
|
||||
struct EventListenerValue
|
||||
{
|
||||
std::string securityContext;
|
||||
std::unique_ptr<evhttp_connection, decltype(&evhttp_connection_free)> connection = { nullptr, &evhttp_connection_free};
|
||||
};
|
||||
|
||||
struct JsonAdapter::Internal
|
||||
{
|
||||
|
@ -389,6 +424,7 @@ struct JsonAdapter::Internal
|
|||
std::unique_ptr<evhttp, decltype(&evhttp_free)> evHttp = {nullptr, &evhttp_free};
|
||||
std::string address;
|
||||
std::string token;
|
||||
std::map<EventListenerKey, EventListenerValue> eventListener;
|
||||
|
||||
unsigned start_port = 0;
|
||||
unsigned end_port = 0;
|
||||
|
@ -397,9 +433,87 @@ struct JsonAdapter::Internal
|
|||
evutil_socket_t sock = -1;
|
||||
bool running = false;
|
||||
ThreadPool threads;
|
||||
|
||||
static
|
||||
void requestDone(evhttp_request* req, void* userdata)
|
||||
{
|
||||
// Hum, what is to do here?
|
||||
}
|
||||
|
||||
PEP_STATUS deliverRequest(std::pair<const EventListenerKey,EventListenerValue>& e, const js::Object& request)
|
||||
{
|
||||
const std::string uri = "http://" + e.first.first + ":" + std::to_string(e.first.second) + "/";
|
||||
const std::string request_s = js::write(request, js::raw_utf8);
|
||||
evhttp_request* ereq = evhttp_request_new( &requestDone, &e ); // ownership goes to the connection in evhttp_make_request() below.
|
||||
evhttp_add_header(ereq->output_headers, "Host", e.first.first.c_str());
|
||||
evhttp_add_header(ereq->output_headers, "Content-Length", std::to_string(request_s.length()).c_str());
|
||||
auto output_buffer = evhttp_request_get_output_buffer(ereq);
|
||||
evbuffer_add(output_buffer, request_s.data(), request_s.size());
|
||||
|
||||
const int ret = evhttp_make_request(e.second.connection.get(), ereq, EVHTTP_REQ_POST, uri.c_str() );
|
||||
|
||||
return (ret == 0) ? PEP_STATUS_OK : PEP_UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
PEP_STATUS messageToSend(const message* msg)
|
||||
{
|
||||
js::Value js_msg = to_json(msg);
|
||||
js::Array param;
|
||||
param.push_back( std::move(js_msg) );
|
||||
|
||||
PEP_STATUS status = PEP_STATUS_OK;
|
||||
|
||||
for(auto& e : eventListener)
|
||||
{
|
||||
js::Object request = make_request( "messageToSend", param, e.second.securityContext );
|
||||
const PEP_STATUS s2 = deliverRequest( e, request );
|
||||
if(s2!=PEP_STATUS_OK)
|
||||
{
|
||||
status = s2;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
PEP_STATUS showHandshake(const pEp_identity* self, const pEp_identity* partner)
|
||||
{
|
||||
// TODO: eliminate redundancy to messageToSend() above
|
||||
js::Array param;
|
||||
param.emplace_back( to_json(self) );
|
||||
param.emplace_back( to_json(partner) );
|
||||
|
||||
PEP_STATUS status = PEP_STATUS_OK;
|
||||
|
||||
for(auto& e : eventListener)
|
||||
{
|
||||
js::Object request = make_request( "showHandshake", param, e.second.securityContext );
|
||||
const PEP_STATUS s2 = deliverRequest( e, request );
|
||||
if(s2!=PEP_STATUS_OK)
|
||||
{
|
||||
status = s2;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
PEP_STATUS JsonAdapter::messageToSend(void* obj, const message* msg)
|
||||
{
|
||||
JsonAdapter* ja = static_cast<JsonAdapter*>(obj);
|
||||
return ja->i->messageToSend(msg);
|
||||
}
|
||||
|
||||
|
||||
PEP_STATUS JsonAdapter::showHandshake(void* obj, const pEp_identity* self, const pEp_identity* partner)
|
||||
{
|
||||
JsonAdapter* ja = static_cast<JsonAdapter*>(obj);
|
||||
return ja->i->showHandshake(self, partner);
|
||||
}
|
||||
|
||||
|
||||
JsonAdapter::JsonAdapter(const std::string& address, unsigned start_port, unsigned end_port)
|
||||
: i(new Internal)
|
||||
{
|
||||
|
@ -447,6 +561,8 @@ try
|
|||
|
||||
session_registry.emplace( id, session);
|
||||
std::cerr << "\tcreated new session for this thread: " << static_cast<void*>(session) << ".\n";
|
||||
|
||||
register_sync_callbacks( session, this, &messageToSend, &showHandshake );
|
||||
}else{
|
||||
std::cerr << "\tsession for this thread: " << static_cast<void*>(q->second) << ".\n";
|
||||
}
|
||||
|
@ -542,18 +658,42 @@ void JsonAdapter::shutdown(timeval* t)
|
|||
}
|
||||
|
||||
|
||||
const std::string& JsonAdapter::sec_token() const
|
||||
{
|
||||
return i->token;
|
||||
}
|
||||
|
||||
|
||||
// returns 'true' if 's' is the security token created by the function above.
|
||||
bool JsonAdapter::verify_security_token(const std::string& s) const
|
||||
{
|
||||
if(s!=i->token)
|
||||
{
|
||||
std::cerr << "sec_token=\"" << i->token << "\" is unequal to \"" << s << "\"!\n";
|
||||
std::cerr << "sec_token=\"" << i->token << "\" (len=" << i->token.size() << ") is unequal to \"" << s << "\" (len=" << s.size() << ")!\n";
|
||||
}
|
||||
return s == i->token;
|
||||
}
|
||||
|
||||
|
||||
void JsonAdapter::registerEventListener(const std::string& address, unsigned port, const std::string& securityContext)
|
||||
{
|
||||
const auto key = std::make_pair(address, port);
|
||||
const auto q = i->eventListener.find(key);
|
||||
if( q != i->eventListener.end() && q->second.securityContext != securityContext)
|
||||
{
|
||||
throw std::runtime_error("EventListener at host \"" + address + "\":" + std::to_string(port) + " is already registered with different securityContext." );
|
||||
}
|
||||
|
||||
EventListenerValue v;
|
||||
v.securityContext = securityContext;
|
||||
v.connection.reset( evhttp_connection_base_new( i->eventBase.get(), nullptr, address.c_str(), port ) );
|
||||
i->eventListener[key] = std::move(v);
|
||||
}
|
||||
|
||||
|
||||
void JsonAdapter::unregisterEventListener(const std::string& address, unsigned port, const std::string& securityContext)
|
||||
{
|
||||
const auto key = std::make_pair(address, port);
|
||||
const auto q = i->eventListener.find(key);
|
||||
if( q == i->eventListener.end() || q->second.securityContext != securityContext)
|
||||
{
|
||||
throw std::runtime_error("Cannot unregister EventListener at host \"" + address + "\":" + std::to_string(port) + ". Not registered or wrong securityContext." );
|
||||
}
|
||||
|
||||
i->eventListener.erase(q);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#ifndef JSON_ADAPTER_HH
|
||||
#define JSON_ADAPTER_HH
|
||||
|
||||
#include <pEp/pEpEngine.h>
|
||||
#include <pEp/message.h>
|
||||
#include "registry.hh"
|
||||
#include "context.hh"
|
||||
|
||||
class JsonAdapter
|
||||
class JsonAdapter : public Context
|
||||
{
|
||||
public:
|
||||
// creates an instance of the JSON adapter. It tries to bind the first available port in the given range
|
||||
|
@ -12,12 +13,15 @@ public:
|
|||
JsonAdapter(const std::string& address, unsigned start_port, unsigned end_port);
|
||||
|
||||
// calls abort() on the instance if it is still running().
|
||||
~JsonAdapter();
|
||||
virtual ~JsonAdapter();
|
||||
|
||||
// don't allow copies
|
||||
JsonAdapter(const JsonAdapter&) = delete;
|
||||
void operator=(const JsonAdapter&) = delete;
|
||||
|
||||
void registerEventListener(const std::string& address, unsigned port, const std::string& securityContext);
|
||||
void unregisterEventListener(const std::string& address, unsigned port, const std::string& securityContext);
|
||||
|
||||
// run the server in another thread and returns immediately.
|
||||
void run();
|
||||
|
||||
|
@ -37,9 +41,7 @@ public:
|
|||
unsigned request_count() const;
|
||||
|
||||
// returns 'true' if 's' is the security token created by the function above.
|
||||
bool verify_security_token(const std::string& s) const;
|
||||
|
||||
const std::string& sec_token() const;
|
||||
virtual bool verify_security_token(const std::string& s) const override;
|
||||
|
||||
static
|
||||
unsigned apiVersion();
|
||||
|
@ -48,6 +50,9 @@ public:
|
|||
static
|
||||
std::string version();
|
||||
|
||||
static PEP_STATUS messageToSend(void* obj, const message* msg);
|
||||
static PEP_STATUS showHandshake(void* obj, const pEp_identity* self, const pEp_identity* partner);
|
||||
|
||||
private:
|
||||
struct Internal;
|
||||
Internal* i; // pimpl for stable interface.
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "json-adapter.hh"
|
||||
#include "security-token.hh"
|
||||
|
||||
// Server side:
|
||||
|
||||
js::Object make_result(const js::Value& result, int id)
|
||||
{
|
||||
|
@ -33,6 +34,22 @@
|
|||
return ret;
|
||||
}
|
||||
|
||||
// Client side:
|
||||
|
||||
js::Object make_request(const std::string& functionName, const js::Array& parameters, const std::string& securityContext)
|
||||
{
|
||||
static int request_id = 2000;
|
||||
|
||||
js::Object request;
|
||||
request.emplace_back( "jsonrpc", "2.0" );
|
||||
request.emplace_back( "id" , ++request_id );
|
||||
request.emplace_back( "security_token", securityContext );
|
||||
request.emplace_back( "method", functionName );
|
||||
request.emplace_back( "params", parameters );
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -45,7 +62,7 @@ namespace
|
|||
using json_spirit::find_value;
|
||||
|
||||
|
||||
js::Object call(const FunctionMap& fm, const js::Object& request, const std::string& sec_token_orig)
|
||||
js::Object call(const FunctionMap& fm, const js::Object& request, Context* context)
|
||||
{
|
||||
int request_id = -1;
|
||||
try
|
||||
|
@ -57,7 +74,7 @@ js::Object call(const FunctionMap& fm, const js::Object& request, const std::str
|
|||
}
|
||||
|
||||
const auto sec_token = find_value(request, "security_token");
|
||||
if(sec_token.type()!=js::str_type || (sec_token.get_str()!=sec_token_orig) )
|
||||
if(sec_token.type()!=js::str_type || context->verify_security_token(sec_token.get_str())==false )
|
||||
{
|
||||
return make_error(JSON_RPC::INVALID_REQUEST, "Invalid request: Wrong security token.", request, request_id);
|
||||
}
|
||||
|
@ -98,7 +115,8 @@ js::Object call(const FunctionMap& fm, const js::Object& request, const std::str
|
|||
std::cerr << "=== Now I do the call!\n"
|
||||
"\tmethod_name=\"" << method_name << "\","
|
||||
"\tparams=" << js::write(params) << ". ===\n";
|
||||
const js::Value result = fn->second->call(p);
|
||||
|
||||
const js::Value result = fn->second->call(p, context);
|
||||
std::cerr << "=== Result of call: " << js::write(result, js::raw_utf8) << ". ===\n";
|
||||
std::cerr << "\tSessions: " << getSessions() << "\n";
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define JSON_RPC_HH
|
||||
|
||||
#include "json_spirit/json_spirit_value.h"
|
||||
#include "context.hh"
|
||||
#include "function_map.hh"
|
||||
|
||||
namespace js = json_spirit;
|
||||
|
@ -16,10 +17,11 @@ enum class JSON_RPC
|
|||
INTERNAL_ERROR = -32603,
|
||||
};
|
||||
|
||||
// Server side:
|
||||
|
||||
// parse the JSON-RPC 2.0 compatible "request", call the function
|
||||
// parse the JSON-RPC 2.0 compatible "request", call the C function
|
||||
// and create an appropiate "response" object (containing a result or an error)
|
||||
js::Object call(const FunctionMap& fm, const js::Object& request, const std::string& sec_token_orig);
|
||||
js::Object call(const FunctionMap& fm, const js::Object& request, Context* context);
|
||||
|
||||
// create a JSON-RPC 2.0 compatible result response object
|
||||
js::Object make_result(const js::Value& result, int id);
|
||||
|
@ -28,4 +30,7 @@ js::Object make_result(const js::Value& result, int id);
|
|||
js::Object make_error(JSON_RPC error_code, const std::string& error_message, const js::Value& data, int id);
|
||||
|
||||
|
||||
// Client side:
|
||||
js::Object make_request(const std::string& functionName, const js::Array& parameters, const std::string& securityContext);
|
||||
|
||||
#endif // JSON_RPC_HH
|
||||
|
|
|
@ -50,7 +50,7 @@ std::string status_to_string(PEP_STATUS status)
|
|||
|
||||
|
||||
template<>
|
||||
In<PEP_SESSION>::~In()
|
||||
In<PEP_SESSION, false>::~In()
|
||||
{
|
||||
// no automatic release!
|
||||
}
|
||||
|
@ -226,13 +226,14 @@ pEp_identity* from_json<pEp_identity*>(const js::Value& v)
|
|||
free(lang);
|
||||
}
|
||||
ident->me = from_json_object<bool, js::bool_type>(o, "me");
|
||||
ident->flags = from_json_object<unsigned, js::int_type>(o, "flags");
|
||||
|
||||
return ident;
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
js::Value to_json<message*>(message* const& msg)
|
||||
js::Value to_json<message const*>(message const* const& msg)
|
||||
{
|
||||
if(msg == nullptr)
|
||||
{
|
||||
|
@ -270,6 +271,12 @@ js::Value to_json<message*>(message* const& msg)
|
|||
return js::Value( std::move(o) );
|
||||
}
|
||||
|
||||
template<>
|
||||
js::Value to_json<message*>(message* const& msg)
|
||||
{
|
||||
return to_json( const_cast<const message*>(msg) );
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
stringlist_t* from_json<stringlist_t*>(const js::Value& v)
|
||||
|
@ -449,7 +456,7 @@ js::Value to_json<stringlist_t*>(stringlist_t* const& osl)
|
|||
|
||||
|
||||
template<>
|
||||
js::Value to_json<pEp_identity*>(pEp_identity* const& id)
|
||||
js::Value to_json<const pEp_identity*>(const pEp_identity* const& id)
|
||||
{
|
||||
if(id == nullptr)
|
||||
{
|
||||
|
@ -468,11 +475,18 @@ js::Value to_json<pEp_identity*>(pEp_identity* const& id)
|
|||
if(id->lang[0] && id->lang[1])
|
||||
o.emplace_back( "lang", js::Value( std::string( id->lang, id->lang+2) ));
|
||||
|
||||
o.emplace_back( "me", js::Value( id->me ));
|
||||
o.emplace_back( "me", bool( id->me ));
|
||||
o.emplace_back( "flags", uint64_t( id->me ));
|
||||
|
||||
return js::Value( std::move(o) );
|
||||
}
|
||||
|
||||
template<>
|
||||
js::Value to_json<pEp_identity*>(pEp_identity* const& id)
|
||||
{
|
||||
return to_json( const_cast<const pEp_identity*>(id) );
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
js::Value to_json<identity_list*>(identity_list* const& idl)
|
||||
|
|
Loading…
Reference in New Issue