Skip to content
This repository has been archived by the owner on Jun 2, 2022. It is now read-only.

ConnectingWithNodeJS

Minkyu Lee edited this page Oct 12, 2015 · 4 revisions

Connecting with Node.js

StarUML is developed based on CEF (Chromium Embedded Framework), one of the web browser technologies. So you can use most of functionalities available in web browsers, to develop extensions. However, sometimes you may want to use Node.js modules which provides functionalities not available in CEF. Fortunately, StarUML supports asynchronous interoperation with Node.js. In this chapter, we're going to learn how to interoperate with Node.js.

You can get insight from a simple example at https://github.com/staruml/staruml-simple-node. You can also get detailed information from Brackets (https://github.com/adobe/brackets/wiki/Brackets-Node-Process:-Overview-for-Developers) since StarUML is developed based on the Brackets.

Since CEF and Node.js are running in separate processes, we need to interoperate between them using a kind of IPC (Inter-Process Communication).This means that we need to develop Node-side module providing functionalities and client-side (or CEF-side) module requesting function calls.

Implementing the Node-side module

First, we need to implement Node-side module as follow.

var os = require("os");
    
/**
 * @private
 * Handler function for the simple.getMemory command.
 * @param {boolean} total If true, return total memory; if false, return free memory only.
 * @return {number} The amount of memory.
 */
function cmdGetMemory(total) {
    if (total) {
        return os.totalmem();
    } else {
        return os.freemem();
    }
}

/**
 * Initializes the test domain with several test commands.
 * @param {DomainManager} domainManager The DomainManager for the server
 */
function init(domainManager) {
    if (!domainManager.hasDomain("simple")) {
        domainManager.registerDomain("simple", {major: 0, minor: 1});
    }
    domainManager.registerCommand(
        "simple",       // domain name
        "getMemory",    // command name
        cmdGetMemory,   // command handler function
        false,          // this command is synchronous in Node
        "Returns the total or free memory on the user's system in bytes",
        [{name: "total", // parameters
            type: "string",
            description: "True to return total memory, false to return free memory"}],
        [{name: "memory", // return values
            type: "number",
            description: "amount of memory in bytes"}]
    );
}

exports.init = init;

cmdGetMemory is an function to be exported so as to be called by client-side module. In this example, only one function is defined but you can define a set of functions to be registered in a module. Then, we need to register these functions using DomainManager.registerCommand with several parameters. Before registering the functions, we need to register a domain (or a module name) first using DomainManager.registerDomain. All these should be implemented inside init function and init will be called automatically for initialization. Finally, don't forget to export init function so that it can be called for initialization.

Implementing the client-side module

After defined Node-side module, you can define client-side module that is a proxy to access the registered functions in a Node-side domain. Remind that client-side module will be executed in CEF while Node-side module will be executed in Node.js. Below is an example client-side module for the Node-side module shown in the above.

define(function (require, exports, module) {
    "use strict";

    var ExtensionUtils = app.getModule("utils/ExtensionUtils"),
        NodeDomain     = app.getModule("utils/NodeDomain");

    var simpleDomain = new NodeDomain("simple", ExtensionUtils.getModulePath(module, "node/SimpleDomain"));

    // Helper function that runs the simple.getMemory command and
    // logs the result to the console
    function logMemory() {
        simpleDomain.exec("getMemory", false)
            .done(function (memory) {
                console.log(
                    "[staruml-simple-node] Memory: %d bytes free",
                    memory
                );
            }).fail(function (err) {
                console.error("[staruml-simple-node] failed to run simple.getMemory", err);
            });
    }

    // Log memory when extension is loaded
    logMemory();
});

It is a good coding convention to define client-side functions corresponding to the registered functions in the Node-module, so we defined logMemory function correspond to the cmdGetMemory. In logMemory function, execute the cmdGetMemory function using simpleDomain.exec. The arguments passed to the exec after the function name "getMemory" are passed as parameters to the cmdGetMemory in Node-side. Communication to the Node-side module is asynchronous, so you can get the results via callback functions. Actually, the returned object is JQuery's Promise object.