Electron JS: Handle CMD+Q in OS X

When creating an Electron desktop application you will find that it does not, out of the box, support the traditional keyboard shortcut CMD+Q to close your application when running on OS X. To solve this situation, you simply need to import the ‘globalShortcut’ object from Electron, check for OS X ‘Darwin’, add a listener for the key combination, and when that combination is hit quit the application.

If you are using the Electron template code for your Main.js file (might be different if you are using custom code, but you can figure it out easy), here is what you need to do:

  1. Add ‘globalShortcut’ to your electron library import statement
const {app, BrowserWindow, Menu, globalShortcut} = require('electron');
  1. In your ‘createWindow’ function, add the following code to check for OS X ‘Darwin’ and add a listener to the CMD+Q key combination that executes the ‘quit’ function on the application
if (process.platform === 'darwin') {
    globalShortcut.register('Command+Q', () => {
        app.quit();
    })
}

Node.js: Simple Queuing for File Processing

QueueManager (JavaScript)

For the past few months I have been in the process of creating a custom, enterprise
grade, distributed media transcoding/encoding system for my employer. Because the
system is meant to be stand alone and can be integrated into any of the company’s
web products it needed to be extremely robust, meaning it needed to handle the
processing of any number of media files being passed to it at any given time and by
any number of clients. It is for this purpose that I used Node.js as the programming
platform. Node has the speed required for a system like this due primarily to its
non-blocking IO implementation.

Because the transcoder has to handle an unspecified number of videos added to it
at any given time, by any number of clients, it needed the ability to asynchronously
handle the addition of new media, queue that media for transcoding, while at the
same time be actively processing media that was previously queued. For this I needed
a simple and easy to understand queuing mechanism. Below is what I came up with.

The code below was written to deal with the processing of a file at the time it
is added to a directory being watched by the transcoding service. To put it simply:

  1. A Node file system watcher, such as Chokidar, watches a specified directory
  2. Each time a file is added to that directory it is wrapped in a ‘File Processor’
    (described below) that is responsible for processing that file type
  3. The processor is then added to the ‘QueueManager’ (described below). The manager places the processor in the primary queue
  4. If the manager is currently processing, files nothing happens after the processor is added to the queue
  5. If the manager is not processing, it will iterate over the main queue removing processors in the main queue and placing a reference to each processor’s ‘process’ method into a processing queue (see Async File Processor below)
  6. Once the main queue has been emptied, the processing queue is passed to the Async library for processing in either a series (one at a time) or parallel (each processor spun off onto its own sudo-subprocess) – see Async Library for details on implementation

Possible Issues:

Question: What happens if the main queue is constantly being added to while the manager is trying to empty it?

Answer: if there is no halt in main queue additions an infinite loop would occur.

Likelihood: Extremely low considering the system and its use.

/**
 - Created by Tim on 5/28/15.
 */

var async = require('async'),
    logger = require('./logger'),
    _ = require('underscore');

var component = 'QueueManager: ';
var queue = [];
var isProcessingQueue = false;
var isParallelProcessingActive = false;

// Event handler called when Async is done processing the current queue
function queueProcessingComplete(err, results){
    isProcessingQueue = false;

    if(err){
        logger.error(component + 'Error Processing queue: ERR-MSG: ' + err.message);
    }else{
        processQueue();
    }

}

// Processes the queue by moving all current items in the queue
// into a temporary list which is then handed to the Async library
// for processing in either series or parallel depending on need
function processQueue(){
    if(!isProcessingQueue){
        var managerList = [];
        var shifted = undefined;
        var flag = true;

        while(flag) {
            shifted = queue.shift();
            if(_.isUndefined(shifted)){
                flag = false
            } else {
                managerList.push(shifted.process);
            }
        }

        if(managerList.length > 0) {
            isProcessingQueue = true;
            // Execute each of the Transcoders in series
            if(isParallelProcessingActive){
                async.parallel(managerList, queueProcessingComplete);
            } else {
                async.series(managerList, queueProcessingComplete);
            }
        }
    }
}

// Public function for adding 'processors' to the queue
exports.pushToQueue = function(processor){
    queue.push(processor);
    processQueue();
};

Async File Processor (JavaScript)

The Async library requires a processing function to be passed to it that accepts a callback
function. The callback is used by the processing function to notify Async of
either its success or failure in performing its job. For that reason I have created
the ‘Processor’ template below.

By using a JavaScript ‘Constructor Function’ to create a new object that wraps the
Async processing function, one can maintain a reference through ‘that’ to any and
all relevant objects and data necessary for not only the processing of the file but
for returning results via the Async callback function.

/**
 * Created by Tim on 5/27/15.
 */

var fs = require('fs-extra'),
    logger = require('./../utils/logger'),
    _ = require('underscore');

var component = 'Processor: ';

// Constructor Function: creates a new unique processor
function Processor(file){
    // Allow reference to instance in callbacks
    var that = this;

    //'Private' Variables
    this._file = file;
    this._active = true;
    this._completeCallback = undefined;

    //'Private' Methods

    //'Event Handlers' Methods
    this._handleProcessingComplete = function (err, results) {
        if(err){
            var msg = component + 'File processing did not complete successfully' +
                '. ERR-MSG: ' + err.message;

            logger.error(msg, null);

            // Your processing error code here

            // End processing and hand execution back to queue
            that._completeCallback(null, new Error(msg));

        } else {

            // Your processing complete handling code here

            // End processing and hand execution back to queue
            that._completeCallback(null, results);
        }
    };

    //'Public' Methods
    this.process = function (callback) {
        // Allow notification of processing completion
        that._completeCallback = callback;

        // Prepare for file processing code here

        // Only execute processing task if initialization was successful
        if(that._active){

            // Non-blocking IO File processing code here that eventually calls the
            // that._handleProcessingComplete function which in turn calls the
            // Async callback function to notify processing is complete

        } else {
            // End processing and hand execution back to queue
            that._completeCallback(null, []);
        }
    };
}

module.exports = Processor;

Conclusion

That about does it, a simple queuing mechanism for Node.js file processing. As always
any feedback or suggestions are welcome so long as they are constructive.

Node.js + Chokidar: Wait for file copy to complete before modifying

If you have ever spent any time dealing with folder watchers in pretty much any language, you will probably have noticed that the watcher usually notifies your application of a new file added to the folder the instant the file is added to the folder’s index. This however does not mean that the file is complete, it may still be in the process of being copied or saved to the disk. This creates a problem when you are watching for new files so that they can then be processed in some manner. To get around this you will need to check the API for the language/platform you are using to find out if the IO library has a way to check if a file is whole before processing.

I ran into this same issue while building a bulk video file transcoding system on top of the Node.js JavaScript platform. Unfortunately I could not find a built in method for checking if a file was completely saved before acting on it and so had to handle this myself. The following assumes you know how to use Chokidar or some other Node file watcher package from NPM. The function of interest is titled ‘checkFileCopyComplete’, hopefully this will help speed things up if you are looking for this solution.

// Setup video source folder observer for notifications of new files
var chokidar = require('chokidar');

var watcher = chokidar.watch(config.videoRawFolder, {
    persistent: true,
    followSymlinks: false,
    usePolling: true,
    depth: undefined,
    interval: 100,
    ignorePermissionErrors: false
});

watcher
    .on('ready', function() { logger.info('Initial scan complete. Ready for changes.'); })
    .on('unlink', function(path) { logger.info('File: ' + path + ', has been REMOVED'); })
    .on('error', function(err) {
        logger.error(component + 'Chokidar file watcher failed. ERR: ' + err.message);
    })
    .on('add', function(path) {
        logger.info('File', path, 'has been ADDED');

        fs.stat(path, function (err, stat) {

            if (err){
                logger.error(component + 'Error watching file for copy completion. ERR: ' + err.message);
                logger.error(component + 'Error file not processed. PATH: ' + path);
            } else {
                logger.info(component + 'File copy started...');
                setTimeout(checkFileCopyComplete, fileCopyDelaySeconds*1000, path, stat);
            }
        });
    });

// Makes sure that the file added to the directory, but may not have been completely copied yet by the
// Operating System, finishes being copied before it attempts to do anything with the file.
function checkFileCopyComplete(path, prev) {
    fs.stat(path, function (err, stat) {

        if (err) {
            throw err;
        }
        if (stat.mtime.getTime() === prev.mtime.getTime()) {
            logger.info(component + 'File copy complete => beginning processing');
            //------------------------------------- 
            // CALL A FUNCTION TO PROCESS FILE HERE
            //-------------------------------------
        }
        else {
            setTimeout(checkFileCopyComplete, fileCopyDelaySeconds*1000, path, stat);
        }
    });
}

JavaScript: Unobtrusive

It all comes down to separation of concerns. When programming, separation of concerns deals with creating clear and concise boundaries between application components that have different responsibilities but work together to carry out a common overarching goal. So it is with the development of web user interfaces using HTML5, CSS3, and JavaScript. Each of these technologies work together to create interactive and beautiful user interfaces within the browser, but they each have very specific jobs that make these interfaces possible.

HTML: structures content in a very semantic (meaningful) and ordered way.

CSS: beautifies HTML by adding visual enhancements such as color, gradients, borders, padding, margin, fonts, animations, and  positioning.

JavaScript: adds behavior to HTML, allowing HTML to respond to DOM events as users interact with the web page within the browser.

Together these three technologies create a very powerful tool set for the modern web developer and web user interface designer. The difficult part for most web developers is not allowing the three, very closely related technologies, to bleed across their boundaries into each other creating tightly coupled code. This tightly coupled code is usually a result of CSS and JavaScript being placed directly in the HTML.

Unobtrusive method to the rescue. Merriam-Webster defines the word unobtrusive as not attracting attention in a way that bothers or annoys. Well, mashed together HTML, CSS, and JavaScript is bothersome and extremely annoying, especially when it comes to maintainability and defect repair. For this reason developers have begun to make sure their web user interfaces are completely separated. This is accomplished by following a few specific rules:

HTML

  1. keeping HTML markup in separate files

CSS

  1. keeping CSS markup in separate files
  2. referencing those files in the ‘head’ element of the HTML files
  3. never use ‘style’ elements in HTML
  4. never use ‘style’ attributes on HTML elements

JavaScript

  1. keeping JavaScript markup in separate files
  2. referencing those files in the ‘head’ element or at the bottom of the ‘body’ element of the HTML files
  3. never use ‘script’ elements to hold JavaScript code in HTML
  4. only use ‘script’ elements to references a JavaScript file
  5. never use HTML element attributes that bind to DOM events such as ‘onclick’ or ‘onmouseenter’

Unobtrusive JS Example:

<!--DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>JavaScript Event Binding</title>
    <script src="jsEventBinding.js"></script>
</head>
<body>
    <div id="click-me">Click Me</div>
</body>
</html>
/**
 * Created by Tim on 9/9/14.
 */

'use strict';

var elem = document.getElementById('click-me'); // a DOM element
elem.onclick = function () {
    // Do something nifty here
};

JavaScript: The Event Loop

JavaScript is event based, meaning everything that happens within a browser window/tab is the result of an event occurring and code responding to that event. There are hundreds of potential events that may need to be responded to throughout the life-cycle of an HTML page.

An important concept to understand, when it comes to JavaScript and the browser, is the event loop, the primary driver of this event based system. The event loop is controlled and managed by the browser which keeps the loop running and dispatches all events as they occur. Due to this, developers are free to focus 100% of their energy on identifying the events they are interested in and writing logic to respond accordingly to those events. This code that is invoked in response to an event is called an ‘event handler’ or ‘listener’.

One of the most complex parts of JavaScript programming is the fact that events are fired unpredictably and in an unpredictable order. This means JS code has to be written in an asynchronous manner with each listener having the ability to be executed independently of all others.

