JBConnect Hooks¶
JBconnect-Hook leverages the Sails Installable Hook framework and adds facilities to extend it for JBConnect:
- Job Service integration - provides a runnable job that is launched by the job queue. This may also include an adapter for local or 3rd party server API access such as Galaxy. It may also implement REST APIs specific to the service. The actual adapter portion is optional.
- The Job Queue relies on the adapter to provide translated job state information and execution pre and post processing of the analysis operations.
- The REST API service of the Job Service is a different interface than the standard sails controller interfaces.
- JBrowse plugin / injection (plugins that are tightly integrated with the server-side hooks) along with client-side module dependencies, used by the JBrowse plugins. The injection occurs upon sails lift and copies the necessary plugins into the JBrowse server plugins directory.
- Model/controllers/services as provided by Sails Blueprints. These services are merged with native server models/controllers/services into globally accessible objects.
- Commands via (jbutil) - command options and implementation are merged with the function of jbutil, providing extended command capabilities specific to the JBConnect hook.
- Configurations are aggregated with the JBConnect server configurations.
Directory Layout¶
This is the standard directory layout of a JBConnect hook module
*-jbconnect-hook project
├── api Standard Sails modules layout
│ ├── controllers
│ ├── hooks
│ │ └── Myhook
│ │ └── index.js The main hook
│ ├── models
│ ├── policies
│ └── services
├── bin
│ └── jbutil-ext.js jbutil extension module
├── config
│ └── globals.js Config file for module
├── plugins Client-side Plugins
│ └── PluginA
└── package.json
package.json¶
JBConnect hooks extend sails hooks and are required to contain the following section in the package.json
:
"sails": {
"isHook": true,
"hookName": "jblast-jbconnect-hook",
"isJBConnectHook": true
}
Note the naming convention *-jbconnect-hook
is required.
Configurations¶
This file contains the default config options that are specific to the hook module.
These config options are merged with other JBConnect hooks and the JBConnect config/globals.js
.
From JBConnect, use ./jbutil --config
to see the aggregated config.
Configurations in globals.js
are intended to be project defaults. Configurations can also be in JBConnect’s root directory, called jbconnect.config.js
,
which are user modified configurations.
Client-Side JBrowse Plugins¶
JBrowse plugin associated with the JBConnect hook can be deployed with the JBConnect hook. The framework provides for injecting JBrowse plugins into the working JBrowse directory along with any client-side dependency modules used by the plugin.
The following illustrates how to create a client-side plugin under the framework, with its various configation options.
Developing JBrowse Plugins Under the Framework¶
Refer to Writing JBrowse Plugins for more information.
Client-side plugins in plugins directory are copied to the target JBrowse plugins
directories upon sails lift
.
A plugin can be disabled if it has an entry in the excludePlugins:
section
of config/globals.js file or jbconnect.config.js.
jbrowse: {
...
excludePlugins: {
"ServerSearch": true // doesn't work with JBrowse 1.13.0+
},
...
}
Web Include (client dependencies)¶
Web Includes maps dependancies for client-side access. These are routes to modules that are required for use by the client-side plugins or other client-side code. The framework looks for globals.js in jbh- (hook modules), in their respective config directories
For example: for the dependency module jquery, Relevant assets are copied into assets/jblib by bin/postinstall.js The mapping the mapping ‘js-jquery’: ‘/jblib/jquery’ makes the jquery directory accessible as /jblib/jquery.min.js from the client side.
globals.js
...
jbrowse: {
/*
* Web Includes
* These includes are injected into JBrowse upon sails lift (see tasks/pipeline.js).
*/
webIncludes: {
"css-bootstrap": {lib: "/jblib/bootstrap.min.css"},
"css-mbextruder": {lib: "/jblib/mb.extruder/mbExtruder.css"},
"css-jqueryui": {lib: "/jblib/jquery-ui.min.css"},
"css-jqueryuistructure": {lib: "/jblib/jquery-ui.structure.min.css"},
"css-jqueryuitheme": {lib: "/jblib/jquery-ui.theme.min.css"},
"js-sailsio": {lib: "/js/dependencies/sails.io.js"},
"js-jquery": {lib: "/jblib/jquery.min.js" },
"js-jqueryui": {lib: "/jblib/jquery-ui.min.js" },
"js-bootstrap": {lib: "/jblib/bootstrap.min.js"},
"js-mbextruderHover": {lib: "/jblib/mb.extruder/jquery.hoverIntent.min.js"},
"js-mbextruderFlip": {lib: "/jblib/mb.extruder/jquery.mb.flipText.js"},
"js-mbextruder": {lib: "/jblib/mb.extruder/mbExtruder.js"}
},
}
...
Extending Commands¶
jbutil
is a general command of JBConnect that are used for various operations.
jbutil-ext.js
can be used by the hook to extend options of jbutil.
- it can extend new command line options
- it can extend the help (i.e.
./jbutil --help
)
This is a simplified example of jbutil-ext.js.
module.exports = {
// defining the options
getOptions: function() {
return [
['f' , 'fox' , 'make a fox sound'],
['d' , 'dog' , 'take out the dog'],
];
},
// this is displayed when the user uses the --help or -h option
getHelpText: function() {
return "What does the fox say\n"+
"./jbutil -fox\n"+
'Take out the dog\n"+
"./jbutil -dog\n";
},
// processing the options
process: function(opt,path,config) {
if (opt.options['cat']) {
....
}
if (opt.options['dog']) {
....
}
},
// do some pre initialization
init: function(opt,path,config) {
return 1; // successful init, or 0 if failed.
}
};
More info about the command options processor can be found in node-getopt .
Additional non-jbutil commands¶
The hook can also deploy any additional commands in the JBConnect’s utils
directory.
Sails Module Layout¶
This is the standard sails directory layout for models, controllers, policies, and services of a sails hook. The framework uses marlinspike to integrate controllers, models, policies, and services into JBConnect.
hook project root
├── api Standard Sails modules layout
├── controllers optional
├── hooks hook core index.js in here
├── models optional
├── policies optional
└── services Job services and supporting modules in here.
A core index.js is in api/hooks/<hook name>/index.js
and can be basically be copied from here .
This core fragment starts the initialization of the hook.
Job Service¶
A job service is a special service that can react to the job queue framework asking it to execute something.
The job service generally resides in api/services
directory of the hook and is named <something>Service.js
.
Function Map¶
Job services must contain a fmap
section which defines the routes that the
job service exposes. And there should be corresponding routes (or REST APIs) defined
in the module. The fmap
section must exist, but does not need to be populated.
module.exports = {
fmap: {
set_filter: 'post',
get_blastdata: 'get',
get_trackdata: 'get'
},
// each function should be implemented in the job service
set_filter(req, res) {
var requestData = req.allParams();
...
return res.send(ret);
},
get_blastdata(req, res) {
var requestData = req.allParams();
...
return res.send(ret);
},
get_trackdata: function(req, res) {
var requestData = req.allParams();
...
return res.send(ret);
},
For request parameters, see: Sails req
For response options, see: Sails res
Calling fmap functions¶
fmap
functions are called with either GET or POST using the URL route
(eg. "/service/exec/set_filter"
). Parameters can be passed as data payload
or as URL parameters.
Our handling functions generally use var requestData = req.allParams()
,
making the handlers rather indiscriminate to how the parameters are passed.
An example of a POST request:
var postData = {
filterParams: filter,
asset: "152_search_1517988101045", // usually the track.label name
dataset: "sample_data/json/volvox"
}
$.post( "/service/exec/set_filter", postData , function(data) {
console.log( data );
}, "json");
An example of a GET request:
$.get("/service/exec/get_blastdata/?asset="+browser.jblast.asset+'&dataset='+encodeURIComponent(browser.config.dataRoot), function(data){
console.log( data );
$('.blast-hit-data').html("Hits: ("+data.filteredHits+'/'+data.hits+")");
});
Function Name Overlap¶
If two job services have the same function name, the first the first job service registered will take precedent.
For example: Say serviceA and serviceB both have a fmap function called my_function,
and serviceA is defined before serviceB, then calling /service/exec/my_function
will
execute serviceA.my_function.
However, serviceB.my_function can still be addressed with the service-specific calling format,
/service/exec/serviceB:my_function
.
Obligatory Functions for Job Runners¶
Job services that are job runners that react to job execution, must implement the following functions:
// job service parameter validation
// jservice calls this to determine if the parameters are sufficient to execute the job.
validateParams: function(params) {
if (typeof params.searchParams === 'undefined') return "searchParams not defined";
if (typeof params.searchParams.expr === 'undefined') return "search string undefined";
return 0; // success
},
// job name generator
// jservice framework calls this to determine the jobs user-readable name that appears in the job queue.
generateName(params) {
return params.searchParams.expr+' search';
},
// jservice calls this to execute the job. ``kJob`` is the kue object.
beginProcessing(kJob) {
if (successful) kJob.kDoneFn();
if (failed) kJob.kDoneFn(Error("this job failed because..."));
}
Job Service Configuration¶
Job services are defined in config/globals.js
or in jbconnect.config.js
.
jbrowse: {
// list of services that will get registered.
services: {
// service display name type alias
'basicWorkflowService': {name: 'basicWorkflowService', type: 'workflow', alias: "jblast"},
'filterService': {name: 'filterService', type: 'service'},
'entrezService': {name: 'entrezService', type: 'service'}
},
where
- service refers to the job service module name
- display name is the human readable name of the service
- type - workflow
means it’s a job runner and service
means it only hosts route functions.
service
can either be the service module name (ie. “basicWorkflowService”)
or an the alias, if an alias if defined, given the configuration example below.
Submitting a Job¶
A Job Service must be implemented as a job runner to be a queueable job. (See jbs-jobrunner)
This is an example of job submission. The content of the POST data will depend
of the type of job that is being submitted. However, service:
must be
included and reference an existing job service.
var postData = {
service: "jblast", // this can be the name of the job service or its alias
dataset: "sample_data/json/volvox",
// FASTA formated query sequence
region: ">ctgA ctgA:44705..47713 (- strand) class=remark length=3009\nacatccaatggcgaacataa...gcgagttt",
workflow: "NCBI.blast.workflow.js"
};
$.post( "/job/submit", postData , function( result ) {
console.log( result );
}, "json");