mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
Core: LoadFile checks whether path is a file (because POSIX opens a dir too), Core/Rpc: StopRpcServerTrace
git-svn-id: svn://ultimatepp.org/upp/trunk@5546 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
bd87a04fda
commit
43e1289eed
4 changed files with 641 additions and 632 deletions
|
|
@ -1,349 +1,350 @@
|
|||
#ifndef Rpc_Rpc_h
|
||||
#define Rpc_Rpc_h
|
||||
|
||||
#include <Core/Core.h>
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
enum {
|
||||
RPC_SERVER_JSON_ERROR = -32700, // Parse error
|
||||
RPC_SERVER_JSON_REQUEST_ERROR = -32600, // Invalid Request
|
||||
RPC_UNKNOWN_METHOD_ERROR = -32601, // Method not found
|
||||
RPC_SERVER_PARAM_ERROR = -32602, // Invalid params
|
||||
RPC_SERVER_PROCESSING_ERROR = -32000, // Server error
|
||||
|
||||
RPC_SERVER_XML_ERROR,
|
||||
|
||||
RPC_CLIENT_HTTP_ERROR = -1000000,
|
||||
RPC_CLIENT_XML_ERROR,
|
||||
RPC_CLIENT_JSON_ERROR,
|
||||
RPC_CLIENT_RESPONSE_ERROR,
|
||||
};
|
||||
|
||||
struct ValueTypeMismatch {};
|
||||
|
||||
String FormatIso8601(Time t);
|
||||
Time ScanIso8601(const String& p);
|
||||
Value JsonRpcData(const Value& v);
|
||||
|
||||
struct RawJsonText {
|
||||
String json;
|
||||
};
|
||||
|
||||
void ValueCheck(bool b);
|
||||
|
||||
void ValueGet(int& n, const Value& v);
|
||||
void ValueGet(bool& b, const Value& v);
|
||||
void ValueGet(String& s, const Value& v);
|
||||
void ValueGet(double& x, const Value& v);
|
||||
void ValueGet(Date& x, const Value& v);
|
||||
void ValueGet(Time& x, const Value& v);
|
||||
void ValueGet(Value& t, const Value& v);
|
||||
void ValueGet(ValueArray& va, const Value& v);
|
||||
void ValueGet(ValueMap& vm, const Value& v);
|
||||
|
||||
template <class T>
|
||||
void ValueGet(Array<T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueArray(v));
|
||||
ValueArray va = v;
|
||||
x.SetCount(va.GetCount());
|
||||
for(int i = 0; i < va.GetCount(); i++)
|
||||
ValueGet(x[i], va[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValueGet(Vector<T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueArray(v));
|
||||
ValueArray va = v;
|
||||
x.SetCount(va.GetCount());
|
||||
for(int i = 0; i < va.GetCount(); i++)
|
||||
ValueGet(x[i], va[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValueGet(ArrayMap<String, T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueMap(v));
|
||||
ValueMap vm = v;
|
||||
const Index<Value>& k = vm.GetKeys();
|
||||
ValueArray va = vm.GetValues();
|
||||
x.Clear();
|
||||
for(int i = 0; i < k.GetCount(); i++)
|
||||
x.Add(k[i], va[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValueGet(VectorMap<String, T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueMap(v));
|
||||
ValueMap vm = v;
|
||||
const Index<Value>& k = vm.GetKeys();
|
||||
ValueArray va = vm.GetValues();
|
||||
x.Clear();
|
||||
for(int i = 0; i < k.GetCount(); i++)
|
||||
x.Add(k[i], va[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValueGet(ArrayMap<int, T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueMap(v));
|
||||
ValueMap vm = v;
|
||||
const Index<Value>& k = vm.GetKeys();
|
||||
ValueArray va = vm.GetValues();
|
||||
x.Clear();
|
||||
for(int i = 0; i < k.GetCount(); i++)
|
||||
x.Add(atoi(AsString(k[i])), va[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValueGet(VectorMap<int, T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueMap(v));
|
||||
ValueMap vm = v;
|
||||
const Index<Value>& k = vm.GetKeys();
|
||||
ValueArray va = vm.GetValues();
|
||||
x.Clear();
|
||||
for(int i = 0; i < k.GetCount(); i++)
|
||||
x.Add(atoi(AsString(k[i])), va[i]);
|
||||
}
|
||||
|
||||
void ValuePut(Value& v, int n);
|
||||
void ValuePut(Value& v, const String& s);
|
||||
void ValuePut(Value& v, const char *s);
|
||||
void ValuePut(Value& v, double x);
|
||||
void ValuePut(Value& v, bool x);
|
||||
void ValuePut(Value& v, const Date& x);
|
||||
void ValuePut(Value& v, const Time& x);
|
||||
void ValuePut(Value& v, const Value& t);
|
||||
void ValuePut(Value& v, const ValueArray& va);
|
||||
void ValuePut(Value& v, const ValueMap& vm);
|
||||
void ValuePut(Value& v, const Json& json);
|
||||
|
||||
template <class T>
|
||||
Value AsXmlRpcValue(const T& x)
|
||||
{
|
||||
Value vs;
|
||||
ValuePut(vs, x);
|
||||
return vs;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const Array<T>& x)
|
||||
{
|
||||
ValueArray va;
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
va.Add(AsXmlRpcValue(x[i]));
|
||||
v = va;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const Vector<T>& x)
|
||||
{
|
||||
ValueArray va;
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
va.Add(AsXmlRpcValue(x[i]));
|
||||
v = va;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const ArrayMap<String, T>& x)
|
||||
{
|
||||
ValueMap vm;
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
if(!x.IsUnlinked(i))
|
||||
vm.Add(x.GetKey(i), AsXmlRpcValue(x[i]));
|
||||
v = vm;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const VectorMap<String, T>& x)
|
||||
{
|
||||
ValueMap vm;
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
if(!x.IsUnlinked(i))
|
||||
vm.Add(x.GetKey(i), AsXmlRpcValue(x[i]));
|
||||
v = vm;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const ArrayMap<int, T>& x)
|
||||
{
|
||||
ValueMap vm;
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
if(!x.IsUnlinked(i))
|
||||
vm.Add(AsString(x.GetKey(i)), AsXmlRpcValue(x[i]));
|
||||
v = vm;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const VectorMap<int, T>& x)
|
||||
{
|
||||
ValueMap vm;
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
if(!x.IsUnlinked(i))
|
||||
vm.Add(AsString(x.GetKey(i)), AsXmlRpcValue(x[i]));
|
||||
v = vm;
|
||||
}
|
||||
|
||||
Value ParseXmlRpcValue(XmlParser& p);
|
||||
Value ParseXmlRpcParam(XmlParser& p);
|
||||
ValueArray ParseXmlRpcParams(XmlParser& p);
|
||||
|
||||
struct RpcGet {
|
||||
Value v;
|
||||
|
||||
template <class T>
|
||||
operator T() { T x; ValueGet(x, v); return x; }
|
||||
|
||||
String ToString() const { return v.ToString(); }
|
||||
};
|
||||
|
||||
struct RpcData {
|
||||
String peeraddr;
|
||||
ValueArray in;
|
||||
int ii;
|
||||
ValueMap in_map;
|
||||
ValueArray out;
|
||||
ValueMap out_map;
|
||||
|
||||
Value Get() { if(ii >= in.GetCount()) throw ValueTypeMismatch(); return in[ii++]; }
|
||||
|
||||
template <class T>
|
||||
RpcData& operator>>(T& x) { ValueGet(x, Get()); return *this; }
|
||||
|
||||
RpcGet operator++(int) { RpcGet h; h.v = Get(); return h; }
|
||||
|
||||
RpcGet operator[](const char *id) { RpcGet h; h.v = in_map[id]; return h; }
|
||||
|
||||
template <class T>
|
||||
RpcData& operator<<(const T& x) { ASSERT(out_map.GetCount() == 0); Value v; ValuePut(v, x); out.Add(v); return *this; }
|
||||
|
||||
template <class T>
|
||||
void Set(int i, const T& x) { ASSERT(out_map.GetCount() == 0); Value v; ValuePut(v, x); out.Set(i, v); }
|
||||
|
||||
template <class T>
|
||||
void operator=(const T& x) { operator<<(x); }
|
||||
|
||||
void Reset() { in.Clear(); out.Clear(); ii = 0; }
|
||||
|
||||
RpcData() { ii = 0; }
|
||||
};
|
||||
|
||||
String FormatXmlRpcValue(const Value& value);
|
||||
String FormatXmlRpcParam(const Value& param);
|
||||
String FormatXmlRpcParams(const ValueArray& params);
|
||||
|
||||
String FormatXmlRpcError(int code, const char *text);
|
||||
|
||||
void Register(const char *name, void (*method)(RpcData&), const char *group = NULL);
|
||||
|
||||
#define RPC_METHOD(name) void name(RpcData& rpc); INITBLOCK { Register(#name, name); } void name(RpcData& rpc)
|
||||
#define RPC_GMETHOD(name, group) void name(RpcData& rpc); INITBLOCK { Register(#name, name, group); } void name(RpcData& rpc)
|
||||
|
||||
struct RpcError {
|
||||
int code;
|
||||
String text;
|
||||
};
|
||||
|
||||
void SetRpcMethodFilter(String (*filter)(const String& methodname));
|
||||
String RpcExecute(const String& request, const char *group, const char *peeraddr);
|
||||
bool RpcPerform(TcpSocket& http, const char *group);
|
||||
bool RpcServerLoop(int port, const char *group = NULL);
|
||||
|
||||
void ThrowRpcError(int code, const char *s);
|
||||
void ThrowRpcError(const char *s);
|
||||
|
||||
class RpcRequest : HttpRequest {
|
||||
bool shorted;
|
||||
RpcData data;
|
||||
String method;
|
||||
String error;
|
||||
String faultString;
|
||||
int faultCode;
|
||||
bool shouldExecute;
|
||||
bool json, notification;
|
||||
void Init();
|
||||
|
||||
public:
|
||||
RpcRequest& Method(const char *name);
|
||||
|
||||
template <class T>
|
||||
RpcRequest& operator<<(const T& x) { data << x; return *this; }
|
||||
template <class T>
|
||||
void Set(int i, const T& x) { data.Set(i, x); }
|
||||
template <class T>
|
||||
RpcRequest& Named(const char *id, const T& x) { data.out_map.Add(id, x); return *this; }
|
||||
|
||||
RpcGet Execute();
|
||||
RpcGet Retry();
|
||||
|
||||
template <class T>
|
||||
bool operator>>(T& x) { if(Execute().v.IsError()) return false;
|
||||
try { data >> x; } catch(ValueTypeMismatch) { return false; } return true; }
|
||||
|
||||
RpcRequest& operator()(const char *method) { Method(method); return *this; }
|
||||
|
||||
#define E__Templ(I) class COMBINE(T, I)
|
||||
#define E__Decl(I) const COMBINE(T, I)& COMBINE(p, I)
|
||||
#define E__Param(I) *this << COMBINE(p, I)
|
||||
#define E__Body(I) \
|
||||
template <__List##I(E__Templ)> \
|
||||
RpcRequest& operator()(const char *method, __List##I(E__Decl)) { \
|
||||
Method(method); \
|
||||
__List##I(E__Param); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
__Expand20(E__Body)
|
||||
|
||||
#undef E__Templ
|
||||
#undef E__Decl
|
||||
#undef E__Param
|
||||
#undef E__Body
|
||||
|
||||
String GetFaultString() const { return faultString; }
|
||||
int GetFaultCode() const { return faultCode; }
|
||||
String GetError() const { return error; }
|
||||
String GetMethod() const { return method; }
|
||||
void ClearError();
|
||||
|
||||
RpcRequest& Url(const char *url);
|
||||
|
||||
RpcRequest& JsonRpc() { json = true; return *this; }
|
||||
RpcRequest& Notification() { notification = true; return *this; }
|
||||
|
||||
RpcRequest(const char *url);
|
||||
RpcRequest();
|
||||
};
|
||||
|
||||
struct XmlRpcRequest : RpcRequest {
|
||||
XmlRpcRequest(const char *url) : RpcRequest(url) {}
|
||||
XmlRpcRequest() {}
|
||||
};
|
||||
|
||||
struct JsonRpcRequest : RpcRequest {
|
||||
JsonRpcRequest(const char *url) : RpcRequest(url) { JsonRpc(); }
|
||||
JsonRpcRequest() { JsonRpc(); }
|
||||
};
|
||||
|
||||
struct JsonRpcRequestNamed : RpcRequest {
|
||||
template <class T>
|
||||
JsonRpcRequestNamed& operator()(const char *id, const T& x) { Named(id, x); return *this; }
|
||||
JsonRpcRequestNamed& operator()(const char *method) { Method(method); return *this; }
|
||||
|
||||
JsonRpcRequestNamed(const char *url) : RpcRequest(url) { JsonRpc(); }
|
||||
JsonRpcRequestNamed() { JsonRpc(); }
|
||||
};
|
||||
|
||||
void LogRpcRequests(bool b = true);
|
||||
|
||||
void SetRpcServerTrace(Stream& s, int level = 1);
|
||||
|
||||
#include "legacy.h"
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
||||
#endif
|
||||
#ifndef Rpc_Rpc_h
|
||||
#define Rpc_Rpc_h
|
||||
|
||||
#include <Core/Core.h>
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
enum {
|
||||
RPC_SERVER_JSON_ERROR = -32700, // Parse error
|
||||
RPC_SERVER_JSON_REQUEST_ERROR = -32600, // Invalid Request
|
||||
RPC_UNKNOWN_METHOD_ERROR = -32601, // Method not found
|
||||
RPC_SERVER_PARAM_ERROR = -32602, // Invalid params
|
||||
RPC_SERVER_PROCESSING_ERROR = -32000, // Server error
|
||||
|
||||
RPC_SERVER_XML_ERROR,
|
||||
|
||||
RPC_CLIENT_HTTP_ERROR = -1000000,
|
||||
RPC_CLIENT_XML_ERROR,
|
||||
RPC_CLIENT_JSON_ERROR,
|
||||
RPC_CLIENT_RESPONSE_ERROR,
|
||||
};
|
||||
|
||||
struct ValueTypeMismatch {};
|
||||
|
||||
String FormatIso8601(Time t);
|
||||
Time ScanIso8601(const String& p);
|
||||
Value JsonRpcData(const Value& v);
|
||||
|
||||
struct RawJsonText {
|
||||
String json;
|
||||
};
|
||||
|
||||
void ValueCheck(bool b);
|
||||
|
||||
void ValueGet(int& n, const Value& v);
|
||||
void ValueGet(bool& b, const Value& v);
|
||||
void ValueGet(String& s, const Value& v);
|
||||
void ValueGet(double& x, const Value& v);
|
||||
void ValueGet(Date& x, const Value& v);
|
||||
void ValueGet(Time& x, const Value& v);
|
||||
void ValueGet(Value& t, const Value& v);
|
||||
void ValueGet(ValueArray& va, const Value& v);
|
||||
void ValueGet(ValueMap& vm, const Value& v);
|
||||
|
||||
template <class T>
|
||||
void ValueGet(Array<T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueArray(v));
|
||||
ValueArray va = v;
|
||||
x.SetCount(va.GetCount());
|
||||
for(int i = 0; i < va.GetCount(); i++)
|
||||
ValueGet(x[i], va[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValueGet(Vector<T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueArray(v));
|
||||
ValueArray va = v;
|
||||
x.SetCount(va.GetCount());
|
||||
for(int i = 0; i < va.GetCount(); i++)
|
||||
ValueGet(x[i], va[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValueGet(ArrayMap<String, T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueMap(v));
|
||||
ValueMap vm = v;
|
||||
const Index<Value>& k = vm.GetKeys();
|
||||
ValueArray va = vm.GetValues();
|
||||
x.Clear();
|
||||
for(int i = 0; i < k.GetCount(); i++)
|
||||
x.Add(k[i], va[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValueGet(VectorMap<String, T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueMap(v));
|
||||
ValueMap vm = v;
|
||||
const Index<Value>& k = vm.GetKeys();
|
||||
ValueArray va = vm.GetValues();
|
||||
x.Clear();
|
||||
for(int i = 0; i < k.GetCount(); i++)
|
||||
x.Add(k[i], va[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValueGet(ArrayMap<int, T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueMap(v));
|
||||
ValueMap vm = v;
|
||||
const Index<Value>& k = vm.GetKeys();
|
||||
ValueArray va = vm.GetValues();
|
||||
x.Clear();
|
||||
for(int i = 0; i < k.GetCount(); i++)
|
||||
x.Add(atoi(AsString(k[i])), va[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValueGet(VectorMap<int, T>& x, const Value& v)
|
||||
{
|
||||
ValueCheck(IsValueMap(v));
|
||||
ValueMap vm = v;
|
||||
const Index<Value>& k = vm.GetKeys();
|
||||
ValueArray va = vm.GetValues();
|
||||
x.Clear();
|
||||
for(int i = 0; i < k.GetCount(); i++)
|
||||
x.Add(atoi(AsString(k[i])), va[i]);
|
||||
}
|
||||
|
||||
void ValuePut(Value& v, int n);
|
||||
void ValuePut(Value& v, const String& s);
|
||||
void ValuePut(Value& v, const char *s);
|
||||
void ValuePut(Value& v, double x);
|
||||
void ValuePut(Value& v, bool x);
|
||||
void ValuePut(Value& v, const Date& x);
|
||||
void ValuePut(Value& v, const Time& x);
|
||||
void ValuePut(Value& v, const Value& t);
|
||||
void ValuePut(Value& v, const ValueArray& va);
|
||||
void ValuePut(Value& v, const ValueMap& vm);
|
||||
void ValuePut(Value& v, const Json& json);
|
||||
|
||||
template <class T>
|
||||
Value AsXmlRpcValue(const T& x)
|
||||
{
|
||||
Value vs;
|
||||
ValuePut(vs, x);
|
||||
return vs;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const Array<T>& x)
|
||||
{
|
||||
ValueArray va;
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
va.Add(AsXmlRpcValue(x[i]));
|
||||
v = va;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const Vector<T>& x)
|
||||
{
|
||||
ValueArray va;
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
va.Add(AsXmlRpcValue(x[i]));
|
||||
v = va;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const ArrayMap<String, T>& x)
|
||||
{
|
||||
ValueMap vm;
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
if(!x.IsUnlinked(i))
|
||||
vm.Add(x.GetKey(i), AsXmlRpcValue(x[i]));
|
||||
v = vm;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const VectorMap<String, T>& x)
|
||||
{
|
||||
ValueMap vm;
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
if(!x.IsUnlinked(i))
|
||||
vm.Add(x.GetKey(i), AsXmlRpcValue(x[i]));
|
||||
v = vm;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const ArrayMap<int, T>& x)
|
||||
{
|
||||
ValueMap vm;
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
if(!x.IsUnlinked(i))
|
||||
vm.Add(AsString(x.GetKey(i)), AsXmlRpcValue(x[i]));
|
||||
v = vm;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ValuePut(Value& v, const VectorMap<int, T>& x)
|
||||
{
|
||||
ValueMap vm;
|
||||
for(int i = 0; i < x.GetCount(); i++)
|
||||
if(!x.IsUnlinked(i))
|
||||
vm.Add(AsString(x.GetKey(i)), AsXmlRpcValue(x[i]));
|
||||
v = vm;
|
||||
}
|
||||
|
||||
Value ParseXmlRpcValue(XmlParser& p);
|
||||
Value ParseXmlRpcParam(XmlParser& p);
|
||||
ValueArray ParseXmlRpcParams(XmlParser& p);
|
||||
|
||||
struct RpcGet {
|
||||
Value v;
|
||||
|
||||
template <class T>
|
||||
operator T() { T x; ValueGet(x, v); return x; }
|
||||
|
||||
String ToString() const { return v.ToString(); }
|
||||
};
|
||||
|
||||
struct RpcData {
|
||||
String peeraddr;
|
||||
ValueArray in;
|
||||
int ii;
|
||||
ValueMap in_map;
|
||||
ValueArray out;
|
||||
ValueMap out_map;
|
||||
|
||||
Value Get() { if(ii >= in.GetCount()) throw ValueTypeMismatch(); return in[ii++]; }
|
||||
|
||||
template <class T>
|
||||
RpcData& operator>>(T& x) { ValueGet(x, Get()); return *this; }
|
||||
|
||||
RpcGet operator++(int) { RpcGet h; h.v = Get(); return h; }
|
||||
|
||||
RpcGet operator[](const char *id) { RpcGet h; h.v = in_map[id]; return h; }
|
||||
|
||||
template <class T>
|
||||
RpcData& operator<<(const T& x) { ASSERT(out_map.GetCount() == 0); Value v; ValuePut(v, x); out.Add(v); return *this; }
|
||||
|
||||
template <class T>
|
||||
void Set(int i, const T& x) { ASSERT(out_map.GetCount() == 0); Value v; ValuePut(v, x); out.Set(i, v); }
|
||||
|
||||
template <class T>
|
||||
void operator=(const T& x) { operator<<(x); }
|
||||
|
||||
void Reset() { in.Clear(); out.Clear(); ii = 0; }
|
||||
|
||||
RpcData() { ii = 0; }
|
||||
};
|
||||
|
||||
String FormatXmlRpcValue(const Value& value);
|
||||
String FormatXmlRpcParam(const Value& param);
|
||||
String FormatXmlRpcParams(const ValueArray& params);
|
||||
|
||||
String FormatXmlRpcError(int code, const char *text);
|
||||
|
||||
void Register(const char *name, void (*method)(RpcData&), const char *group = NULL);
|
||||
|
||||
#define RPC_METHOD(name) void name(RpcData& rpc); INITBLOCK { Register(#name, name); } void name(RpcData& rpc)
|
||||
#define RPC_GMETHOD(name, group) void name(RpcData& rpc); INITBLOCK { Register(#name, name, group); } void name(RpcData& rpc)
|
||||
|
||||
struct RpcError {
|
||||
int code;
|
||||
String text;
|
||||
};
|
||||
|
||||
void SetRpcMethodFilter(String (*filter)(const String& methodname));
|
||||
String RpcExecute(const String& request, const char *group, const char *peeraddr);
|
||||
bool RpcPerform(TcpSocket& http, const char *group);
|
||||
bool RpcServerLoop(int port, const char *group = NULL);
|
||||
|
||||
void ThrowRpcError(int code, const char *s);
|
||||
void ThrowRpcError(const char *s);
|
||||
|
||||
class RpcRequest : HttpRequest {
|
||||
bool shorted;
|
||||
RpcData data;
|
||||
String method;
|
||||
String error;
|
||||
String faultString;
|
||||
int faultCode;
|
||||
bool shouldExecute;
|
||||
bool json, notification;
|
||||
void Init();
|
||||
|
||||
public:
|
||||
RpcRequest& Method(const char *name);
|
||||
|
||||
template <class T>
|
||||
RpcRequest& operator<<(const T& x) { data << x; return *this; }
|
||||
template <class T>
|
||||
void Set(int i, const T& x) { data.Set(i, x); }
|
||||
template <class T>
|
||||
RpcRequest& Named(const char *id, const T& x) { data.out_map.Add(id, x); return *this; }
|
||||
|
||||
RpcGet Execute();
|
||||
RpcGet Retry();
|
||||
|
||||
template <class T>
|
||||
bool operator>>(T& x) { if(Execute().v.IsError()) return false;
|
||||
try { data >> x; } catch(ValueTypeMismatch) { return false; } return true; }
|
||||
|
||||
RpcRequest& operator()(const char *method) { Method(method); return *this; }
|
||||
|
||||
#define E__Templ(I) class COMBINE(T, I)
|
||||
#define E__Decl(I) const COMBINE(T, I)& COMBINE(p, I)
|
||||
#define E__Param(I) *this << COMBINE(p, I)
|
||||
#define E__Body(I) \
|
||||
template <__List##I(E__Templ)> \
|
||||
RpcRequest& operator()(const char *method, __List##I(E__Decl)) { \
|
||||
Method(method); \
|
||||
__List##I(E__Param); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
__Expand20(E__Body)
|
||||
|
||||
#undef E__Templ
|
||||
#undef E__Decl
|
||||
#undef E__Param
|
||||
#undef E__Body
|
||||
|
||||
String GetFaultString() const { return faultString; }
|
||||
int GetFaultCode() const { return faultCode; }
|
||||
String GetError() const { return error; }
|
||||
String GetMethod() const { return method; }
|
||||
void ClearError();
|
||||
|
||||
RpcRequest& Url(const char *url);
|
||||
|
||||
RpcRequest& JsonRpc() { json = true; return *this; }
|
||||
RpcRequest& Notification() { notification = true; return *this; }
|
||||
|
||||
RpcRequest(const char *url);
|
||||
RpcRequest();
|
||||
};
|
||||
|
||||
struct XmlRpcRequest : RpcRequest {
|
||||
XmlRpcRequest(const char *url) : RpcRequest(url) {}
|
||||
XmlRpcRequest() {}
|
||||
};
|
||||
|
||||
struct JsonRpcRequest : RpcRequest {
|
||||
JsonRpcRequest(const char *url) : RpcRequest(url) { JsonRpc(); }
|
||||
JsonRpcRequest() { JsonRpc(); }
|
||||
};
|
||||
|
||||
struct JsonRpcRequestNamed : RpcRequest {
|
||||
template <class T>
|
||||
JsonRpcRequestNamed& operator()(const char *id, const T& x) { Named(id, x); return *this; }
|
||||
JsonRpcRequestNamed& operator()(const char *method) { Method(method); return *this; }
|
||||
|
||||
JsonRpcRequestNamed(const char *url) : RpcRequest(url) { JsonRpc(); }
|
||||
JsonRpcRequestNamed() { JsonRpc(); }
|
||||
};
|
||||
|
||||
void LogRpcRequests(bool b = true);
|
||||
|
||||
void SetRpcServerTrace(Stream& s, int level = 1);
|
||||
void StopRpcServerTrace();
|
||||
|
||||
#include "legacy.h"
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,280 +1,285 @@
|
|||
#include "Rpc.h"
|
||||
|
||||
#define LLOG(x) // DLOG(x)
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
typedef void (*RpcFnPtr)(RpcData&);
|
||||
|
||||
static StaticMutex RpcMapMutex;
|
||||
|
||||
VectorMap<String, RpcFnPtr>& RpcMap(const char *group)
|
||||
{
|
||||
static VectorMap<String, VectorMap< String, void (*)(RpcData&) > > mm;
|
||||
return mm.GetAdd(group);
|
||||
}
|
||||
|
||||
void Register(const char *name, void (*method)(RpcData&), const char *group)
|
||||
{
|
||||
Mutex::Lock __(RpcMapMutex);
|
||||
RpcMap(group).Add(name, method);
|
||||
}
|
||||
|
||||
RpcFnPtr RpcMapGet(const char *group, const char *name)
|
||||
{
|
||||
Mutex::Lock __(RpcMapMutex);
|
||||
return RpcMap(group).Get(name, NULL);
|
||||
}
|
||||
|
||||
String (*sRpcMethodFilter)(const String& methodname);
|
||||
|
||||
void SetRpcMethodFilter(String (*filter)(const String& methodname))
|
||||
{
|
||||
sRpcMethodFilter = filter;
|
||||
}
|
||||
|
||||
void ThrowRpcError(int code, const char *s)
|
||||
{
|
||||
RpcError e;
|
||||
e.code = code;
|
||||
e.text = s;
|
||||
throw e;
|
||||
}
|
||||
|
||||
void ThrowRpcError(const char *s)
|
||||
{
|
||||
ThrowRpcError(RPC_SERVER_PROCESSING_ERROR, s);
|
||||
}
|
||||
|
||||
static Stream *rpc_trace;
|
||||
static int rpc_trace_level;
|
||||
|
||||
void SetRpcServerTrace(Stream& s, int level)
|
||||
{
|
||||
rpc_trace = &s;
|
||||
rpc_trace_level = level;
|
||||
}
|
||||
|
||||
bool CallRpcMethod(RpcData& data, const char *group, String methodname)
|
||||
{
|
||||
LLOG("method name: " << methodname);
|
||||
if(rpc_trace && rpc_trace_level == 0)
|
||||
*rpc_trace << "RpcRequest method:\n" << methodname << '\n';
|
||||
if(sRpcMethodFilter)
|
||||
methodname = (*sRpcMethodFilter)(methodname);
|
||||
void (*fn)(RpcData&) = RpcMapGet(group, methodname);
|
||||
if(!fn)
|
||||
return false;
|
||||
(*fn)(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
String DoXmlRpc(const String& request, const char *group, const char *peeraddr)
|
||||
{
|
||||
XmlParser p(request);
|
||||
RpcData data;
|
||||
try {
|
||||
String methodname;
|
||||
String r = XmlHeader();
|
||||
r << "<methodResponse>\r\n";
|
||||
p.ReadPI();
|
||||
p.PassTag("methodCall");
|
||||
p.PassTag("methodName");
|
||||
methodname = p.ReadText();
|
||||
p.PassEnd();
|
||||
data.peeraddr = peeraddr;
|
||||
data.in = ParseXmlRpcParams(p);
|
||||
if(CallRpcMethod(data, group, methodname)) {
|
||||
if(IsValueArray(data.out)) {
|
||||
ValueArray va = data.out;
|
||||
if(va.GetCount() && IsError(va[0])) {
|
||||
LLOG("ProcessingError");
|
||||
String e = GetErrorText(data.out[0]);
|
||||
if(rpc_trace)
|
||||
*rpc_trace << "Processing error: " << e << '\n';
|
||||
return FormatXmlRpcError(RPC_SERVER_PROCESSING_ERROR, "Processing error: " + e);
|
||||
}
|
||||
r << FormatXmlRpcParams(data.out);
|
||||
}
|
||||
r << "\r\n</methodResponse>\r\n";
|
||||
}
|
||||
else
|
||||
return FormatXmlRpcError(RPC_UNKNOWN_METHOD_ERROR, "\'" + methodname + "\' method is unknown");
|
||||
p.PassEnd();
|
||||
return r;
|
||||
}
|
||||
catch(RpcError e) {
|
||||
LLOG("Processing error: " << e.text);
|
||||
if(rpc_trace)
|
||||
*rpc_trace << "Processing error: " << e.text << '\n';
|
||||
return FormatXmlRpcError(e.code, e.text);
|
||||
}
|
||||
catch(XmlError e) {
|
||||
LLOG("XmlError " << e << ": " << p.GetPtr());
|
||||
if(rpc_trace)
|
||||
*rpc_trace << "XmlError: " << e << '\n';
|
||||
return FormatXmlRpcError(RPC_SERVER_XML_ERROR, "XML Error: " + e);
|
||||
}
|
||||
catch(ValueTypeMismatch) {
|
||||
LLOG("ValueTypeMismatch at parameter " << data.ii);
|
||||
if(rpc_trace)
|
||||
*rpc_trace << "ValueTypeMismatch at parameter " << data.ii << '\n';
|
||||
return FormatXmlRpcError(RPC_SERVER_PARAM_ERROR, "Parameter mismatch at parameter " + AsString(data.ii));
|
||||
}
|
||||
return Null;
|
||||
}
|
||||
|
||||
String JsonRpcError(int code, const char *text, const Value& id)
|
||||
{
|
||||
Json m;
|
||||
m("jsonrpc", "2.0");
|
||||
ValueMap err;
|
||||
err.Add("code", code);
|
||||
err.Add("message", text);
|
||||
m("error", err);
|
||||
m("id", id);
|
||||
return m;
|
||||
}
|
||||
|
||||
String ProcessJsonRpc(const Value& v, const char *group, const char *peeraddr)
|
||||
{
|
||||
LLOG("Parsed JSON request: " << v);
|
||||
Value id = v["id"];
|
||||
Value methodname = v["method"];
|
||||
Value param = v["params"];
|
||||
RpcData data;
|
||||
data.peeraddr = peeraddr;
|
||||
if(param.Is<ValueMap>())
|
||||
data.in_map = param;
|
||||
else
|
||||
data.in = param;
|
||||
try {
|
||||
if(CallRpcMethod(data, group, methodname)) {
|
||||
if(IsValueArray(data.out)) {
|
||||
ValueArray va = data.out;
|
||||
Value result = Null;
|
||||
if(va.GetCount()) {
|
||||
if(IsError(va[0])) {
|
||||
LLOG("ProcessingError");
|
||||
String e = GetErrorText(data.out[0]);
|
||||
if(rpc_trace)
|
||||
*rpc_trace << "Processing error: " << e << '\n';
|
||||
return JsonRpcError(RPC_SERVER_PROCESSING_ERROR, "Processing error: " + e, id);
|
||||
}
|
||||
result = JsonRpcData(va[0]);
|
||||
}
|
||||
Json json;
|
||||
json("jsonrpc", "2.0");
|
||||
if(result.Is<RawJsonText>())
|
||||
json.CatRaw("result", result.To<RawJsonText>().json);
|
||||
else
|
||||
json("result", result);
|
||||
json("id", id);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
return JsonRpcError(RPC_UNKNOWN_METHOD_ERROR, "Method not found", id);
|
||||
}
|
||||
catch(RpcError e) {
|
||||
LLOG("Processing error: " << e.text);
|
||||
if(rpc_trace)
|
||||
*rpc_trace << "Processing error: " << e.text << '\n';
|
||||
return JsonRpcError(e.code, e.text, id);
|
||||
}
|
||||
catch(ValueTypeMismatch) {
|
||||
LLOG("ValueTypeMismatch at parameter " << data.ii);
|
||||
if(rpc_trace)
|
||||
*rpc_trace << "ValueTypeMismatch at parameter " << data.ii << '\n';
|
||||
return JsonRpcError(RPC_SERVER_PARAM_ERROR, "Invalid params", id);
|
||||
}
|
||||
}
|
||||
|
||||
String DoJsonRpc(const String& request, const char *group, const char *peeraddr)
|
||||
{
|
||||
try {
|
||||
Value v = ParseJSON(request);
|
||||
if(v.Is<ValueMap>())
|
||||
return ProcessJsonRpc(v, group, peeraddr);
|
||||
if(v.Is<ValueArray>()) {
|
||||
JsonArray a;
|
||||
for(int i = 0; i < v.GetCount(); i++)
|
||||
a.CatRaw(ProcessJsonRpc(v[i], group, peeraddr));
|
||||
return v.GetCount() ? ~a : String();
|
||||
}
|
||||
}
|
||||
catch(CParser::Error e) {}
|
||||
return AsJSON(JsonRpcError(RPC_SERVER_JSON_ERROR, "Parse error", Null));
|
||||
}
|
||||
|
||||
String RpcExecute(const String& request, const char *group, const char *peeraddr, bool& json)
|
||||
{
|
||||
if(rpc_trace && rpc_trace_level == 1)
|
||||
*rpc_trace << "RPC Request:\n" << request << '\n';
|
||||
CParser p(request);
|
||||
String r;
|
||||
if(p.Char('{') || p.Char('[')) {
|
||||
json = true;
|
||||
r = DoJsonRpc(request, group, peeraddr);
|
||||
}
|
||||
else {
|
||||
json = false;
|
||||
r = DoXmlRpc(request, group, peeraddr);
|
||||
}
|
||||
if(rpc_trace)
|
||||
if(rpc_trace_level == 0)
|
||||
*rpc_trace << "Rpc finished OK\n";
|
||||
else
|
||||
*rpc_trace << "Server response:\n" << r << '\n';
|
||||
return r;
|
||||
}
|
||||
|
||||
String RpcExecute(const String& request, const char *group, const char *peeraddr)
|
||||
{
|
||||
bool dummy;
|
||||
return RpcExecute(request, group, peeraddr, dummy);
|
||||
}
|
||||
|
||||
bool RpcPerform(TcpSocket& http, const char *group)
|
||||
{
|
||||
LLOG("=== Accepted connection ===================================================");
|
||||
HttpHeader hdr;
|
||||
if(hdr.Read(http) && hdr.GetMethod() == "POST") {
|
||||
int len = atoi(hdr["content-length"]);
|
||||
if(len > 0 && len < 1024 * 1024 * 1024) {
|
||||
bool json;
|
||||
String r = RpcExecute(http.GetAll(len), group, http.GetPeerAddr(), json);
|
||||
LLOG("--------- Server response:\n" << r << "=============");
|
||||
String response;
|
||||
String ts = WwwFormat(GetUtcTime());
|
||||
response <<
|
||||
"HTTP/1.0 200 OK\r\n"
|
||||
"Date: " << ts << "\r\n"
|
||||
"Server: U++ RPC server\r\n"
|
||||
"Content-Length: " << r.GetCount() << "\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-Type: text/" << (json ? "json" : "xml") << "\r\n\r\n"
|
||||
<< r;
|
||||
LLOG(response);
|
||||
if(r.GetCount())
|
||||
http.Put(response);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
http.Put("HTTP/1.0 400 Bad request\r\n"
|
||||
"Server: U++\r\n\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RpcServerLoop(int port, const char *group)
|
||||
{
|
||||
TcpSocket rpc;
|
||||
if(!rpc.Listen(port, 5))
|
||||
return false;
|
||||
for(;;) {
|
||||
TcpSocket http;
|
||||
if(http.Accept(rpc))
|
||||
RpcPerform(http, group);
|
||||
}
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
#include "Rpc.h"
|
||||
|
||||
#define LLOG(x) // DLOG(x)
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
typedef void (*RpcFnPtr)(RpcData&);
|
||||
|
||||
static StaticMutex RpcMapMutex;
|
||||
|
||||
VectorMap<String, RpcFnPtr>& RpcMap(const char *group)
|
||||
{
|
||||
static VectorMap<String, VectorMap< String, void (*)(RpcData&) > > mm;
|
||||
return mm.GetAdd(group);
|
||||
}
|
||||
|
||||
void Register(const char *name, void (*method)(RpcData&), const char *group)
|
||||
{
|
||||
Mutex::Lock __(RpcMapMutex);
|
||||
RpcMap(group).Add(name, method);
|
||||
}
|
||||
|
||||
RpcFnPtr RpcMapGet(const char *group, const char *name)
|
||||
{
|
||||
Mutex::Lock __(RpcMapMutex);
|
||||
return RpcMap(group).Get(name, NULL);
|
||||
}
|
||||
|
||||
String (*sRpcMethodFilter)(const String& methodname);
|
||||
|
||||
void SetRpcMethodFilter(String (*filter)(const String& methodname))
|
||||
{
|
||||
sRpcMethodFilter = filter;
|
||||
}
|
||||
|
||||
void ThrowRpcError(int code, const char *s)
|
||||
{
|
||||
RpcError e;
|
||||
e.code = code;
|
||||
e.text = s;
|
||||
throw e;
|
||||
}
|
||||
|
||||
void ThrowRpcError(const char *s)
|
||||
{
|
||||
ThrowRpcError(RPC_SERVER_PROCESSING_ERROR, s);
|
||||
}
|
||||
|
||||
static Stream *rpc_trace;
|
||||
static int rpc_trace_level;
|
||||
|
||||
void SetRpcServerTrace(Stream& s, int level)
|
||||
{
|
||||
rpc_trace = &s;
|
||||
rpc_trace_level = level;
|
||||
}
|
||||
|
||||
void StopRpcServerTrace()
|
||||
{
|
||||
rpc_trace = NULL;
|
||||
}
|
||||
|
||||
bool CallRpcMethod(RpcData& data, const char *group, String methodname)
|
||||
{
|
||||
LLOG("method name: " << methodname);
|
||||
if(rpc_trace && rpc_trace_level == 0)
|
||||
*rpc_trace << "RpcRequest method:\n" << methodname << '\n';
|
||||
if(sRpcMethodFilter)
|
||||
methodname = (*sRpcMethodFilter)(methodname);
|
||||
void (*fn)(RpcData&) = RpcMapGet(group, methodname);
|
||||
if(!fn)
|
||||
return false;
|
||||
(*fn)(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
String DoXmlRpc(const String& request, const char *group, const char *peeraddr)
|
||||
{
|
||||
XmlParser p(request);
|
||||
RpcData data;
|
||||
try {
|
||||
String methodname;
|
||||
String r = XmlHeader();
|
||||
r << "<methodResponse>\r\n";
|
||||
p.ReadPI();
|
||||
p.PassTag("methodCall");
|
||||
p.PassTag("methodName");
|
||||
methodname = p.ReadText();
|
||||
p.PassEnd();
|
||||
data.peeraddr = peeraddr;
|
||||
data.in = ParseXmlRpcParams(p);
|
||||
if(CallRpcMethod(data, group, methodname)) {
|
||||
if(IsValueArray(data.out)) {
|
||||
ValueArray va = data.out;
|
||||
if(va.GetCount() && IsError(va[0])) {
|
||||
LLOG("ProcessingError");
|
||||
String e = GetErrorText(data.out[0]);
|
||||
if(rpc_trace)
|
||||
*rpc_trace << "Processing error: " << e << '\n';
|
||||
return FormatXmlRpcError(RPC_SERVER_PROCESSING_ERROR, "Processing error: " + e);
|
||||
}
|
||||
r << FormatXmlRpcParams(data.out);
|
||||
}
|
||||
r << "\r\n</methodResponse>\r\n";
|
||||
}
|
||||
else
|
||||
return FormatXmlRpcError(RPC_UNKNOWN_METHOD_ERROR, "\'" + methodname + "\' method is unknown");
|
||||
p.PassEnd();
|
||||
return r;
|
||||
}
|
||||
catch(RpcError e) {
|
||||
LLOG("Processing error: " << e.text);
|
||||
if(rpc_trace)
|
||||
*rpc_trace << "Processing error: " << e.text << '\n';
|
||||
return FormatXmlRpcError(e.code, e.text);
|
||||
}
|
||||
catch(XmlError e) {
|
||||
LLOG("XmlError " << e << ": " << p.GetPtr());
|
||||
if(rpc_trace)
|
||||
*rpc_trace << "XmlError: " << e << '\n';
|
||||
return FormatXmlRpcError(RPC_SERVER_XML_ERROR, "XML Error: " + e);
|
||||
}
|
||||
catch(ValueTypeMismatch) {
|
||||
LLOG("ValueTypeMismatch at parameter " << data.ii);
|
||||
if(rpc_trace)
|
||||
*rpc_trace << "ValueTypeMismatch at parameter " << data.ii << '\n';
|
||||
return FormatXmlRpcError(RPC_SERVER_PARAM_ERROR, "Parameter mismatch at parameter " + AsString(data.ii));
|
||||
}
|
||||
return Null;
|
||||
}
|
||||
|
||||
String JsonRpcError(int code, const char *text, const Value& id)
|
||||
{
|
||||
Json m;
|
||||
m("jsonrpc", "2.0");
|
||||
ValueMap err;
|
||||
err.Add("code", code);
|
||||
err.Add("message", text);
|
||||
m("error", err);
|
||||
m("id", id);
|
||||
return m;
|
||||
}
|
||||
|
||||
String ProcessJsonRpc(const Value& v, const char *group, const char *peeraddr)
|
||||
{
|
||||
LLOG("Parsed JSON request: " << v);
|
||||
Value id = v["id"];
|
||||
Value methodname = v["method"];
|
||||
Value param = v["params"];
|
||||
RpcData data;
|
||||
data.peeraddr = peeraddr;
|
||||
if(param.Is<ValueMap>())
|
||||
data.in_map = param;
|
||||
else
|
||||
data.in = param;
|
||||
try {
|
||||
if(CallRpcMethod(data, group, methodname)) {
|
||||
if(IsValueArray(data.out)) {
|
||||
ValueArray va = data.out;
|
||||
Value result = Null;
|
||||
if(va.GetCount()) {
|
||||
if(IsError(va[0])) {
|
||||
LLOG("ProcessingError");
|
||||
String e = GetErrorText(data.out[0]);
|
||||
if(rpc_trace)
|
||||
*rpc_trace << "Processing error: " << e << '\n';
|
||||
return JsonRpcError(RPC_SERVER_PROCESSING_ERROR, "Processing error: " + e, id);
|
||||
}
|
||||
result = JsonRpcData(va[0]);
|
||||
}
|
||||
Json json;
|
||||
json("jsonrpc", "2.0");
|
||||
if(result.Is<RawJsonText>())
|
||||
json.CatRaw("result", result.To<RawJsonText>().json);
|
||||
else
|
||||
json("result", result);
|
||||
json("id", id);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
return JsonRpcError(RPC_UNKNOWN_METHOD_ERROR, "Method not found", id);
|
||||
}
|
||||
catch(RpcError e) {
|
||||
LLOG("Processing error: " << e.text);
|
||||
if(rpc_trace)
|
||||
*rpc_trace << "Processing error: " << e.text << '\n';
|
||||
return JsonRpcError(e.code, e.text, id);
|
||||
}
|
||||
catch(ValueTypeMismatch) {
|
||||
LLOG("ValueTypeMismatch at parameter " << data.ii);
|
||||
if(rpc_trace)
|
||||
*rpc_trace << "ValueTypeMismatch at parameter " << data.ii << '\n';
|
||||
return JsonRpcError(RPC_SERVER_PARAM_ERROR, "Invalid params", id);
|
||||
}
|
||||
}
|
||||
|
||||
String DoJsonRpc(const String& request, const char *group, const char *peeraddr)
|
||||
{
|
||||
try {
|
||||
Value v = ParseJSON(request);
|
||||
if(v.Is<ValueMap>())
|
||||
return ProcessJsonRpc(v, group, peeraddr);
|
||||
if(v.Is<ValueArray>()) {
|
||||
JsonArray a;
|
||||
for(int i = 0; i < v.GetCount(); i++)
|
||||
a.CatRaw(ProcessJsonRpc(v[i], group, peeraddr));
|
||||
return v.GetCount() ? ~a : String();
|
||||
}
|
||||
}
|
||||
catch(CParser::Error e) {}
|
||||
return AsJSON(JsonRpcError(RPC_SERVER_JSON_ERROR, "Parse error", Null));
|
||||
}
|
||||
|
||||
String RpcExecute(const String& request, const char *group, const char *peeraddr, bool& json)
|
||||
{
|
||||
if(rpc_trace && rpc_trace_level == 1)
|
||||
*rpc_trace << "RPC Request:\n" << request << '\n';
|
||||
CParser p(request);
|
||||
String r;
|
||||
if(p.Char('{') || p.Char('[')) {
|
||||
json = true;
|
||||
r = DoJsonRpc(request, group, peeraddr);
|
||||
}
|
||||
else {
|
||||
json = false;
|
||||
r = DoXmlRpc(request, group, peeraddr);
|
||||
}
|
||||
if(rpc_trace)
|
||||
if(rpc_trace_level == 0)
|
||||
*rpc_trace << "Rpc finished OK\n";
|
||||
else
|
||||
*rpc_trace << "Server response:\n" << r << '\n';
|
||||
return r;
|
||||
}
|
||||
|
||||
String RpcExecute(const String& request, const char *group, const char *peeraddr)
|
||||
{
|
||||
bool dummy;
|
||||
return RpcExecute(request, group, peeraddr, dummy);
|
||||
}
|
||||
|
||||
bool RpcPerform(TcpSocket& http, const char *group)
|
||||
{
|
||||
LLOG("=== Accepted connection ===================================================");
|
||||
HttpHeader hdr;
|
||||
if(hdr.Read(http) && hdr.GetMethod() == "POST") {
|
||||
int len = atoi(hdr["content-length"]);
|
||||
if(len > 0 && len < 1024 * 1024 * 1024) {
|
||||
bool json;
|
||||
String r = RpcExecute(http.GetAll(len), group, http.GetPeerAddr(), json);
|
||||
LLOG("--------- Server response:\n" << r << "=============");
|
||||
String response;
|
||||
String ts = WwwFormat(GetUtcTime());
|
||||
response <<
|
||||
"HTTP/1.0 200 OK\r\n"
|
||||
"Date: " << ts << "\r\n"
|
||||
"Server: U++ RPC server\r\n"
|
||||
"Content-Length: " << r.GetCount() << "\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-Type: text/" << (json ? "json" : "xml") << "\r\n\r\n"
|
||||
<< r;
|
||||
LLOG(response);
|
||||
if(r.GetCount())
|
||||
http.Put(response);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
http.Put("HTTP/1.0 400 Bad request\r\n"
|
||||
"Server: U++\r\n\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RpcServerLoop(int port, const char *group)
|
||||
{
|
||||
TcpSocket rpc;
|
||||
if(!rpc.Listen(port, 5))
|
||||
return false;
|
||||
for(;;) {
|
||||
TcpSocket http;
|
||||
if(http.Accept(rpc))
|
||||
RpcPerform(http, group);
|
||||
}
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#ifndef _Core_Rpc_icpp_init_stub
|
||||
#define _Core_Rpc_icpp_init_stub
|
||||
#include "Web/init"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1496,8 +1496,12 @@ String LoadStream(Stream& in) {
|
|||
}
|
||||
|
||||
String LoadFile(const char *filename) {
|
||||
FileIn in(filename);
|
||||
return LoadStream(in);
|
||||
FindFile ff(filename);
|
||||
if(ff && ff.IsFile()) {
|
||||
FileIn in(filename);
|
||||
return LoadStream(in);
|
||||
}
|
||||
return String::GetVoid();
|
||||
}
|
||||
|
||||
bool SaveStream(Stream& out, const String& data) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue