ZooKeeper JavaScript Implementation

ZooKeeper JavaScript Implementation

Def from Apache: ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services.

ZooKeeper Node Class Structure:

class ZooNode {
  key = null;
  value = null;
  watchers = [];
  children = [];
  constructor(key, value, watcherFn) {
    this.key = key;
    this.value = value;
    if (watcherFn) {
      this.watchers.push(watcherFn);
    }
  }
}

ZooKeeper Implementation:


class ZooKeeper {
  root = new ZooNode('root');

  /*get path segments*/
  getPathSegments(path) {
    const ps = path.split('/');
    ps.shift();
    return ps;
  }

  /*call watchers*/
  callWatchers(fns) {
    fns.forEach(fn => fn?.());
  }

  /*find a node and it's watchers*/
  dfs(root, pathSegments, idx, watcherFns = []) {
    if (!pathSegments.length) {
      return { node: root, watcherFns: [...root.watchers] };
    }
    const key = pathSegments[idx];
    watcherFns = watcherFns.concat(root.watchers);
    const nodeIdx = root.children.map(p => p.key).indexOf(key);
    if (nodeIdx > -1) {
      const nextRoot = root.children[nodeIdx];
      if (pathSegments.length === idx + 1) {
        watcherFns = watcherFns.concat(nextRoot.watchers);
        return { node: nextRoot, watcherFns };
      }
      return this.dfs(nextRoot, pathSegments, idx + 1, watcherFns);
    }
  }

  create(path, value) {
    const ps = this.getPathSegments(path, true);
    const newChildKey = ps.pop();
    const { node: parentNode, watcherFns } = this.dfs(this.root, ps, 0) || {};
    if (parentNode) {
      parentNode.children.push(new ZooNode(newChildKey, value));
      this.callWatchers(watcherFns);
    } else {
      console.log(`unable to add, path is not exist: ${path}`);
    }
  }

  setValue(path, value) {
    const ps = this.getPathSegments(path, true);
    const { node, watcherFns } = this.dfs(this.root, ps, 0) || {};
    if (node) {
      node.value = value;
      this.callWatchers(watcherFns);
    } else {
      console.log(`unable to update, path is not exist: ${path}`);
    }
  }

  getValue(path) {
    const ps = this.getPathSegments(path, true);
    const { node } = this.dfs(this.root, ps, 0) || {};
    if (node) {
      return node.value;
    } else {
      console.log(`unable to update, path is not exist: ${path}`);
    }
  }

  watch(path, fn) {
    const ps = this.getPathSegments(path, true);
    const { node } = this.dfs(this.root, ps, 0) || {};
    if (node) {
      node.watchers = [fn];//concat for multiple listeners
    } else {
      console.log(`unable to update, path is not exist: ${path}`);
    }
  }
}

Execution:

let z = new ZooKeeper();
z.create('/a', 'foo');
z.create('/a/c', 'bar');
z.create('/a/d', 'foo_d');
z.setValue('/a/d', 'foo_d_update');
console.log(z.getValue('/a/d')); 
//foo_d_update

z.watch('/a/d', () => { console.log('a watch at /a/d') });
z.watch('/a', () => { console.log('a watch at /a') });
z.setValue('/a/d', 'foo_d_update_again'); 
//1. a watch at /a 
//2. a watch at /a/d

z.setValue('/a', 'foo_a_update_again');
//a watch at /a

Recursive Implementation for Asyn.series

We are going to look into a recursive solution for the series method. Note that recursive always comes with a performance dent with a deeper call stack of instruction execution in the hardware.

The idea here will start with a function1 from the tasks array and then pass a wrapped callback function on reading the result of function1, then invoking function2 and vice versa. If any error occurs in the process, the algorithom will exit by calling the final callback with error and results collection.

    fn((error, result) => {
      if (error) {
        callback(error, results);
        return;
      }
      results.push(result);
      //invoke a recursive call to next method 
    });

The full code is available in the below code block and it is ready to execute in your console for analysis or debug to see how this works in action.

const sampleTasks =  [ function (callback) { setTimeout(function () { console.log("1"); callback(null, "one"); }, 200); }, function (callback) { setTimeout(function () { console.log("2"); callback(null, "two"); }, 100); }, function (callback) { setTimeout(function () { console.log("3"); callback(null, "three"); }, 90); }, function (callback) { setTimeout(function () { console.log("4"); callback(Error("some error")); }, 10); }, function (callback) { setTimeout(function () { console.log("5"); callback(null, "five"); }, 1000); }, ];
 
