1 #include "osrf_application.h"
2 #include "objson/object.h"
4 //osrfApplication* __osrfAppList = NULL;
6 osrfHash* __osrfAppHash = NULL;
9 int osrfAppRegisterApplication( char* appName, char* soFile ) {
10 if(!appName || ! soFile) return -1;
13 if(!__osrfAppHash) __osrfAppHash = osrfNewHash();
15 osrfLogInfo( OSRF_LOG_MARK, "Registering application %s with file %s", appName, soFile );
17 osrfApplication* app = safe_malloc(sizeof(osrfApplication));
18 app->handle = dlopen (soFile, RTLD_NOW);
21 osrfLogWarning( OSRF_LOG_MARK, "Failed to dlopen library file %s: %s", soFile, dlerror() );
22 dlerror(); /* clear the error */
27 app->methods = osrfNewHash();
28 osrfHashSet( __osrfAppHash, app, appName );
30 /* see if we can run the initialize method */
32 *(void **) (&init) = dlsym(app->handle, "osrfAppInitialize");
34 if( (error = dlerror()) != NULL ) {
35 osrfLogWarning( OSRF_LOG_MARK,
36 "! Unable to locate method symbol [osrfAppInitialize] for app %s: %s", appName, error );
42 if( (ret = (*init)()) ) {
43 osrfLogWarning( OSRF_LOG_MARK, "Application %s returned non-zero value from "
44 "'osrfAppInitialize', not registering...", appName );
45 //free(app->name); /* need a method to remove an application from the list */
51 __osrfAppRegisterSysMethods(appName);
53 osrfLogInfo( OSRF_LOG_MARK, "Application %s registered successfully", appName );
55 osrfLogSetAppname(appName);
60 int osrfAppRunChildInit(char* appname) {
61 osrfApplication* app = _osrfAppFindApplication(appname);
66 int (*childInit) (void);
68 *(void**) (&childInit) = dlsym(app->handle, "osrfAppChildInit");
70 if( (error = dlerror()) != NULL ) {
71 osrfLogInfo( OSRF_LOG_MARK, "No child init defined for app %s : %s", appname, error);
75 if( (ret = (*childInit)()) ) {
76 osrfLogError(OSRF_LOG_MARK, "App %s child init failed", appname);
80 osrfLogInfo(OSRF_LOG_MARK, "%s child init succeeded", appname);
85 int osrfAppRegisterMethod( char* appName, char* methodName,
86 char* symbolName, char* notes, int argc, int options ) {
88 if( !appName || ! methodName ) return -1;
90 osrfApplication* app = _osrfAppFindApplication(appName);
92 osrfLogWarning( OSRF_LOG_MARK, "Unable to locate application %s", appName );
96 osrfLogDebug( OSRF_LOG_MARK, "Registering method %s for app %s", methodName, appName );
98 osrfMethod* method = _osrfAppBuildMethod(
99 methodName, symbolName, notes, argc, options );
100 method->options = options;
102 /* plug the method into the list of methods */
103 osrfHashSet( app->methods, method, method->name );
105 if( options & OSRF_METHOD_STREAMING ) { /* build the atomic counterpart */
106 int newops = options | OSRF_METHOD_ATOMIC;
107 osrfMethod* atomicMethod = _osrfAppBuildMethod(
108 methodName, symbolName, notes, argc, newops );
109 osrfHashSet( app->methods, atomicMethod, atomicMethod->name );
117 osrfMethod* _osrfAppBuildMethod( char* methodName,
118 char* symbolName, char* notes, int argc, int options ) {
120 osrfMethod* method = safe_malloc(sizeof(osrfMethod));
122 if(methodName) method->name = strdup(methodName);
123 if(symbolName) method->symbol = strdup(symbolName);
124 if(notes) method->notes = strdup(notes);
127 method->options = options;
129 if(options & OSRF_METHOD_ATOMIC) { /* add ".atomic" to the end of the name */
130 char mb[strlen(method->name) + 8];
131 sprintf(mb, "%s.atomic", method->name);
133 method->name = strdup(mb);
134 method->options |= OSRF_METHOD_STREAMING;
141 int __osrfAppRegisterSysMethods( char* app ) {
143 osrfAppRegisterMethod(
144 app, OSRF_SYSMETHOD_INTROSPECT, NULL,
145 "Return a list of methods whose names have the same initial "
146 "substring as that of the provided method name PARAMS( methodNameSubstring )",
147 1, OSRF_METHOD_SYSTEM | OSRF_METHOD_STREAMING );
149 osrfAppRegisterMethod(
150 app, OSRF_SYSMETHOD_INTROSPECT_ALL, NULL,
151 "Returns a complete list of methods. PARAMS()", 0,
152 OSRF_METHOD_SYSTEM | OSRF_METHOD_STREAMING );
154 osrfAppRegisterMethod(
155 app, OSRF_SYSMETHOD_ECHO, NULL,
156 "Echos all data sent to the server back to the client. PARAMS([a, b, ...])", 0,
157 OSRF_METHOD_SYSTEM | OSRF_METHOD_STREAMING );
162 osrfApplication* _osrfAppFindApplication( char* name ) {
163 if(!name) return NULL;
164 return (osrfApplication*) osrfHashGet(__osrfAppHash, name);
167 osrfMethod* __osrfAppFindMethod( osrfApplication* app, char* methodName ) {
168 if(!app || ! methodName) return NULL;
169 return (osrfMethod*) osrfHashGet( app->methods, methodName );
172 osrfMethod* _osrfAppFindMethod( char* appName, char* methodName ) {
173 if(!appName || ! methodName) return NULL;
174 return __osrfAppFindMethod( _osrfAppFindApplication(appName), methodName );
178 int osrfAppRunMethod( char* appName, char* methodName,
179 osrfAppSession* ses, int reqId, jsonObject* params ) {
181 if( !(appName && methodName && ses) ) return -1;
184 osrfApplication* app;
186 osrfMethodContext context;
188 context.session = ses;
189 context.params = params;
190 context.request = reqId;
191 context.responses = NULL;
193 /* this is the method we're gonna run */
194 int (*meth) (osrfMethodContext*);
196 osrfLogInfo( OSRF_LOG_MARK, "Running method [%s] for app [%s] with request id %d and "
197 "thread trace %s", methodName, appName, reqId, ses->session_id );
199 if( !(app = _osrfAppFindApplication(appName)) )
200 return osrfAppRequestRespondException( ses,
201 reqId, "Application not found: %s", appName );
203 if( !(method = __osrfAppFindMethod( app, methodName )) )
204 return osrfAppRequestRespondException( ses, reqId,
205 "Method [%s] not found for service %s", methodName, appName );
207 context.method = method;
209 #ifdef OSRF_STRICT_PARAMS
210 if( method->argc > 0 ) {
211 if(!params || params->type != JSON_ARRAY || params->size < method->argc )
212 return osrfAppRequestRespondException( ses, reqId,
213 "Not enough params for method %s / service %s", methodName, appName );
219 if( method->options & OSRF_METHOD_SYSTEM ) {
220 retcode = __osrfAppRunSystemMethod(&context);
224 /* open and now run the method */
225 *(void **) (&meth) = dlsym(app->handle, method->symbol);
227 if( (error = dlerror()) != NULL ) {
228 return osrfAppRequestRespondException( ses, reqId,
229 "Unable to execute method [%s] for service %s", methodName, appName );
232 retcode = (*meth) (&context);
236 return osrfAppRequestRespondException(
237 ses, reqId, "An unknown server error occurred" );
239 return __osrfAppPostProcess( &context, retcode );
244 int osrfAppRespond( osrfMethodContext* ctx, jsonObject* data ) {
245 return _osrfAppRespond( ctx, data, 0 );
248 int osrfAppRespondComplete( osrfMethodContext* context, jsonObject* data ) {
249 return _osrfAppRespond( context, data, 1 );
252 int _osrfAppRespond( osrfMethodContext* ctx, jsonObject* data, int complete ) {
253 if(!(ctx && ctx->method)) return -1;
255 if( ctx->method->options & OSRF_METHOD_ATOMIC ) {
256 osrfLogDebug( OSRF_LOG_MARK,
257 "Adding responses to stash for atomic method %s", ctx->method );
259 if( ctx->responses == NULL )
260 ctx->responses = jsonParseString("[]");
261 jsonObjectPush( ctx->responses, jsonObjectClone(data) );
265 if( !(ctx->method->options & OSRF_METHOD_ATOMIC) &&
266 !(ctx->method->options & OSRF_METHOD_CACHABLE) ) {
269 osrfAppRequestRespondComplete( ctx->session, ctx->request, data );
271 osrfAppRequestRespond( ctx->session, ctx->request, data );
281 int __osrfAppPostProcess( osrfMethodContext* ctx, int retcode ) {
282 if(!(ctx && ctx->method)) return -1;
284 osrfLogDebug( OSRF_LOG_MARK, "Postprocessing method %s with retcode %d",
285 ctx->method->name, retcode );
287 if(ctx->responses) { /* we have cached responses to return (no responses have been sent) */
289 osrfAppRequestRespondComplete( ctx->session, ctx->request, ctx->responses );
290 jsonObjectFree(ctx->responses);
291 ctx->responses = NULL;
296 osrfAppSessionStatus( ctx->session, OSRF_STATUS_COMPLETE,
297 "osrfConnectStatus", ctx->request, "Request Complete" );
304 int osrfAppRequestRespondException( osrfAppSession* ses, int request, char* msg, ... ) {
307 VA_LIST_TO_STRING(msg);
308 osrfLogWarning( OSRF_LOG_MARK, "Returning method exception with message: %s", VA_BUF );
309 osrfAppSessionStatus( ses, OSRF_STATUS_NOTFOUND, "osrfMethodException", request, VA_BUF );
314 static void __osrfAppSetIntrospectMethod( osrfMethodContext* ctx, osrfMethod* method, jsonObject* resp ) {
315 if(!(ctx && resp)) return;
317 jsonObjectSetKey(resp, "api_name", jsonNewObject(method->name));
318 jsonObjectSetKey(resp, "method", jsonNewObject(method->symbol));
319 jsonObjectSetKey(resp, "service", jsonNewObject(ctx->session->remote_service));
320 jsonObjectSetKey(resp, "notes", jsonNewObject(method->notes));
321 jsonObjectSetKey(resp, "argc", jsonNewNumberObject(method->argc));
323 jsonObjectSetKey(resp, "sysmethod",
324 jsonNewNumberObject( (method->options & OSRF_METHOD_SYSTEM) ? 1 : 0 ));
325 jsonObjectSetKey(resp, "atomic",
326 jsonNewNumberObject( (method->options & OSRF_METHOD_ATOMIC) ? 1 : 0 ));
327 jsonObjectSetKey(resp, "cachable",
328 jsonNewNumberObject( (method->options & OSRF_METHOD_CACHABLE) ? 1 : 0 ));
330 jsonObjectSetClass(resp, "method");
335 int __osrfAppRunSystemMethod(osrfMethodContext* ctx) {
336 OSRF_METHOD_VERIFY_CONTEXT(ctx);
338 if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ALL ) ||
339 !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ALL_ATOMIC )) {
341 return osrfAppIntrospectAll(ctx);
345 if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT ) ||
346 !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ATOMIC )) {
348 return osrfAppIntrospect(ctx);
351 osrfAppRequestRespondException( ctx->session,
352 ctx->request, "System method implementation not found");
358 int osrfAppIntrospect( osrfMethodContext* ctx ) {
360 jsonObject* resp = NULL;
361 char* methodSubstring = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
362 osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service );
365 if(!methodSubstring) return 1; /* respond with no methods */
369 osrfHashIterator* itr = osrfNewHashIterator(app->methods);
372 while( (method = osrfHashIteratorNext(itr)) ) {
373 if( (len = strlen(methodSubstring)) <= strlen(method->name) ) {
374 if( !strncmp( method->name, methodSubstring, len) ) {
375 resp = jsonNewObject(NULL);
376 __osrfAppSetIntrospectMethod( ctx, method, resp );
377 osrfAppRespond(ctx, resp);
378 jsonObjectFree(resp);
382 osrfHashIteratorFree(itr);
391 int osrfAppIntrospectAll( osrfMethodContext* ctx ) {
392 jsonObject* resp = NULL;
393 osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service );
396 osrfHashIterator* itr = osrfNewHashIterator(app->methods);
398 while( (method = osrfHashIteratorNext(itr)) ) {
399 resp = jsonNewObject(NULL);
400 __osrfAppSetIntrospectMethod( ctx, method, resp );
401 osrfAppRespond(ctx, resp);
402 jsonObjectFree(resp);
404 osrfHashIteratorFree(itr);