summaryrefslogtreecommitdiff
path: root/indra/llmessage/llsdrpcclient.h
blob: 02891d4f32d6879599e7316cf32ad098a7db6422 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
/** 
 * @file llsdrpcclient.h
 * @author Phoenix
 * @date 2005-11-05
 * @brief Implementation and helpers for structure data RPC clients.
 *
 * $LicenseInfo:firstyear=2005&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * 
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#ifndef LL_LLSDRPCCLIENT_H
#define LL_LLSDRPCCLIENT_H

/** 
 * This file declares classes to encapsulate a basic structured data
 * remote procedure client.
 */

#include "llchainio.h"
#include "llfiltersd2xmlrpc.h"
#include "lliopipe.h"
#include "llurlrequest.h"

/** 
 * @class LLSDRPCClientResponse
 * @brief Abstract base class to represent a response from an SD server.
 *
 * This is used as a base class for callbacks generated from an
 * structured data remote procedure call. The
 * <code>extractResponse</code> method will deal with the llsdrpc method
 * call overhead, and keep track of what to call during the next call
 * into <code>process</code>. If you use this as a base class, you
 * need to implement <code>response</code>, <code>fault</code>, and
 * <code>error</code> to do something useful. When in those methods,
 * you can parse and utilize the mReturnValue member data.
 */
class LLSDRPCResponse : public LLIOPipe
{
public:
	LLSDRPCResponse();
	virtual ~LLSDRPCResponse();

	/** 
	 * @brief This method extracts the response out of the sd passed in
	 *
	 * Any appropriate data found in the sd passed in will be
	 * extracted and managed by this object - not copied or cloned. It
	 * will still be up to the caller to delete the pointer passed in.
	 * @param sd The raw structured data response from the remote server.
	 * @return Returns true if this was able to parse the structured data.
	 */
	bool extractResponse(const LLSD& sd);

protected:
	/** 
	 * @brief Method called when the response is ready.
	 */
	virtual bool response(LLPumpIO* pump) = 0;

	/** 
	 * @brief Method called when a fault is generated by the remote server.
	 */
	virtual bool fault(LLPumpIO* pump) = 0;

	/** 
	 * @brief Method called when there was an error
	 */
	virtual bool error(LLPumpIO* pump) = 0;

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:
	LLSD mReturnValue;
	bool mIsError;
	bool mIsFault;
};

/** 
 * @class LLSDRPCClient
 * @brief Client class for a structured data remote procedure call.
 *
 * This class helps deal with making structured data calls to a remote
 * server. You can visualize the calls as:
 * <code>
 * response = uri.method(parameter)
 * </code>
 * where you pass in everything to <code>call</code> and this class
 * takes care of the rest of the details.
 * In typical usage, you will derive a class from this class and
 * provide an API more useful for the specific application at
 * hand. For example, if you were writing a service to send an instant
 * message, you could create an API for it to send the messsage, and
 * that class would do the work of translating it into the method and
 * parameter, find the destination, and invoke <code>call</call> with
 * a useful implementation of LLSDRPCResponse passed in to handle the
 * response from the network.
 */
class LLSDRPCClient : public LLIOPipe
{
public:
	LLSDRPCClient();
	virtual ~LLSDRPCClient();

	/** 
	 * @brief Enumeration for tracking which queue to process the
	 * response.
	 */
	enum EPassBackQueue
	{
		EPBQ_PROCESS,
		EPBQ_CALLBACK,
	};

	/** 
	 * @brief Call a method on a remote LLSDRPCServer
	 *
	 * @param uri The remote object to call, eg,
	 * http://localhost/usher. If you are using a factory with a fixed
	 * url, the uri passed in will probably be ignored.
	 * @param method The method to call on the remote object
	 * @param parameter The parameter to pass into the remote
	 * object. It is up to the caller to delete the value passed in.
	 * @param response The object which gets the response.
	 * @param queue Specifies to call the response on the process or
	 * callback queue.
	 * @return Returns true if this object will be able to make the RPC call.
	 */
	bool call(
		const std::string& uri,
		const std::string& method,
		const LLSD& parameter,
		LLSDRPCResponse* response,
		EPassBackQueue queue);