function onSeriesCompleted(error, results) {
  console.log("Error stack", error);
  console.log("Results of successfully executed tasks", results);
}

function startTask(tasks, callback, counter = 0, results = []) {
  if (counter < tasks.length) {
    const fn = tasks[counter];
    const fn2 = tasks[counter + 1];
    fn((error, result) => {
      if (error) {
        callback(error, results);
        return;
      }
      results.push(result);
      startTask(tasks, callback, ++counter, results);
    });
  }
}

function series(tasks, finalCallback) {
  startTask(tasks, finalCallback);
}

series(sampleTasks, onSeriesCompleted);

Output

Polyfill for Async.series(tasks, callback)

The series method was quite a different one when we compared it to other sequential call stacks. The series method will take two arguments one is an array of functions and another one is the finalCallback which is optional to call with the first occurred error and obtained results until then.

 

async.series( 
  [fn-1(callback), fn-2(callback), ... fn-n(callback)], 
  finalCallback( error, results ){ ... }
);

Now will talk about the implementation. We can solve this problem by making Asyncify each task from the tasks array. This way, we can extract the result from each task, review for errors, and move to the next task. Let’s move to the code implementation.

Asyncify a task


function Asyncify(task) {
  return new Promise((resolve, reject) =&gt; {
    task((error, result) =&gt; (error ? reject(error) : resolve(result)));
  });
}

That’s all we have completed with the implementation, and we need to use this method to queue up the tasks in a sequential way of execution.

async function series(tasks, finalCallback) {
  const allResults = [];
  for (let i = 0; i &lt; tasks.length; i++) {
    try {
      allResults.push(await Asyncify(tasks[i]));
    } catch (error) {
      finalCallback(error, allResults);
      break;
    }
  }
  console.log(allResults);
  finalCallback(null, allResults);
}

This solution is based on Promise API, and you can execute the below code in the browser console for quick analysis. And we can also implement a recursive-based solution and will look into it in our next post.
The full spec you can read from https://caolan.github.io/async/v3/docs.html#series.

Now, add some sample tasks to test and see how this works.

const sampleTasks =  [ function (callback) { setTimeout(function () { console.log("1"); callback(null, "one"); }, 200); }, function (callback) { setTimeout(function () { console.log("2"); callback(null, "two"); }, 100); }, function (callback) { setTimeout(function () { console.log("3"); callback(null, "three"); }, 90); }, function (callback) { setTimeout(function () { console.log("4"); callback(Error("some error")); }, 10); }, function (callback) { setTimeout(function () { console.log("5"); callback(null, "five"); }, 1000); }, ];

function onSeriesCompleted(error, results) {
  console.log("Error stack", error);
  console.log("Results of successfully executed tasks", results);
}

function Asyncify(task) {
  return new Promise((resolve, reject) => {
    task((error, result) => (error ? reject(error) : resolve(result)));
  });
}

async function series(tasks = [], finalCallback) {
  const allResults = [];
  for (let i = 0; i < tasks.length; i++) {
    try {
      allResults.push(await Asyncify(tasks[i]));
    } catch (error) {
      finalCallback?.(error, allResults);
      return; //remove if you want continue even after error
    }
  }
  finalCallback?.(null, allResults);
}

series(sampleTasks, onSeriesCompleted);

Output

Angular JS 1.x Security CSRF Protection

Defination: (Source:wiki)
Cross-site request forgery is an attack technique by which the attacker can trick an authenticated user into unknowingly executing actions on your website.
(or)
Cross-site request forgery, also known as one-click attack or session riding and abbreviated as CSRF or XSRF, is a type of malicious exploit of a website where unauthorized commands are transmitted from a user that the website trusts.
Prevention methods:

  1. Check standard headers to verify the request from same origin or not
  2. Check CSRF token and it’s validity against to user session Id.

AngularJS will support by default to avoid CSRF attacks, we need to send XSRF-TOKEN into browsers cookie, then angular will automatically pick and append X-XSRF-TOKEN as a header.

Cookie info:

