<commit_before>'use strict';

/**
 * ButtressJS - Realtime datastore for business software
 *
 * @file bootstrap-socket.js
 * @description Bootstrap the socket app
 * @module Model
 * @author <NAME>
 *
 */
const os = require('os');
const cluster = require('cluster');
const net = require('net');
const Express = require('express');
const sio = require('socket.io');
const sioRedis = require('socket.io-redis');
const sioEmitter = require('socket.io-emitter');

const Config = require('node-env-obj')('../');
const Model = require('./model');
const Logging = require('./logging');
const MongoClient = require('mongodb').MongoClient;
const NRP = require('node-redis-pubsub');

/* ********************************************************************************
 *
 *
 *
 **********************************************************************************/
const processes = os.cpus().length;
const _workers = [];

/* ********************************************************************************
 *
 * HELPERS
 *
 **********************************************************************************/
const __indexFromIP = (ip, spread) => {
  let s = '';
  for (let i = 0, _len = ip.length; i < _len; i++) {
    if (!isNaN(ip[i])) {
      s += ip[i];
    }
  }

  return Number(s) % spread;
};

/* ********************************************************************************
 *
 * MONGODB
 *
 **********************************************************************************/
const __nativeMongoConnect = app => {
  const mongoUrl = `mongodb://${Config.mongoDb.url}`;
  const dbName = `${Config.app.code}-${Config.env}`;
  return MongoClient.connect(mongoUrl, Config.mongoDb.options) // eslint-disable-line camelcase
  .then(client => {
    return client.db(dbName);
  });
};
const __initMongoConnect = () => {
  return __nativeMongoConnect()
  .then(db => {
    Model.init(db);
    return db;
  })
  .catch(e => Logging.logError(e));
};

/* ********************************************************************************
 *
 * WORKERS
 *
 **********************************************************************************/
const __spawnWorkers = appTokens => {
  Logging.log(`Spawning ${processes} Socket Workers`);

  const __spawn = idx => {
    _workers[idx] = cluster.fork();
    _workers[idx].send({'buttress:initAppTokens': appTokens});
  };

  for (let x = 0; x < processes; x++) {
    __spawn(x);
  }

  net.createServer({pauseOnConnect: true}, connection => {
    const worker = _workers[__indexFromIP(connection.remoteAddress, processes)];
    worker.send('buttress:connection', connection);
  }).listen(Config.listenPorts.sock);
};

const __initSocketNamespace = (io, publicId, appTokens) => {
  const namespace = io.of(`/${publicId}`);
  namespace.on('connect', socket => {
    const userToken = socket.handshake.query.token;
    const token = appTokens.tokens.find(t => t.value === userToken);
    if (!token) {
      Logging.logDebug(`Invalid token, closing connection: ${socket.id}`);
      return socket.disconnect(0);
    }

    const app = appTokens.apps.find(a => a.publicId === publicId);
    if (!app) {
      Logging.logDebug(`Invalid app, closing connection: ${socket.id}`);
      return socket.disconnect(0);
    }

    Logging.logSilly(`${socket.id} Connected on ${publicId}`);
    socket.on('disconnect', () => {
      Logging.logSilly(`${socket.id} Disconnect on ${publicId}`);
    });
  });

  return namespace;
};

const __initWorker = () => {
  const app = new Express();
  const server = app.listen(0, 'localhost');
  const io = sio(server);
  const namespace = [];
  io.origins('*:*');
  io.adapter(sioRedis(Config.redis));

  io.on('connect', socket => {
    Logging.logSilly(`${socket.id} Connected on global space`);
    socket.on('disconnect', socket => {
      Logging.logSilly(`${socket.id} Disconnect on global space`);
    });
  });

  process.on('message', (message, input) => {
    if (message === 'buttress:connection') {
      const connection = input;
      server.emit('connection', connection);
      connection.resume();
      return;
    }
    if (message['buttress:initAppTokens']) {
      const appTokens = message['buttress:initAppTokens'];
      appTokens.apps.forEach(app => {
        namespace.push(__initSocketNamespace(io, app.publicId, appTokens));
      });
    }
  });
};

/* ********************************************************************************
 *<commit_msg>- TWEAK: Bump logging level on socket process<commit_after>'use strict';

/**
 * ButtressJS - Realtime datastore for business software
 *
 * @file bootstrap-socket.js
 * @description Bootstrap the socket app
 * @module Model
 * @author <NAME>
 *
 */