	/** 
	 * @brief Call a method on a remote LLSDRPCServer
	 *
	 * @param uri The remote object to call, eg,
	 * http://localhost/usher. If you are using a factory with a fixed
	 * url, the uri passed in will probably be ignored.
	 * @param method The method to call on the remote object
	 * @param parameter The seriailized parameter to pass into the
	 * remote object.
	 * @param response The object which gets the response.
	 * @param queue Specifies to call the response on the process or
	 * callback queue.
	 * @return Returns true if this object will be able to make the RPC call.
	 */
	bool call(
		const std::string& uri,
		const std::string& method,
		const std::string& parameter,
		LLSDRPCResponse* response,
		EPassBackQueue queue);

protected:
	/** 
	 * @brief Enumeration for tracking client state.
	 */
	enum EState
	{
		STATE_NONE,
		STATE_READY,
		STATE_WAITING_FOR_RESPONSE,
		STATE_DONE
	};
	
	/* @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:
	EState mState;
	std::string mURI;
	std::string mRequest;
	EPassBackQueue mQueue;
	LLIOPipe::ptr_t mResponse;
};

/** 
 * @class LLSDRPCClientFactory
 * @brief Basic implementation for making an SD RPC client factory
 *
 * This class eases construction of a basic sd rpc client. Here is an
 * example of it's use:
 * <code>
 *  class LLUsefulService : public LLService { ... }
 *  LLService::registerCreator(
 *    "useful",
 *    LLService::creator_t(new LLSDRPCClientFactory<LLUsefulService>))
 * </code>
 */
template<class Client>
class LLSDRPCClientFactory : public LLChainIOFactory
{
public:
	LLSDRPCClientFactory() {}
	LLSDRPCClientFactory(const std::string& fixed_url) : mURL(fixed_url) {}
	virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
	{
		lldebugs << "LLSDRPCClientFactory::build" << llendl;
		LLURLRequest* http(new LLURLRequest(HTTP_POST));
		if(!http->isValid())
		{
			llwarns << "Creating LLURLRequest failed." << llendl ;
			delete http;
			return false;
		}

		LLIOPipe::ptr_t service(new Client);
		chain.push_back(service);		
		LLIOPipe::ptr_t http_pipe(http);
		http->addHeader(HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_LLSD);
		if(mURL.empty())
		{
			chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http)));
		}
		else
		{
			http->setURL(mURL);
		}
		chain.push_back(http_pipe);
		chain.push_back(service);
		return true;
	}
protected:
	std::string mURL;
};

/** 
 * @class LLXMLSDRPCClientFactory
 * @brief Basic implementation for making an XMLRPC to SD RPC client factory
 *
 * This class eases construction of a basic sd rpc client which uses
 * xmlrpc as a serialization grammar. Here is an example of it's use:
 * <code>
 *  class LLUsefulService : public LLService { ... }
 *  LLService::registerCreator(
 *    "useful",
 *    LLService::creator_t(new LLXMLSDRPCClientFactory<LLUsefulService>))
 * </code>
 */
template<class Client>
class LLXMLSDRPCClientFactory : public LLChainIOFactory
{
public:
	LLXMLSDRPCClientFactory() {}
	LLXMLSDRPCClientFactory(const std::string& fixed_url) : mURL(fixed_url) {}
	virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
	{
		lldebugs << "LLXMLSDRPCClientFactory::build" << llendl;

		LLURLRequest* http(new LLURLRequest(HTTP_POST));
		if(!http->isValid())
		{
			llwarns << "Creating LLURLRequest failed." << llendl ;
			delete http;
			return false ;
		}
		LLIOPipe::ptr_t service(new Client);
		chain.push_back(service);		
		LLIOPipe::ptr_t http_pipe(http);
		http->addHeader(HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
		if(mURL.empty())
		{
			chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http)));
		}
		else
		{
			http->setURL(mURL);
		}
		chain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCRequest(NULL)));
		chain.push_back(http_pipe);
		chain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCResponse2LLSD));
		chain.push_back(service);
		return true;
	}
protected:
	std::string mURL;
};

#endif // LL_LLSDRPCCLIENT_H