• 7.8.1 Core module (Cont)

    Except that the Buffer module is quite special and put in the limax.node.js package, the other code modules are all put in the limax.node.js.modules package, and make a pair based on one .java file and one .js file, and the first letter is capital and all letters are lowcase when requiring according to the Java custom.

    • Events

      Provide the complete java implementation, and js is just a simple package.

      The setMaxListeners method is actually ignored without limiting the number of the listener, and the getMaxListeners always returns Integer.MAX_VALUE. The instruction of the node.js manual is that limiting the number of the listener is helpful to find the memory leaks. It is no need to consider this issue in Java environment.


    • File System

      Use java.nio.file package to implement, which is a little different from the implementation of node.js.

      • 1. The difference of fs.Stats. The information obtained by java is different from the struct stat and could be compared with the datailed information dumped by the below code.


        fs.stat(file, console.log);
        
      • 2. The Java does not provide the hard link capability, so fs.link and fs.linkSync are not provided.

      • 3. fs.watch, is changed to callback via absolute path, which is convenient to use the single listener to monitor multiple directories. The options.recursive is ignored and java does not provide. The description of options.encoding from the node.js manual is context contradiction.

      • 4. The options parameter of the six methods fs.readFile, fs.readFileSync, fs.writeFile, fs.writeFileSync, fs.appendFile, and fs.appendFileSync does not support object, and only performs the Buffer.isEncoding test as encoding string. The test failure is UTF8 as default directly. Otherwise there is a large number of logical contradictions, for example, when executing writeFile, provide flag='r', which is ridicuous.

      • 5. The options parameter of the two methods fs.mkdtemp and fs.mkdtempSync has no any meaning and is ignored. The prefix requires a string with no path delimiter, and generates the file name in the user's temporay directory to avoid the permission issue when creating the temporary files.

      • 6. The fs.constants is actually a java object, and only has R_OK, W_OK, X_OK, and F_OK four values.

      • 7. The java.nio.file does not support the file descriptors. So the file descriptor returned by the open is actually an internal forged integer which is used to index FileChannel.


    • Global

      The global variables described in the node.js manual are all supported, and the require related members are expanded and add parameters and java two module level global variable. Please refer the module section for the details.


    • HTTP

      • 1. The options.keepAlive in the constructor parameter options of http.Agent is ignored. The Agent always supports keep-alive of HTTP/1.1. The options.maxSockets has no meaning and is ignored. The options.keepAliveMsec is reinterpreted as the connection idle timeout, and the connection is closed after timeout and the default is 60000ms. In multiple NAT environment, the TCP IDLE is 5 mins as default and has no problem. The default configuration tcp-keepalive=1000ms in the node.js document, is implemented through setting tcp option TCP_KEEPINTVAL in linux and not portable.

      • 2. In http.Request, the second parameter initialDelay of http.setSocketKeepAlive is ignored. The jdk does not support this parameter and there is no idea which protocol stack can support this behavior.


    • HTTPS

      The design of Node.js is too redundant, the Limax version is directly implemented in the HTTP module (actually, there is no https module), and only simply modifies two methods. (For more information about TLS, please reference the TLS/SSL section )

      1. The http.createServer([requestListener]) is extended as http.createServer([requestListener], [tls]). The tls is the TLS configuration information. As long as the TLS configuration is provided, the server is started as the HTTPS server. If the configuration requires the client authentication, the properties socket.tlsPeerPrincipal and socket.tlsPeerCertificateChain can be read on http.IncomingMessage, respectively getting the subject and certificate chain of the client certificate.

      2. Add the options.tls property into the constructor parameter options of http.ClientRequest. If this property is set, the HTTPS is used to send the client request. If this field is not provided, check whether theoptions.protocol is 'https:'. If yes, the HTTPS is used to send the client request. In this case, the trusted root certificate in the cacerts prvoided by JDK is used to verify the server, specify the SNIHostName as the server name of connection, do not support the client authentication, and do not check the certificate revocation status.


      For example: the simplest https client:


      var http = require(‘http’)
      var req = http.get('https://www.alipay.com', function(res) {
          res.pipe(process.stdout);
      });
      req.once('socket', function(socket) {
          socket.once('tlsHandshaked', function() {
              for (var i = 0; i < arguments.length; i++)
                  console.log(arguments[i].toString());
          });
      })
      

      The last statement can get the subject and certificate chain of the server certificate by listening to the tlsHandshaked message on the socket.


    • Module

      In addition to implementing the function described in the node.js document, more functions have been added.

      • 1. require(module[, parameter1[, parameter2,…]])

        Allow to transfer the launch parameters to the module. Because the module is cached by default, the first input launch parameters are meanful.

      • 2. require.reload(module[, parameter1[, parameter2,…]])

        Reload the module. There is no trouble caused by the C++ plugin, so all modules are allowed to reload.

      • 3. require.launch(module[, parameter1[, parameter2,…]])

        Launch the new Nashorn virtual machine in the new thread, and load the module. The loaded module is main module and this method could implement the behavior described by Cluster.

      • 4. Load the module with the name which does not contain the path prefix (./, ../, /). After searching fails by core module name, insert a java module loading step before loading according to Node module. If success, directly return this module. For example, there is a module class app.Jmodule in current ClassLoader, using require('app.Jmodule') to load this module before loading Node module.

      • 5. The global directory loading location does not include $PREIFX/lib/node, because there is no suitable place to configure node_prefix.

      • 6. The added outer wrapper when loading module, addes parameters and java two parameter.


        (function (exports, require, module, __filename, __dirname, parameters[, java]) {
            // your module code
        });
        

        The parameters is the parameter Array passed by require.

        When implementing java plugin, the java variable is the associated java object instance, and the js accesses the corresponding java object via this object. For the other module types, the java object is undefined.

      • 7. The require.extensions, despite being discarded by node.js document, actually could be used to extend the stronger module support abilities by user, so it is kept. The key in this object is the file extension and value is function(path, parameters). Here the path is the absolute path of the module file, and parameters is the parameter passed by require. We have no idea why the designer discards this extension.

      • 8. The implementation of Cluster version for the node.js classic example.

        example.js


        if (--parameters[0] > 0)
            require.launch(__filename, parameters[0]);
        var http = require('http');
        var hostname = '127.0.0.1';
        var port = 3000;
        var Thread = Java.type('java.lang.Thread');
        var server = http.createServer(function(req, res) {
            res.statusCode = 200;
            res.setHeader('Content-Type', 'text/plain');
            res.end('Hello World ' + Thread.currentThread() + '\n');
        });
        server.listen(port, hostname, function() {
            console.log('server launch');
        });
        

        Use java –jar limax.jar node example.js 3 to launch the server, three server instances have been launched. The key is the first two lines, and require.launch coordinates with require parameter to provide Cluster support. The service thread name could be seen when using browser to access http://127.0.0.1:3000/. When refreshing the browser, the service thread name has not changed, wihch reflects the Keep-Alive feature. When restarting the browser access, the thread name has changed, which reflects the Cluster feature.

      • 9. The communication between the virtual machine threads is the basis to implement the Cluster, which could refer the implementation of limax.node.js.module.Net. The basic method is implementing the own plugin, exchanging the data through class staic members, and correctly synchronizing.


    • Net

      This module uses the asychronous IO support class of the java.nio.channels to implement, which is corresponding to the js asychronous feature.

      • 1. The java itself only supports the TCP service, and does not support the LocalDomain service.

      • 2. The server.listen port-binding failure will directly report the exception, however the node.js does not report but repeatly retry, which should be the compromise to support the Cluster.

      • 3. The node.js document requires that the server.listen could be executed mutliple times, which should be the compromise to support the Cluster, but it is not allowed here.

      • 4. The server.maxConnections mentioned in the node.js document has no meaning in the Cluster environment, but the limax re-finds the meaning of this member. The ServerChannel is actually globally managed. The channel obtained by accept rotationly deliveries to each virtual machine. When the maxConnections limit in a virtual machine is exceeded, the channel is deliveried to the next virtual machine. This channel will be closed when all the virtual machines reject accepting it. So configuring this option coornidating with the number of Cluster could achieve the more reasonable load balance.

      • 5. The second parameter initialDelay of the method socket.KeepAlive is still not clear.

      • 6. The ECHO server and client provided in the node.js document, although most of time can be run correctly, actually is not reasonable. It must be clear at any time that the TCP is a stream, so it should not assume that a packet is able to carry all the data, even though the amount of data is very small.


    • OS

      In theory, since the application runs on the java virtual machine, the issue of operating system level should not be considered, and this module just provides the information provided by java virtual machine, including os.arch(), os.endianess(), os.homedir(), os.hostname(), os.networkInterfaces(), os.platform(), os.release(), os.tmpdir(), os.type(), and os.userInfo(). The information returned by some methods might have some difference to that mentioned in the node.js document, such as that x64 might be the amd64 here.


    • Path

      Basically consistent with node.js document, except that path.win32 equals to path.posix, it should be said that both are equivalent to path.java. It is no need too much to consider the system-related issue and the explanation from the java virtual machine level is acceptable.


    • Process

      The java virtual machine does not require too many process-related features, so this module just provides process.chdir(), process.cwd(), process.env, process.exit(), process.exitCode, process.hrtime(), process.memoryUsage(), process.nextTick(), process.platform, process.stderr, process.stdin, and process.stdout. Among them, process.memoryUsage() returns the memory usage of java virtual machine. Different from the description in node.js, process.nextTick() is completely implemented with setImmediate().


    • Punycode

      Since the node.js module itself discards it, it is not implemented.


    • Query String

      Pure js code, is completely implemented.


Prev Next