From 921df3c172d87936a45ff1223c0614273ef08429 Mon Sep 17 00:00:00 2001 From: Eduardo Pinho Date: Tue, 16 Feb 2016 16:55:59 +0000 Subject: [PATCH] add TypeScript typings ; slight refactor ; improve documentation --- gulpfile.js | 2 +- package.json | 3 +- src/{dicoogle-client.js => index.js} | 31 ++- test/mock/service-auth-mock.js | 4 +- test/mock/service-mock.js | 5 +- test/test-base.js | 3 +- typings/dicoogle-client.d.ts | 346 +++++++++++++++++++++++++++ 7 files changed, 375 insertions(+), 19 deletions(-) rename src/{dicoogle-client.js => index.js} (95%) create mode 100644 typings/dicoogle-client.d.ts diff --git a/gulpfile.js b/gulpfile.js index 69ad69c..fe0c5b3 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -38,7 +38,7 @@ gulp.task('main', ['lint'], function () { gulp.task('bundle', ['lint', 'main'], function () { // set up the browserify instance on a task basis var b = browserify({ - entries: './lib/dicoogle-client.js', + entries: './lib/index.js', debug: false, transform: [ ['envify', { diff --git a/package.json b/package.json index 8d9b455..c003054 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "api" ], "version": "3.2.0", - "main": "./lib/dicoogle-client", + "main": "./lib/index", + "typings": "./typings/dicoogle-client.d.ts", "browserify": { "transforms": [ "envify" diff --git a/src/dicoogle-client.js b/src/index.js similarity index 95% rename from src/dicoogle-client.js rename to src/index.js index 9d6de6c..b5fc53a 100644 --- a/src/dicoogle-client.js +++ b/src/index.js @@ -87,7 +87,15 @@ DicoogleAccess.prototype.IndexerSettings = IndexerSettings; callback = options; options = {}; } - const endpoint = options.dim ? Endpoints.SEARCH_DIM : Endpoints.SEARCH; + let endpoint = Endpoints.SEARCH; + if (options.dim) { + endpoint = Endpoints.SEARCH_DIM; + if (process.end.NODE_ENV !== 'production') { + /*eslint-disable no-console */ + console.error("Warning: 'dim' flag in method search is deprecated! Please use searchDIM instead."); + /*eslint-enable no-console */ + } + } let provider = options.provider || options.providers; let keyword = typeof options.keyword === 'boolean' ? options.keyword : !!query.match(/[^\s\\]:\S/); serviceRequest('GET', [url_, endpoint], { @@ -138,7 +146,7 @@ DicoogleAccess.prototype.IndexerSettings = IndexerSettings; /** * Retrieve a list of provider plugins * @param {string} [type] the type of provider ("query", "index", ...) - defaults to "query" - * @param {function(error:any, result:string)} callback the callback function + * @param {function(error:any, result:string[])} callback the callback function */ DicoogleAccess.prototype.getProviders = function Dicoogle_getProviders(type, callback) { if (typeof type === 'function' && !callback) { @@ -185,7 +193,7 @@ DicoogleAccess.prototype.IndexerSettings = IndexerSettings; }; /** - * Obtain information about the DICOM Query Retrieve service. + * Obtain information about the DICOM Query/Retrieve service. * @param {function(error:any, {running:boolean, autostart:boolean, port:number})} callback the callback function */ DicoogleAccess.prototype.getQueryRetrieveServiceStatus = function Dicoogle_getQueryRetrieveServiceStatus(callback) { @@ -289,7 +297,6 @@ DicoogleAccess.prototype.IndexerSettings = IndexerSettings; }; /** Retrieve the running Dicoogle version. - * Indices will not be updated, hence the files should be unindexed manually if so is intended. * @param {function(error:any, {version:string})} callback the callback function */ DicoogleAccess.prototype.getVersion = function Dicoogle_getVersion(callback) { @@ -319,7 +326,7 @@ DicoogleAccess.prototype.IndexerSettings = IndexerSettings; /** * Check whether the user is authenticated to the server. Authenticated clients will hold an * authentication token. - * @returns {boolean} whether the user is authenticated to not. + * @returns {boolean} whether the user is authenticated or not. */ DicoogleAccess.prototype.isAuthenticated = function Dicoogle_isAuthenticated() { return token_ !== null; @@ -371,7 +378,7 @@ DicoogleAccess.prototype.IndexerSettings = IndexerSettings; /** * Log out from the server. - * @param {function(error:any)} callback the callback function + * @param {function(error:any)} [callback] the callback function */ DicoogleAccess.prototype.logout = function Dicoogle_logout(callback) { serviceRequest('POST', [url_, Endpoints.LOGOUT], {}, function(error) { @@ -379,13 +386,13 @@ DicoogleAccess.prototype.IndexerSettings = IndexerSettings; if (error.status === 405) { Dicoogle_logout_fallback(callback); } else { - callback(error); + if (callback) callback(error); } } else { username_ = null; token_ = null; roles_ = null; - callback(null); + if (callback) callback(null); } }, token_); }; @@ -402,7 +409,7 @@ DicoogleAccess.prototype.IndexerSettings = IndexerSettings; token_ = null; roles_ = null; } - callback(error); + if (callback) callback(error); }, token_); } @@ -440,7 +447,11 @@ DicoogleAccess.prototype.IndexerSettings = IndexerSettings; callback(err); return; } - callback(null, res.text); + let out = res.text; + if (field === 'effort' || field === 'thumbnailSize') { + out = +out; + } + callback(null, out); }); return; } diff --git a/test/mock/service-auth-mock.js b/test/mock/service-auth-mock.js index 2d4d6b4..3a66a43 100644 --- a/test/mock/service-auth-mock.js +++ b/test/mock/service-auth-mock.js @@ -1,5 +1,5 @@ /* eslint-env node */ -var DicoogleClient = require('../..'); +var dicoogleClient = require('../..'); var nock = require('nock'); var nockDone = false; var qs = require('querystring'); @@ -54,5 +54,5 @@ module.exports = function createDicoogleMock() { nockDone = true; } - return DicoogleClient(BASE_URL); + return dicoogleClient(BASE_URL); }; diff --git a/test/mock/service-mock.js b/test/mock/service-mock.js index 8792d2a..9884487 100644 --- a/test/mock/service-mock.js +++ b/test/mock/service-mock.js @@ -1,7 +1,6 @@ /* eslint-env node */ -var DicoogleClient = require('../..'); +var dicoogleClient = require('../..'); var nock = require('nock'); - var nockDone = false; /** Use nock to intercept Dicoogle client requests. @@ -248,5 +247,5 @@ module.exports = function createDicoogleMock() { nockDone = true; } - return DicoogleClient(BASE_URL); + return dicoogleClient(BASE_URL); }; diff --git a/test/test-base.js b/test/test-base.js index 830e975..9e5ed68 100644 --- a/test/test-base.js +++ b/test/test-base.js @@ -20,8 +20,7 @@ function assertDicomUUID(uid) { assert(uid.match(/(\d+\.?)*/), "'" + uid + "' must be a valid DICOM UUID"); } - -describe('Dicoogle Node.js Client', function() { +describe('Dicoogle Client (under Node.js)', function() { var Dicoogle; function initBaseURL() { Dicoogle = createMockedDicoogle(); diff --git a/typings/dicoogle-client.d.ts b/typings/dicoogle-client.d.ts new file mode 100644 index 0000000..fb80c18 --- /dev/null +++ b/typings/dicoogle-client.d.ts @@ -0,0 +1,346 @@ + +declare module "dicoogle-client" { + export default dicoogleClient; + + type password = string; + + /** Web service endpoints + * @enum {string} + */ + export type Endpoints = { [e: string]: string }; + + export interface DicoogleClientOptions { + token?: string + secure?: boolean + /** @deprecated */ + user?: string + /** @deprecated */ + password?: password + } + + function dicoogleClient(url?: string, options?: DicoogleClientOptions): DicoogleAccess; + + export interface SearchOptions { + /** Force whether the query is keyword-based, defaults to automatic detection */ + keyword?: boolean + /** An array of query provider names, or a string of a provider, defaults to the server's default query provider(s) */ + provider?: string | string[] + /** @deprecated + * Return the results as a DICOM Object Model tree (Patients -> Studies -> Series -> Instances), false by default */ + dim?: boolean + } + + export interface SearchResult { + [attribute: string]: any + uri: string + score?: number + } + + export interface SearchOutcome { + /** The list of results */ + results: SearchResult[] + /** The time spent performing the search in the server, in milliseconds */ + elapsedTime: number + } + + export interface DumpOutcome { + /** The contents of the requested item */ + results: SearchResult + /** The time spent performing the search in the server, in milliseconds */ + elapsedTime: number + } + + export interface ServiceStatus { + running: boolean + autostart: boolean + port: number + } + + export interface LoginOutcome { + /** The user's unique name */ + user: string + /** The current session token */ + token: string + /** The current user's assigned roles */ + roles: string[] + /** Whether this user is an administrator */ + admin: boolean + } + + export interface TaskInfo { + /** the UUID of the task */ + taskUid: string + /** a human readable task name */ + taskName: string + /** a number between 0 and 1 representing the task's progress; any negative number means that no prediction is available */ + taskProgress: number + /** whether the task is complete, assume not if not provided */ + complete?: boolean + /** only if complete; the time elapsed while the task was running, in milliseconds */ + elapsedTime?: number + /** only if complete; the number of files successfully indexed */ + nIndexed?: number + /** only if complete; the number of indexation errors */ + nErrors?: number + } + + /** Indexer settings fields + */ + export interface IndexerSettings { + /** The path to the directory to watch. */ + path: string + /** Whether to index zip files. */ + zip: boolean + /** The percentage of indexation effort (from 0 to 100). */ + effort: number + /** Whether to index thumbnails. */ + thumbnail: boolean + /** The size of generated thumbnails in pixels. */ + thumbnailSize: number + /** Listen for changes in the directory for automatic indexation. */ + watcher: boolean + } + + export interface DicoogleAccess { + + /** + * Perform a text query. + * @param query the text query + * @param callback the callback function providing the outcome + */ + search(query: string, callback: (error: Error, outcome: SearchOutcome) => any); + /** + * Perform a text query. + * @param query the text query + * @param options a hash of options related to the search + * @param callback the callback function providing the outcome + */ + search(query: string, options: SearchOptions, callback: (error: Error, outcome: SearchOutcome) => any); + + /** + * Perform a text query with DIM-formatted outcome. + * @param query the text query + * @param callback the callback function providing the outcome + */ + searchDIM(query: string, callback: (error: Error, outcome: SearchOutcome) => any); + /** + * Perform a text query with DIM-formatted outcome. + * @param query the text query + * @param options a hash of options related to the search + * @param callback the callback function providing the outcome + */ + searchDIM(query: string, options: SearchOptions, callback: (error: Error, outcome: SearchOutcome) => any); + + /** + * Retrieve an image's meta-data (perform an information dump) + * @param uid the SOP instance UID + * @param callback the callback function + */ + dump(uid: string, callback: (error: Error, outcome: SearchOutcome) => any); + /** + * Retrieve an image's meta-data (perform an information dump) + * @param uid the SOP instance UID + * @param provider a list of provider plugins + * @param callback the callback function + */ + dump(uid: string, provider: string | string[], callback: (error: Error, outcome: SearchOutcome) => any); + + /** + * Retrieve a list of provider plugins + * @param type the type of provider ("query", "index", ...) - defaults to "query" + * @param callback the callback function + */ + getProviders(type: string, callback: (error: Error, outcome: string[]) => any); + /** + * Retrieve a list of query provider plugins + * @param callback the callback function + */ + getProviders(callback: (error: Error, outcome: string[]) => any); + + /** + * Retrieve a list of query provider plugins + * @param callback the callback function + */ + getQueryProviders(callback: (error: Error, outcome: string[]) => any); + + /** + * Retrieve a list of index provider plugins + * @param callback the callback function + */ + getIndexProviders(callback: (error: Error, outcome: string[]) => any); + + /** + * Retrieve a list of storage provider plugins + * @param callback the callback function + */ + getStorageProviders(callback: (error: Error, outcome: string[]) => any); + + /** + * Obtain information about the DICOM Storage service. + * @param callback the callback function + */ + getStorageServiceStatus(callback: (error: Error, outcome: ServiceStatus) => any); + + /** + * Obtain information about the DICOM Query/Retrieve service. + * @param callback the callback function + */ + getQueryRetrieveServiceStatus(callback: (error: Error, outcome: ServiceStatus) => any); + + /** + * Manually log in to Dicoogle using the given credentials. + * @param username the unique user name for the client + * @param password the user's password for authentication + * @param callback the callback function, + * providing the authentication token and other information + */ + login(username: string, password: password, callback?: (error: Error, outcome: LoginOutcome) => any); + + /** + * Log out from the server. + * @param callback the callback function + */ + logout(callback?: (error: Error) => any); + + /** + * Perform a generic request to Dicoogle's services. Users of this method can + * invoke any REST service exposed by Dicoogle, including those from plugins. + * @param method the kind of HTTP method to make, defaults to "GET" + * @param uri a URI or array of resource sequences to the service, relative to Dicoogle's base URL + * @param callback the callback function + */ + request(method: string, uri: string | string[], callback: (error: Error, outcome: any) => any) + /** + * Perform a generic request to Dicoogle's services. Users of this method can + * invoke any REST service exposed by Dicoogle, including those from plugins. + * @param method the kind of HTTP method to make, defaults to "GET" + * @param uri a URI or array of resource sequences to the service, relative to Dicoogle's base URL + * @param options an object of options to be passed as query strings + * @param callback the callback function + */ + request(method: string, uri: string | string[], options: { [attribute: string]: any }, callback: (error: Error, outcome: any) => any) + + /** + * Request a new indexation task over a given URI. The operation is recursive, + * indexing anything in the URI's endpoint. The callback will be called after + * the task is created, not when it is complete. + * @param uri a URI or array of URIs representing the root resource of the files to be indexed + * @param callback the function to call when the task is successfully issued + */ + index(uri: string, callback: (error: Error) => any); + /** + * Request a new indexation task over a given URI. The operation is recursive, + * indexing anything in the URI's endpoint. The callback will be called after + * the task is created, not when it is complete. + * @param uri a URI or array of URIs representing the root resource of the files to be indexed + * @param provider a provider or array of provider names in which the indexation will carry out, all by default + * @param callback the function to call when the task is successfully issued + */ + index(uri: string, provider: string | string[], callback: (error: Error) => any); + + /** + * Request that the file at the given URI is unindexed in all indexers. The operation, unlike index(), is not recursive and will not unindex sub-entries. + * @param uri a URI or array of URIs representing the files to be unindexed + * @param callback the function to call on completion + */ + unindex(uri: string, callback: (error: Error) => any); + /** + * Request that the file at the given URI is unindexed to a specific set of indexers. The operation, unlike index(), is not recursive and will not unindex sub-entries. + * @param uri a URI or array of URIs representing the files to be unindexed + * @param provider a provider or array of provider names in which the unindexation will carry out, all by default + * @param callback the function to call on completion + */ + unindex(uri: string, provider: string | string[], callback: (error: Error) => any); + + /** Request that the file at the given URI is permanently removed. The operation, unlike index(), is not recursive. + * Indices will not be updated, hence the files should be unindexed manually if so is intended. + * @param uri a URI or array of URIs representing the files to be removed + * @param callback the function to call on completion + */ + remove(uri: string, callback: (error: Error) => any); + + /** + * Obtain information about Dicoogle's running (or terminated) tasks. + * @param callback the callback function + */ + getRunningTasks(callback: (error: Error, outcome: { tasks: TaskInfo[], count: number }) => any); + + /** + * Close a terminated task from the list of tasks. + * @param uid the task's unique ID + * @param callback the callback function + */ + closeTask(uid: string, callback: (error: Error) => any); + + /** + * Request that a task is stopped. + * @param uid the task's unique ID + * @param callback the callback function + */ + stopTask(uid: string, callback: (error: Error) => any); + + /** Retrieve the running Dicoogle version. + * @param {function(error:any, {version:string})} callback the callback function + */ + getVersion(callback: (error: Error, outcome: { version: string }) => any); + + /** Get all of the current Indexer settings. + * @param callback the callback function + */ + getIndexerSettings(callback: (error: Error, outcome: IndexerSettings) => any) + + /** Get the current Indexer settings. The type of the given outcome depends on + * the particular field that was chosen. + * @param field a particular field to retrieve + * @param callback the callback function + */ + getIndexerSettings(field: string, callback: (error: Error, outcome: any) => any) + + /** Set a particular Indexer setting. A valid field and value pair is required. + * @param field a particular field to set + * @param value the value to assign to the field + * @param callback the callback function + */ + setIndexerSettings(field: string, value: any, callback: (error: Error) => any) + + /** Obtain the base URL of all Dicoogle services. + * This method is synchronous. + * @returns the currently configured base endpoint of Dicoogle + */ + getBase(): string; + + /** + * Get the user name of the currently authenticated user. + * @returns the unique user name + */ + getUsername(): string; + + /** + * Get the names of the roles assigned to this user. + * @returns an array of role names, null if the user is not authenticated + */ + getRoles(): string[]; + + /** + * Retrieve the authentication token. This token is ephemeral and may expire after some time. + * This method is synchronous. + * @returns the user's current authentication token + */ + getToken(): string; + + /** + * Check whether the user is authenticated to the server. Authenticated clients will hold an + * authentication token. + * @returns whether the user is authenticated or not. + */ + isAuthenticated(): boolean; + + /** + * Assign the module's session token, used only for restoring previous (but recent) sessions. + * This method is synchronous. + * @param token the same user's token of a previous session + */ + setToken(token: string); + } +} +