AngularJS with a general $http promise will prepare header with X-XSRF-TOKEN, if one of the domain cookies contains a token with XSRF-TOKEN key name.
If we want to change HTTP header key name, with custom  XSRF token we need to provide defaults.xsrfHeaderName so that angular will prepare with custom token key.
Please check below code snap from angularJS framework for better understanding of how it works:

var xsrfValue = urlIsSameOrigin(config.url) ?
     $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
     : undefined;
if (xsrfValue) {
  reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
}

And check out this working example, inspect HTTP headers via developer tools.

 var app = angular.module('csrf_example', []);
 app.controller('MainCtrl', function($scope, $log, $http) {
 document.cookie = "XSRF-TOKEN=sjdjsdjsdbjhfg";
 $http.get('path').then(function() {
 console.log('Network call done!');
 });
 });

Angular 2 – Router – Well usage of Depth first search (DFS)

One of the major module in angular 2 is router module, it will handle application navigation, authorization and application modularity.
Definition [Angular 2 router by @vsavkin]:
A router state is an arrangement of application components that defines what is visible on the screen.
Router is a tree of components, which will be navigable by user actions and based on URL segments it will move from one route to other route.
Sample routes: it’s an array of routes.

[{path: '', pathMatch: 'full', redirectTo: '/home'},
{ path: 'home', component: GoGreenAgriHome }
{ path: 'farms', component: AgriFarms },
{ path: 'agri-tech', component: AgriTech
children: [
{ path: ':id', component: AgriTechTypes}
]
}
]

A example code you can find at Github.

Angular 2.0 Hello World in 2 min

Finally angular js 2 shipped with the new web components. It’s modular based framework, which contains compiler, core, common, http and etc…
After Adobe Flex SDK, Angular is the first framework to address rapid fast development application needs, with the addition of angular material components it will become one of the best frameworks to build applications with new web standards.
To avoid complexity of setting up environment I made system config, which look for dependencies on UNPKG npm cdn network. So, it will avoid you all the process to setup your environment. Lets enter into application example.

  • Angular 2 is simple, latest web standards, lightning fast and works everywhere.
  • Angular with TypeScript will give us good application code maintenance, great editor support.
  • Angular-cli will help to create and build apps.

Angular2 With TypeScript Hello Word example:

  1. First we need a application root component, in our example we are using AppComponent as root component.
  2. A NgModule to initialize our app.
  3. Finally need to bootstrap our app by mentioning root module.
  4. Need a html wrapper to instantiate html component in the browser. i.e. <app></app>
  5. SystemJS config to find required module loading.
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import {Component} from '@angular/core';
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
//Root Component
@Component({
    selector: 'app',
    template: `&lt;h1&gt;Hello {{ name }}!&lt;/h1&gt;`
})
export class AppComponent {
    name: string;
    constructor() {
        this.name = 'Angular 2';
    }
    //Lifecycle init method
    ngOnInit() {
      console.log('AppComponent initialisation');
    }
}
//Root Module: NgModule to bootstrap your application
@NgModule({
    imports:      [ BrowserModule ], /*Allows your app’s module to use code from another module.*/
    declarations: [ AppComponent ],  /*Declares all components used in the  module.*/
    bootstrap:    [ AppComponent ]   /*Tells Angular 2 to bootstrap the 'Appcomponent' as the root of the application.*/
})
export class AppModule { }
//Bootstrap Angular 2 with the 'AppModule' NgModule.
platformBrowserDynamic().bootstrapModule(AppModule);

HTML wrapper:

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;Angular seed project&lt;/title&gt;
  &lt;meta charset="UTF-8"&gt;
  &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;
  &lt;script src="https://unpkg.com/typescript@2.0.0/lib/typescript.js"&gt;&lt;/script&gt;
  &lt;script src="https://unpkg.com/core-js/client/shim.min.js"&gt;&lt;/script&gt;
  &lt;script src="https://unpkg.com/zone.js/dist/zone.js"&gt;&lt;/script&gt;
  &lt;script src="https://unpkg.com/zone.js/dist/long-stack-trace-zone.js"&gt;&lt;/script&gt;
  &lt;script src="https://unpkg.com/systemjs@0.19.37/dist/system.src.js"&gt;&lt;/script&gt;
  &lt;script&gt;
    var rxjsVer = "5.0.0-beta.12";
    //System Js Config, you may move it into systemjs.config.js
    System.config({
      transpiler: 'typescript',
      typescriptOptions: {emitDecoratorMetadata: true},
      map: {
        'app': './main.ts',
        '@angular': 'https://unpkg.com/@angular',
        'rxjs': 'https://unpkg.com/rxjs@' + rxjsVer
      },
    });
    //Load application root component file
    System.import('app').catch(function(err) {
      console.error(err);//If any eerors while loading root module
    });
  &lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;app&gt;Loading...&lt;/app&gt;
