#include "objson/object.h"
#include "opensrf/osrf_log.h"
+#define MODULENAME "opensrf.dbmath"
+
int osrfAppInitialize();
int osrfAppChildInit();
int osrfMathRun( osrfMethodContext* );
int osrfAppInitialize() {
- osrfLogInit("opensrf.dbmath");
- osrfAppRegisterMethod( "opensrf.dbmath", "add", "osrfMathRun", "send 2 numbers and I'll add them", 2 );
- osrfAppRegisterMethod( "opensrf.dbmath", "sub", "osrfMathRun", "send 2 numbers and I'll divide them", 2 );
- osrfAppRegisterMethod( "opensrf.dbmath", "mult", "osrfMathRun", "send 2 numbers and I'll multiply them", 2 );
- osrfAppRegisterMethod( "opensrf.dbmath", "div", "osrfMathRun", "send 2 numbers and I'll subtract them", 2 );
+
+ osrfLogInit(MODULENAME);
+
+ osrfAppRegisterMethod(
+ MODULENAME,
+ "add",
+ "osrfMathRun",
+ "Addss two numbers",
+ "[ num1, num2 ]", 2 );
+
+ osrfAppRegisterMethod(
+ MODULENAME,
+ "sub",
+ "osrfMathRun",
+ "Subtracts two numbers",
+ "[ num1, num2 ]", 2 );
+
+ osrfAppRegisterMethod(
+ MODULENAME,
+ "mult",
+ "osrfMathRun",
+ "Multiplies two numbers",
+ "[ num1, num2 ]", 2 );
+
+ osrfAppRegisterMethod(
+ MODULENAME,
+ "div",
+ "osrfMathRun",
+ "Divides two numbers",
+ "[ num1, num2 ]", 2 );
+
return 0;
}
#include "objson/object.h"
#include "opensrf/osrf_log.h"
+#define MODULENAME "opensrf.math"
+
int osrfAppInitialize();
int osrfAppChildInit();
int osrfMathRun( osrfMethodContext* );
int osrfAppInitialize() {
- osrfLogInit("opensrf.math");
- /* tell the server about the methods we handle */
- osrfAppRegisterMethod( "opensrf.math", "add", "osrfMathRun", "send 2 numbers and I'll add them", 2 );
- osrfAppRegisterMethod( "opensrf.math", "sub", "osrfMathRun", "send 2 numbers and I'll divide them", 2 );
- osrfAppRegisterMethod( "opensrf.math", "mult", "osrfMathRun", "send 2 numbers and I'll multiply them", 2 );
- osrfAppRegisterMethod( "opensrf.math", "div", "osrfMathRun", "send 2 numbers and I'll subtract them", 2 );
+ osrfLogInit(MODULENAME);
+
+ osrfAppRegisterMethod(
+ MODULENAME,
+ "add",
+ "osrfMathRun",
+ "Addss two numbers",
+ "( num1, num2 )", 2 );
+
+ osrfAppRegisterMethod(
+ MODULENAME,
+ "sub",
+ "osrfMathRun",
+ "Subtracts two numbers",
+ "( num1, num2 )", 2 );
+
+ osrfAppRegisterMethod(
+ MODULENAME,
+ "mult",
+ "osrfMathRun",
+ "Multiplies two numbers",
+ "( num1, num2 )", 2 );
+
+ osrfAppRegisterMethod(
+ MODULENAME,
+ "div",
+ "osrfMathRun",
+ "Divides two numbers",
+ "( num1, num2 )", 2 );
+
return 0;
}
int osrfAppInitialize() {
osrfLogInit("opensrf.version");
+
osrfAppRegisterMethod(
"opensrf.version",
"opensrf.version.verify",
"osrfVersion",
- "Send the service, method, and params as paramters to this method "
- "The data for this service/method/params combination will be retrieved "
+ "The data for a service/method/params combination will be retrieved "
"from the necessary server and the MD5 sum of the total values received "
- "will be returned", 2 );
+ "will be returned",
+ "( serviceName, methodName, [param1, ...] )", 2 );
return 0;
}
+# OSRF_LOG_PARAMS log all incoming method params at OSRF_INFO log level.
+# OSRF_STRICT_PARAMS instructs the app handler to return an error if the number of method arguments
+# provided to any method is not at least as large as the 'argc' setting for the method
-CFLAGS += -DASSUME_STATELESS -DOSRF_LOG_PARAMS -rdynamic -fno-strict-aliasing
+CFLAGS += -DASSUME_STATELESS -DOSRF_LOG_PARAMS -DOSRF_STRICT_PARAMS -rdynamic -fno-strict-aliasing
LDLIBS += -lxml2 -lobjson -ldl -lmemcache
TARGETS = osrf_message.o \
}
}
+ __osrfAppRegisterSysMethods(appName);
info_handler("Application %s registered successfully", appName );
return 0;
}
-
int osrfAppRegisterMethod( char* appName,
- char* methodName, char* symbolName, char* notes, int argc ) {
+ char* methodName, char* symbolName, char* notes, char* params, int argc ) {
+
if( !appName || ! methodName || ! symbolName ) 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", appName, methodName );
+ debug_handler("Registering method %s for app %s", methodName, appName );
- osrfMethod* method = safe_malloc(sizeof(osrfMethod));
- method->name = strdup(methodName);
- method->symbol = strdup(symbolName);
- if(notes) method->notes = strdup(notes);
- method->argc = argc;
+ osrfMethod* method = _osrfAppBuildMethod(
+ methodName, symbolName, notes, params, argc, 0 );
/* plug the method into the list of methods */
method->next = app->methods;
return 0;
}
+
+osrfMethod* _osrfAppBuildMethod( char* methodName,
+ char* symbolName, char* notes, char* params, int argc, int sysmethod ) {
+
+ 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;
+}
+
+
+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;
+
+}
+
+int __osrfAppRegisterSysMethods( char* app ) {
+
+ _osrfAppRegisterSystemMethod(
+ app, OSRF_SYSMETHOD_INTROSPECT,
+ "Return a list of methods whose names have the same initial "
+ "substring as that of the provided method name",
+ "( methodNameSubstring )", 1 );
+
+ _osrfAppRegisterSystemMethod(
+ app, OSRF_SYSMETHOD_INTROSPECT_ALL,
+ "Returns a complete list of methods", "()", 0 );
+
+ return 0;
+}
+
osrfApplication* _osrfAppFindApplication( char* name ) {
if(!name) return NULL;
osrfApplication* app = __osrfAppList;
}
+int osrfAppRunMethod( char* appName, char* methodName,
+ osrfAppSession* ses, int reqId, jsonObject* params ) {
-
-int osrfAppRunMethod( char* appName, char* methodName, osrfAppSession* ses, int reqId, jsonObject* params ) {
if( !(appName && methodName && ses) ) return -1;
char* error;
"thread trace %s", methodName, appName, reqId, ses->session_id );
if( !(app = _osrfAppFindApplication(appName)) )
- return warning_handler( "Application not found: %s", appName );
-
+ return osrfAppRequestRespondException( ses,
+ reqId, "Application not found: %s", appName );
- if( !(method = __osrfAppFindMethod( app, methodName )) ) {
- /* see if the unfound method is a system method */
- info_handler("Method %s not found, checking to see if it's a system method...", methodName );
- osrfMethod meth;
- meth.name = methodName;
- context.method = &meth;
+ if( !(method = __osrfAppFindMethod( app, methodName )) )
+ return osrfAppRequestRespondException( ses, reqId,
+ "Method [%s] not found for service %s", methodName, appName );
+
+ context.method = method;
+
+ #ifdef OSRF_STRICT_PARAMS
+ if( method->argc > 0 ) {
+ if(!params || params->type != JSON_ARRAY || params->size < method->argc )
+ return osrfAppRequestRespondException( ses, reqId,
+ "Not enough params for method %s / service %s", methodName, appName );
+ }
+ #endif
+
+ if( method->sysmethod ) {
+
int sysres = __osrfAppRunSystemMethod(&context);
if(sysres == 0) return 0;
- if(sysres > 0) {
- osrfAppSessionStatus( ses, OSRF_STATUS_COMPLETE, "osrfConnectStatus", reqId, "Request Complete" );
- return 0;
- }
- return warning_handler( "NOT FOUND: app %s / method %s", appName, methodName );
+
+ if(sysres > 0)
+ return osrfAppSessionStatus( ses, OSRF_STATUS_COMPLETE,
+ "osrfConnectStatus", reqId, "Request Complete" );
+
+ if(sysres < 0)
+ return osrfAppRequestRespondException(
+ ses, reqId, "An unknown server error occurred" );
}
- context.method = method;
-
/* open the method */
*(void **) (&meth) = dlsym(app->handle, method->symbol);
if( (error = dlerror()) != NULL ) {
- return warning_handler("Unable to locate method symbol [%s] "
- "for method %s and app %s", method->symbol, method->name, app->name );
+ return osrfAppRequestRespondException( ses, reqId,
+ "Unable to execute method [%s] for service %s", methodName, appName );
}
/* run the method */
- int ret = (*meth) (&context);
-
- debug_handler("method returned %d", ret );
-
- if(ret == -1) {
- osrfAppSessionStatus( ses, OSRF_STATUS_INTERNALSERVERERROR,
- "Server Error", reqId, "An unknown server error occurred" );
- return -1;
- }
+ 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" );
+ osrfAppSessionStatus( ses, OSRF_STATUS_COMPLETE,
+ "osrfConnectStatus", reqId, "Request Complete" );
+
+ return 0;
+}
+int osrfAppRequestRespondException( osrfAppSession* ses, int request, char* msg, ... ) {
+ if(!ses) return -1;
+ if(!msg) msg = "";
+ VA_LIST_TO_STRING(msg);
+ osrfLog( OSRF_WARN, "Returning method exception with message: %s", VA_BUF );
+ osrfAppSessionStatus( ses, OSRF_STATUS_NOTFOUND, "osrfMethodException", request, VA_BUF );
return 0;
}
+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, "sysmethod", jsonNewNumberObject(method->sysmethod) );
+ jsonObjectSetClass(resp, "method");
+}
+
+
int __osrfAppRunSystemMethod(osrfMethodContext* ctx) {
OSRF_METHOD_VERIFY_CONTEXT(ctx);
osrfMethod* method = app->methods;
while(method) {
resp = jsonNewObject(NULL);
- 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));
+ __osrfAppSetIntrospectMethod( ctx, method, resp );
osrfAppRequestRespond(ctx->session, ctx->request, resp);
- method = method->next;
- jsonObjectSetClass(resp, "method");
jsonObjectFree(resp);
+ method = method->next;
+ }
+ return 1;
+ }
+
+ return -1;
+ }
+
+
+ if( !strcmp(ctx->method->name, OSRF_SYSMETHOD_INTROSPECT )) {
+
+ 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(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);
+ }
+ }
+ method = method->next;
}
return 1;
}
-
#include <stdio.h>
#include <dlfcn.h>
#include "opensrf/utils.h"
#include "osrf_app_session.h"
-/**
- This macro verifies methods receive the correct parameters
+/**
+ All OpenSRF methods take the signature
+ int methodName( osrfMethodContext* );
+ If a negative number is returned, it means an unknown error occured and an exception
+ will be returned to the client automatically.
+ If a positive number is returned, it means that libopensrf should send a 'Request Complete'
+ message following any messages sent by the method.
+ If 0 is returned, it tells libopensrf that the method completed successfully and
+ there is no need to send any further data to the client.
*/
+
+
+/**
+ This macro verifies methods receive the correct parameters */
#define _OSRF_METHOD_VERIFY_CONTEXT(d) \
if(!d) return -1; \
if(!d->session) { osrfLog( OSRF_ERROR, "Session is NULL in app reqeust" ); return -1; }\
return -1; }\
if( !d->method->name ) { osrfLog(OSRF_ERROR, "Method name is NULL"); return -1; }
-
#ifdef OSRF_LOG_PARAMS
#define OSRF_METHOD_VERIFY_CONTEXT(d) \
_OSRF_METHOD_VERIFY_CONTEXT(d); \
-#define OSRF_SYSMETHOD_INTROSPECT "opensrf.system.method"
-#define OSRF_SYSMETHOD_INTROSPECT_ALL "opensrf.system.method.all"
+/* used internally to make sure the method description provided is OK */
+#define OSRF_METHOD_VERIFY_DESCRIPTION(app, d) \
+ if(!app) return -1; \
+ if(!d) return -1;\
+ if(!d->name) { osrfLog( OSRF_ERROR, "No method name provided in description" ), return -1; } \
+ if(!d->symbol) { osrfLog( OSRF_ERROR, "No method symbol provided in description" ), return -1; } \
+ if(!d->notes) d->notes = ""; \
+ if(!d->paramNotes) d->paramNotes = "";\
+ if(!d->returnNotes) d->returnNotes = "";
-
+
+/* Some well known parameters */
+#define OSRF_SYSMETHOD_INTROSPECT "opensrf.system.method"
+#define OSRF_SYSMETHOD_INTROSPECT_ALL "opensrf.system.method.all"
struct _osrfApplicationStruct {
- char* name; /* the name of our application */
- void* handle; /* the lib handle */
- struct _osrfMethodStruct* methods; /* list of methods */
- struct _osrfApplicationStruct* next; /* next application */
+ char* name; /* the name of our application */
+ void* handle; /* the lib handle */
+ struct _osrfMethodStruct* methods; /* list of methods */
+ struct _osrfApplicationStruct* next; /* next application */
};
typedef struct _osrfApplicationStruct osrfApplication;
struct _osrfMethodStruct {
- char* name; /* the method name */
- char* symbol; /* the symbol name (function) */
- char* notes; /* public method documentation */
- int argc; /* how many args this method expects */
- void* methodHandle; /* cached version of the method handle */
- struct _osrfMethodStruct* next;
+ char* name; /* the method name */
+ char* symbol; /* the symbol name (function) */
+ 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 */
+ int sysmethod; /* true if this is a system method */
};
typedef struct _osrfMethodStruct osrfMethod;
struct _osrfMethodContextStruct {
- osrfAppSession* session;
- osrfMethod* method;
- jsonObject* params;
- int request;
+ osrfAppSession* session; /* the current session */
+ osrfMethod* method; /* the requested method */
+ jsonObject* params; /* the params to the method */
+ int request; /* request id */
};
typedef struct _osrfMethodContextStruct osrfMethodContext;
+
/**
Register an application
@param appName The name of the application
@param methodName The fully qualified name of the method
@param symbolName The symbol name (function) that implements the method
@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
@return 0 on success, -1 on error
*/
int osrfAppRegisterMethod( char* appName,
- char* methodName, char* symbolName, char* notes, int argc );
+ char* methodName, char* symbolName, char* notes, char* params, int argc );
+
+int _osrfAppRegisterSystemMethod( char* appName, char* methodName,
+ char* notes, char* params, int argc );
+
+osrfMethod* _osrfAppBuildMethod( char* methodName,
+ char* symbolName, char* notes, char* params, int argc, int sysmethod );
+
+/**
+ Registher a method
+ @param appName The name of the application that implements the method
+ @params desc The method description
+ @return 0 on success, -1 on error
+ */
+/*
+int osrfAppRegisterMethod( char* appName, osrfMethodDescription* desc );
+*/
/**
Finds the given app in the list of apps
A system method is a well known method that all
servers implement.
@param context The current method context
- @return 0 if the method is run, -1 otherwise
+ @return 0 if the method is run successfully, return < 0 means
+ the method was not run, return > 0 means the method was run
+ and the application code now needs to send a 'request complete'
+ message
*/
int __osrfAppRunSystemMethod(osrfMethodContext* context);
+/**
+ Registers all of the system methods for this app so that they may be
+ treated the same as other methods */
+int __osrfAppRegisterSysMethods( char* app );
+
+
+
+/**
+ Responds to the client with a method exception
+ @param ses The current session
+ @param request The request id
+ @param msg The debug message to send to the client
+ @return 0 on successfully sending of the message, -1 otherwise
+ */
+int osrfAppRequestRespondException( osrfAppSession* ses, int request, char* msg, ... );
if( !(key && obj) ) return -1;
char* s = jsonObjectToJSON( obj );
if( seconds < 0 ) seconds = __osrfCacheMaxSeconds;
- mc_add(__osrfCache, key, strlen(key), s, strlen(s), seconds, 0);
+
+ mc_set(__osrfCache, key, strlen(key), s, strlen(s), seconds, 0);
free(s);
return 0;
}
int osrfCachePutString( char* key, const char* value, time_t seconds ) {
if( !(key && value) ) return -1;
if( seconds < 0 ) seconds = __osrfCacheMaxSeconds;
- mc_add(__osrfCache, key, strlen(key), value, strlen(value), seconds, 0 );
+ mc_set(__osrfCache, key, strlen(key), value, strlen(value), seconds, 0);
return 0;
}
void osrf_message_set_params( osrf_message* msg, jsonObject* o ) {
if(!msg || !o) return;
- if(!o->type == JSON_ARRAY) {
- warning_handler("passing non-array to osrf_message_set_params()");
+ if(o->type != JSON_ARRAY) {
+ warning_handler("passing non-array to osrf_message_set_params(), fixing...");
+ jsonObject* clone = jsonObjectClone(o);
+ o = jsonNewObject(NULL);
+ jsonObjectPush(o, clone);
+ if(msg->_params) jsonObjectFree(msg->_params);
+ msg->_params = o;
return;
}
if(msg->_params) jsonObjectFree(msg->_params);
-
- char* j = jsonObjectToJSON(o);
- msg->_params = jsonParseString(j);
- free(j);
+ msg->_params = jsonObjectClone(o);
}