<commit_before>
// require daemon
const daemon = require ('daemon');

// require helpers
const socket = helper ('socket');

/**
 * create live daemon
 *
 * @compute 0
 * @extends daemon
 */
class liveDaemon extends daemon {

  /**
   * constructor
   */
  constructor () {
    // run arguments
    super (...arguments);

    // bind build
    this.build = this.build.bind (this);

    // bind private methods
    this._save   = this._save.bind (this);
    this._deafen = this._deafen.bind (this);
    this._listen = this._listen.bind (this);

    // bind building
    this.building = this.build ();
  }

  /**
   * build live daemon
   */
  build () {
    // add endpoint for listen
    this.eden.endpoint ('live.listen', this._listen, true);
    this.eden.endpoint ('live.deafen', this._deafen, true);

    // add listeners for events
    this.eden.on ('model.save', this._save, true);
  }

  /**
   * on model save
   * @param  {Object}  opts
   */
  async _save (opts) {
    // get cache
    let listeners = await this.eden.get ('live.listen.' + opts.model + '.' + opts.id) || [];

    // check length
    if (!listeners.length) return;

    // log to eden
    this.logger.log ('debug', 'sending live response on ' + opts.model + ' #' + opts.id, {
      'class' : 'liveDaemon'
    });

    // get model
    let Model = model (opts.model);

    // load by id
    Model = await Model.findById (opts.id);

    // emit sanitised
    let sanitised = await Model.sanitise ();

    // loop listeners
    listeners.forEach ((listener) => {
      // emit to socket
      socket.session (listener.session, 'live.update.' + opts.model + '.' + opts.id, sanitised);
    });
  }

  /**
   * listen to endpoint for live data
   *
   * @param  {String}  sessionID
   * @param  {String}  type
   * @param  {String}  id
   * @param  {String}  listenID
   */
  async _deafen (sessionID, type, id, listenID) {
    // log to eden
    this.logger.log ('debug', 'removing live listener on ' + type + ' #' + id + ' for ' + sessionID, {
      'class' : 'liveDaemon'
    });

    // lock listen
    let unlock = await this.eden.lock ('live.listen.' + type + '.' + id);

    // set cache
    let listeners = await this.eden.get ('live.listen.' + type + '.' + id) || [];

    // add sessionID to listeners
    listeners = listeners.filter ((listener) => {
      // return filtered
      return listener.session !== sessionID && listener.uuid !== listenID;
    });

    // set to eden again
    await this.eden.set ('live.listen.' + type + '.' + id, listeners, 60 * 60 * 1000);

    // unlock live listen set
    unlock ();
  }

  /**
   * listen to endpoint for live data
   *
   * @param  {String}  sessionID
   * @param  {String}  type
   * @param  {String}  id
   * @param  {String}  listenID
   */
  async _listen (sessionID, type, id, listenID) {
    // log to eden
    this.logger.log ('debug', 'adding live listener on ' + type + ' #' + id + ' for ' + sessionID, {
      'class' : 'liveDaemon'
    });

    // lock listen
    let unlock = await this.eden.lock ('live.listen.' + type + '.' + id);

    // set cache
    let listeners = await this.eden.get ('live.listen.' + type + '.' + id) || [];

    // add sessionID to listeners
    if (!listeners.find ((listener) => {
      // return filtered
      return listener.session === sessionID && listener.uuid === listenID;
    })) listeners.push ({
      'uuid'    : listenID,
      'session' : sessionID
    });

    // set to eden again
    await this.eden.set ('live.listen.' + type + '.' + id, listeners, 60 * 60 * 1000);

    // unlock live listen set
    unlock ();
  }

}

/**
 * build live daemon class
 *
 * @type {liveDaemon}
 */
exports = module.exports = liveDaemon;
<commit_msg>only send one event per listener session<commit_after>
// require daemon
const daemon = require ('daemon');

// require helpers
const socket = helper ('socket');

/**
 * create live daemon
 *
 * @compute 0
 * @extends daemon
 */