&lt;/body&gt;
&lt;/html&gt;

Working Plunker: http://embed.plnkr.co/prB7BO
Angular 2 ES5 Example:
working plunker:
http://embed.plnkr.co/y5tuUIBEBDWO3d254pCf

Arrow Functions – Environment Remembering

Arrow functions are mainly intended to resolve several common pain points of traditional Function Expression. it will provide Lexical this binding and Short hand notations with ‘=>’ arrow symbol.
Definition (ECMA6 Standard): Arrow functions bind this lexically, bind return in the Block body case so it returns from the immediately enclosing arrow function.
Syntax: ArrowParameters [no LineTerminator here] => ConciseBody
[table class=”table table-striped”]
Arrow Function Syntax,Arrow Function Examples
(parameters) -> expression,”(x,y) => x * y”
(parameters) -> statement,() => console.log(“Hello JS”);
(parameters) -> { statements },(s) => { n = s.length(); return n;}
[/table]
Simply: which provide a shorter notation of anonymous functions + which binds only lexical this, no dynamic this
Pros: 

  • Much easier for the compiler to optimize, because it doesn’t need to worry about variables escaping from their lexical context, and so doesn’t need to go for chaining lookup.
  • Scope safety, Compactness, and Readability
  • An arrow function expression has a shorter syntax compared to function expressions
    Lexically binds the this value
  • Arrow functions are always anonymous
  • Arrow functions cannot be used as constructors.
  • Arrow functions never have an arguments objects
  • “=>” has only lexical this, no dynamic this

Cons: Not fit when a dynamic context is required like defining methods and get the target from this when handling events.
Lexical (Static) VS Dynamic Scope:
Lexical: Creates a new copy of variable names and values, organized in a hierarchy called “the environment”.
Dynamic: All variable names and their values live in one global table.
Common mistakes of using Arrow Functions:

  • new (() => {}) throws TypeError: (intermediate value) is not a constructor
  • a = (() => {});a.arguments;
    Throws TypeError: ‘caller’ and ‘arguments’ are restricted function properties and cannot be accessed in this context.

JSA
 

Javascript Closures

Many people are looking for JavaScript learning experience simple and covering info without confusion. I thought to introduce a series of ‘SimpleCards’ to explain JavaScript concepts in effective and efficient way. To avoid confusion on JS Closure concept I made a simple card for it.
Definition (Mozilla Docs): Closures are functions whose inner functions refer to independent (free) variables (variables that are used locally, but defined in an enclosing scope). In other words, the functions defined in the closure ‘remember’ the environment in which they were created
Simply: A closure is a special kind of object that combines two things: a function + environment in which that function were created.
Pros:

  • Bind a variable to an execution context
  • Emulating private methods with closures

Cons: Unnecessarily create closures will affect script performance both in terms of

  • Processing speed and
  • Memory consumption
    JavaScript Closures
    JavaScript Closures

Promises/deferred objects – asynchronous computations

Definition: (ECMA-2015)
A Promise is an object that is used as a placeholder for the eventual results of a deferred (and possibly asynchronous) computation.
A Promise represents an operation that hasn’t completed yet, but is expected in the future, while it’s in execution. Promises are very useful for remote calls to overcome network latency, once network responded promise will resolve or reject based on returned data.
Promise Abstract Operations:
[table class=”table table-striped”]
Field Name,Value type,Meaning
[[Promise]], An object, An object that is usable as a promise.
[[Resolve]], A function object, The function that is used to resolve the given promise object.
[[Reject]], A function object, the function that is used to reject the given promise object.
[/table]
We are using angular 1.x $q service to illustrate promises. $q is a similar implementation of promises concept by Kris Kowal’s Q.js. we can generate a new instance of promise by calling $q.defer(), which is equals new Promise() in ES 6. Deferred object contains promise property which is responsible for callback function executions such as onFulfilled, onRejected and progressBack.
Flex frameworks Action Script 3.0 also have a similar implementation like Q.js as AsyncToken,AsyncResponder. The syntax looks like below

