Example #1
0
module.exports = internals.Server = function (/* host, port, options */) {        // all optional

    var self = this;

    Utils.assert(this.constructor === internals.Server, 'Server must be instantiated using new');

    // Register as event emitter

    Events.EventEmitter.call(this);

    // Validate arguments

    Utils.assert(arguments.length <= 3, 'Too many arguments');

    var argMap = {
        string: 'host',
        number: 'port',
        object: 'options'
    };

    var args = {};

    for (var a = 0, al = arguments.length; a < al; ++a) {
        var type = typeof arguments[a];
        var key = argMap[type];
        Utils.assert(key, 'Bad server constructor arguments: no match for arg type ' + type);
        Utils.assert(!args[key], 'Bad server constructor arguments: duplicated arg type: ' + type);
        args[key] = arguments[a];
    }

    // Set basic configuration

    this._started = false;
    this.settings = Utils.applyToDefaults(Defaults.server, args.options);
    this.settings.host = args.host ? args.host.toLowerCase() : '0.0.0.0';
    this.settings.port = typeof args.port !== 'undefined' ? args.port : (this.settings.tls ? 443 : 80);

    if (this.settings.port) {
        this.settings.nickname = this.settings.host + ':' + this.settings.port;
        this.settings.uri = (this.settings.tls ? 'https://' : 'http://') + this.settings.host + ':' + this.settings.port;
    }

    // Extensions

    this._ext = {

        // The following extension functions use the following signature:
        // function (request, next) { next(); }

        onRequest: null,                            // New request, before handing over to the router (allows changes to the request method, url, etc.)
        onPreHandler: null,                         // After validation and body parsing, before route handler
        onPostHandler: null,                        // After route handler returns, before sending response
        onPostRoute: null                           // After response sent
    };

    // Set optional configuration
    // false -> null, true -> defaults, {} -> override defaults

    this.settings.cors = Utils.applyToDefaults(Defaults.cors, this.settings.cors);
    this.settings.monitor = Utils.applyToDefaults(Defaults.monitor, this.settings.monitor);
    this.settings.debug = Utils.applyToDefaults(Defaults.debug, this.settings.debug);
    this.settings.docs = Utils.applyToDefaults(Defaults.docs, this.settings.docs);

    // Initialize process monitoring

    if (this.settings.monitor) {
        if (!this.settings.monitor.subscribers) {
            this.settings.monitor.subscribers = {
                console: ['ops', 'request', 'log']
            };
        }

        this._monitor = new Log.Monitor(this);
    }

    // Create routing table

    Utils.assert(!this.settings.router.routeDefaults || !this.settings.router.routeDefaults.handler, 'Route defaults cannot include a handler');

    this._router = {
        table: {}                                   // Array per HTTP method, including * for catch-all
    };

    this._router.notFound = new Route({
        method: 'notFound',
        path: '/{p*}',
        config: {
            auth: { mode: 'none' },                 // In case defaults are set otherwise
            handler: 'notFound'
        }
    }, this);

    // Plugin interface (pack)

    this._pack = null;
    this.plugins = {};                              // Loaded plugins by plugin name
    this.api = {};                                  // Registered plugin APIs by plugin name

    // Initialize Views

    if (this.settings.views) {
        this.views = new Views(this.settings.views);
    }

    // Create server

    if (this.settings.tls) {
        this.listener = Https.createServer(this.settings.tls, this._dispatch());
    }
    else {
        this.listener = Http.createServer(this._dispatch());
    }

    // Helpers registry

    this.helpers = [];

    // State management

    this._stateDefinitions = {};

    // Generate CORS headers

    if (this.settings.cors) {
        this.settings.cors._origin = (this.settings.cors.origin || []).join(' ');
        this.settings.cors._headers = (this.settings.cors.headers || []).concat(this.settings.cors.additionalHeaders || []).join(', ');
        this.settings.cors._methods = (this.settings.cors.methods || []).concat(this.settings.cors.additionalMethods || []).join(', ');

        var optionsConfig = {
            path: '/{p*}',
            method: 'options',
            config: {
                auth: { mode: 'none' },                 // In case defaults are set otherwise
                handler: function (request) {

                    request.reply({});
                }
            }
        };

        this._router.cors = new Route(optionsConfig, this);
    }

    // Initialize cache engine

    if (this.settings.cache) {
        this.cache = new Catbox.Client(this.settings.cache);
    }

    // Authentication

    if (this.settings.auth) {
        this.auth = new Auth(this, this.settings.auth);
    }

    // Setup debug endpoint

    if (this.settings.debug) {
        this._debugConsole = new Helmet(this.settings.debug);
        var debugMarkup = this._debugConsole.getMarkup();
        this.route({
            method: 'GET',
            path: this.settings.debug.debugEndpoint,
            config: {
                auth: { mode: 'none' },                 // In case defaults are set otherwise
                handler: function (request) {

                    request.reply(debugMarkup);
                }
            }
        });
    }

    // Setup batch endpoint

    if (this.settings.batch) {
        this.settings.batch = Utils.applyToDefaults(Defaults.batch, (typeof this.settings.batch === 'boolean' ? {} : this.settings.batch));

        this.route({
            method: 'POST',
            path: this.settings.batch.batchEndpoint,
            config: Batch.config
        });
    }

    return this;
};
Example #2
0
function Route () {
  if (!(this instanceof Route)) return new Route();
  events.EventEmitter.call(this);
}
Example #3
0
function Importer () {
  events.EventEmitter.call(this);
}
Example #4
0
function FakeServer(options) {
    EventEmitter.call(this);

    this._server = null;
    this._connections = [];
}
Example #5
0
function Formatter() {
    EventEmitter.call(this);
}
Example #6
0
/**
 * @public
 * @constructor
 * @memberof log.logger
 * @since 1.0.0
 *
 * Represents a logger.
 *
 * @param {LoggerSettings} [settings] - the settings to be used to configure the logger.
 */
export default function Logger (settings) {
  EventEmitter.call(this);
  this.configure(settings);
}
function User(data) {
    this.data = data;
    this.on('user:save', sendMail);
    this.on('error', sendError);
    EventEmitter.call(this);
};
Example #8
0
var Base = module.exports = function Base(args, options) {
  events.EventEmitter.call(this);

  if (!Array.isArray(args)) {
    options = args;
    args = [];
  }

  this.options = options || {};
  this._args = args || [];
  this._options = {};
  this._arguments = [];
  this._hooks = [];
  this._composedWith = [];
  this._transformStreams = [];

  this.option('help', {
    alias: 'h',
    desc: 'Print the generator\'s options and usage'
  });

  this.option('skip-cache', {
    type: Boolean,
    desc: 'Do not remember prompt answers',
    default: false
  });

  this.option('skip-install', {
    type: Boolean,
    desc: 'Do not automatically install dependencies',
    default: false
  });

  // checks required paramaters
  assert(this.options.env, 'You must provide the environment object. Use env#create() to create a new generator.');
  assert(this.options.resolved, 'You must provide the resolved path value. Use env#create() to create a new generator.');
  this.env = this.options.env;
  this.resolved = this.options.resolved;

  // Ensure the environment support features this yeoman-generator version require.
  require('yeoman-environment').enforceUpdate(this.env);

  this.description = this.description || '';

  this.async = function () {
    return function () {};
  };

  this.fs = FileEditor.create(this.env.sharedFs);
  this.conflicter = new Conflicter(this.env.adapter, this.options.force);

  // Mirror the adapter log method on the generator.
  //
  // example:
  // this.log('foo');
  // this.log.error('bar');
  this.log = this.env.adapter.log;

  // determine the app root
  var rootPath = findUp.sync('.yo-rc.json', {
    cwd: this.env.cwd
  });
  rootPath = rootPath ? path.dirname(rootPath) : this.env.cwd;

  if (rootPath !== this.env.cwd) {
    this.log([
      '',
      'Just found a `.yo-rc.json` in a parent directory.',
      'Setting the project root at: ' + rootPath
    ].join('\n'));
    this.destinationRoot(rootPath);
  }

  var deprecatedFileUtils = deprecate.log.bind(null, [
    '#src() and #dest() are deprecated. Please read the documentation to learn about',
    'the new ways of handling files. http://yeoman.io/authoring/file-system.html'
  ].join('\n'));

  Object.defineProperty(this, 'src', { get: deprecatedFileUtils });
  Object.defineProperty(this, 'dest', { get: deprecatedFileUtils });
  Object.defineProperty(this, '_', {
    get: deprecate.log.bind(null, [
      '#_ is deprecated. Require your own version of', chalk.cyan('Lodash'), 'or', chalk.cyan('underscore.string')
    ].join(' '))
  });

  this.appname = this.determineAppname();
  this.config = this._getStorage();
  this._globalConfig = this._getGlobalStorage();

  // ensure source/destination path, can be configured from subclasses
  this.sourceRoot(path.join(path.dirname(this.resolved), 'templates'));

  // Only instantiate the Gruntfile API when requested
  Object.defineProperty(this, 'gruntfile', {
    get: function () {
      if (!this.env.gruntfile) {
        var gruntfile = '';
        var gruntPath = this.destinationPath('Gruntfile.js');

        if (this.fs.exists(gruntPath)) {
          gruntfile = this.fs.read(gruntPath);
        }

        this.env.gruntfile = new GruntfileEditor(gruntfile);
      }

      // Schedule the creation/update of the Gruntfile
      this.env.runLoop.add('writing', function (done) {
        this.fs.write(
          this.destinationPath('Gruntfile.js'),
          this.env.gruntfile.toString()
        );
        done();
      }.bind(this), { once: 'gruntfile:write' });

      return this.env.gruntfile;
    }
  });
};
Example #9
0
var ViewEngine = exports.ViewEngine = function() {
  events.EventEmitter.call(this);
};
Example #10
0
// Channel
// =======

