<commit_before>'use strict';

var PrimusError = require('./errors').PrimusError
  , EventEmitter = require('eventemitter3')
  , Transformer = require('./transformer')
  , log = require('diagnostics')('primus')
  , Spark = require('./spark')
  , fuse = require('fusing')
  , fs = require('fs')
  , vm = require('vm');

/**
 * Primus is a universal wrapper for real-time frameworks that provides a common
 * interface for server and client interaction.
 *
 * @constructor
 * @param {HTTP.Server} server HTTP or HTTPS server instance.
 * @param {Object} options Configuration
 * @api public
 */
function Primus(server, options) {
  if (!(this instanceof Primus)) return new Primus(server, options);
  if ('object' !== typeof server) {
    var message = 'The first argument of the constructor must be ' +
      'an HTTP or HTTPS server instance';
    throw new PrimusError(message, this);
  }

  options = options || {};
  this.fuse();

  var primus = this
    , key;

  this.auth = options.authorization || null;  // Do we have an authorization handler.
  this.connections = Object.create(null);     // Connection storage.
  this.ark = Object.create(null);             // Plugin storage.
  this.layers = [];                           // Middleware layers.
  this.transformer = null;                    // Reference to the real-time engine instance.
  this.encoder = null;                        // Shorthand to the parser's encoder.
  this.decoder = null;                        // Shorthand to the parser's decoder.
  this.connected = 0;                         // Connection counter.
  this.timeout = 'timeout' in options         // The timeout used to detect zombie sparks.
    ? options.timeout
    : 35000;
  this.whitelist = [];                        // Forwarded-for white listing.
  this.options = options;                     // The configuration.
  this.transformers = {                       // Message transformers.
    outgoing: [],
    incoming: []
  };

  this.server = server;
  this.pathname = 'string' === typeof options.pathname
    ? options.pathname.charAt(0) !== '/'
      ? '/'+ options.pathname
      : options.pathname
    : '/primus';

  //
  // Create a specification file with the information that people might need to
  // connect to the server.
  //
  this.spec = {
    version: this.version,
    pathname: this.pathname,
    timeout: this.timeout
  };

  //
  // Create a pre-bound Spark constructor. Doing a Spark.bind(Spark, this) doesn't
  // work as we cannot extend the constructor of it anymore. The added benefit of
  // approach listed below is that the prototype extensions are only applied to
  // the Spark of this Primus instance.
  //
  this.Spark = function Sparky(headers, address, query, id, request) {
    Spark.call(this, primus, headers, address, query, id, request);
  };

  this.Spark.prototype = Object.create(Spark.prototype, {
    constructor: {
      configurable: true,
      value: this.Spark,
      writable: true
    },
    __initialise: {
      value: Spark.prototype.__initialise.slice(),
      configurable: true,
      writable: true
    }
  });

  //
  // Copy over the original Spark static properties and methods so readable and
  // writable can also be used.
  //
  for (key in Spark) {
    this.Spark[key] = Spark[key];
  }

  this.parsers(options.parser);
  this.initialise(options.transformer || options.transport, options);

  //
  // If the plugins are supplied through the options, also initialise them.
  // This also allows us to use plugins when creating a client constructor
  // with the `Primus.createSocket({})` method.
  //
  if ('string' === typeof options.plugin) {
    options.plugin.split(/[, ]+/).forEach(function register(name) {
      primus.use(name, name);
    });

    return;
  }

  if ('object' === typeof options.plugin) {
    for (key in options.plugin) {
      this.use(key, options.plugin[key]);
    }
  }

  //
  // - Cluster node 0.10 lets the Operating System decide to which worker a request
  //   goes. This can result in a not even distribution where some workers are
  //   used at 10% while others at 90%. In addition to that the load balancing
  //   isn't sticky.
  //
  // - Cluster node 0.12 implements a custom round robin algorithm. This solves the
  //   not even distribution of work but it does not address our sticky session
  //   requirement.
  //
  // Projects like `sticky-session` attempt to implement sticky sessions but they
  // are using `net` server instead of a HTTP server in combination with the
  // remoteAddress of the connection to load balance. This does not work when you
  // address your servers behind a load balancer as the IP is set to the load
  // balancer, not the connecting clients. All in all, it only causes more
  // scalability problems. So we've opted-in to warn users about the<commit_msg>[minor] Show cluster warning also when `options.plugin` is a string<commit_after>'use strict';

var PrimusError = require('./errors').PrimusError
  , EventEmitter = require('eventemitter3')
  , Transformer = require('./transformer')
  , log = require('diagnostics')('primus')
  , Spark = require('./spark')
  , fuse = require('fusing')
  , fs = require('fs')
  , vm = require('vm');

/**
 * Primus is a universal wrapper for real-time frameworks that provides a common
 * interface for server and client interaction.
 *
 * @constructor
 * @param {HTTP.Server} server HTTP or HTTPS server instance.
 * @param {Object} options Configuration
 * @api public
 */
function Primus(server, options) {
  if (!(this instanceof Primus)) return new Primus(server, options);
  if ('object' !== typeof server) {
    var message = 'The first argument of the constructor must be ' +
      'an HTTP or HTTPS server instance';
    throw new PrimusError(message, this);
  }

  options = options || {};
  this.fuse();

  var primus = this
    , key;

  this.auth = options.authorization || null;  // Do we have an authorization handler.
  this.connections = Object.create(null);     // Connection storage.
  this.ark = Object.create(null);             // Plugin storage.
  this.layers = [];                           // Middleware layers.
  this.transformer = null;                    // Reference to the real-time engine instance.
  this.encoder = null;                        // Shorthand to the parser's encoder.
  this.decoder = null;                        // Shorthand to the parser's decoder.
  this.connected = 0;                         // Connection counter.
  this.timeout = 'timeout' in options         // The timeout used to detect zombie sparks.
    ? options.timeout
    : 35000;
  this.whitelist = [];                        // Forwarded-for white listing.
  this.options = options;                     // The configuration.
  this.transformers = {                       // Message transformers.
    outgoing: [],
    incoming: []
  };

  this.server = server;
  this.pathname = 'string' === typeof options.pathname
    ? options.pathname.charAt(0) !== '/'
      ? '/'+ options.pathname
      : options.pathname
    : '/primus';

  //
  // Create a specification file with the information that people might need to
  // connect to the server.
  //
  this.spec = {
    version: this.version,
    pathname: this.pathname,
    timeout: this.timeout
  };

  //
  // Create a pre-bound Spark constructor. Doing a Spark.bind(Spark, this) doesn't
  // work as we cannot extend the constructor of it anymore. The added benefit of
  // approach listed below is that the prototype extensions are only applied to
  // the Spark of this Primus instance.
  //
  this.Spark = function Sparky(headers, address, query, id, request) {
    Spark.call(this, primus, headers, address, query, id, request);
  };

  this.Spark.prototype = Object.create(Spark.prototype, {
    constructor: {
      configurable: true,
      value: this.Spark,
      writable: true
    },
    __initialise: {
      value: Spark.prototype.__initialise.slice(),
      configurable: true,
      writable: true
    }
  });

  //
  // Copy over the original Spark static properties and methods so readable and
  // writable can also be used.
  //
  for (key in Spark) {
    this.Spark[key] = Spark[key];
  }

  this.parsers(options.parser);
  this.initialise(options.transformer || options.transport, options);

  //
  // If the plugins are supplied through the options, also initialise them.
  // This also allows us to use plugins when creating a client constructor
  // with the `Primus.createSocket({})` method.
  //
  if ('string' === typeof options.plugin) {
    options.plugin.split(/[, ]+/).forEach(function register(name) {
      primus.use(name, name);
    });
  } else if ('object' === typeof options.plugin) {
    for (key in options.plugin) {
      this.use(key, options.plugin[key]);
    }
  }

  //
  // - Cluster node 0.10 lets the Operating System decide to which worker a request
  //   goes. This can result in a not even distribution where some workers are
  //   used at 10% while others at 90%. In addition to that the load balancing
  //   isn't sticky.
  //
  // - Cluster node 0.12 implements a custom round robin algorithm. This solves the
  //   not even distribution of work but it does not address our sticky session
  //   requirement.
  //
  // Projects like `sticky-session` attempt to implement sticky sessions but they
  // are using `net` server instead of a HTTP server in combination with the
  // remoteAddress of the connection to load balance. This does not work when you
  // address your servers behind a load balancer as the IP is set to the load
  // balancer, not the connecting clients. All in all, it only causes more
  // scalability problems. So we've opted-in to warn users about the
{'fraction_non_alphanumeric': 0.11107682813946312, 'fraction_numerical': 0.0037025609379821045, 'mean_word_length': 2.5168173598553345, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1703946', 'n_tokens_mistral': 2776, 'n_tokens_neox': 2637, 'n_words': 982}