summaryrefslogtreecommitdiff
path: root/indra/llmessage/llsdrpcserver.h
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
committerJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
commit420b91db29485df39fd6e724e782c449158811cb (patch)
treeb471a94563af914d3ed3edd3e856d21cb1b69945 /indra/llmessage/llsdrpcserver.h
Print done when done.
Diffstat (limited to 'indra/llmessage/llsdrpcserver.h')
-rw-r--r--indra/llmessage/llsdrpcserver.h342
1 files changed, 342 insertions, 0 deletions
diff --git a/indra/llmessage/llsdrpcserver.h b/indra/llmessage/llsdrpcserver.h
new file mode 100644
index 0000000000..abb291d007
--- /dev/null
+++ b/indra/llmessage/llsdrpcserver.h
@@ -0,0 +1,342 @@
+/**
+ * @file llsdrpcserver.h
+ * @author Phoenix
+ * @date 2005-10-11
+ * @brief Declaration of the structured data remote procedure call server.
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLSDRPCSERVER_H
+#define LL_LLSDRPCSERVER_H
+
+/**
+ * I've set this up to be pretty easy to use when you want to make a
+ * structured data rpc server which responds to methods by
+ * name. Derive a class from the LLSDRPCServer, and during
+ * construction (or initialization if you have the luxury) map method
+ * names to pointers to member functions. This will look a lot like:
+ *
+ * <code>
+ * class LLMessageAgents : public LLSDRPCServer {<br>
+ * public:<br>
+ * typedef LLSDRPCServer<LLUsher> mem_fn_t;<br>
+ * LLMessageAgents() {<br>
+ * mMethods["message"] = new mem_fn_t(this, &LLMessageAgents::rpc_IM);<br>
+ * mMethods["alert"] = new mem_fn_t(this, &LLMessageAgents::rpc_Alrt);<br>
+ * }<br>
+ * protected:<br>
+ * rpc_IM(const LLSD& params,
+ * const LLChannelDescriptors& channels,
+ * LLBufferArray* data)
+ * {...}<br>
+ * rpc_Alert(const LLSD& params,
+ * const LLChannelDescriptors& channels,
+ * LLBufferArray* data)
+ * {...}<br>
+ * };<br>
+ * </code>
+ *
+ * The params are an array where each element in the array is a single
+ * parameter in the call.
+ *
+ * It is up to you to pack a valid serialized llsd response into the
+ * data object passed into the method, but you can use the helper
+ * methods below to help.
+ */
+
+#include <map>
+#include "lliopipe.h"
+#include "lliohttpserver.h"
+#include "llfiltersd2xmlrpc.h"
+
+class LLSD;
+
+/**
+ * @brief Enumeration for specifying server method call status. This
+ * enumeration controls how the server class will manage the pump
+ * process/callback mechanism.
+ */
+enum ESDRPCSStatus
+{
+ // The call went ok, but the response is not yet ready. The
+ // method will arrange for the clearLock() call to be made at
+ // a later date, after which, once the chain is being pumped
+ // again, deferredResponse() will be called to gather the result
+ ESDRPCS_DEFERRED,
+
+ // The LLSDRPCServer would like to handle the method on the
+ // callback queue of the pump.
+ ESDRPCS_CALLBACK,
+
+ // The method call finished and generated output.
+ ESDRPCS_DONE,
+
+ // Method failed for some unspecified reason - you should avoid
+ // this. A generic fault will be sent to the output.
+ ESDRPCS_ERROR,
+
+ ESDRPCS_COUNT,
+};
+
+/**
+ * @class LLSDRPCMethodCallBase
+ * @brief Base class for calling a member function in an sd rpcserver
+ * implementation.
+ */
+class LLSDRPCMethodCallBase
+{
+public:
+ LLSDRPCMethodCallBase() {}
+ virtual ~LLSDRPCMethodCallBase() {}
+
+ virtual ESDRPCSStatus call(
+ const LLSD& params,
+ const LLChannelDescriptors& channels,
+ LLBufferArray* response) = 0;
+protected:
+};
+
+/**
+ * @class LLSDRPCMethodCall
+ * @brief Class which implements member function calls.
+ */
+template<class Server>
+class LLSDRPCMethodCall : public LLSDRPCMethodCallBase
+{
+public:
+ typedef ESDRPCSStatus (Server::*mem_fn)(
+ const LLSD& params,
+ const LLChannelDescriptors& channels,
+ LLBufferArray* data);
+ LLSDRPCMethodCall(Server* s, mem_fn fn) :
+ mServer(s),
+ mMemFn(fn)
+ {
+ }
+ virtual ~LLSDRPCMethodCall() {}
+ virtual ESDRPCSStatus call(
+ const LLSD& params,
+ const LLChannelDescriptors& channels,
+ LLBufferArray* data)
+ {
+ return (*mServer.*mMemFn)(params, channels, data);
+ }
+
+protected:
+ Server* mServer;
+ mem_fn mMemFn;
+ //bool (Server::*mMemFn)(const LLSD& params, LLBufferArray& data);
+};
+
+
+/**
+ * @class LLSDRPCServer
+ * @brief Basic implementation of a structure data rpc server
+ *
+ * The rpc server is also designed to appropriately straddle the pump
+ * <code>process()</code> and <code>callback()</code> to specify which
+ * thread you want to work on when handling a method call. The
+ * <code>mMethods</code> methods are called from
+ * <code>process()</code>, while the <code>mCallbackMethods</code> are
+ * called when a pump is in a <code>callback()</code> cycle.
+ */
+class LLSDRPCServer : public LLIOPipe
+{
+public:
+ LLSDRPCServer();
+ virtual ~LLSDRPCServer();
+
+ /**
+ * enumeration for generic fault codes
+ */
+ enum
+ {
+ FAULT_BAD_REQUEST = 2000,
+ FAULT_NO_RESPONSE = 2001,
+ };
+
+ /**
+ * @brief Call this method to return an rpc fault.
+ *
+ * @param channel The channel for output on the data buffer
+ * @param data buffer which will recieve the final output
+ * @param code The fault code
+ * @param msg The fault message
+ */
+ static void buildFault(
+ const LLChannelDescriptors& channels,
+ LLBufferArray* data,
+ S32 code,
+ const std::string& msg);
+
+ /**
+ * @brief Call this method to build an rpc response.
+ *
+ * @param channel The channel for output on the data buffer
+ * @param data buffer which will recieve the final output
+ * @param response The return value from the method call
+ */
+ static void buildResponse(
+ const LLChannelDescriptors& channels,
+ LLBufferArray* data,
+ const LLSD& response);
+
+protected:
+ /* @name LLIOPipe virtual implementations
+ */
+ //@{
+ /**
+ * @brief Process the data in buffer
+ */
+ virtual EStatus process_impl(
+ const LLChannelDescriptors& channels,
+ buffer_ptr_t& buffer,
+ bool& eos,
+ LLSD& context,
+ LLPumpIO* pump);
+ //@}
+
+protected:
+
+ /**
+ * @brief Enumeration to track the state of the rpc server instance
+ */
+ enum EState
+ {
+ STATE_NONE,
+ STATE_CALLBACK,
+ STATE_DEFERRED,
+ STATE_DONE
+ };
+
+ /**
+ * @brief This method is called when an http post comes in.
+ *
+ * The default behavior is to look at the method name, look up the
+ * method in the method table, and call it. If the method is not
+ * found, this function will build a fault response. You can
+ * implement your own version of this function if you want to hard
+ * wire some behavior or optimize things a bit.
+ * @param method The method name being called
+ * @param params The parameters
+ * @param channel The channel for output on the data buffer
+ * @param data The http data
+ * @return Returns the status of the method call, done/deferred/etc
+ */
+ virtual ESDRPCSStatus callMethod(
+ const std::string& method,
+ const LLSD& params,
+ const LLChannelDescriptors& channels,
+ LLBufferArray* data);
+
+ /**
+ * @brief This method is called when a pump callback is processed.
+ *
+ * The default behavior is to look at the method name, look up the
+ * method in the callback method table, and call it. If the method
+ * is not found, this function will build a fault response. You
+ * can implement your own version of this function if you want to
+ * hard wire some behavior or optimize things a bit.
+ * @param method The method name being called
+ * @param params The parameters
+ * @param channel The channel for output on the data buffer
+ * @param data The http data
+ * @return Returns the status of the method call, done/deferred/etc
+ */
+ virtual ESDRPCSStatus callbackMethod(
+ const std::string& method,
+ const LLSD& params,
+ const LLChannelDescriptors& channels,
+ LLBufferArray* data);
+
+ /**
+ * @brief Called after a deferred service is unlocked
+ *
+ * If a method returns ESDRPCS_DEFERRED, then the service chain
+ * will be locked and not processed until some other system calls
+ * clearLock() on the service instance again. At that point,
+ * once the pump starts processing the chain again, this method
+ * will be called so the service can output the final result
+ * into the buffers.
+ */
+ virtual ESDRPCSStatus deferredResponse(
+ const LLChannelDescriptors& channels,
+ LLBufferArray* data);
+
+ // donovan put this public here 7/27/06
+public:
+ /**
+ * @brief unlock a service that as ESDRPCS_DEFERRED
+ */
+ void clearLock();
+
+protected:
+ EState mState;
+ LLSD mRequest;
+ LLPumpIO* mPump;
+ S32 mLock;
+ typedef std::map<std::string, LLSDRPCMethodCallBase*> method_map_t;
+ method_map_t mMethods;
+ method_map_t mCallbackMethods;
+};
+
+/**
+ * @name Helper Templates for making LLHTTPNodes
+ *
+ * These templates help in creating nodes for handing a service from
+ * either SDRPC or XMLRPC, given a single implementation of LLSDRPCServer.
+ *
+ * To use it:
+ * \code
+ * class LLUsefulServer : public LLSDRPCServer { ... }
+ *
+ * LLHTTPNode& root = LLCreateHTTPWireServer(...);
+ * root.addNode("llsdrpc/useful", new LLSDRPCNode<LLUsefulServer>);
+ * root.addNode("xmlrpc/useful", new LLXMLRPCNode<LLUsefulServer>);
+ * \endcode
+ */
+//@{
+
+template<class Server>
+class LLSDRPCServerFactory : public LLChainIOFactory
+{
+public:
+ virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
+ {
+ lldebugs << "LLXMLSDRPCServerFactory::build" << llendl;
+ chain.push_back(LLIOPipe::ptr_t(new Server));
+ return true;
+ }
+};
+
+template<class Server>
+class LLSDRPCNode : public LLHTTPNodeForFactory<
+ LLSDRPCServerFactory<Server> >
+{
+};
+
+template<class Server>
+class LLXMLRPCServerFactory : public LLChainIOFactory
+{
+public:
+ virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
+ {
+ lldebugs << "LLXMLSDRPCServerFactory::build" << llendl;
+ chain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCRequest2LLSD));
+ chain.push_back(LLIOPipe::ptr_t(new Server));
+ chain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCResponse));
+ return true;
+ }
+};
+
+template<class Server>
+class LLXMLRPCNode : public LLHTTPNodeForFactory<
+ LLXMLRPCServerFactory<Server> >
+{
+};
+
+//@}
+
+#endif // LL_LLSDRPCSERVER_H