//Flex AsyncToken usage
var token:AsyncToken = service.send();
token.addResponder(new mx.rpc.Responder(result, fault));

The $q object:
[table class=”table table-striped”]
Method Name,Meaning
$q. defer(),new instance of promise will returns a deferred object
$q.all(ArrayOfPromises),Combines multiple promises into a single promise that is resolved when all of the input promises are resolved.
[/table]
The Deferred object:
$q.defer() will returns a deferred object, which have below methods:
[table class=”table table-striped”]
Method Name,Meaning
deferred.resolve(value),resolves the derived promise with the value.
deferred.reject(reason),rejects the derived promise with the reason.
deferred.notify(value),provides updates on the status of the promise’s execution. This may be called multiple times before the promise is either resolved or rejected.
deferred.promise{}, An object that is usable as a promise
[/table]
The Promise object:
[table class=”table table-striped”]
Method Name,Meaning
then:function(onFulfilled, onRejected, progressBack)“, “it will hook result,fault and progress methods to a promise. then calls one of the callback methods asynchronously as soon as the result is available.”
catch(errorCallback), “shorthand for promise.then(null, errorCallback).one more way to provide fault method.”
[/table]
Below example will illustrate promises usage,

//$q for promises
//create module
var myApp = angular.module("promisesApp",[]);
//get $q as global Q for better and simple analysis
angular.injector(['ng', 'promisesApp']).invoke(function ($q) {window.Q = $q;});
//promisesApp.controller("promisCtrl",["$q",function(Q){
function result(response){
 console.log("Resolved and Response is:"+response);
 }
function fault(reason){
 console.log("Rejected and Error info: "+reason);
 }
function notify(update){
 console.log("Notification: "+update);
 }
function asyncExecution(resultObj,isResolvable,atTime){
 var defered = Q.defer();
 var promise = defered.promise;
 //Simulating network latency
 setTimeout(function(isResolvable){
 if(isResolvable){
 defered.notify('resolving now...');
 defered.resolve(resultObj);
 defered.notify('resolved');//notify Never prints, once promise resolved or rejects
 }
 else{
 defered.notify('rejecting now...');
 defered.reject("Got an Error");
 defered.notify('rejected');//notify Never prints, once promise resolved or rejects
 }
 },atTime,isResolvable);
 return promise;
}
var p1 = asyncExecution('p1',true,2000);
p1.then(result,fault,notify);
var p2 = asyncExecution('p2',false,3000);
p2.then(result,fault,notify);
var p3 = asyncExecution('p3',true,4000);
p3.then(result,fault,notify);

Output as following:

Notification: resolving now...
Resolved and Response is:p1
Notification: rejecting now...
Rejected and Error info: Got an Error
Notification: resolving now...
Resolved and Response is:p3

Promises Chaining:
Chaining is useful when we need to make synchronous calls to server. always promises will look for failure handler, if not present in current then-able it will look for next available then-able. chaining will continue only if a success handler on returning a promise object.  below example will explain about chaining of multiple promises.

//Chaining
var p1 = asyncExecution('p1',true,2000);
var p2 = asyncExecution('p2',true,3000);
var p3 = asyncExecution('p3',true,4000);
//promises will look for failure handler, if not present
//in current then-able it will look for next available then-able
p1.then(function(a){result(a);return p2})
//return Promise to continue chaining
.then(function(a){result(a);return p3})
.then(result);

Output as following:

Resolved and Response is:p1
Resolved and Response is:p2
Resolved and Response is:p3

Combine Multiple promises as one promise:

//let combin and know all promises are done or not
var p1 = asyncExecution('p1',true,2000);
var p2 = asyncExecution('p2',true,3000);
var p3 = asyncExecution('p3',true,4000);
Q.all([p1,p2,p3])
.then(function(){console.log('All Async tasks done')},
     function(){console.log('Failed:Soming worng!!')})
.finally(function(){
     console.log('Finally: I will execute any way')});

Output as following:

All Async tasks done
Finally: I will execute any way