// Channels can receive message from one or multiple Chakras it is connected to and 
// send messages to the Chakra in order to have the message transmitted over other 
// Channels connected to the Chakra.
// A `config` object can be used to configure the Channel and will be passed to the 
// `configure` function.
function Channel(config) {
    EventEmitter.call(this);

    // Event emitter for message to separate message from the Channels events
    this.messages = new Vortex();
}
Example #11
0
var Connection = function(hostname, username, password, dbname, port) {
    events.EventEmitter.call(this);
    this.protocol = undefined;
    this.active = false;
    this.connect_parameter = Array.prototype.slice.call(arguments);
}
Example #12
0
function Web() 
{
	EventEmitter.call(this);
}
Example #13
0
exports = module.exports = internals.Connection = function (server, options) {

    const now = Date.now();

    Events.EventEmitter.call(this);

    this.settings = options;                                                        // options cloned in server.connection()
    this.server = server;

    // Normalize settings

    this.settings.labels = Hoek.unique(this.settings.labels || []);                 // Remove duplicates
    if (this.settings.port === undefined) {
        this.settings.port = 0;
    }

    this.type = (typeof this.settings.port === 'string' ? 'socket' : 'tcp');
    if (this.type === 'socket') {
        this.settings.port = (this.settings.port.indexOf('/') !== -1 ? Path.resolve(this.settings.port) : this.settings.port.toLowerCase());
    }

    if (this.settings.autoListen === undefined) {
        this.settings.autoListen = true;
    }

    Hoek.assert(this.settings.autoListen || !this.settings.port, 'Cannot specify port when autoListen is false');
    Hoek.assert(this.settings.autoListen || !this.settings.address, 'Cannot specify address when autoListen is false');

    // Connection facilities

    this._started = false;
    this._connections = {};
    this._onConnection = null;          // Used to remove event listener on stop
    this.registrations = {};            // Tracks plugin for dependency validation { name -> { version } }

    this._extensions = {
        onRequest: new Ext(this.server),
        onPreAuth: new Ext(this.server),
        onPostAuth: new Ext(this.server),
        onPreHandler: new Ext(this.server),
        onPostHandler: new Ext(this.server),
        onPreResponse: new Ext(this.server)
    };

    this._requestCounter = { value: internals.counter.min, min: internals.counter.min, max: internals.counter.max };
    this._load = server._heavy.policy(this.settings.load);
    this.states = new Statehood.Definitions(this.settings.state);
    this.auth = new Auth(this);
    this._router = new Call.Router(this.settings.router);
    this._defaultRoutes();

    this.plugins = {};                  // Registered plugin APIs by plugin name
    this.app = {};                      // Place for application-specific state without conflicts with hapi, should not be used by plugins

    // Create listener

    this.listener = this.settings.listener || (this.settings.tls ? Https.createServer(this.settings.tls) : Http.createServer());
    this.listener.on('request', this._dispatch());
    this._init();

    this.listener.on('clientError', (err, socket) => {

        this.server._log(['connection', 'client', 'error'], err);
    });

    // Connection information

    this.info = {
        created: now,
        started: 0,
        host: this.settings.host || Os.hostname() || 'localhost',
        port: this.settings.port,
        protocol: this.type === 'tcp' ? (this.settings.tls ? 'https' : 'http') : this.type,
        id: Os.hostname() + ':' + process.pid + ':' + now.toString(36)
    };

    this.info.uri = (this.settings.uri || (this.info.protocol + ':' + (this.type === 'tcp' ? '//' + this.info.host + (this.info.port ? ':' + this.info.port : '') : this.info.port)));

    this.on('route', Cors.options);
};
Example #14
0
var JqueryFileUploadMiddleware = function () {
    EventEmitter.call(this);
    // setting default options
    this.options = this.prepareOptions({});
};
Example #15
0
function Client(opts) {
  events.EventEmitter.call(this);
  this.parseOptions(opts);
  this.initState();
  this.createConnection();
}
Example #16
0
var moduleFunction = function(args) {
	events.EventEmitter.call(this);
	this.forceEvent = forceEvent;
	this.args = args;

	qtools.validateProperties({
		subject: args,
		targetScope: this, //will add listed items to targetScope
		propList: [
			{
				name: 'version',
				optional: false
			},
			{
				name: 'name',
				optional: false
			}
		]
	});

	var self = this,
		forceEvent = function(eventName, outData) {
			this.emit(eventName, {
				eventName: eventName,
				data: outData
			});
		};


	//LOCAL FUNCTIONS ====================================

	var extractFields = function(inString) {
		return inString.replace(/\/$/, '').split('/');
	}

	var checkQuery1 = function(callback) {
		var newQuery = self.queryInfo;

		for (var i = 0, len = newQuery.length; i < len; i++) {
			var element = newQuery[i].name;

			if (self.validSegmentNames.indexOf(element) == -1) {
				if (typeof (outList) == 'undefined') {
					var outList = [];
				}
				outList.push(element);
			}

		}
		if (typeof (outList) == 'undefined') {

			var badSequence = false;
			for (var i = 0, len = newQuery.length; i < len; i++) {
				var element = newQuery[i].name,
					comparison = self.validSegmentNames[i];
				if (element != comparison) {
					badSequence = true;
				}
			}
			if (badSequence) {
				callback({
					data: {
						message: 'Bad URI. Segments are out of sequence. Use: ' + self.validSegmentNames.join('/value/') + '/value',
						evidence: self.originalQueryString
					},
					meta: qtools.getMetaData()
				}, '');

			} else {
				callback('', {});
			}
		} else {
			callback({
				data: {
					message: 'Bad segment(s) in URI ('+outList.join(' ')+')',
					evidence: outList
				},
				meta: qtools.getMetaData()
			}, '');
		}
	}

	//PARSERS ====================================


	this.parsers = {};
	this.parsers.uff = {};

	this.parsers.uff['1.0'] = function(uriPath) {
		/*
		Note to self: fileAccessor, the thing that uses the result of this, loops over
		the queryInfo, assuming it's in the right order (after validating with checkQuery()).
		That means that the sequence in validSegmentNames is significant. 
		
		I think that I should make it so that fileAccessor grabs this stuff and sequences
		it to match its file system layout before it builds a path.
		
		That means that the URI probably should not care what order the values arrive in.
		*/

		self.validSegmentNames = ['districts', 'schools', 'segments']; //the sequence is important
		self.originalQueryString = uriPath;

		var queryInfo = [];
		var list = extractFields(uriPath);
		for (var i = 0, len = list.length; i < len; i = i + 2) {
			var operand = list[i + 1];

			queryInfo.push({
				name: list[i],
				value: operand ? operand : 'list'
			});

			if (!operand) {
				break;
			}

		}
		
		this.queryInfo = queryInfo;
		self.checkQuery=checkQuery1; //ps, the client uses this to check the query when it has fabricated the callback
		
		self.accessorList={};
		
		self.accessorList.file='fileAccessor';
		
		self.accessorList.mssql='mssqlAccessor';
		
		return queryInfo;

	}


	//METHODS AND PROPERTIES ====================================


	this.parse = self.parsers[self.name][self.version];




	//INITIALIZATION ====================================



	return this;
};
Example #17
0
var Server = function(options) {
  var self = this;

  // Add event listener
  EventEmitter.call(this);

  // BSON Parser, ensure we have a single instance
  if(bsonInstance == null) {
    bsonInstance = new BSON(bsonTypes);
  }

  // Reconnect retries
  var reconnectTries = options.reconnectTries || 30;

  // Keeps all the internal state of the server
  this.s = {
    // Options
      options: options
    // Contains all the callbacks
    , callbacks: new Callbacks()
    // Logger
    , logger: Logger('Server', options)
    // Server state
    , state: DISCONNECTED
    // Reconnect option
    , reconnect: typeof options.reconnect == 'boolean' ? options.reconnect :  true
    , reconnectTries: reconnectTries
    , reconnectInterval: options.reconnectInterval || 1000
    // Swallow or emit errors
    , emitError: typeof options.emitError == 'boolean' ? options.emitError : false
    // Current state
    , currentReconnectRetry: reconnectTries
    // Contains the ismaster
    , ismaster: null
    // Contains any alternate strategies for picking
    , readPreferenceStrategies: options.readPreferenceStrategies
    // Auth providers
    , authProviders: options.authProviders || {}
    // Server instance id
    , id: serverId++
    // Grouping tag used for debugging purposes
    , tag: options.tag
    // Do we have a not connected handler
    , disconnectHandler: options.disconnectHandler
    // wireProtocolHandler methods
    , wireProtocolHandler: options.wireProtocolHandler || new PreTwoSixWireProtocolSupport()
    // Factory overrides
    , Cursor: options.cursorFactory || BasicCursor
    // BSON Parser, ensure we have a single instance
    , bsonInstance: bsonInstance
    // Pick the right bson parser
    , bson: options.bson ? options.bson : bsonInstance
    // Internal connection pool
    , pool: null
    // Server details
    , serverDetails: {
        host: options.host
      , port: options.port
      , name: options.port ? f("%s:%s", options.host, options.port) : options.host
    }
  }

  // Reference state
  var s = this.s;

  // Add bson parser to options
  options.bson = s.bson;

  // Set error properties
  getProperty(this, 'name', 'name', s.serverDetails, {});
  getProperty(this, 'bson', 'bson', s.options, {});
  getProperty(this, 'wireProtocolHandler', 'wireProtocolHandler', s.options, {});
  getSingleProperty(this, 'id', s.id);

  // Add auth providers
  this.addAuthProvider('mongocr', new MongoCR());
  this.addAuthProvider('x509', new X509());
  this.addAuthProvider('plain', new Plain());
  this.addAuthProvider('gssapi', new GSSAPI());
  this.addAuthProvider('sspi', new SSPI());
  this.addAuthProvider('scram-sha-1', new ScramSHA1());
}
Example #18
0
var Server = function() {
	EventEmitter.call(this);
	this._socket = null;
	this._connections = {};
};
Example #19
0
 let Process = function ( id ) {
   EventEmitter.call( this );
   this.pid = id;
 };