class liveDaemon extends daemon {

  /**
   * constructor
   */
  constructor () {
    // run arguments
    super (...arguments);

    // bind build
    this.build = this.build.bind (this);

    // bind private methods
    this._save   = this._save.bind (this);
    this._deafen = this._deafen.bind (this);
    this._listen = this._listen.bind (this);

    // bind building
    this.building = this.build ();
  }

  /**
   * build live daemon
   */
  build () {
    // add endpoint for listen
    this.eden.endpoint ('live.listen', this._listen, true);
    this.eden.endpoint ('live.deafen', this._deafen, true);

    // add listeners for events
    this.eden.on ('model.save', this._save, true);
  }

  /**
   * on model save
   * @param  {Object}  opts
   */
  async _save (opts) {
    // get cache
    let listeners = await this.eden.get ('live.listen.' + opts.model + '.' + opts.id) || [];

    // check length
    if (!listeners.length) return;

    // log to eden
    this.logger.log ('debug', 'sending live response on ' + opts.model + ' #' + opts.id, {
      'class' : 'liveDaemon'
    });

    // get model
    let Model = model (opts.model);

    // load by id
    Model = await Model.findById (opts.id);

    // emit sanitised
    let sent      = [];
    let sanitised = await Model.sanitise ();

    // loop listeners
    listeners.forEach ((listener) => {
      // emit to socket
      if (sent.indexOf (listener.session) === -1) socket.session (listener.session, 'live.update.' + opts.model + '.' + opts.id, sanitised);

      // push to sent
      sent.push (listener.session);
    });
  }

  /**
   * listen to endpoint for live data
   *
   * @param  {String}  sessionID
   * @param  {String}  type
   * @param  {String}  id
   * @param  {String}  listenID
   */
  async _deafen (sessionID, type, id, listenID) {
    // log to eden
    this.logger.log ('debug', 'removing live listener on ' + type + ' #' + id + ' for ' + sessionID, {
      'class' : 'liveDaemon'
    });

    // lock listen
    let unlock = await this.eden.lock ('live.listen.' + type + '.' + id);

    // set cache
    let listeners = await this.eden.get ('live.listen.' + type + '.' + id) || [];

    // add sessionID to listeners
    listeners = listeners.filter ((listener) => {
      // return filtered
      return listener.session !== sessionID && listener.uuid !== listenID;
    });

    // set to eden again
    await this.eden.set ('live.listen.' + type + '.' + id, listeners, 60 * 60 * 1000);

    // unlock live listen set
    unlock ();
  }

  /**
   * listen to endpoint for live data
   *
   * @param  {String}  sessionID
   * @param  {String}  type
   * @param  {String}  id
   * @param  {String}  listenID
   */
  async _listen (sessionID, type, id, listenID) {
    // log to eden
    this.logger.log ('debug', 'adding live listener on ' + type + ' #' + id + ' for ' + sessionID, {
      'class' : 'liveDaemon'
    });

    // lock listen
    let unlock = await this.eden.lock ('live.listen.' + type + '.' + id);

    // set cache
    let listeners = await this.eden.get ('live.listen.' + type + '.' + id) || [];

    // add sessionID to listeners
    if (!listeners.find ((listener) => {
      // return filtered
      return listener.session === sessionID && listener.uuid === listenID;
    })) listeners.push ({
      'uuid'    : listenID,
      'session' : sessionID
    });

    // set to eden again
    await this.eden.set ('live.listen.' + type + '.' + id, listeners, 60 * 60 * 1000);

    // unlock live listen set
    unlock ();
  }

}

/**
 * build live daemon class
 *
 * @type {liveDaemon}
 */
exports = module.exports = liveDaemon;

{'fraction_non_alphanumeric': 0.16017372992892867, 'fraction_numerical': 0.004606475388260069, 'mean_word_length': 2.1968868321413546, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, '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': '2114364', 'n_tokens_mistral': 2491, 'n_tokens_neox': 2415, 'n_words': 687}