const os = require('os');
const cluster = require('cluster');
const net = require('net');
const Express = require('express');
const sio = require('socket.io');
const sioRedis = require('socket.io-redis');
const sioEmitter = require('socket.io-emitter');

const Config = require('node-env-obj')('../');
const Model = require('./model');
const Logging = require('./logging');
const MongoClient = require('mongodb').MongoClient;
const NRP = require('node-redis-pubsub');

/* ********************************************************************************
 *
 *
 *
 **********************************************************************************/
const processes = os.cpus().length;
const _workers = [];

/* ********************************************************************************
 *
 * HELPERS
 *
 **********************************************************************************/
const __indexFromIP = (ip, spread) => {
  let s = '';
  for (let i = 0, _len = ip.length; i < _len; i++) {
    if (!isNaN(ip[i])) {
      s += ip[i];
    }
  }

  return Number(s) % spread;
};

/* ********************************************************************************
 *
 * MONGODB
 *
 **********************************************************************************/
const __nativeMongoConnect = app => {
  const mongoUrl = `mongodb://${Config.mongoDb.url}`;
  const dbName = `${Config.app.code}-${Config.env}`;
  return MongoClient.connect(mongoUrl, Config.mongoDb.options) // eslint-disable-line camelcase
  .then(client => {
    return client.db(dbName);
  });
};
const __initMongoConnect = () => {
  return __nativeMongoConnect()
  .then(db => {
    Model.init(db);
    return db;
  })
  .catch(e => Logging.logError(e));
};

/* ********************************************************************************
 *
 * WORKERS
 *
 **********************************************************************************/
const __spawnWorkers = appTokens => {
  Logging.log(`Spawning ${processes} Socket Workers`);

  const __spawn = idx => {
    _workers[idx] = cluster.fork();
    _workers[idx].send({'buttress:initAppTokens': appTokens});
  };

  for (let x = 0; x < processes; x++) {
    __spawn(x);
  }

  net.createServer({pauseOnConnect: true}, connection => {
    const worker = _workers[__indexFromIP(connection.remoteAddress, processes)];
    worker.send('buttress:connection', connection);
  }).listen(Config.listenPorts.sock);
};

const __initSocketNamespace = (io, publicId, appTokens) => {
  const namespace = io.of(`/${publicId}`);
  namespace.on('connect', socket => {
    const userToken = socket.handshake.query.token;
    const token = appTokens.tokens.find(t => t.value === userToken);
    if (!token) {
      Logging.logDebug(`Invalid token, closing connection: ${socket.id}`);
      return socket.disconnect(0);
    }

    const app = appTokens.apps.find(a => a.publicId === publicId);
    if (!app) {
      Logging.logDebug(`Invalid app, closing connection: ${socket.id}`);
      return socket.disconnect(0);
    }

    Logging.logDebug(`${socket.id} Connected on ${publicId}`);
    socket.on('disconnect', () => {
      Logging.logDebug(`${socket.id} Disconnect on ${publicId}`);
    });
  });

  return namespace;
};

const __initWorker = () => {
  const app = new Express();
  const server = app.listen(0, 'localhost');
  const io = sio(server);
  const namespace = [];
  io.origins('*:*');
  io.adapter(sioRedis(Config.redis));

  io.on('connect', socket => {
    Logging.logDebug(`${socket.id} Connected on global space`);
    socket.on('disconnect', socket => {
      Logging.logDebug(`${socket.id} Disconnect on global space`);
    });
  });

  process.on('message', (message, input) => {
    if (message === 'buttress:connection') {
      const connection = input;
      server.emit('connection', connection);
      connection.resume();
      return;
    }
    if (message['buttress:initAppTokens']) {
      const appTokens = message['buttress:initAppTokens'];
      appTokens.apps.forEach(app => {
        namespace.push(__initSocketNamespace(io, app.publicId, appTokens));
      });
    }
  });
};

/* ********************************************************************************
 *
{'fraction_non_alphanumeric': 0.3150561797752809, 'fraction_numerical': 0.0011235955056179776, 'mean_word_length': 4.417528910529519, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 43, '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': '2621058', 'n_tokens_mistral': 2594, 'n_tokens_neox': 2546, 'n_words': 505}