<commit_before>/** @module archmage-socket
 * @description High level Socket class agains an ARCHMAGE server.
 */
import WsClient from './ws-client';
import * as tiip from 'jstiip';
import Promise from 'bluebird';
import { Map, Set, fromJS, Iterable, OrderedSet } from 'immutable';

const defaults = Map({
  initTarget: 'TiipController',
  timeoutOnRequests: 30 * 1000,
  midMax: 10000,
  timeoutErrorMessage: 'Timeout',
});

export class ArchmageSocket {

  /**
   * ArchmageSocket constructor. Does not connect.
   * @param  {object} url Websocket URL
   * @param  {string} protocols Protocols object for the browser WebSocket API
   * @param  {string} options Options object {onSend, onSendFail, onReceive, timeoutOnRequests}
   */
  constructor(url, protocols, options = {}) {
    this.currentCallbackId = 0;
    this.reqCallbacks = Map();
    this.subCallbacks = Map();
    this.setOptions(options);

    this.ws = new WsClient(url, protocols, {
      reconnectIfNotNormalClose: true,
      ...options,
    });
    this.ws.onMessage(::this.onMessage);
  }

  /**
   * Connect the socket. Will handle same arguments as the constructor.
   * @param  {object} url Websocket URL
   * @param  {string} protocols Protocols object for the browser WebSocket API
   * @param  {string} options Options object {onSend, onSendFail, onReceive, timeoutOnRequests}
   * @return {object}  The whole Socket (this)
   */
  connect(url, protocols, options = {}) {
    this.setOptions(options);
    this.ws.connect(url, protocols, {
      reconnectIfNotNormalClose: true,
      ...options,
    });
    return this;
  }

  setOptions(options) {
    this.sendCallback = options.onSend || this.sendCallback;
    this.sendFailCallback = options.onSendFail || this.sendFailCallback;
    this.receiveCallback = options.onReceive || this.receiveCallback;
    this.timeoutOnRequests = options.timeoutOnRequests || this.timeoutOnRequests;
  }

  init(userId, passwordHash, tenant, target, signal, args) {
    let argumentz = Map({ id: userId, password: <PASSWORD> });
    if (args) {
      argumentz = args.merge(argumentz);
    }
    return this.request(
      'init', target || defaults.get('initTarget'), signal, argumentz, undefined, tenant
    );
  }

  kill(force) {
    this.reqCallbacks.forEach(reqObj => {
      clearTimeout(reqObj.get('timeoutPromise'));
    });
    return this.ws.close(force);
  }

  req(target, signal, args, tenant) {
    return this.request('req', target, signal, args, undefined, tenant);
  }

  sub(callback, channel, subChannel, tenant, args) {
    const secondaryKey = OrderedSet.of(channel, subChannel, tenant);
    let argumentz = Map({ subChannel });
    if (args) argumentz = args.merge(argumentz);

    return this.request(
      'sub', undefined, undefined, argumentz, undefined, tenant, undefined, channel
    )
      .then(tiipMsg => {
        if (tiipMsg.has('channel')) {
          // Only support for subscription to one channel at a time
          this.subCallbacks = this.subCallbacks.set(tiipMsg.get('channel'), Map({
            callback,
            key: secondaryKey,
          }));
        }
        return tiipMsg;
      });
  }

  /**
   * (FUTURE) Subscribe to multiple channels. UNTESTED!
   * @param {object} subscriptions as List:[{ callback:<func>, rid:<rid>, subChannel:<>}]
   */
  subMulti(subscriptions, tenant, args) {
    const ridToSubscr = subscriptions.toMap().mapKeys((val, key) =>
      val.get('rid')
    );
    let argumentz = Map({ subscriptions: subscriptions.map(
      s => s.delete('callback')
    ) });
    if (args) argumentz = args.merge(argumentz);

    return this.request('sub', undefined, undefined, argumentz, undefined, tenant, undefined)
      .then(tiipMsg => {
        this.subCallbacks = this.subCallbacks.merge(
          tiipMsg.get('payload').toMap().mapKeys((s, key) => // payload to map on actual channels
            s.get('channel')
          ).map((s, channel) => // convert to subCallback objects
            Map({
              callback,
              key: OrderedSet.of(s.get('rid'), ridToSubscr.get(rid).get('subChannel'), tenant),
            })
          )
        );
        return tiipMsg;
      });
  }

