The F.A.S.T. Cloud SDK provides features to allow the client to call
custom function plugins that will be run on the server. These plugins
can be used to load custom data types or to implement custom data
analysis and manipulation algorithms. The plugins are written in C++
and they will be dynamically loaded (.dll's in
Windows, and runtime loaded .so's in Linux) into the address space of
the server at program start. You will have access to all the relevant
data structures in
memory so you can perform almost any processing you wish. We recomend
that processing which requires high compute resources and/or acces to
the original DICOM images be done through custom functions implemented
in plugins. There are four types of functions that can be implemented
in a plugin file. These are 3D custom functions, 3D data loaders, 2D
custom functions, and 2D data loaders.
Creating a Plugin File
The websdk distribution includes a basic sample plugin in the directory
websdk/examples/plugins/plugin_sample that can be used as a reference.
The source code for a number of other plugins packaged with the websdk
distribution are also included in websdk/examples/plugins/.
A websdk plugin file is a Windows .dll or Linux .so file that exports a
one or more functions designed to be called from the websdk server. The
exported functions can have any name, but to be compatable with websdk,
the exported functions must have the following prototypes.
3D Custom Function Prototype:
string customFunction3D(std::list<IVolumeData> &volumes,
std::list<IVolumeOctree> &octrees,
std::list<IRenderEngine> &renderEngines,
std::list<IVolumeSegmentation> &segmentations, const
nlohmann::json pJSONObjectInput, nlohmann::json pJSONObjectOutput);
A websdk plugin must include the file websdk_plugin_defines.h. This
file is included in the websdk distribution in the
websdk/examples/customfunctions/Headers directory. The
websdk_plugin_defines.h contains a number of predefined values that
facilitate plugin development. The plugin must also include the
appropriate header files with definitions for the websdk data types
used by the function protoypes. The developer may also wish to include
the header files for HDVR In-Process SDK, which allows direct access to
low level native data structures.
A websdk plugin must export an enumeration function called
EnumerateFunctions(), as shown below. This function returns to the
websdk plugin loader a std::string that contains the names and types of
functions included in the plugin so they may be bound to the websdk
server. Any combination or number of 2D/3D custom functions and custom
loaders may be packaged in a plugin file. The only restrictions are
that the exported functions must comform the the required prototypes
listed above, and that function names must be gloabally unique across
all plugin files within the four function types. For example, amonsts
all 3D custom data loader functions, a function name must be unique,
but the same function name could be used in a 2D custom data loader, if
desired. The EnumerateFunctions() function must also return in output
paramaters the plugin version identifier. The plugin version numbers
are provided in websdk_plugin_defines.h and should be returned as shown
below.
string EnumerateFunctions(int pMajorVersion, int pMinorVersion) {
string functionBuf;
// Create list of function names and types.
functionBuf += "customFunction3D" +
PLUGIN_TYPE_FUNC3D;
functionBuf += "customFunction2D" +
PLUGIN_TYPE_FUNC2D;
functionBuf += "customLoad3D" + PLUGIN_TYPE_LOAD3D;
functionBuf += "customLoad2D" + PLUGIN_TYPE_LOAD2D;
// Return plugin version number.
if (pMajorVersion) pMajorVersion =
PLUGIN_MAJOR_VERSION;
if (pMinorVersion) *pMinorVersion =
PLUGIN_MINOR_VERSION;
return functionBuf;
}
The compiled plugin binary file should be placed in the
websdk/foviaserver/nodeaddon/plugins directory.
Calling Custom Functions and Loaders from the Client
Invoke a server-side 3D custom function with a call to Fovia.ServerContext.callCustomFunction
passing in an array of Volumes, an array of Octrees, an array of Render
Engines, an array of Segmentation objects and a JSON object of
parameters that you build up as required. The arrays can be
either null (if that data structure is not needed by your custom
functions on the other side) or an array of one or more objects. For
most cases only one object is needed but the array implementation
allows for multiple objects to be passed in case comparaisons or
multi-object processing is necessary. Invoke a server-side 2D custom
function with a call to Fovia.ServerContext.callCustomFunction2D
passing in an array of SeriesDataContext and SeriesSegmentationContext
objects. The input JSON object is decoded within the custom function so
the input paramaters can be processed. A JSON object is returned from
the custom function containing custom output values generated by the
server-side implementation.
Invoke a server-side 3D custom data loader with a call to Fovia.ServerContext.loadCustomData
, passing in a JSON object of
parameters that you build up as required. This function also takes a
boolean flag indicating if an octree structure should be built for the
dataset. Invoke a server-side 2D custom data loader with a call to
Fovia.ServerContext.load2DCustomData,
which also takes an input JSON
object of paramaters. The input JSON object is decoded within the
custom function so the input paramaters can be processed. A JSON object
is returned from the custom function containing custom output values
generated by the server-side implementation.
The call returns a promise that is fulfilled when the custom function
completes on the
server side. Another JSON object is returned which is built on the
server side in the plugin implementation so it can be decoded and read
on the client.
Concurrent Processing.
Crashes or data corruption could happen if custom functions are running
and
changing data while the server is trying to render. For this reason you
want to avoid the possiblity of calling custom functions to change data
while rendering or segmenting data on server side. You can do this
inside your app,
or you can use the two client-side functions below.
pauseServerOperations() with the same parameters as the
callCustomFunctions(). It will pause and return a promise that is
fulfilled only when
all operations on those data structures are completed and flag is set
indicating that no more can start.
resumeServerOperations() either again with all the objects that would
like to resume or resumeAllServerOperations() which will enable all
operations on all objects.
Websdk Plugins
The F.A.S.T. Cloud SDK provides features to allow the client to call custom function plugins that will be run on the server. These plugins can be used to load custom data types or to implement custom data analysis and manipulation algorithms. The plugins are written in C++ and they will be dynamically loaded (.dll's in Windows, and runtime loaded .so's in Linux) into the address space of the server at program start. You will have access to all the relevant data structures in memory so you can perform almost any processing you wish. We recomend that processing which requires high compute resources and/or acces to the original DICOM images be done through custom functions implemented in plugins. There are four types of functions that can be implemented in a plugin file. These are 3D custom functions, 3D data loaders, 2D custom functions, and 2D data loaders.Creating a Plugin File
The websdk distribution includes a basic sample plugin in the directory websdk/examples/plugins/plugin_sample that can be used as a reference. The source code for a number of other plugins packaged with the websdk distribution are also included in websdk/examples/plugins/.A websdk plugin file is a Windows .dll or Linux .so file that exports a one or more functions designed to be called from the websdk server. The exported functions can have any name, but to be compatable with websdk, the exported functions must have the following prototypes.
3D Custom Function Prototype:
string customFunction3D(std::list<IVolumeData> &volumes, std::list<IVolumeOctree> &octrees, std::list<IRenderEngine> &renderEngines, std::list<IVolumeSegmentation> &segmentations, const nlohmann::json pJSONObjectInput, nlohmann::json pJSONObjectOutput);
3D Custom Loader Protoype:
string customLoad3D(const nlohmann::json pJSONObjectInput, IVolumeData** ppi, nlohmann::json pJSONObjectOutput);
2D Custom Function Prototype:
string customFunction2D(std::list<ISeriesDataContext> &series, std::list<ISegmentation2DContext> &segmentations, const nlohmann::json pJSONObjectInput, nlohmann::json pJSONObjectOutput);
2D Custom Loader Prototype:
string customLoad2D(const nlohmann::json pJSONObjectInput, IDicomStudyData** ppi, nlohmann::json pScanDirResultsJson, nlohmann::json pJSONObjectOutput);
A websdk plugin must include the file websdk_plugin_defines.h. This file is included in the websdk distribution in the websdk/examples/customfunctions/Headers directory. The websdk_plugin_defines.h contains a number of predefined values that facilitate plugin development. The plugin must also include the appropriate header files with definitions for the websdk data types used by the function protoypes. The developer may also wish to include the header files for HDVR In-Process SDK, which allows direct access to low level native data structures.
#include "websdk_plugin_defines.h"
#include "hdrc/hdrc.h"
#include "sysapi/sysdef.h"
#include "FoviaCustomInterfaces.h"
#include "foviaJSONtoCPPConverter.h"
A websdk plugin must export an enumeration function called EnumerateFunctions(), as shown below. This function returns to the websdk plugin loader a std::string that contains the names and types of functions included in the plugin so they may be bound to the websdk server. Any combination or number of 2D/3D custom functions and custom loaders may be packaged in a plugin file. The only restrictions are that the exported functions must comform the the required prototypes listed above, and that function names must be gloabally unique across all plugin files within the four function types. For example, amonsts all 3D custom data loader functions, a function name must be unique, but the same function name could be used in a 2D custom data loader, if desired. The EnumerateFunctions() function must also return in output paramaters the plugin version identifier. The plugin version numbers are provided in websdk_plugin_defines.h and should be returned as shown below.
string EnumerateFunctions(int pMajorVersion, int pMinorVersion) {
string functionBuf;
// Create list of function names and types.
functionBuf += "customFunction3D" + PLUGIN_TYPE_FUNC3D;
functionBuf += "customFunction2D" + PLUGIN_TYPE_FUNC2D;
functionBuf += "customLoad3D" + PLUGIN_TYPE_LOAD3D;
functionBuf += "customLoad2D" + PLUGIN_TYPE_LOAD2D;
// Return plugin version number.
if (pMajorVersion) pMajorVersion = PLUGIN_MAJOR_VERSION;
if (pMinorVersion) *pMinorVersion = PLUGIN_MINOR_VERSION;
return functionBuf;
}
The compiled plugin binary file should be placed in the websdk/foviaserver/nodeaddon/plugins directory.
Calling Custom Functions and Loaders from the Client
Invoke a server-side 3D custom function with a call to Fovia.ServerContext.callCustomFunction passing in an array of Volumes, an array of Octrees, an array of Render Engines, an array of Segmentation objects and a JSON object of parameters that you build up as required. The arrays can be either null (if that data structure is not needed by your custom functions on the other side) or an array of one or more objects. For most cases only one object is needed but the array implementation allows for multiple objects to be passed in case comparaisons or multi-object processing is necessary. Invoke a server-side 2D custom function with a call to Fovia.ServerContext.callCustomFunction2D passing in an array of SeriesDataContext and SeriesSegmentationContext objects. The input JSON object is decoded within the custom function so the input paramaters can be processed. A JSON object is returned from the custom function containing custom output values generated by the server-side implementation.Invoke a server-side 3D custom data loader with a call to Fovia.ServerContext.loadCustomData , passing in a JSON object of parameters that you build up as required. This function also takes a boolean flag indicating if an octree structure should be built for the dataset. Invoke a server-side 2D custom data loader with a call to Fovia.ServerContext.load2DCustomData, which also takes an input JSON object of paramaters. The input JSON object is decoded within the custom function so the input paramaters can be processed. A JSON object is returned from the custom function containing custom output values generated by the server-side implementation.
The call returns a promise that is fulfilled when the custom function completes on the server side. Another JSON object is returned which is built on the server side in the plugin implementation so it can be decoded and read on the client.
Concurrent Processing.
Crashes or data corruption could happen if custom functions are running and changing data while the server is trying to render. For this reason you want to avoid the possiblity of calling custom functions to change data while rendering or segmenting data on server side. You can do this inside your app, or you can use the two client-side functions below.pauseServerOperations() with the same parameters as the callCustomFunctions(). It will pause and return a promise that is fulfilled only when all operations on those data structures are completed and flag is set indicating that no more can start.
resumeServerOperations() either again with all the objects that would like to resume or resumeAllServerOperations() which will enable all operations on all objects.