#include "osrf_log.h"
#include "objson/object.h"
-osrfApplication* __osrfAppList = NULL;
+//osrfApplication* __osrfAppList = NULL;
+
+osrfHash* __osrfAppHash = NULL;
int osrfAppRegisterApplication( char* appName, char* soFile ) {
if(!appName || ! soFile) return -1;
char* error;
+ if(!__osrfAppHash) __osrfAppHash = osrfNewHash();
+
info_handler("Registering application %s with file %s", appName, soFile );
osrfApplication* app = safe_malloc(sizeof(osrfApplication));
return -1;
}
- app->name = strdup(appName);
-
- /* this has to be done before initting the application */
- app->next = __osrfAppList;
- __osrfAppList = app;
-
+ app->methods = osrfNewHash();
+ osrfHashSet( __osrfAppHash, app, appName );
/* see if we can run the initialize method */
int (*init) (void);
info_handler("Application %s registered successfully", appName );
+ osrfLogInit(appName);
return 0;
}
-int osrfAppRegisterMethod( char* appName,
- char* methodName, char* symbolName, char* notes, char* params, int argc ) {
- if( !appName || ! methodName || ! symbolName ) return -1;
+int osrfAppRegisterMethod( char* appName, char* methodName,
+ char* symbolName, char* notes, char* params, int argc, int streaming ) {
+
+ return _osrfAppRegisterMethod(appName, methodName,
+ symbolName, notes, params, argc, streaming, 0 );
+}
+
+int _osrfAppRegisterMethod( char* appName, char* methodName,
+ char* symbolName, char* notes, char* params, int argc, int streaming, int system ) {
+
+ if( !appName || ! methodName ) return -1;
osrfApplication* app = _osrfAppFindApplication(appName);
if(!app) return warning_handler("Unable to locate application %s", appName );
debug_handler("Registering method %s for app %s", methodName, appName );
osrfMethod* method = _osrfAppBuildMethod(
- methodName, symbolName, notes, params, argc, 0 );
+ methodName, symbolName, notes, params, argc, system, 0 );
+ method->streaming = streaming;
/* plug the method into the list of methods */
- method->next = app->methods;
- app->methods = method;
+ osrfHashSet( app->methods, method, method->name );
+
+ if( streaming ) { /* build the atomic counterpart */
+ osrfMethod* atomicMethod = _osrfAppBuildMethod(
+ methodName, symbolName, notes, params, argc, system, 1 );
+ osrfHashSet( app->methods, atomicMethod, atomicMethod->name );
+ }
+
return 0;
}
+
osrfMethod* _osrfAppBuildMethod( char* methodName,
- char* symbolName, char* notes, char* params, int argc, int sysmethod ) {
+ char* symbolName, char* notes, char* params, int argc, int sysmethod, int atomic ) {
osrfMethod* method = safe_malloc(sizeof(osrfMethod));
+
if(methodName) method->name = strdup(methodName);
if(symbolName) method->symbol = strdup(symbolName);
if(notes) method->notes = strdup(notes);
if(params) method->paramNotes = strdup(params);
+
method->argc = argc;
method->sysmethod = sysmethod;
- return method;
-}
+ method->atomic = atomic;
+ method->cachable = 0;
+
+ if(atomic) { /* add ".atomic" to the end of the name */
+ char mb[strlen(method->name) + 8];
+ sprintf(mb, "%s.atomic", method->name);
+ free(method->name);
+ method->name = strdup(mb);
+ method->streaming = 1;
+ }
+ debug_handler("Built method %s", method->name );
-int _osrfAppRegisterSystemMethod( char* appName, char* methodName,
- char* notes, char* params, int argc ) {
- if(!(appName && methodName)) return -1;
- osrfApplication* app = _osrfAppFindApplication(appName);
- if(!app) return warning_handler("Unable to locate application %s", appName );
- debug_handler("Registering system method %s for app %s", methodName, appName );
- osrfMethod* method = _osrfAppBuildMethod(
- methodName, NULL, notes, params, argc, 1 );
-
- /* plug the method into the list of methods */
- method->next = app->methods;
- app->methods = method;
- return 0;
-
+ return method;
}
+
int __osrfAppRegisterSysMethods( char* app ) {
- _osrfAppRegisterSystemMethod(
- app, OSRF_SYSMETHOD_INTROSPECT,
+ _osrfAppRegisterMethod(
+ app, OSRF_SYSMETHOD_INTROSPECT, NULL,
"Return a list of methods whose names have the same initial "
"substring as that of the provided method name",
- "( methodNameSubstring )", 1 );
+ "( methodNameSubstring )", 1, 1 , 1);
- _osrfAppRegisterSystemMethod(
- app, OSRF_SYSMETHOD_INTROSPECT_ALL,
- "Returns a complete list of methods", "()", 0 );
+ _osrfAppRegisterMethod(
+ app, OSRF_SYSMETHOD_INTROSPECT_ALL, NULL,
+ "Returns a complete list of methods", "()", 0, 1, 1 );
+
+ _osrfAppRegisterMethod(
+ app, OSRF_SYSMETHOD_ECHO, NULL,
+ "Echos all data sent to the server back to the client",
+ "([a, b, ...])", 0, 1, 1);
return 0;
}
osrfApplication* _osrfAppFindApplication( char* name ) {
if(!name) return NULL;
- osrfApplication* app = __osrfAppList;
- while(app) {
- if(!strcmp(app->name, name))
- return app;
- app = app->next;
- }
- return NULL;
+ return (osrfApplication*) osrfHashGet(__osrfAppHash, name);
}
osrfMethod* __osrfAppFindMethod( osrfApplication* app, char* methodName ) {
if(!app || ! methodName) return NULL;
- osrfMethod* method = app->methods;
- while(method) {
- if(!strcmp(method->name, methodName))
- return method;
- method = method->next;
- }
- return NULL;
+ return (osrfMethod*) osrfHashGet( app->methods, methodName );
}
osrfMethod* _osrfAppFindMethod( char* appName, char* methodName ) {
context.session = ses;
context.params = params;
context.request = reqId;
+ context.responses = NULL;
/* this is the method we're gonna run */
int (*meth) (osrfMethodContext*);
}
#endif
+ int retcode = 0;
+
if( method->sysmethod ) {
+ retcode = __osrfAppRunSystemMethod(&context);
- int sysres = __osrfAppRunSystemMethod(&context);
- if(sysres == 0) return 0;
+ } else {
- if(sysres > 0)
- return osrfAppSessionStatus( ses, OSRF_STATUS_COMPLETE,
- "osrfConnectStatus", reqId, "Request Complete" );
+ /* open and now run the method */
+ *(void **) (&meth) = dlsym(app->handle, method->symbol);
- if(sysres < 0)
- return osrfAppRequestRespondException(
- ses, reqId, "An unknown server error occurred" );
+ if( (error = dlerror()) != NULL ) {
+ return osrfAppRequestRespondException( ses, reqId,
+ "Unable to execute method [%s] for service %s", methodName, appName );
+ }
+
+ retcode = (*meth) (&context);
}
+ if(retcode < 0)
+ return osrfAppRequestRespondException(
+ ses, reqId, "An unknown server error occurred" );
- /* open the method */
- *(void **) (&meth) = dlsym(app->handle, method->symbol);
+ return __osrfAppPostProcess( &context, retcode );
- if( (error = dlerror()) != NULL ) {
- return osrfAppRequestRespondException( ses, reqId,
- "Unable to execute method [%s] for service %s", methodName, appName );
+}
+
+
+int osrfAppRespond( osrfMethodContext* ctx, jsonObject* data ) {
+ return _osrfAppRespond( ctx, data, 0 );
+}
+
+int osrfAppRespondComplete( osrfMethodContext* context, jsonObject* data ) {
+ return _osrfAppRespond( context, data, 1 );
+}
+
+int _osrfAppRespond( osrfMethodContext* ctx, jsonObject* data, int complete ) {
+ if(!(ctx && ctx->method)) return -1;
+
+ if( ctx->method->atomic ) {
+ osrfLog( OSRF_DEBUG,
+ "Adding responses to stash for atomic method %s", ctx->method );
+
+ if( ctx->responses == NULL )
+ ctx->responses = jsonParseString("[]");
+ jsonObjectPush( ctx->responses, jsonObjectClone(data) );
}
- /* run the method */
- int ret;
- if( (ret = (*meth) (&context)) < 0 )
- return osrfAppRequestRespondException(
- ses, reqId, "An unknown server error occurred" );
- if( ret > 0 )
- osrfAppSessionStatus( ses, OSRF_STATUS_COMPLETE,
- "osrfConnectStatus", reqId, "Request Complete" );
+ if( !ctx->method->atomic && ! ctx->method->cachable ) {
+ if(complete)
+ osrfAppRequestRespondComplete( ctx->session, ctx->request, data );
+ else
+ osrfAppRequestRespond( ctx->session, ctx->request, data );
+ return 0;
+ }
return 0;
}
+
+
+
+int __osrfAppPostProcess( osrfMethodContext* ctx, int retcode ) {
+ if(!(ctx && ctx->method)) return -1;
+
+ osrfLog( OSRF_DEBUG, "Postprocessing method %s with retcode %d",
+ ctx->method->name, retcode );
+
+ if(ctx->responses) { /* we have cached responses to return */
+
+ osrfAppRequestRespondComplete( ctx->session, ctx->request, ctx->responses );
+ jsonObjectFree(ctx->responses);
+ ctx->responses = NULL;
+
+ } else {
+
+ if( retcode > 0 )
+ osrfAppSessionStatus( ctx->session, OSRF_STATUS_COMPLETE,
+ "osrfConnectStatus", ctx->request, "Request Complete" );
+ }
+
+ return 0;
+
+}
+
int osrfAppRequestRespondException( osrfAppSession* ses, int request, char* msg, ... ) {
if(!ses) return -1;
if(!msg) msg = "";
static void __osrfAppSetIntrospectMethod( osrfMethodContext* ctx, osrfMethod* method, jsonObject* resp ) {
if(!(ctx && resp)) return;
- jsonObjectSetKey(resp, "api_name", jsonNewObject(method->name));
- jsonObjectSetKey(resp, "method", jsonNewObject(method->symbol));
- jsonObjectSetKey(resp, "service", jsonNewObject(ctx->session->remote_service));
- jsonObjectSetKey(resp, "notes", jsonNewObject(method->notes));
- jsonObjectSetKey(resp, "argc", jsonNewNumberObject(method->argc));
- jsonObjectSetKey(resp, "params", jsonNewObject(method->paramNotes) );
+ jsonObjectSetKey(resp, "api_name", jsonNewObject(method->name));
+ jsonObjectSetKey(resp, "method", jsonNewObject(method->symbol));
+ jsonObjectSetKey(resp, "service", jsonNewObject(ctx->session->remote_service));
+ jsonObjectSetKey(resp, "notes", jsonNewObject(method->notes));
+ jsonObjectSetKey(resp, "argc", jsonNewNumberObject(method->argc));
+ jsonObjectSetKey(resp, "params", jsonNewObject(method->paramNotes) );
jsonObjectSetKey(resp, "sysmethod", jsonNewNumberObject(method->sysmethod) );
+ jsonObjectSetKey(resp, "atomic", jsonNewNumberObject(method->atomic) );
+ jsonObjectSetKey(resp, "cachable", jsonNewNumberObject(method->cachable) );
jsonObjectSetClass(resp, "method");
}
int __osrfAppRunSystemMethod(osrfMethodContext* ctx) {
OSRF_METHOD_VERIFY_CONTEXT(ctx);
- if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ALL )) {
-
- jsonObject* resp = NULL;
- osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service );
- if(app) {
- osrfMethod* method = app->methods;
- while(method) {
- resp = jsonNewObject(NULL);
- __osrfAppSetIntrospectMethod( ctx, method, resp );
- osrfAppRequestRespond(ctx->session, ctx->request, resp);
- jsonObjectFree(resp);
- method = method->next;
- }
- return 1;
- }
+ if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ALL ) ||
+ !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ALL_ATOMIC )) {
- return -1;
+ return osrfAppIntrospectAll(ctx);
}
- if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT )) {
+ if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT ) ||
+ !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT_ATOMIC )) {
+
+ return osrfAppIntrospect(ctx);
+ }
+
+ osrfAppRequestRespondException( ctx->session,
+ ctx->request, "System method implementation not found");
+
+ return 0;
+}
+
+
+int osrfAppIntrospect( osrfMethodContext* ctx ) {
- jsonObject* resp = NULL;
- char* methodSubstring = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
- osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service );
- int len = 0;
+ jsonObject* resp = NULL;
+ char* methodSubstring = jsonObjectGetString( jsonObjectGetIndex(ctx->params, 0) );
+ osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service );
+ int len = 0;
- if(!methodSubstring) return 1; /* respond with no methods */
+ if(!methodSubstring) return 1; /* respond with no methods */
- if(app) {
- osrfMethod* method = app->methods;
- while(method) {
- if( (len = strlen(methodSubstring)) <= strlen(method->name) ) {
- if( !strncmp( method->name, methodSubstring, len) ) {
- resp = jsonNewObject(NULL);
- __osrfAppSetIntrospectMethod( ctx, method, resp );
- osrfAppRequestRespond(ctx->session, ctx->request, resp);
- jsonObjectFree(resp);
- }
+ if(app) {
+
+ osrfHashIterator* itr = osrfNewHashIterator(app->methods);
+ osrfMethod* method;
+
+ while( (method = osrfHashIteratorNext(itr)) ) {
+ if( (len = strlen(methodSubstring)) <= strlen(method->name) ) {
+ if( !strncmp( method->name, methodSubstring, len) ) {
+ resp = jsonNewObject(NULL);
+ __osrfAppSetIntrospectMethod( ctx, method, resp );
+ osrfAppRespond(ctx, resp);
+ jsonObjectFree(resp);
}
- method = method->next;
}
- return 1;
}
-
- return -1;
+ osrfHashIteratorFree(itr);
+ return 1;
}
return -1;
+
}
+int osrfAppIntrospectAll( osrfMethodContext* ctx ) {
+ jsonObject* resp = NULL;
+ osrfApplication* app = _osrfAppFindApplication( ctx->session->remote_service );
+
+ if(app) {
+ osrfHashIterator* itr = osrfNewHashIterator(app->methods);
+ osrfMethod* method;
+ while( (method = osrfHashIteratorNext(itr)) ) {
+ resp = jsonNewObject(NULL);
+ __osrfAppSetIntrospectMethod( ctx, method, resp );
+ osrfAppRespond(ctx, resp);
+ jsonObjectFree(resp);
+ }
+ osrfHashIteratorFree(itr);
+ return 1;
+ }
+
+ return -1;
+}
#include "opensrf/logging.h"
#include "objson/object.h"
#include "osrf_app_session.h"
+#include "osrf_hash.h"
/**
_OSRF_METHOD_VERIFY_CONTEXT(d); \
char* __j = jsonObjectToJSON(d->params);\
if(__j) { \
- osrfLog( OSRF_INFO, "[%s:%s] params: %s", d->session->remote_service, d->method->name, __j);\
+ osrfLog( OSRF_INFO, "%s %s - %s", d->session->remote_service, d->method->name, __j);\
free(__j); \
}
#else
-
/* used internally to make sure the method description provided is OK */
#define OSRF_METHOD_VERIFY_DESCRIPTION(app, d) \
if(!app) return -1; \
+
/* Some well known parameters */
-#define OSRF_SYSMETHOD_INTROSPECT "opensrf.system.method"
-#define OSRF_SYSMETHOD_INTROSPECT_ALL "opensrf.system.method.all"
+#define OSRF_SYSMETHOD_INTROSPECT "opensrf.system.method"
+#define OSRF_SYSMETHOD_INTROSPECT_ATOMIC "opensrf.system.method.atomic"
+#define OSRF_SYSMETHOD_INTROSPECT_ALL "opensrf.system.method.all"
+#define OSRF_SYSMETHOD_INTROSPECT_ALL_ATOMIC "opensrf.system.method.all.atomic"
+#define OSRF_SYSMETHOD_ECHO "opensrf.system.echo"
+#define OSRF_SYSMETHOD_ECHO_ATOMIC "opensrf.system.echo.atomic"
+
+//#define OSRF_METHOD_ATOMIC 1
+//#define OSRF_METHOD_CACHABLE 2
struct _osrfApplicationStruct {
- char* name; /* the name of our application */
+ //char* name; /* the name of our application */
void* handle; /* the lib handle */
- struct _osrfMethodStruct* methods; /* list of methods */
- struct _osrfApplicationStruct* next; /* next application */
+ osrfHash* methods;
+ //struct _osrfMethodStruct* methods; /* list of methods */
+// struct _osrfApplicationStruct* next; /* next application */
};
typedef struct _osrfApplicationStruct osrfApplication;
char* notes; /* public method documentation */
int argc; /* how many args this method expects */
char* paramNotes; /* Description of the params expected for this method */
- struct _osrfMethodStruct* next; /* nest method in the list */
+// struct _osrfMethodStruct* next; /* nest method in the list */
int sysmethod; /* true if this is a system method */
+ int streaming; /* true if this is a streamable method */
+ int atomic; /* true if the method is an atomic method */
+ int cachable; /* true if the method is cachable */
};
typedef struct _osrfMethodStruct osrfMethod;
osrfMethod* method; /* the requested method */
jsonObject* params; /* the params to the method */
int request; /* request id */
+ jsonObject* responses; /* array of cached responses. */
};
typedef struct _osrfMethodContextStruct osrfMethodContext;
@param notes Public documentation for this method.
@params params String description description of the params expected
@params argc The number of arguments this method expects
+ @param streaming True if this is a streaming method that requires an atomic version
@return 0 on success, -1 on error
*/
-int osrfAppRegisterMethod( char* appName,
- char* methodName, char* symbolName, char* notes, char* params, int argc );
+int osrfAppRegisterMethod( char* appName, char* methodName,
+ char* symbolName, char* notes, char* params, int argc, int streaming );
-int _osrfAppRegisterSystemMethod( char* appName, char* methodName,
- char* notes, char* params, int argc );
+int _osrfAppRegisterMethod( char* appName, char* methodName,
+ char* symbolName, char* notes, char* params, int argc, int streaming, int system );
osrfMethod* _osrfAppBuildMethod( char* methodName,
- char* symbolName, char* notes, char* params, int argc, int sysmethod );
+ char* symbolName, char* notes, char* params, int argc, int sysmethod, int streaming );
/**
Registher a method
*/
int osrfAppRequestRespondException( osrfAppSession* ses, int request, char* msg, ... );
+int __osrfAppPostProcess( osrfMethodContext* context, int retcode );
+
+
+int osrfAppRespond( osrfMethodContext* context, jsonObject* data );
+int _osrfAppRespond( osrfMethodContext* context, jsonObject* data, int complete );
+int osrfAppRespondComplete( osrfMethodContext* context, jsonObject* data );
+
+/* OSRF_METHOD_ATOMIC and/or OSRF_METHOD_CACHABLE and/or 0 for no special options */
+//int osrfAppProcessMethodOptions( char* method );
+
+int osrfAppIntrospect( osrfMethodContext* ctx );
+int osrfAppIntrospectAll( osrfMethodContext* ctx );
+