Example #20
0
function Request(uri, options) {
  events.EventEmitter.call(this);
  this.url = url.parse(uri);
  this.options = options;
  this.headers = {
    'Accept': '*/*',
    'User-Agent': 'Restler for node.js',
    'Host': this.url.host
  };

  if (zlib) {
    this.headers['Accept-Encoding'] = 'gzip, deflate';
  }
  
  mixin(this.headers, options.headers || {});
  
  // set port and method defaults
  if (!this.url.port) this.url.port = (this.url.protocol == 'https:') ? '443' : '80';
  if (!this.options.method) this.options.method = (this.options.data) ? 'POST' : 'GET';
  if (typeof this.options.followRedirects == 'undefined') this.options.followRedirects = true;
  
  // stringify query given in options of not given in URL
  if (this.options.query && !this.url.query) {
    if (typeof this.options.query == 'object') 
      this.url.query = qs.stringify(this.options.query);
    else this.url.query = this.options.query;
  }
  
  this._applyBasicAuth();
  
  if (this.options.multipart) {
    this.headers['Content-Type'] = 'multipart/form-data; boundary=' + multipart.defaultBoundary;
    var multipart_size = multipart.sizeOf(this.options.data, multipart.defaultBoundary);
    if (typeof multipart_size === 'number' && multipart_size === multipart_size) {
        this.headers['Content-Length'] = multipart_size;
    }
    else {
        console.log("Building multipart request without Content-Length header, please specify all file sizes");
    }
  } else {
    if (typeof this.options.data == 'object') {
      this.options.data = qs.stringify(this.options.data);
      this.headers['Content-Type'] = 'application/x-www-form-urlencoded';
      this.headers['Content-Length'] = this.options.data.length;
    }
    if(typeof this.options.data == 'string') {
      var buffer = new Buffer(this.options.data, this.options.encoding || 'utf8');
      this.options.data = buffer;
      this.headers['Content-Length'] = buffer.length;
    }
  }
  
  var proto = (this.url.protocol == 'https:') ? https : http;
  
  this.request = proto.request({
    host: this.url.hostname,
    port: this.url.port,
    path: this._fullPath(),
    method: this.options.method,
    headers: this.headers
  });
  
  this._makeRequest();
}
Example #21
0
var Fluke289 = function() {

    // Init the EventEmitter
    events.EventEmitter.call(this);

    /////////
    // Public variables
    /////////
    this.name = "fluke28x";

    /////////
    // Private variables
    /////////

    // We have a lot of internal variables to manage
    // the link protocol:

    // Session layer. Whenever a command is sent, the DMM
    // replies first with a response code ('ACK' below) then
    // the actual response if needed.
    var state = { idle: 0,            // session is idle
             wait_ack: 1,        // command send, expecting ACK code
             wait_response: 2,   // ACK received, waiting for command response
             error: 3
           };

    // Low level parsing of incoming binary data
    var protostate = { stx:0,         // Looking for 'STX' sequence
                  etx: 1,        // Looking for 'ETX' sequence
                };

    // Link layer protocol: state of the link layer
    var linkstate = {  closed:0,       // Link closed
                  wantconnect: 1, // Link open request is sent by computer
                  open: 2         // Link open
               };

    // Tables that contain the mapping of various fields in binary structures:
    var mapReadingID = [],
        mapUnit = [],
        mapState = [],
        mapAttribute = [],
        mapRecordType = [],
        mapIsStableFlag = [],
        mapPrimFunction = [],
        mapSecFunction = [],
        mapAutoRange = [],
        mapBolt = [],
        mapMode = [],
    // We keep track of the last sent command for which we are
    // expecting a response, to enable parsing of the response:
        pendingCommand = "",
        pendingCommandArgument = "",
        noReplyCommands = [ "LEDT", "PRESS", "MPQ", "SAVNAME", "MP" ], // Some commands don't send a reply except the ACK code
    // We manage a command queue on the link, as well as a
    // command timeout:
        commandQueue = [],
        timeoutTimer = null,
    // See 'state' above. This is session level
        currentState = 0;

    // Pointer to the serial port & socket, since we need to handle it directly for
    // some protocol link layer operations and command queue management
    var port = null,
        uidrequested = false,
        instrumentid = null,
        isopen = false,
        recording = false,     // to call the main app in case we need to record readings
        streaming = false,
        livePoller = null,
        port_close_requested = false,
        self = this,


    // Link state handling
        currentLinkstate = 0,     // see linkstate above
        currentStatusByte = 0x00, // TODO: fully clarify how this one works...

    // Binary buffer handling:
        currentProtoState=  0,          // see protostate above
        inputBuffer = new Buffer(2048), // meter never sends more than 1024 bytes anyway
        ibIdx =0,

    // Special handling of the bitmap download case: we get the whole
    // bitmap in several calls, so the variable below stores the parts
        tmpBitmap = [],
        tmpBitmapIndex = 0;

    /////////
    // Private methods
    /////////

    var status = function(stat) {
        debug('Port status change', stat);
        isopen = stat.portopen;

        if (isopen) {
            // Should run any "onOpen" initialization routine here if
            // necessary.
        } else {
            // We remove the listener so that the serial port can be GC'ed
            if (port_close_requested) {
                port.removeListener('status', status);
                port_close_requested = false;
            }
        }
    };

// How the device is connected on the serial port
    var portSettings = function() {
        return  {
            baudRate: 115200,
            dataBits: 8,
            parity: 'none',
            stopBits: 1,
            flowControl: false,
            parser: serialport.parsers.raw,
        }
    };


    var resetState = function() {
        currentLinkstate = 0;
        currentStatusByte = 0x00;
        currentProtoState = 0;
        ibIdx = 0;
        tmpBitmapIndex = 0;
        commandQueue = [];
        currentState = 0;
        pendingCommand = "";
    };

    var sendData = function(data) {
        if (data) {
            self.emit('data',data);
        }
    };

    // Returns starting index of 0x10 0x02
     var sync = function(buffer, maxIndex) {
        for (var i= 0; i < maxIndex-1; i++) {
            if (buffer[i] == 0x10 && buffer[i+1] == 0x10)
                i += 2;
            if (buffer[i] == 0x10 && buffer[i+1] == 0x02) {
                return i;
            }
        }
        return -1;
    };

    var etx = function(buffer, maxIndex) {
        for (var i= 0; i < maxIndex-3; i++) {
            if (buffer[i] == 0x10 && buffer[i+1] == 0x10)
                i += 2;
            if (buffer[i] == 0x10 && buffer[i+1] == 0x03) {
                return i+4; // Include CRC
            }
        }
        return -1;
    };

    // Unescapes character 0x10:
    var unescape = function(buffer) {
        var readIdx = 0;
        var writeIdx = 0;
        var tmpBuffer = new Buffer(buffer.length);
        while (readIdx < buffer.length) {
            tmpBuffer[writeIdx] = buffer[readIdx];
            if (buffer[readIdx] == 0x10)
                readIdx++;
            writeIdx++;
            readIdx++;
        }
        // Now generate a recut buffer of the right size:
        var retBuffer = new Buffer(writeIdx);
        tmpBuffer.copy(retBuffer,0,0,writeIdx);
        return retBuffer;
    };

    var queryMeasurementFull = function() {
        self.output("QDDA");
        // Query battery level every minute
        if (new Date().getSeconds() == 0) {
            self.output("QBL");
        }
    };

    // Link layer protocol management: receives raw data from
    // the serial port, saves it and as soon as a complete data packet
    // is received, forward it to the upper layer.
    //
    // data is a buffer
    var format = function(data) {

        if (data) { // we sometimes get called without data, to further process the
                    // existing buffer
            // First of all, append the incoming data to our input buffer:
            debug("LLP: Received new serial data, appended at index " + ibIdx);
            data.copy(inputBuffer,ibIdx);
            ibIdx += data.length;
        }
        var start=-1, stop=-1;
        if (currentProtoState == protostate.stx) {
            start = sync(inputBuffer, ibIdx);
            debug("Found STX: " + start);
            if (start > -1) {
                currentProtoState = protostate.etx;
                // Realign our buffer (we can copy over overlapping regions):
                inputBuffer.copy(inputBuffer,0,start);
                ibIdx -= start;
            } else {
                return;
            }
        }
        if (currentProtoState == protostate.etx) {
            stop = etx(inputBuffer, ibIdx);
            debug("Found ETX: " + stop);
            currentProtoState = protostate.stx;
        }
        if (stop == -1) {
            // We are receiving a packet but have not reached the end yet
            return;
        }
        // We have reached the end of the packet: copy the packet to a new buffer
        // for processing, and realign the input buffer:
        var controlByte = inputBuffer[2];
        debug("Control byte: " + controlByte.toString(16));

        // Check for control byte value:
        // I was not able to fully understand the logic of this byte...
        switch(controlByte) {
            case 0x05: // CRC Error
                debug("LLP: CRC Error on packet coming from computer");
                break;
            case 0x07: // Response to link open request
                debug("LLP: Link open");
                currentLinkstate = linkstate.open;
                // Now that our link is open, request a few basic infos that
                // we will need to decode binary logs:
                commandQueue.push("QEMAP readingID");
                commandQueue.push("QEMAP primFunction");
                commandQueue.push("QEMAP secFunction");
                commandQueue.push("QEMAP autoRange");
                commandQueue.push("QEMAP state");
                commandQueue.push("QEMAP unit");
                commandQueue.push("QEMAP attribute");
                commandQueue.push("QEMAP recordType");
                commandQueue.push("QEMAP isStableFlag");
                commandQueue.push("QEMAP bolt");
                commandQueue.push("QEMAP mode");
                break;
            case 0x0b: // Error (?)
                debug("LLP: Link closed - error (resetting LLP)");
                resetState(); // Reset our state, we have lost our sync...
                currentLinkstate = linkstate.closed;
                break;
            case 0x01: // Command reception acknowledge
            case 0x41:
                debug("LLP: Command ACK received");
                break;
            case 0x20: // Need to send an Acknowledge
                // Send packet with 0x21
                // - just send the prepackaged data...
                debug("LLP: Sending ACK");
                try {port.write(Buffer("10022110032138","hex")); }catch (err) {
                        debug("Error on serial port while writing : " + err);
                }
                currentStatusByte = 0x40;
                break;
            case 0x60:
                // Send packet with 0x61
                // - just send the prepackaged data...
                debug("LLP: Sending ACK");
                try { port.write(Buffer("1002611003573e","hex")); }catch (err) {
                        debug("Error on serial port while writing : " + err);
                }
                currentStatusByte = 0x00;
                break;
        }

        var response = '';
        // Process the packet if it contains a payload
        if (stop > 7) {
            var escapedPacket = new Buffer(stop-7);
            inputBuffer.copy(escapedPacket,0,3,stop-4);
            // One last thing before the packet is ready: 0x10 is escaped,
            // so we need to replace any instance of 0x10 0x10 in the buffer
            // by a single 0x10
            var packet = unescape(escapedPacket);
            debug("LLP: New packet ready:");
            debug(packet);
            response = processPacket(packet);
        } else if (controlByte == 0x07) {
            response = processPacket();
        }

        inputBuffer.copy(inputBuffer,0,stop);
        ibIdx -= stop;

        if (ibIdx > stop) {
            sendData(response);
            format(); // We still have data to process, so we call ourselves recursively
            return;
        }

        sendData(response);
    };

    // processPacket is called by format once a packet is received, for actual
    // processing and sending over the socket.io pipe
    var processPacket = function(buffer) {
        debug('Fluke 289 - Packet received - execting it to be a response to ' + pendingCommand);
        if (timeoutTimer) { // Disarm watchdog
            clearTimeout(timeoutTimer);
            timeoutTimer = null;
        }

        // We process in two stages:
        // 1. Check the response code
        // 2. Parse the response data
        //  Response data parsing is split in two:
        //    2.1 If expected response is binary, parse it
        //    2.2 If expected response is ASCII, parse it
        var response = {};
        if (currentState == state.wait_ack) {
            // Get the response code from the buffer: in case the response
            // is binary, data[1] as a string is not what we want, but we'll
            // address this in time
            var data = buffer.toString().split('\x0d');
            switch (data[0]) {
                case "0": // OK
                    // Some commands don't return anything else than an ACK, identify them here
                    // for performance reasons (skips all the processing below...)
                    if (noReplyCommands.indexOf(pendingCommand) != -1) {
                        currentState = state.idle;
                    } else {
                        currentState = state.wait_response;
                    }
                    break;
                    case "1": // Syntax Error
                        currentState = state.error;
                        break;
                    case "2": // Execution Error
                        currentState = state.error;
                        break;
                    case "5": // No data available
                        currentState = state.idle;
                        break;
                    default:
                        currentState = state.error;
                        break;
            }
            if (currentState == state.error) {
                currentState = state.idle;
                response = { "error":true };
            } else {
                response = { "error": false};
            }
        }

        if (currentState == state.wait_response) {
            var commandProcessed = false;
            //////////////////
            // First, process binary replies
            //////////////////
            switch(pendingCommand) {
                    case "QLCDBM":
                        commandProcessed = true;
                        // The meter only returns data in chunks of 1024 bytes
                        // so we need to request two QLCDBM commands to get
                        // everything
                            debug("Processing screenshot part 1");
                            tmpBitmap.push(buffer);
                            // Find start of data (after #0)
                            var idx = 0;
                            while(idx < buffer.length) {
                                if (buffer[idx]==0x23 && buffer[idx+1] == 0x30)
                                    break;
                                idx++;
                            }
                            tmpBitmapIndex += buffer.length-(idx+2);
                            debug("Received " + buffer.length + " bytes of Bitmap data");
                            // if we got a full buffer (1024 bytes), then we are not at the end
                            // of our bitmap
                            if (buffer.length == 1024) {
                                debug("Requesting more bitmap data");
                                // Bitmap processing is asynchronous...
                                commandQueue.push("QLCDBM " + tmpBitmapIndex);
                            } else {
                                // Got less than a full buffer, this means we have the
                                // complete bitmap:
                                processBitmap();
                                debug("Bitmap processing requested");
                            }
                        break;
                    case "QSMR":
                        commandProcessed = true;
                        // Query Saved Measurement Reading
                        debug(Hexdump.dump(buffer.toString('binary')));
                        break;
                    case "QRSI":
                        commandProcessed = true;
                        // Query Recording Summary Information
                        commandProcessed = true;
                        response = processRecordingSummary(buffer);
                        response.recordingID = pendingCommandArgument;
                        break;
                    case "QSRR":
                        commandProcessed = true;
                        // Query Saved Recording Record (??? :) )
                        response = processRecordingEntry(buffer);
                        response.recordingID = pendingCommandArgument;
                        break;
                    case "QMMSI":
                        commandProcessed = true;
                        response = processMinMaxRecording(buffer);
                        response.minmaxRecordingID = pendingCommandArgument;
                        debug(Hexdump.dump(buffer.toString('binary')));
                        break;
                    case "QPSI":
                        commandProcessed = true;
                        debug(Hexdump.dump(buffer.toString('binary')));
                        break;
                    default:
                        commandProcessed = false;
                        break;
            }

            //////////////////
            // Then process ASCII replies
            //////////////////
            if (!commandProcessed && ! (data[1] == undefined)) {
                // Below are ASCII replies, so it's time to
                // do the split on CSV fields:
                var fields = data[1].split(',');
                switch (pendingCommand) {
                        case "ID": // Short Identification of meter
                            response.model = fields[0];
                            response.version = fields[1];
                            response.serial = fields[2];
                            break;
                        case "IM": // Long identification of meter
                            response.model   = fields[0];
                            response.version = fields[1];
                            response.serial  = fields[2]
                            response.mspversion = fields[3];
                            response.buildbranch = fields[4];
                            response.buildrevision = fields[5];
                            response.boardid = fields[6];
                            break;
                        case "QM": // Query Measurement: READING_VALUE, UNIT, STATE, ATTRIBUTE
                            response.value = Number(fields[0]);
                            response.unit = fields[1];
                            response.readingState = fields[2];
                            response.attribute = fields[3];
                            break;
                        case "QCCV": // Calibration counter
                            response.calcounter = data[1];
                            break;
                        case "QCVN": // Calibration version
                            response.calversion = data[1];
                            break;
                        case "QBL": // Query battery life
                            response.battery = data[1];
                            break;
                        case "QMPQ": // Query Meter asset properties
                            // Remove single quotes:
                            data[1] = data[1].replace(/'/g,'');
                            switch(pendingCommandArgument) {
                                    case 'operator':
                                        response.operator = data[1];
                                        break;
                                    case 'company':
                                        response.company = data[1];
                                        break;
                                    case 'site':
                                        response.site = data[1];
                                        break;
                                    case 'contact':
                                        response.contact = data[1];
                                        break;
                            }
                            break;
                        case "QMEMLEVEL":
                            response.memlevel = data[1];
                            break;
                        case "QSN":
                            response.serial = data[1];
                            if (uidrequested) {
                                debug("Sending uniqueID message");
                                self.emit('data', {uniqueID: data[1]});
                                uidrequested = false;
                            }
                            break;
                        case "QSAVNAME":
                            response.savname = { id: pendingCommandArgument, value:data[1] };
                            break;
                        case "QSLS": // TODO: confirm this ?
                            response.savedlogs = {
                                record: fields[0],  // This is a log session
                                minmax: fields[1],
                                peak: fields[2],
                                measurement: fields[3]
                            };
                            break;
                        case "QDDA": // Extended version of meter value reading
                            response = processQDDA(data[1]);
                            response.error = false;
                            break;

                        case "QEMAP": // Property mapping
                            response = processEmap(data[1]);
                            response.error = false;
                            break;
                        default:
                            // We don't know what we received, just
                            // pass it on:
                            response.raw = data[1];
                            break;
                }
            }
            if (data[1] == undefined) {
                    debug("WARNING: no return value for " + pendingCommand + ", you should add it to the noReplyCommands list");
            }
            currentState = state.idle;
        }

        // If we have more commands in the queue, now is the time to process them
        if (commandQueue.length && currentState == state.idle) {
            var cmd = commandQueue.pop();
            debug("Command queue: dequeuing command " + cmd );
            self.output(cmd);
        }
        debug("Sending response ");
        debug(response);
        // TODO: move sending on socket in here
        return response;
    };

    // Sends back a JSON-formatted structure describing the complete meter reading.
    // This is also what can/should be recorded in logs
    // { primaryFunction:   ,
    //   secondaryFunction: ,
    //   rangeData: { autoRangeState:,
    //                baseUnit: ,
    //                rangeNumber: ,
    //                rangeMultiplier:
    //              },
    //    lightningBold: boolean,
    //    minMaxStartTime: number of milliseconds since January 1 1970
    //    measurementModes: [ 'measurementMode' ],  // Array of measurement modes, can be empty
    //    readingData: [
    //           reading1
    //           ...
    //           readingN
    //           ],
    //   }
    var processQDDA = function(data) {
        var fields = data.split(',');
        var res = {};
        res.primaryFunction = fields[0];
        res.secondaryFunction = fields[1];
        res.rangeData = { autoRangeState: fields[2],
                          baseUnit: fields[3],
                          rangeNumber: Number(fields[4]),
                          rangeMultiplier: Number(fields[5])
                        };
        res.lightningBolt = (fields[6] == "OFF") ? false: true;
        res.minMaxStartTime = fields[7]*1000;
        res.measurementModes = [];
        var i = 0;
        while (i < fields[8]) {
            res.measurementModes.push(fields[9+i++]);
        }
        // Now decode the readings:
        var numberOfReadings = fields[9+i];
        res.readings = [];
        var j = 0;
        while (j < numberOfReadings) {
            res.readings.push(decodeReading(fields.slice(10+i+j*9, 19+i+j*9)));
            j++;
        }
        return { reading:res };
    };

    var decodeReading = function(reading) {
        var res = {};
        res.readingID = reading[0];
        res.readingValue = Number(reading[1]);
        res.baseUnit = reading[2];
        res.unitMultiplier = Number(reading[3]);
        res.decimalPlaces = Number(reading[4]);
        res.displayDigits = Number(reading[5]);
        res.readingState = reading[6];
        res.readingAttribute = reading[7];
        res.timeStamp = reading[8]*1000;
        return res;
    };

    var waitTimeout = function() {
        debug("Timeout waiting for command response");
        sendData({error:true});
        currentState = state.idle;
        // We timed out waiting for a command, process the next one in the queue if there is one
        if (commandQueue.length) {
            var cmd = commandQueue.pop();
            debug("Command queue: dequeuing command " + cmd );
            self.output(cmd);
        }
    };

    // We now have a gzipped BMP contained in those two buffers
    // we need to decompress it, turn it into a structure that is intelligible
    // to a browser.
    var processBitmap = function() {
        var bmBuffers = [];
        // First of all, we need to remove the remaining framing:
        for (var i=0; i < tmpBitmap.length; i++) {
            // Find start of data (after #0)
            var idx = 0;
            while(idx < tmpBitmap[i].length) {
                if (tmpBitmap[i][idx]== 0x23 && tmpBitmap[i][idx+1] == 0x30)
                    break;
                idx++;
            }
            var bmBuffer = new Buffer(tmpBitmap[i].length-(idx+2));
            tmpBitmap[i].copy(bmBuffer,0,idx+2);
            bmBuffers.push(bmBuffer);
            //this.debug("GZipped data buffer length is " + bmBuffer.length);
            //this.debug(Hexdump.dump(bmBuffer2.toString("binary")));
        }

        // Flush our temp buffer
        tmpBitmap = [];
        tmpBitmapIndex = 0;

        // Now assemble buffers & dezip:
        var bmBuffer = Buffer.concat(bmBuffers);
        debug("Compressed bitmap data is " + bmBuffer.length + " bytes long.");
        //this.debug(Hexdump.dump(bmBuffer.toString("binary")));

        zlib.unzip(bmBuffer, function(err, buffer) {
            if (!err) {
                // Also copy the result to a temporary file:
                var stream = fs.createWriteStream('screenshot.bmp');
                stream.write(buffer);
                stream.end();
                debug("Decompress successful, bitmap data length is " + buffer.length);
                try {
                    // Package the BMP bitmap into an RGBA image to send
                    // to a canvas element:
                    var bm = new Bitmap(buffer);
                    bm.init();
                    var data = bm.getData();
                    debug("Sending bitmap to application");
                    debug(data);
                    sendData({screenshot: data, width:bm.getWidth(), height: bm.getHeight()});
                } catch (err) {
                    debug("Something went wrong during bitmap decoding, data was probably corrupted ?\n" +err);
                }
            }
        });
    };

    var syncBuffer = function(buffer) {
        var idx = 0;

        while(idx < buffer.length) {
            if (buffer[idx]==0x23 && buffer[idx+1] == 0x30)
                break;
            idx++;
        }
        idx += 2; // Now idx is at the start of our data:
        return idx;
    };

    var processMinMaxRecording = function(buffer) {
        // Find start of data (after #0)
        var idx = syncBuffer(buffer);

        var summary = {
            address0:  buffer.readUInt32LE(idx),
            // We use Unix timestamps for our stamps:
            startTime: Math.floor(decodeFloat(buffer,idx +=4)*1000),
            endTime: Math.floor(decodeFloat(buffer,idx += 8)*1000),
        };

        var ret = decodeBinaryReading(buffer, idx += 8);
        summary.reading = ret[0];
        idx = ret[1];
        summary.recordingName = buffer.toString('ascii',idx);
        return summary;
    };

    var processMeasurementRecording = function(buffer) {
      // To be implemented...
    };


    // Decode a Trendlog recording summary
    var processRecordingSummary = function(buffer) {

        // Find start of data (after #0)
        var idx =  syncBuffer(buffer);

        var summary = {
            address0:  buffer.readUInt32LE(idx),
            // We use Unix timestamps for our stamps:
            startTime: Math.floor(decodeFloat(buffer,idx +=4)*1000),
            endTime: Math.floor(decodeFloat(buffer,idx += 8)*1000),
            interval : decodeFloat(buffer,idx +=8),
            evtThreshold: decodeFloat(buffer,idx +=8),
            recordingAddress: buffer.readUInt32LE(idx +=8),
            numberOfRecords: buffer.readUInt32LE(idx +=4),
        };

        var ret = decodeBinaryReading(buffer, idx +=4);
        summary.reading = ret[0];
        idx = ret[1];

        summary.recordingName = buffer.toString('ascii',idx);

        debug(summary);
        return summary;
    };

    // A Reading contains range info and primary/secondary functions,
    // then all the readingIDs.
    // idx needs to be the starting offset of the structure
    // returns an object containing the decoded reading + the updated index.
    var decodeBinaryReading = function(buffer, idx) {

        var reading = {
            primaryFunction: mapPrimFunction[buffer.readUInt16LE(idx)],
            secondaryFunction: mapSecFunction[buffer.readUInt16LE(idx += 2)] ,
            rangeData: {
                autoRangeState: mapAutoRange[buffer.readUInt16LE(idx += 2)],
                baseUnit: mapUnit[buffer.readUInt16LE(idx += 2)],
                rangeNumber: decodeFloat(buffer, idx +=2),
                rangeMultiplier: buffer.readInt16LE(idx +=8)
            },
            lightningBolt: mapBolt[buffer.readUInt16LE(idx +=2)],
            minMaxStartTime: Math.floor(decodeFloat(buffer, idx += 2)*1000),
            // TODO: not 100% sure about the below !
            measurementMode1: mapMode[buffer.readUInt16LE(idx +=8)],
            measurementMode2: buffer.readUInt16LE(idx +=2),
        };

        var numberOfReadings = buffer.readUInt16LE( idx +=2);
        // Now decode the readings:
        idx += 2;

        var readings = [];
        for (var i = 0; i < numberOfReadings; i++) {
            readings.push(decodeBinaryReadingId(buffer,idx));
            idx += 30;
        }
        reading.readings = readings;
        return [reading, idx];
    };


    // Decode a readingId located at offset idx in the buffer
    var decodeBinaryReadingId = function(buffer,idx) {
        var reading = {
            readingID: mapReadingID[buffer.readUInt16LE(idx)],
            readingValue: decodeFloat(buffer, idx += 2),
            baseUnit: mapUnit[buffer.readUInt16LE(idx +=8)],
            unitMultiplier: buffer.readInt16LE(idx +=2),
            decimalPlaces: buffer.readUInt16LE(idx +=2),
            displayDigits: buffer.readUInt16LE(idx +=2),
            readingState: mapState[buffer.readUInt16LE(idx +=2)],
            readingAttribute: mapAttribute[buffer.readUInt16LE(idx +=2)],
            timeStamp: Math.floor(decodeFloat(buffer,idx+=2)*1000)
        };
        //console.log(reading);
        return reading;
    };

    var decodeFloat = function(buffer,idx) {
        // Unless I missed something, data is packed as 32bit little endian
        // integers, so the 64bit floats have to be reassembled as two separate
        // reversed buffers to be put back in order. Strange...
        var b2 = new Buffer(8);
        var v1 = buffer.readUInt32LE(idx+0);
        var v2 = buffer.readUInt32LE(idx+4);
        b2.writeUInt32BE(v1,0);
        b2.writeUInt32BE(v2,4);
        //console.log(b2);
        return b2.readDoubleBE(0);
    };

    // Decode a Trendlog entry:
    var processRecordingEntry = function(buffer) {
        console.log(Hexdump.dump(buffer.toString('binary')));
        // Find start of data (after #0)
        var idx =  syncBuffer(buffer);

        var record = {
            startTime: Math.floor(decodeFloat(buffer,idx)*1000),
            endTime: Math.floor(decodeFloat(buffer,idx +=8)*1000),
            maxReading: decodeBinaryReadingId(buffer, idx +=8),
            minReading: decodeBinaryReadingId(buffer, idx +=30),
            averageReading: decodeBinaryReadingId(buffer, idx +=30),
            averageSamples: buffer.readUInt32LE(idx +=30),
            primaryReading: decodeBinaryReadingId(buffer, idx +=4),
            recordType: mapRecordType[buffer.readUInt16LE(idx +=30)],
            isStableFlag: mapIsStableFlag[buffer.readUInt16LE(idx +=2)],
            otherFlag: buffer.readUInt16LE(idx +=2),
        };

        console.log(record);
        // Now package the trendlog record
        return { record: record};
    };


    // Transform a comma-separated list of props into a JSON object
    // and also catches any interesting proplist for our own use.
    var processEmap = function(data) {
        var fields = data.split(',');
        debug(fields);
        var emap = [];
        for (var i=1; i < fields.length; i++) {
            // Note: some prop fields have very high indexes, but...
            emap[fields[i++]] = fields[i];
        }
        debug(emap);
        switch (pendingCommandArgument) {
                case "unit":
                    mapUnit = emap;
                    break;
                case "readingID":
                    mapReadingID = emap;
                    break;
                case "state":
                    mapState = emap;
                    break;
                case "attribute":
                    mapAttribute = emap;
                    break;
                case "isStableFlag":
                    mapIsStableFlag = emap;
                    break;
                case "recordType":
                    mapRecordType = emap;
                    break;
                case "primFunction":
                    mapPrimFunction = emap;
                    break;
                case "secFunction":
                    mapSecFunction = emap;
                    break;
                case "autoRange":
                    mapAutoRange = emap;
                    break;
                case "bolt":
                    mapBolt = emap;
                    break;
                case "mode":
                    mapMode = emap;
                    break;
        }
        return { emap : {id: pendingCommandArgument, props: emap }};
    }


    /////////
    // Public API
    /////////

    // Creates and opens the connection to the instrument.
    // for all practical purposes, this is really the init method of the
    // driver

    this.openPort = function(id) {
        instrumentid = id;
        dbs.instruments.get(id, function(err,item) {
            port = new serialconnection(item.port, portSettings());
            port.on('data', format);
            port.on('status', status);
        });
    }


    this.closePort = function(data) {
        // We need to remove all listeners otherwise the serial port
        // will never be GC'ed
        this.stopLiveStream();
        port.removeListener('data', format);
        port_close_requested = true;
        port.close();
    }

    this.isOpen = function() {
        return isopen;
    }

    this.getInstrumentId = function(format) {
        return instrumentid;
    };


    // Called when the HTML app needs a unique identifier.
    // this is a standardized call across all drivers.
    // For the Fluke, the UID is the serial number, so this is
    // what we will request, but we will return it inside a special
    // message.
    this.sendUniqueID = function() {
        debug("[fluke289] Asking for serial number for UID request");
        uidrequested = true;
        this.output("QSN");
    };

    this.isStreaming = function() {
        return streaming;
    };

    // period is in seconds
    this.startLiveStream = function(period) {
        if (!streaming) {
            debug("Starting live data stream");
            this.output("QBL"); // Query battery level first
            livePoller = setInterval(queryMeasurementFull.bind(this), (period) ? period*1000: 1000);
            streaming = true;
        }
    };

    this.stopLiveStream = function(period) {
        if (streaming) {
            debug("[fluke289] Stopping live data stream");
            clearInterval(livePoller);
            this.streaming = false;
        }
    };

    // output takes data and sends it to the port after
    // protocol encapsulation. For this driver, this is fairly
    // complex because we have a queue of commands, etc...
    this.output = function(data) {

        // before being able to send commands, we need to ask to open
        // the link by sending status byte 0x03:
        if (currentLinkstate == linkstate.closed) {
            currentLinkstate = linkstate.wantconnect;
            var buf = new Buffer("1002031003a28e","hex");
            commandQueue.push(data);
            debug("Link closed: requested link open, queued command (" + data + ")");
            port.write(buf);
            return;
        }
        if (currentLinkstate == linkstate.wantconnect) {
            debug("Waiting for link to open, queue command");
            commandQueue.push(data);
            return;
        }

        if (currentState == null)
            currentState = state.idle;

        if (currentState != state.idle) {
            // We are working on a command, so queue this one
            commandQueue.push(data);
            debug("Waiting for command response, queuing command - " + data);
            return;
        }
        // We need to save the previous command name because the meter does
        // not echo the command we send
        pendingCommand = data.split(" ")[0];
        pendingCommandArgument = data.split(" ")[1];
        debug("Sending command " + data );
        currentState = state.wait_ack;
        // We'll wait for 300ms for a response, otherwise we reset.
        timeoutTimer = setTimeout(waitTimeout, 300);

        var cmdToBuffer = new Buffer(data,'ascii'); // Turn our command to a buffer
        var tmp = new Buffer(cmdToBuffer.length+5);
        tmp.writeUInt16BE(0x1002,0);
        tmp.writeUInt8(currentStatusByte,2);
        cmdToBuffer.copy(tmp,3);
        tmp.writeUInt16BE(0x1003,tmp.length-2);

        var crc = crcCalc.fluke_crc(tmp);
        //console.log('crc: ' + crc.toString(16));
        var finalBuffer = new Buffer(tmp.length+2);
        tmp.copy(finalBuffer,0);
        finalBuffer.writeUInt16LE(crc,finalBuffer.length-2);
        debug(finalBuffer);

        try {
            port.write(finalBuffer);
        } catch (err) {
            debug("Error on serial port while writing data : " + err);
        }
    };

}
Example #22
0
function RedisClient(stream, options) {
    this.stream = stream;
    this.options = options = options || {};

    this.connection_id = ++connection_id;
    this.connected = false;
    this.ready = false;
    this.connections = 0;
    if (this.options.socket_nodelay === undefined) {
        this.options.socket_nodelay = true;
    }
    this.should_buffer = false;
    this.command_queue_high_water = this.options.command_queue_high_water || 1000;
    this.command_queue_low_water = this.options.command_queue_low_water || 0;
    this.max_attempts = null;
    if (options.max_attempts && !isNaN(options.max_attempts) && options.max_attempts > 0) {
        this.max_attempts = +options.max_attempts;
    }
    this.command_queue = new Queue(); // holds sent commands to de-pipeline them
    this.offline_queue = new Queue(); // holds commands issued but not able to be sent
    this.commands_sent = 0;
    this.connect_timeout = false;
    if (options.connect_timeout && !isNaN(options.connect_timeout) && options.connect_timeout > 0) {
        this.connect_timeout = +options.connect_timeout;
    }
    this.enable_offline_queue = true;
    if (typeof this.options.enable_offline_queue === "boolean") {
        this.enable_offline_queue = this.options.enable_offline_queue;
    }
    this.retry_max_delay = null;
    if (options.retry_max_delay !== undefined && !isNaN(options.retry_max_delay) && options.retry_max_delay > 0) {
        this.retry_max_delay = options.retry_max_delay;
    }

    this.initialize_retry_vars();
    this.pub_sub_mode = false;
    this.subscription_set = {};
    this.monitoring = false;
    this.closing = false;
    this.server_info = {};
    this.auth_pass = null;
    if (options.auth_pass !== undefined) {
        this.auth_pass = options.auth_pass;
    }
    this.parser_module = null;
    this.selected_db = null;	// save the selected db here, used when reconnecting

    this.old_state = null;

    var self = this;

    this.stream.on("connect", function () {
        self.on_connect();
    });

    this.stream.on("data", function (buffer_from_socket) {
        self.on_data(buffer_from_socket);
    });

    this.stream.on("error", function (msg) {
        self.on_error(msg.message);
    });

    this.stream.on("close", function () {
        self.connection_gone("close");
    });

    this.stream.on("end", function () {
        self.connection_gone("end");
    });

    this.stream.on("drain", function () {
        self.should_buffer = false;
        self.emit("drain");
    });

    events.EventEmitter.call(this);
}
function CheckForDatabaseCreated () {
  events.EventEmitter.call(this);
}
Example #24
0
function HttpClient(options) {
  EventEmitter.call(this);
  options = options || {};
  this.agent = options.agent || exports.agent;
  this.httpsAgent = options.httpsAgent || exports.httpsAgent;
}
Example #25
0
function Decoder(options) {
    EventEmitter.call(this);
    options = options || {};
    this.formatter = options.formatter || Der.defaultFormatter;
}
Example #26
0
function Messi(){
	this.trophies = 0;
	this.lastEventAmount = 0;
	this.lastEventAmountFlag = 0;
	events.EventEmitter.call(this);
}
function CarShow() {
  events.EventEmitter.call(this);
  this.seeCar = function(make){
    this.emit('sawCar', make);
  };
}
Example #28
0
var Pool = function(options) {
  // Add event listener
  EventEmitter.call(this);
  // Add the options
  this.options = assign({
    // Host and port settings
    host: 'localhost',
    port: 27017,
    // Pool default max size
    size: 5,
    // socket settings
    connectionTimeout: 30000,
    socketTimeout: 360000,
    keepAlive: true,
    keepAliveInitialDelay: 300000,
    noDelay: true,
    // SSL Settings
    ssl: false, checkServerIdentity: true,
    ca: null, crl: null, cert: null, key: null, passPhrase: null,
    rejectUnauthorized: false,
    promoteLongs: true,
    promoteValues: true,
    promoteBuffers: false,
    // Reconnection options
    reconnect: true,
    reconnectInterval: 1000,
    reconnectTries: 30,
    // Enable domains
    domainsEnabled: false
  }, options);

  // console.log("=================================== pool options")
  // console.dir(this.options)

  // Identification information
  this.id = _id++;
  // Current reconnect retries
  this.retriesLeft = this.options.reconnectTries;
  this.reconnectId = null;
  // No bson parser passed in
  if(!options.bson || (options.bson
    && (typeof options.bson.serialize != 'function'
    || typeof options.bson.deserialize != 'function'))) {
      throw new Error("must pass in valid bson parser");
  }

  // Logger instance
  this.logger = Logger('Pool', options);
  // Pool state
  this.state = DISCONNECTED;
  // Connections
  this.availableConnections = [];
  this.inUseConnections = [];
  this.connectingConnections = [];
  // Currently executing
  this.executing = false;
  // Operation work queue
  this.queue = [];

  // All the authProviders
  this.authProviders = options.authProviders || {
      'mongocr': new MongoCR(options.bson), 'x509': new X509(options.bson)
    , 'plain': new Plain(options.bson), 'gssapi': new GSSAPI(options.bson)
    , 'sspi': new SSPI(options.bson), 'scram-sha-1': new ScramSHA1(options.bson)
  }

  // Contains the reconnect connection
  this.reconnectConnection = null;

  // Are we currently authenticating
  this.authenticating = false;
  this.loggingout = false;
  this.nonAuthenticatedConnections = [];
  this.authenticatingTimestamp = null;
  // Number of consecutive timeouts caught
  this.numberOfConsecutiveTimeouts = 0;
  // Current pool Index
  this.connectionIndex = 0;
}
/**
 * @module Core
 */

/**
 * Provides the RiakConnection class.
 * @class RiakConnection
 * @constructor
 * @param {Object} options - the options to use.
 */
function RiakConnection(options) {
    events.EventEmitter.call(this);

    this.remoteAddress = options.remoteAddress;
    this.remotePort = options.remotePort;

    // This is to facilitate debugging
    if (!cid[this.remotePort]) {
        cid[this.remotePort] = 1;
    }
    this.name = util.format('[RiakConnection] (%s:%d-%d)',
        this.remoteAddress, this.remotePort, cid[this.remotePort]);
    cid[this.remotePort]++;

    if (options.cork) {
        this.cork = true;
    }

    if (options.auth) {
        this.auth = options.auth;
        this.auth.ciphers = RIAK_R16_CIPHERS;
    }

    if (options.healthCheck) {
        this.healthCheck = options.healthCheck;
    }

    this.connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
    if (options.hasOwnProperty('connectionTimeout')) {
        this.connectionTimeout = options.connectionTimeout;
    }

    this.requestTimeout = DEFAULT_REQUEST_TIMEOUT;
    if (options.hasOwnProperty('requestTimeout')) {
        this.requestTimeout = options.requestTimeout;
    }

    this.maxBufferSize = DEFAULT_MAX_BUFFER;
    if (options.hasOwnProperty('maxBufferSize')) {
        this.maxBufferSize = options.maxBufferSize;
    }

    var initBufferSize = DEFAULT_INIT_BUFFER;
    if (options.hasOwnProperty('initBufferSize')) {
        initBufferSize = options.initBufferSize;
    }

    this._emitAndClose = function(evt, evt_args) {
        if (!this.closed) {
            // NB: this can be useful
            // logger.debug("%s emitting '%s' args '%s'", this.name, evt, evt_args);
            // NB: RiakNode checks inFlight to re-try command if necessary
            // so don't set inFlight to false here, it will be set to false in close()
            this.closed = true;
            this._connection.end();
            this.emit(evt, this, evt_args);
            this.close();
        }
    };

    this._connHandleEnd = function () {
        logger.debug('%s handling "end" event', this.name);
        this._emitAndClose('connectionClosed');
    };

    this._connHandleTimeout = function (command) {
        var err = util.format("%s command '%s' timed out (in-flight: %s)",
            this.name, command.name, this.inFlight);
        if (logger.debug) {
            logger.debug(err);
        }
        this._emitAndClose('connectionClosed');
    };

    this._clearSocketTimeout = function() {
        if (this._connection) {
            if (this._boundConnectionTimeout) {
                this._connection.removeListener('timeout', this._boundConnectionTimeout);
                this._boundConnectionTimeout = null;
            }
            this._connection.setTimeout(0);
        }
    };

    // buffer is private
    var buffer = null;

    // private buffer functions
    function initBuffer(data) {
        // Create a new buffer to receive data if needed
        if (buffer === null) {
            buffer = new ByteBuffer(initBufferSize);
        }
        buffer.append(data);
        buffer.flip();
    }

    function getProtobufsFromBuffer(protobufArray) {
        if (arguments.length === 0) {
            protobufArray = [];
        }

        if (buffer.remaining() >= 4) {
            buffer.mark();
            var messageLength = buffer.readUint32();

            // See if we have the complete message
            if (buffer.remaining() >= messageLength) {
                // We have a complete message from riak
                var slice = buffer.slice(undefined, buffer.offset + messageLength);
                var code = slice.readUint8();

                // Our fun API does some creative things like ... returning only
                // a code, with 0 bytes following. In those cases we want to set
                // decoded to null.
                var decoded = null;
                if (messageLength - 1 > 0) {
                    var ResponseProto = rpb.getProtoFor(code);
                    // GH issue #45
                    // Must use 'true' as argument to force copy of data
                    // otherwise, subsequent fetches will clobber data
                    decoded = ResponseProto.decode(slice.toBuffer(true));
                }

                protobufArray[protobufArray.length] = { msgCode : code, protobuf : decoded };
                // skip past message in buffer
                buffer.skip(messageLength);
                // recursively call this until we are out of messages
                return getProtobufsFromBuffer(protobufArray);
            } else {
                // rewind the offset
                buffer.reset();
            }
        }

        // ByteBuffer's 'flip()' effectively clears the buffer which we don't
        // want. We want to flip while preserving anything in the buffer and
        // compact if necessary.

        var newOffset = buffer.remaining();
        // Compact if necessary
        if (newOffset > 0 && buffer.offset !== 0) {
            buffer.copyTo(buffer, 0);
        }
        buffer.offset = newOffset;
        buffer.limit = buffer.capacity();

        return protobufArray;
    }

    function closeBuffer() {
        if (buffer) {
            buffer.clear();
            buffer = null;
        }
    }

    // protected buffer functions
    this._closeBuffer = function () {
        closeBuffer();
    };

    this._resetBuffer = function () {
        if (buffer && buffer.capacity() > this.maxBufferSize) {
            closeBuffer();
        }
    };

    this._buildProtobufArray = function (data) {
        initBuffer(data);
        return getProtobufsFromBuffer();
    };

    // protected execute functions
    this._executeInit = function() {
        this.lastUsed = Date.now();
        this.executeDone();
    };

    this._executeStart = function(command) {
        this.command = command;
        logger.debug('%s execute command:', this.name, command.name);
        this.inFlight = true;
        this.lastUsed = Date.now();
    };

    this._executeInit();

    this.closed = false;
    this._connectedEmitted = false;

    this._connection = new net.Socket();
    if (this._connection.setKeepAlive) {
        this._connection.setKeepAlive(true, 0);
    }
    if (this._connection.setNoDelay) {
        this._connection.setNoDelay(true);
    }

    // Note: useful for debugging event issues
    /*
    debugOutputConnectionListeners(this.name, this._connection);
    this.setMaxListeners(1);
    this._connection.setMaxListeners(1);
    */

    if (this.cork && !this._connection.cork) {
        logger.warn('%s wanted to use cork/uncork but not supported!', this.name);
        this.cork = false;
    } else {
        logger.debug('%s using cork() / uncork()', this.name);
    }
}
Example #30
0
// util.inherits(constructor, superConstructor)
// RyStream inherits from superConstrutor
function RyStream() {
	"use strict"
	events.EventEmitter.call(this)
}