Unlike a lot of other languages out there, the JavaScript event loop is ‘non-blocking’ meaning that JavaScript does not allow the event loop to be monopolized by any single function. This includes I/O (input/output) events, instead of waiting for a file read to complete or a database call to return before moving on, JavaScript requires a listener to be provided and assigns that listener to the I/O return event and it moves on. Ultimately what this does is keep the browser window responsive and usable while long running tasks are taken care of asynchronously. This is a huge advantage being that the browser window is the user interface, which should remain responsive at all times.

Reference: Mozilla Developer Event Loop

To get an idea, here are just some of the most common events that front-end developers deal with on a daily basis, of course there are many more that are just as important as these:

Window Events

  • onload: fires after the page finished loading
  • onerror: fires when an error occurs
  • onresize: fires when the browser window is resized
  • onunload: fires when the page is unloaded or browser window closes

Keyboard Events

  • onkeydown: fires when the user presses a key down and holds it down
  • onkeypress: fires when the user presses a key down and then releases it
  • onkeyup: fires when the user releases the key

Mouse Events

  • onclick: fires when the user clicks on an HTML element
  • ondblclick: fires when the user double clicks on an HTML element
  • ondrag: fires when the user drags an HTML element
  • onmouseover: fires when a user hovers the mouse cursor over an HTML element
  • onmousemove: fires when a user moves the mouse cursor over an HTML element

Reference: Mozilla Developer Web Events

JavaScript: Exception Handling

Exception handling in JavaScript is extremely similar to that in C# or Java. Js utilizes the familiar try-catch blocks to capture exceptions and handle them. You simply wrap code that might throw an exception in the try and then provide a catch to handle the captured exceptions.

Unlike C# and Java, JavaScript does not allow multiple catch blocks nor does it handle capturing exceptions based on specificity. For this you must implement your own code by checking the exception name or using reflection methods to identify the exception types you are after. This is a little cumbersome but doable.

'use strict';

// Exception Handling
//  1. Use 'throw' to create and throw an Exception
//  2. Use the 'name' property to give the Exception an identifiable name
//  3. Use the 'message' property to give the Exception a meaningful message for the user
//  4. Standard Try-Catch as we are used to in Java and C#
//  5. Place code which might create an error in the 'try' block
//  6. Place rescue code in the 'catch' block
//  7. 'try' blocks can only have one 'catch' and one only
//  8. Must check Exception name in order to handle more than one type of Exception at a time

try{
    // Code that can cause an error during execution

    // Code actually throwing an Exception
    throw {
        name: "CustomErrorType",
        message: "I just threw an error at you."
    }
}catch(error){
    if(error.name === "SomeOtherError"){
        // Do something here
    }

    if(error.name === "CustomErrorType"){
        // Code to rescue processing from the error
        console.log("Captured and error: " + error.name);
        console.log("Its message is: " + error.message);
    }
}

JavaScript: Cascading Methods (Method Chaining)

One extremely useful programming pattern that can be implemented in JavaScript is that of ‘cascading methods’ also known as ‘method chaining’. Method chaining is accomplished in JS by simply returning the object that was just operated on as the result of the method call. By doing this, a developer can call a method and then instantly call another method on the same object without referencing the object or capturing the result of the previous method call.

This is possible due to the fact that the result of a method is returned directly after the method call itself and is therefore used as the object of interest for the following (chained) method call (see example code below).

'use strict';

// Cascading/Chaining Methods
//  1. Return 'this' instead of 'undefined' at the end of your Methods
//  2. This allows the focused Object to be returned and additional Methods to be called on it

var person = {
    first_name: 'First name not provided',
    middle_initial: 'initial not provided',
    last_name: 'Last name not provided',
    age: 'Age not provided',

    change_first_name: function(new_name){
        this.first_name = new_name;
        return this; // Return the current object
    },

    change_last_name: function(new_name){
        this.last_name = new_name;
        return this; // Return the current object
    },

    change_middle_initial: function(new_initial){
        this.middle_initial = new_initial;
        return this; // Return the current object
    }
};

// Call each of the Object's methods one right after the other
person.change_first_name('Tim').change_middle_initial('').change_last_name('Clark');

console.log('First Name: ' + person.first_name);
console.log('Middle Initial: ' + person.middle_initial);
console.log('Last Name: ' + person.last_name);