diff --git a/uppsrc/Core/XmlRpc/Client.cpp b/uppsrc/Core/XmlRpc/Client.cpp new file mode 100644 index 000000000..6d7034230 --- /dev/null +++ b/uppsrc/Core/XmlRpc/Client.cpp @@ -0,0 +1,122 @@ +#include "XmlRpc.h" + +NAMESPACE_UPP + +#define LLOG(x) // LOG(x) + +static bool sLogRpcCalls; + +void LogXmlRpcRequests(bool b) +{ + sLogRpcCalls = b; +} + +XmlRpcRequest& XmlRpcRequest::Url(const char *url) +{ + shorted = true; + if(url && *url) { + HttpRequest::Url(url); + shorted = false; + } + shouldExecute = true; + return *this; +} + +XmlRpcRequest& XmlRpcRequest::Method(const char *name) +{ + shouldExecute = true; + method = name; + data.Reset(); + error.Clear(); + return *this; +} + +XmlRpcRequest::XmlRpcRequest(const char *url) +{ + Url(url); + ContentType("text/xml"); + RequestTimeout(30000); +} + +XmlRpcRequest::XmlRpcRequest() +{ + Url(NULL); + ContentType("text/xml"); + RequestTimeout(30000); +} + +String XmlRpcExecute(const String& request, const char *group, const char *peeraddr); + +Value XmlRpcRequest::Retry() +{ + ClearError(); + shouldExecute = true; + return Execute(); +} + +Value XmlRpcRequest::Execute() +{ + if(!shouldExecute) + return Value(); + shouldExecute = false; + String request = XmlHeader(); + request << XmlTag("methodCall")(XmlTag("methodName")(method) + FormatXmlRpcParams(data.out)); + if(sLogRpcCalls) + RLOG("XmlRpc call request:\n" << request); + String response; + New(); + if(shorted) + response = XmlRpcExecute(request, "", "127.0.0.1"); + else + response = Post(request).Execute(); + if(sLogRpcCalls) + RLOG("XmlRpc call response:\n" << response); + if(IsNull(response)) { + faultCode = XMLRPC_CLIENT_HTTP_ERROR; + faultString = GetErrorDesc(); + error = "Http request failed: " + faultString; + LLOG(error); + return ErrorValue(error); + } + XmlParser p(response); + try { + p.ReadPI(); + p.PassTag("methodResponse"); + if(p.Tag("fault")) { + Value m = ParseXmlRpcValue(p); + if(IsValueMap(m)) { + ValueMap mm = m; + faultString = mm["faultString"]; + faultCode = mm["faultCode"]; + error.Clear(); + error << "Failed '" << faultString << "' (" << faultCode << ')'; + LLOG(s); + return ErrorValue(error); + } + } + else { + data.in = ParseXmlRpcParams(p); + data.ii = 0; + p.PassEnd(); + } + } + catch(XmlError e) { + String s; + faultString = e; + faultCode = XMLRPC_CLIENT_XML_ERROR; + error.Clear(); + error << "XML Error: " << faultString; + LLOG(error << ": " << p.GetPtr()); + return ErrorValue(error); + } + return data.in.GetCount() ? data.in[0] : Null; +} + +void XmlRpcRequest::ClearError() +{ + faultCode = 0; + faultString.Clear(); + error.Clear(); +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Core/XmlRpc/Server.cpp b/uppsrc/Core/XmlRpc/Server.cpp new file mode 100644 index 000000000..25d7b69a8 --- /dev/null +++ b/uppsrc/Core/XmlRpc/Server.cpp @@ -0,0 +1,185 @@ +#include "XmlRpc.h" +#include "XmlRpc.h" + +#define LLOG(x) // DLOG(x) + +NAMESPACE_UPP + +typedef void (*XmlRpcFnPtr)(XmlRpcData&); + +static StaticMutex XmlRpcMapMutex; + +VectorMap& XmlRpcMap(const char *group) +{ + static VectorMap > mm; + return mm.GetAdd(group); +} + +void Register(const char *name, void (*method)(XmlRpcData&), const char *group) +{ + Mutex::Lock __(XmlRpcMapMutex); + XmlRpcMap(group).Add(name, method); +} + +XmlRpcFnPtr XmlRpcMapGet(const char *group, const char *name) +{ + Mutex::Lock __(XmlRpcMapMutex); + return XmlRpcMap(group).Get(name, NULL); +} + +String (*sXmlRpcMethodFilter)(const String& methodname); + +void SetXmlRpcMethodFilter(String (*filter)(const String& methodname)) +{ + sXmlRpcMethodFilter = filter; +} + +void ThrowXmlRpcError(int code, const char *s) +{ + XmlRpcError e; + e.code = code; + e.text = s; + throw e; +} + +void ThrowXmlRpcError(const char *s) +{ + ThrowXmlRpcError(-1, s); +} + +static Stream *xmlrpc_trace; +static int xmlrpc_trace_level; + +void SetXmlRpcServerTrace(Stream& s, int level) +{ + xmlrpc_trace = &s; + xmlrpc_trace_level = level; +} + +String XmlRpcExecute(const String& request, const char *group, const char *peeraddr) +{ + if(xmlrpc_trace && xmlrpc_trace_level == 1) + *xmlrpc_trace << "XmlRpcRequest:\n" << request << '\n'; + XmlParser p(request); + XmlRpcData data; + String methodname; + try { + String r = XmlHeader(); + r << "\r\n"; + p.ReadPI(); + p.PassTag("methodCall"); + p.PassTag("methodName"); + methodname = p.ReadText(); + LLOG("method name: " << methodname); + if(xmlrpc_trace && xmlrpc_trace_level == 0) + *xmlrpc_trace << "XmlRpcRequest method:\n" << methodname << '\n'; + p.PassEnd(); + data.peeraddr = peeraddr; + data.in = ParseXmlRpcParams(p); + XmlRpcMapMutex.Enter(); + if(sXmlRpcMethodFilter) + methodname = (*sXmlRpcMethodFilter)(methodname); + void (*fn)(XmlRpcData&) = XmlRpcMapGet(group, methodname); + if(fn) { + (*fn)(data); + if(IsValueArray(data.out)) { + ValueArray va = data.out; + if(va.GetCount() && IsError(va[0])) { + LLOG("ProcessingError"); + return FormatXmlRpcError(XMLRPC_SERVER_PROCESSING_ERROR, "Processing error: " + GetErrorText(data.out[0])); + } + r << FormatXmlRpcParams(data.out); + } + r << "\r\n\r\n"; + } + else { + XmlRpcMapMutex.Leave(); + return FormatXmlRpcError(XMLRPC_UNKNOWN_METHOD_ERROR, "\'" + methodname + "\' method is unknown"); + } + p.PassEnd(); + if(xmlrpc_trace) + if(xmlrpc_trace_level == 0) + *xmlrpc_trace << "XmlRpc finished OK\n"; + else + *xmlrpc_trace << "Server response:\n" << r << '\n'; + return r; + } + catch(XmlRpcError e) { + LLOG("Client error: " << e.text); + if(xmlrpc_trace) + *xmlrpc_trace << "Client error: " << e.text << '\n'; + return FormatXmlRpcError(e.code, e.text); + } + catch(XmlError e) { + LLOG("XmlError " << e << ": " << p.GetPtr()); + if(xmlrpc_trace) + *xmlrpc_trace << "XmlError: " << e << '\n'; + return FormatXmlRpcError(XMLRPC_SERVER_XML_ERROR, "XML Error: " + e); + } + catch(ValueTypeMismatch) { + LLOG("ValueTypeMismatch at parameter " << data.ii); + if(xmlrpc_trace) + *xmlrpc_trace << "ValueTypeMismatch at parameter " << data.ii << '\n'; + return FormatXmlRpcError(XMLRPC_SERVER_PARAM_ERROR, "Parameter mismatch at parameter " + AsString(data.ii)); + } + return Null; +} + + +bool XmlRpcPerform(TcpSocket& http, const char *group) +{ + LLOG("=== Accepted connection ==================================================="); + String request = ToUpper(http.GetLine()); + LLOG(request); + if(http.IsError() || request.GetCount() == 0) + return false; + if(request.Find("POST") >= 0 || request.Find("HTTP") >= 0) { + VectorMap hdr; + for(;;) { + String s = http.GetLine(); + if(s.IsEmpty()) break; + LLOG(s); + int q = s.Find(':'); + if(q >= 0) + hdr.GetAdd(s.Mid(0, q)) = TrimLeft(s.Mid(q + 1)); + } + if(!http.IsError()) { + int len = atoi(hdr.Get("Content-Length", "")); + String r; + if(len > 0 && len < 1024 * 1024 * 1024) { + r = XmlRpcExecute(http.GetAll(len), group, http.GetPeerAddr()); + 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++ XMLRPC server\r\n" + "Content-Length: " << r.GetCount() << "\r\n" + "Connection: close\r\n" + "Content-Type: text/xml\r\n\r\n" + << r; + LLOG(response); + http.Put(response); + return true; + } + } + } + http.Put("HTTP/1.0 400 Bad request\r\n" + "Server: U++\r\n\r\n"); + return false; +} + +bool XmlRpcServerLoop(int port, const char *group) +{ + TcpSocket rpc; + if(!rpc.Listen(port, 5)) + return false; + for(;;) { + TcpSocket http; + if(rpc.Accept(http)) + XmlRpcPerform(http, group); + } +} + +END_UPP_NAMESPACE diff --git a/uppsrc/XmlRpc/Value.cpp b/uppsrc/Core/XmlRpc/Value.cpp similarity index 90% rename from uppsrc/XmlRpc/Value.cpp rename to uppsrc/Core/XmlRpc/Value.cpp index 9828bd23f..5996e82c9 100644 --- a/uppsrc/XmlRpc/Value.cpp +++ b/uppsrc/Core/XmlRpc/Value.cpp @@ -1,5 +1,7 @@ #include "XmlRpc.h" +NAMESPACE_UPP + void ValueCheck(bool b) { if(!b) @@ -108,3 +110,5 @@ void ValuePut(Value& v, const ValueMap& vm) { v = vm; } + +END_UPP_NAMESPACE \ No newline at end of file diff --git a/uppsrc/XmlRpc/Xml.cpp b/uppsrc/Core/XmlRpc/Xml.cpp similarity index 94% rename from uppsrc/XmlRpc/Xml.cpp rename to uppsrc/Core/XmlRpc/Xml.cpp index 23e17ca83..8d0ac5642 100644 --- a/uppsrc/XmlRpc/Xml.cpp +++ b/uppsrc/Core/XmlRpc/Xml.cpp @@ -1,5 +1,7 @@ #include "XmlRpc.h" +NAMESPACE_UPP + Value ParseXmlRpcValue(XmlParser& p) { Value r; @@ -182,3 +184,5 @@ String FormatXmlRpcError(int code, const char *text) << "\r\n"; return r; } + +END_UPP_NAMESPACE diff --git a/uppsrc/Core/XmlRpc/XmlRpc.h b/uppsrc/Core/XmlRpc/XmlRpc.h new file mode 100644 index 000000000..54677683e --- /dev/null +++ b/uppsrc/Core/XmlRpc/XmlRpc.h @@ -0,0 +1,336 @@ +#ifndef _XmlRpc_XmlRpc_h +#define _XmlRpc_XmlRpc_h + +#include + +NAMESPACE_UPP + +enum { + XMLRPC_CLIENT_HTTP_ERROR = -1000000, + XMLRPC_CLIENT_XML_ERROR, + XMLRPC_CLIENT_RETTYPE_ERROR, + XMLRPC_SERVER_PARAM_ERROR, + XMLRPC_SERVER_XML_ERROR, + XMLRPC_SERVER_PROCESSING_ERROR, + XMLRPC_UNKNOWN_METHOD_ERROR, +}; + +struct ValueTypeMismatch {}; + +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 +void ValueGet(Array& 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 +void ValueGet(Vector& 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 +void ValueGet(ArrayMap& x, const Value& v) +{ + ValueCheck(IsValueMap(v)); + ValueMap vm = v; + const Index& k = vm.GetKeys(); + ValueArray va = vm.GetValues(); + x.Clear(); + for(int i = 0; i < k.GetCount(); i++) + x.Add(k[i], va[i]); +} + +template +void ValueGet(VectorMap& x, const Value& v) +{ + ValueCheck(IsValueMap(v)); + ValueMap vm = v; + const Index& k = vm.GetKeys(); + ValueArray va = vm.GetValues(); + x.Clear(); + for(int i = 0; i < k.GetCount(); i++) + x.Add(k[i], va[i]); +} + +template +void ValueGet(ArrayMap& x, const Value& v) +{ + ValueCheck(IsValueMap(v)); + ValueMap vm = v; + const Index& 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 +void ValueGet(VectorMap& x, const Value& v) +{ + ValueCheck(IsValueMap(v)); + ValueMap vm = v; + const Index& 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); + +template +Value AsXmlRpcValue(const T& x) +{ + Value vs; + ValuePut(vs, x); + return vs; +} + +template +void ValuePut(Value& v, const Array& x) +{ + ValueArray va; + for(int i = 0; i < x.GetCount(); i++) + va.Add(AsXmlRpcValue(x[i])); + v = va; +} + +template +void ValuePut(Value& v, const Vector& x) +{ + ValueArray va; + for(int i = 0; i < x.GetCount(); i++) + va.Add(AsXmlRpcValue(x[i])); + v = va; +} + +template +void ValuePut(Value& v, const ArrayMap& 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 +void ValuePut(Value& v, const VectorMap& 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 +void ValuePut(Value& v, const ArrayMap& 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 +void ValuePut(Value& v, const VectorMap& 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; +} + +struct ValueMapper { + ValueMap map; + bool get; + + template + ValueMapper& operator()(const char *name, T& x) { + if(get) + ValueGet(x, map[name]); + else { + Value v; + ValuePut(v, x); + map.Add(name, v); + } + return *this; + } +}; + +template +void ValueGetStruct_(T& x, const Value& v) { + ValueCheck(IsNull(v) || IsValueMap(v)); + ValueMapper m; + m.map = v; + m.get = true; + x.Map(m); +} + +template +void ValuePutStruct_(Value& v, const T& x) { + ValueMapper m; + m.get = false; + const_cast(x).Map(m); + v = m.map; +} + +template +struct XmlRpcStruct { + friend void ValueGet(T& x, const Value& v) { ValueGetStruct_(x, v); } + friend void ValuePut(Value& v, const T& x) { ValuePutStruct_(v, x); } +}; + +#define XMLRPC_STRUCT(T) \ +inline void ValueGet(T& x, const Value& v) { ValueGetStruct_(x, v); } \ +inline void ValuePut(Value& v, const T& x) { ValuePutStruct_(v, x); } + +Value ParseXmlRpcValue(XmlParser& p); +Value ParseXmlRpcParam(XmlParser& p); +ValueArray ParseXmlRpcParams(XmlParser& p); + +struct XmlRpcData { + String peeraddr; + ValueArray in; + int ii; + ValueArray out; + + Value Get() { if(ii >= in.GetCount()) throw ValueTypeMismatch(); return in[ii++]; } + + template + XmlRpcData& operator>>(T& x) { ValueGet(x, Get()); return *this; } + + template + XmlRpcData& operator<<(const T& x) { Value v; ValuePut(v, x); out.Add(v); return *this; } + template + void Set(int i, const T& x) { Value v; ValuePut(v, x); out.Set(i, v); } + + void Reset() { in.Clear(); out.Clear(); ii = 0; } + + XmlRpcData() { 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)(XmlRpcData&), const char *group = NULL); +void SetXmlRpcMethodFilter(String (*filter)(const String& methodname)); +bool XmlRpcPerform(TcpSocket& http, const char *group); +bool XmlRpcServerLoop(int port, const char *group); + +#define XMLRPC_METHOD(x) \ +void xmlrpc##x(XmlRpcData& rpc); \ +INITBLOCK { Register(#x, xmlrpc##x); } \ +void xmlrpc##x(XmlRpcData& rpc) + +#define XMLRPC_GMETHOD(x, group) \ +void xmlrpc##x(XmlRpcData& rpc); \ +INITBLOCK { Register(#x, xmlrpc##x, group); } \ +void xmlrpc##x(XmlRpcData& rpc) + +struct XmlRpcError { + int code; + String text; +}; + +void ThrowXmlRpcError(int code, const char *s); +void ThrowXmlRpcError(const char *s); + +class XmlRpcRequest : HttpRequest { + bool shorted; + XmlRpcData data; + String method; + String error; + String faultString; + int faultCode; + bool shouldExecute; + +public: + XmlRpcRequest& Method(const char *name); + + template + XmlRpcRequest& operator<<(const T& x) { data << x; return *this; } + template + void Set(int i, const T& x) { data.Set(i, x); } + + Value Execute(); + Value Retry(); + + template + bool operator>>(T& x) { if(Execute().IsError()) return false; + try { data >> x; } catch(ValueTypeMismatch) { return false; } return true; } + XmlRpcRequest& 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)> \ + XmlRpcRequest& 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(); + + XmlRpcRequest& Url(const char *url); + + XmlRpcRequest(const char *url); + XmlRpcRequest(); +}; + +void LogXmlRpcRequests(bool b = true); + +void SetXmlRpcServerTrace(Stream& s, int level = 1); + +END_UPP_NAMESPACE + +#endif diff --git a/uppsrc/Core/XmlRpc/XmlRpc.upp b/uppsrc/Core/XmlRpc/XmlRpc.upp index e69de29bb..fb59d6bd0 100644 --- a/uppsrc/Core/XmlRpc/XmlRpc.upp +++ b/uppsrc/Core/XmlRpc/XmlRpc.upp @@ -0,0 +1,12 @@ +description "XML-RPC support package (both server and client stuff)\3770,128,128"; + +uses + Web; + +file + XmlRpc.h, + Value.cpp, + Xml.cpp, + Server.cpp, + Client.cpp; + diff --git a/uppsrc/Core/XmlRpc/init b/uppsrc/Core/XmlRpc/init new file mode 100644 index 000000000..061809f74 --- /dev/null +++ b/uppsrc/Core/XmlRpc/init @@ -0,0 +1,4 @@ +#ifndef _Core_XmlRpc_icpp_init_stub +#define _Core_XmlRpc_icpp_init_stub +#include "Web/init" +#endif diff --git a/uppsrc/XmlRpc/Server.cpp b/uppsrc/XmlRpc/Server.cpp index 75e010358..853520e0a 100644 --- a/uppsrc/XmlRpc/Server.cpp +++ b/uppsrc/XmlRpc/Server.cpp @@ -32,24 +32,6 @@ void SetXmlRpcMethodFilter(String (*filter)(const String& methodname)) sXmlRpcMethodFilter = filter; } -struct XmlRpcError { - int code; - String text; -}; - -void ThrowXmlRpcError(int code, const char *s) -{ - XmlRpcError e; - e.code = code; - e.text = s; - throw e; -} - -void ThrowXmlRpcError(const char *s) -{ - ThrowXmlRpcError(-1, s); -} - static Stream *xmlrpc_trace; static int xmlrpc_trace_level; @@ -186,7 +168,7 @@ bool XmlRpcPerform(Socket& http, const char *group) bool XmlRpcServer(int port, const char *group) { Socket rpc; - if(!ServerSocket(rpc, 1234, true, 5)) + if(!ServerSocket(rpc, port, true, 5)) return false; for(;;) { Socket http; diff --git a/uppsrc/XmlRpc/XmlRpc.h b/uppsrc/XmlRpc/XmlRpc.h index 1a82df2c1..6b1b39eca 100644 --- a/uppsrc/XmlRpc/XmlRpc.h +++ b/uppsrc/XmlRpc/XmlRpc.h @@ -1,272 +1,14 @@ -#ifndef _XmlRpc_XmlRpc_h -#define _XmlRpc_XmlRpc_h +#ifndef _XmlRpc_XmlRpc2_h +#define _XmlRpc_XmlRpc2_h #include +#include using namespace Upp; -enum { - XMLRPC_CLIENT_HTTP_ERROR = -1000000, - XMLRPC_CLIENT_XML_ERROR, - XMLRPC_CLIENT_RETTYPE_ERROR, - XMLRPC_SERVER_PARAM_ERROR, - XMLRPC_SERVER_XML_ERROR, - XMLRPC_SERVER_PROCESSING_ERROR, - XMLRPC_UNKNOWN_METHOD_ERROR, -}; - -struct ValueTypeMismatch {}; - -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 -void ValueGet(Array& 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 -void ValueGet(Vector& 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 -void ValueGet(ArrayMap& x, const Value& v) -{ - ValueCheck(IsValueMap(v)); - ValueMap vm = v; - const Index& k = vm.GetKeys(); - ValueArray va = vm.GetValues(); - x.Clear(); - for(int i = 0; i < k.GetCount(); i++) - x.Add(k[i], va[i]); -} - -template -void ValueGet(VectorMap& x, const Value& v) -{ - ValueCheck(IsValueMap(v)); - ValueMap vm = v; - const Index& k = vm.GetKeys(); - ValueArray va = vm.GetValues(); - x.Clear(); - for(int i = 0; i < k.GetCount(); i++) - x.Add(k[i], va[i]); -} - -template -void ValueGet(ArrayMap& x, const Value& v) -{ - ValueCheck(IsValueMap(v)); - ValueMap vm = v; - const Index& 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 -void ValueGet(VectorMap& x, const Value& v) -{ - ValueCheck(IsValueMap(v)); - ValueMap vm = v; - const Index& 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); - -template -Value AsXmlRpcValue(const T& x) -{ - Value vs; - ValuePut(vs, x); - return vs; -} - -template -void ValuePut(Value& v, const Array& x) -{ - ValueArray va; - for(int i = 0; i < x.GetCount(); i++) - va.Add(AsXmlRpcValue(x[i])); - v = va; -} - -template -void ValuePut(Value& v, const Vector& x) -{ - ValueArray va; - for(int i = 0; i < x.GetCount(); i++) - va.Add(AsXmlRpcValue(x[i])); - v = va; -} - -template -void ValuePut(Value& v, const ArrayMap& 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 -void ValuePut(Value& v, const VectorMap& 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 -void ValuePut(Value& v, const ArrayMap& 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 -void ValuePut(Value& v, const VectorMap& 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; -} - -struct ValueMapper { - ValueMap map; - bool get; - - template - ValueMapper& operator()(const char *name, T& x) { - if(get) - ValueGet(x, map[name]); - else { - Value v; - ValuePut(v, x); - map.Add(name, v); - } - return *this; - } -}; - -template -void ValueGetStruct_(T& x, const Value& v) { - ValueCheck(IsNull(v) || IsValueMap(v)); - ValueMapper m; - m.map = v; - m.get = true; - x.Map(m); -} - -template -void ValuePutStruct_(Value& v, const T& x) { - ValueMapper m; - m.get = false; - const_cast(x).Map(m); - v = m.map; -} - -template -struct XmlRpcStruct { - friend void ValueGet(T& x, const Value& v) { ValueGetStruct_(x, v); } - friend void ValuePut(Value& v, const T& x) { ValuePutStruct_(v, x); } -}; - -#define XMLRPC_STRUCT(T) \ -inline void ValueGet(T& x, const Value& v) { ValueGetStruct_(x, v); } \ -inline void ValuePut(Value& v, const T& x) { ValuePutStruct_(v, x); } - -Value ParseXmlRpcValue(XmlParser& p); -Value ParseXmlRpcParam(XmlParser& p); -ValueArray ParseXmlRpcParams(XmlParser& p); - -struct XmlRpcData { - String peeraddr; - ValueArray in; - int ii; - ValueArray out; - - Value Get() { if(ii >= in.GetCount()) throw ValueTypeMismatch(); return in[ii++]; } - - template - XmlRpcData& operator>>(T& x) { ValueGet(x, Get()); return *this; } - - template - XmlRpcData& operator<<(const T& x) { Value v; ValuePut(v, x); out.Add(v); return *this; } - template - void Set(int i, const T& x) { Value v; ValuePut(v, x); out.Set(i, v); } - - void Reset() { in.Clear(); out.Clear(); ii = 0; } - - XmlRpcData() { 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)(XmlRpcData&), const char *group = NULL); -void SetXmlRpcMethodFilter(String (*filter)(const String& methodname)); bool XmlRpcPerform(Socket& http, const char *group); bool XmlRpcServer(int port = 80, const char *group = NULL); -#define XMLRPC_METHOD(x) \ -void xmlrpc##x(XmlRpcData& rpc); \ -INITBLOCK { Register(#x, xmlrpc##x); } \ -void xmlrpc##x(XmlRpcData& rpc) - -#define XMLRPC_GMETHOD(x, group) \ -void xmlrpc##x(XmlRpcData& rpc); \ -INITBLOCK { Register(#x, xmlrpc##x, group); } \ -void xmlrpc##x(XmlRpcData& rpc) - -void ThrowXmlRpcError(int code, const char *s); -void ThrowXmlRpcError(const char *s); - class XmlRpcCall { bool shorted; HttpClient server; diff --git a/uppsrc/XmlRpc/XmlRpc.upp b/uppsrc/XmlRpc/XmlRpc.upp index 3e2413e51..ee330c91e 100644 --- a/uppsrc/XmlRpc/XmlRpc.upp +++ b/uppsrc/XmlRpc/XmlRpc.upp @@ -5,8 +5,6 @@ uses file XmlRpc.h, - Value.cpp, - Xml.cpp, Client.cpp, Server.cpp, xrs readonly separator,