Implement the chunking of OSRF messages. I.e. bundle multiple
[OpenSRF.git] / include / opensrf / osrf_application.h
1 #ifndef OSRF_APPLICATION_H
2 #define OSRF_APPLICATION_H
3
4 /**
5         @file osrf_application.h
6         @brief Routines to load and manage shared object libraries.
7
8         Every method of a service is implemented by a C function.  In a few cases those
9         functions are generic to all services.  In other cases they are loaded and executed from
10         a shared object library that is specific to the application offering the service,  A
11         registry maps method names to function names so that we can call the right function.
12
13         Each such function has a similar signature:
14
15                 int method_name( osrfMethodContext* ctx );
16
17         The return value is negative in case of an error.  A return code of zero implies that
18         the method has already sent the client a STATUS message to say that it is finished.
19         A return code greater than zero implies that the method has not sent such a STATUS
20         message, so we need to do so after the method returns.
21
22         Any arguments passed to the method are bundled together in a jsonObject inside the
23         osrfMethodContext.
24
25         An application's shared object may also implement any or all of three standard functions:
26
27         - int osrfAppInitialize( void ) Called when an application is registered
28         - int osrfAppChildInit( void ) Called when a server drone is spawned
29         - void osrfAppChildExit( void ) Called when a server drone terminates
30
31         osrfAppInitialize() and osrfAppChild return zero if successful, and non-zero if not.
32 */
33
34 #include <opensrf/utils.h>
35 #include <opensrf/log.h>
36 #include <opensrf/osrf_app_session.h>
37 #include <opensrf/osrf_hash.h>
38
39 #include <opensrf/osrf_json.h>
40 #include <stdio.h>
41 #include <dlfcn.h>
42
43 #ifdef __cplusplus
44 extern "C" {
45 #endif
46
47 /**
48         All OpenSRF methods take the signature
49         int methodName( osrfMethodContext* );
50         If a negative number is returned, it means an unknown error occured and an exception
51         will be returned to the client automatically.
52         If a positive number is returned, it means that libopensrf should send a 'Request Complete'
53         message following any messages sent by the method.
54         If 0 is returned, it tells libopensrf that the method completed successfully and
55         there is no need to send any further data to the client.
56 */
57
58 /** This macro verifies that methods receive the correct parameters */
59 #define _OSRF_METHOD_VERIFY_CONTEXT(d) \
60         if(!d) return -1; \
61         if(!d->session) { \
62                  osrfLogError( OSRF_LOG_MARK, "Session is NULL in app request" ); \
63                  return -1; \
64         } \
65         if(!d->method) { \
66                 osrfLogError( OSRF_LOG_MARK, "Method is NULL in app request" ); \
67                 return -1; \
68         } \
69         if(d->method->argc) { \
70                 if(!d->params) { \
71                         osrfLogError( OSRF_LOG_MARK, "Params is NULL in app request %s", d->method->name ); \
72                         return -1; \
73                 } \
74                 if( d->params->type != JSON_ARRAY ) { \
75                         osrfLogError( OSRF_LOG_MARK, "'params' is not a JSON array for method %s", \
76                                 d->method->name); \
77                         return -1; } \
78         } \
79         if( !d->method->name ) { \
80                 osrfLogError( OSRF_LOG_MARK, "Method name is NULL"); return -1; \
81         }
82
83 #ifdef OSRF_LOG_PARAMS
84 #define OSRF_METHOD_VERIFY_CONTEXT(d) \
85         _OSRF_METHOD_VERIFY_CONTEXT(d); \
86         char* __j = jsonObjectToJSON(d->params); \
87         if(__j) { \
88                 osrfLogInfo( OSRF_LOG_MARK, "CALL:\t%s %s - %s", d->session->remote_service, \
89                                 d->method->name, __j);\
90                 free(__j); \
91         }
92 #else
93 #define OSRF_METHOD_VERIFY_CONTEXT(d) _OSRF_METHOD_VERIFY_CONTEXT(d);
94 #endif
95
96 /**
97         @name Method options
98         @brief Macros that get OR'd together to form method options.
99 */
100 /*@{*/
101 /**
102         @brief  Marks a method as a system method.
103
104         System methods are implemented by generic functions, called via static linkage.  They
105         are not loaded or executed from shared objects.
106 */
107 #define OSRF_METHOD_SYSTEM          1
108 /**
109         @brief Notes that the method may return more than one result.
110
111         For a @em streaming method, we register both an atomic method and a non-atomic method.
112         See also OSRF_METHOD_ATOMIC.
113 */
114 #define OSRF_METHOD_STREAMING       2
115 /**
116         @brief  Combines all responses into a single RESULT message.
117
118         For a @em non-atomic method, the server returns each response to the client in a
119         separate RESULT message.  It sends a STATUS message at the end to signify the end of the
120         message stream.
121
122         For an @em atomic method, the server buffers all responses until the method returns,
123         and then sends them all at once in a single RESULT message (followed by a STATUS message).
124         Each individual response is encoded as an entry in a JSON array.  This buffering is
125         transparent to the function that implements the method.
126
127         Atomic methods incur less networking overhead than non-atomic methods, at the risk of
128         creating excessively large RESULT messages.  The HTTP gateway requires the atomic versions
129         of streaming methods because of the stateless nature of the HTTP protocol.
130
131         If OSRF_METHOD_STREAMING is set for a method, the application generates both an atomic
132         and a non-atomic method, whose names are identical except that the atomic one carries a
133         suffix of ".atomic".
134 */
135 #define OSRF_METHOD_ATOMIC          4
136 /**
137         @brief  Notes that a previous result to the same call may be available in memcache.
138
139         Before calling the registered function, a cachable method checks memcache for a previously
140         determined result for the same call.  If no such result is available, it calls the
141         registered function and caches the new result before returning.
142
143         This caching is not currently implemented for C methods.
144 */
145 #define OSRF_METHOD_CACHABLE        8
146 /*@}*/
147
148 typedef struct {
149         char* name;                 /**< Method name. */
150         char* symbol;               /**< Symbol name (function name) within the shared object. */
151         char* notes;                /**< Public method documentation. */
152         int argc;                   /**< The minimum number of arguments for the method. */
153         //char* paramNotes;         /**< Description of the params expected for this method. */
154         int options;                /**< Bit switches setting various options for this method. */
155         void* userData;             /**< Opaque pointer to application-specific data. */
156
157         /*
158         int sysmethod;
159         int streaming;
160         int atomic;
161         int cachable;
162         */
163 } osrfMethod;
164
165 typedef struct {
166         osrfAppSession* session;    /**< Pointer to the current application session. */
167         osrfMethod* method;         /**< Pointer to the requested method. */
168         jsonObject* params;         /**< Parameters to the method. */
169         int request;                /**< Request id. */
170         jsonObject* responses;      /**< Array of cached responses. */
171 } osrfMethodContext;
172
173 int osrfAppRegisterApplication( const char* appName, const char* soFile );
174
175 int osrfAppRegisterMethod( const char* appName, const char* methodName,
176                 const char* symbolName, const char* notes, int argc, int options );
177
178 int osrfAppRegisterExtendedMethod( const char* appName, const char* methodName,
179                 const char* symbolName, const char* notes, int argc, int options, void* );
180
181 osrfMethod* _osrfAppFindMethod( const char* appName, const char* methodName );
182
183 int osrfAppRunMethod( const char* appName, const char* methodName,
184                 osrfAppSession* ses, int reqId, jsonObject* params );
185
186 int osrfAppRequestRespondException( osrfAppSession* ses, int request, const char* msg, ... );
187
188 int osrfAppRespond( osrfMethodContext* context, const jsonObject* data );
189
190 int osrfAppRespondComplete( osrfMethodContext* context, const jsonObject* data );
191
192 int osrfAppRunChildInit(const char* appname);
193
194 void osrfAppRunExitCode( void );
195
196 int osrfMethodVerifyContext( osrfMethodContext* ctx );
197
198 #ifdef __cplusplus
199 }
200 #endif
201
202 #endif