  unsub(channel, subChannel, tenant, args) {
    const secondaryKey = OrderedSet.of(channel, subChannel, tenant);
    let fullChannel;
    this.subCallbacks.some((obj, key) => {
      if (secondaryKey.equals(obj.get('key'))) {
        fullChannel = key;
        this.subCallbacks = this.subCallbacks.delete(channel);
        return true; // exit loop<commit_msg>Got rid of errors in the new (future) function after activating lint<commit_after>/** @module archmage-socket
 * @description High level Socket class agains an ARCHMAGE server.
 */
import WsClient from './ws-client';
import * as tiip from 'jstiip';
import Promise from 'bluebird';
import { Map, Set, fromJS, Iterable, OrderedSet } from 'immutable';

const defaults = Map({
  initTarget: 'TiipController',
  timeoutOnRequests: 30 * 1000,
  midMax: 10000,
  timeoutErrorMessage: 'Timeout',
});

export class ArchmageSocket {

  /**
   * ArchmageSocket constructor. Does not connect.
   * @param  {object} url Websocket URL
   * @param  {string} protocols Protocols object for the browser WebSocket API
   * @param  {string} options Options object {onSend, onSendFail, onReceive, timeoutOnRequests}
   */
  constructor(url, protocols, options = {}) {
    this.currentCallbackId = 0;
    this.reqCallbacks = Map();
    this.subCallbacks = Map();
    this.setOptions(options);

    this.ws = new WsClient(url, protocols, {
      reconnectIfNotNormalClose: true,
      ...options,
    });
    this.ws.onMessage(::this.onMessage);
  }

  /**
   * Connect the socket. Will handle same arguments as the constructor.
   * @param  {object} url Websocket URL
   * @param  {string} protocols Protocols object for the browser WebSocket API
   * @param  {string} options Options object {onSend, onSendFail, onReceive, timeoutOnRequests}
   * @return {object}  The whole Socket (this)
   */
  connect(url, protocols, options = {}) {
    this.setOptions(options);
    this.ws.connect(url, protocols, {
      reconnectIfNotNormalClose: true,
      ...options,
    });
    return this;
  }

  setOptions(options) {
    this.sendCallback = options.onSend || this.sendCallback;
    this.sendFailCallback = options.onSendFail || this.sendFailCallback;
    this.receiveCallback = options.onReceive || this.receiveCallback;
    this.timeoutOnRequests = options.timeoutOnRequests || this.timeoutOnRequests;
  }

  init(userId, passwordHash, tenant, target, signal, args) {
    let argumentz = Map({ id: userId, password: <PASSWORD> });
    if (args) {
      argumentz = args.merge(argumentz);
    }
    return this.request(
      'init', target || defaults.get('initTarget'), signal, argumentz, undefined, tenant
    );
  }

  kill(force) {
    this.reqCallbacks.forEach(reqObj => {
      clearTimeout(reqObj.get('timeoutPromise'));
    });
    return this.ws.close(force);
  }

  req(target, signal, args, tenant) {
    return this.request('req', target, signal, args, undefined, tenant);
  }

  sub(callback, channel, subChannel, tenant, args) {
    const secondaryKey = OrderedSet.of(channel, subChannel, tenant);
    let argumentz = Map({ subChannel });
    if (args) argumentz = args.merge(argumentz);

    return this.request(
      'sub', undefined, undefined, argumentz, undefined, tenant, undefined, channel
    )
      .then(tiipMsg => {
        if (tiipMsg.has('channel')) {
          // Only support for subscription to one channel at a time
          this.subCallbacks = this.subCallbacks.set(tiipMsg.get('channel'), Map({
            callback,
            key: secondaryKey,
          }));
        }
        return tiipMsg;
      });
  }

  /**
   * (FUTURE) Subscribe to multiple channels. UNTESTED!
   * @param {object} subscriptions as List:[{ callback:<func>, rid:<rid>, subChannel:<>}]
   */
  subMulti(subscriptions, tenant, args) {
    const ridToSubscr = subscriptions.toMap().mapKeys(val =>
      val.get('rid')
    );
    let argumentz = Map({ subscriptions: subscriptions.map(
      s => s.delete('callback')
    ) });
    if (args) argumentz = args.merge(argumentz);

    return this.request('sub', undefined, undefined, argumentz, undefined, tenant, undefined)
      .then(tiipMsg => {
        this.subCallbacks = this.subCallbacks.merge(
          // payload to map on actual channels:
          tiipMsg.get('payload').toMap().mapKeys(s => s.get('channel'))
          .map(s => { // convert to subCallback objects
            const subscr = ridToSubscr.get(s.get('rid'));
            return Map({
              callback: subscr.get('callback'),
              key: OrderedSet.of(
                s.get('rid'), subscr.get('subChannel'), tenant
              ),
            });
          })
        );
        return tiipMsg;
      });
  }

  unsub(channel, subChannel, tenant, args) {
    const secondaryKey = OrderedSet.of(channel, subChannel, tenant);
    let fullChannel;
    this.subCallbacks.some((obj, key) => {
      if (secondaryKey.equals(obj.get('key'))) {
        fullChannel = key;
        this.subCallbacks = this.subCallbacks.delete(channel);
        return true; // exit loop
{'fraction_non_alphanumeric': 0.13114044579095435, 'fraction_numerical': 0.002596840510711967, 'mean_word_length': 2.99438202247191, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 27, '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': '6237387', 'n_tokens_mistral': 2800, 'n_tokens_neox': 2740, 'n_words': 693}