<commit_before>if (typeof Meteor === "undefined") Meteor = {};

// socket.io reconnect is broken and doesn't tell us when it gives up:
// https://github.com/LearnBoost/socket.io/issues/652
// also, seems to have some issues with re-handshaking
// https://github.com/LearnBoost/socket.io/issues/438
//
// we wanted our own logic on top of socket.io anyway, since their
// reconnect is a little broken. So this just means we have to do it all
// ourselves instead of allowing socket.io to handle the short-term
// transient reconnects.
//
// We may be able to drop a lot of this code when socket.io gets its act
// together with regards to reconnect. Some people are working on it
// already:
// https://github.com/3rd-Eden/Socket.IO/tree/bugs/reconnect


(function () {

  ////////// Constants //////////

  // how long to wait until we declare the connection attempt
  // failed. socket.io doesn't tell us sometimes.
  // https://github.com/LearnBoost/socket.io-client/issues/214
  // https://github.com/LearnBoost/socket.io-client/issues/311
  var CONNECT_TIMEOUT = 10000;
  // extra time to make sure our timer and socket.ios timer don't
  // collide.
  var CONNECT_TIMEOUT_SLOP = 1000;
  // time for initial reconnect attempt.
  var RETRY_BASE_TIMEOUT = 3000;
  // exponential factor to increase timeout each attempt.
  var RETRY_EXPONENT = 2.2;
  // maximum time between reconnects.
  var RETRY_MAX_TIMEOUT = 1800000; // 30min.
  // fuzz factor to randomize reconnect times by. avoid reconnect
  // storms.
  var RETRY_FUZZ = 0.5; // +- 25%

  ////////// Internals //////////

  var socket;
  var event_callbacks = {}; // name -> [callback]
  var reset_callbacks = [];
  var message_queue = {}; // id -> message
  var next_message_id = 0;
  var server_id;

  //// reactive status stuff
  var status = {
    status: "waiting", connected: false, retry_count: 0
  };

  var status_listeners = {}; // context.id -> context
  var status_changed = function () {
    _.each(status_listeners, function (context) {
      context.invalidate();
    });
  };

  //// retry logic
  var retry_timer;
  var connection_timer;

  var connected = function (welcome_data) {
    if (connection_timer) {
      clearTimeout(connection_timer);
      connection_timer = undefined;
    }

    if (status.connected) {
      // already connected. do nothing. this probably shouldn't happen.
      return;
    }

    // inspect the welcome data and decide if we have to reload
    if (welcome_data && welcome_data.server_id) {
      if (server_id && server_id !== welcome_data.server_id) {
        Meteor._reload.reload();
        // world's about to end, just leave the connection 'connecting'
        // until it does.
        return;
      }
      server_id = welcome_data.server_id;
    } else {
      Meteor._debug("DEBUG: invalid welcome packet", welcome_data);
    }

    // give everyone a chance to munge the message queue.
    var msg_list = _.toArray(message_queue);
    _.each(reset_callbacks, function (callback) {
      msg_list = callback(msg_list);
    });
    message_queue = {};
    _.each(msg_list, function (msg) {
      message_queue[next_message_id++] = msg;
    });

    // send the pending message queue. this should always be in
    // order, since the keys are ordered numerically and they are added
    // in order.
    _.each(message_queue, function (msg, id) {
      socket.json.send(msg, function () {
        delete message_queue[id];
      });
    });

    status.status = "connected";
    status.connected = true;
    status.retry_count = 0;
    status_changed();


  };
  var cleanup_socket = function () {
    if (socket) {

      if (socket.$events) {
        _.each(socket.$events, function (v, k) {
          socket.removeAllListeners(k);
        });
      }
      socket.disconnect();

      var old_socket = socket;
      socket = undefined;

      old_socket.on('connect', function () {
        Meteor._debug("DEBUG: OLD SOCKET RECONNECTED", old_socket);
        old_socket.disconnect();
      });
    }
  };

  var disconnected = function () {
    if (connection_timer) {
      clearTimeout(connection_timer);
      connection_timer = undefined;
    }
    cleanup_socket();
    retry_later(); // sets status. no need to do it here.
  };
  var fake_connect_failed = function () {
    // sometimes socket.io just doesn't tell us when it failed. we
    // detect this with a timer and force failure.
    cleanup_socket();
    disconnected();
  };

  var retry_timeout = function (count) {
    var timeout = Math.min(
      RETRY_MAX_TIMEOUT,
      RETRY_BASE_TIMEOUT * Math.pow(RETRY_EXPONENT, count));
    // fuzz the timeout randomly, to avoid reconnect storms when a
    // server goes down.
    timeout = timeout * ((Math.random() * RETRY_FUZZ) + (1 - RETRY_FUZZ/2));

    return timeout;
  };
  var retry_later = function () {
    var timeout = retry_timeout(status.retry_count)
    if (retry_timer) { clearTimeout(retry_timer); }
    retry_timer = setTimeout(retry_now, timeout);

    status.status = "waiting"
    status.connected = false;
    status.retry_time = (new Date()).getTime() + timeout;
    status_changed();<commit_msg>Tweak retry timeout to try to reconnect quickly the first few times. This makes automatic reloads much faster.<commit_after>if (typeof Meteor === "undefined") Meteor = {};

// socket.io reconnect is broken and doesn't tell us when it gives up:
// https://github.com/LearnBoost/socket.io/issues/652
// also, seems to have some issues with re-handshaking
// https://github.com/LearnBoost/socket.io/issues/438
//
// we wanted our own logic on top of socket.io anyway, since their
// reconnect is a little broken. So this just means we have to do it all
// ourselves instead of allowing socket.io to handle the short-term
// transient reconnects.
//
// We may be able to drop a lot of this code when socket.io gets its act
// together with regards to reconnect. Some people are working on it
// already:
// https://github.com/3rd-Eden/Socket.IO/tree/bugs/reconnect


(function () {

  ////////// Constants //////////

  // how long to wait until we declare the connection attempt
  // failed. socket.io doesn't tell us sometimes.
  // https://github.com/LearnBoost/socket.io-client/issues/214
  // https://github.com/LearnBoost/socket.io-client/issues/311
  var CONNECT_TIMEOUT = 10000;
  // extra time to make sure our timer and socket.ios timer don't
  // collide.
  var CONNECT_TIMEOUT_SLOP = 1000;
  // time for initial reconnect attempt.
  var RETRY_BASE_TIMEOUT = 1000;
  // exponential factor to increase timeout each attempt.
  var RETRY_EXPONENT = 2.2;
  // maximum time between reconnects.
  var RETRY_MAX_TIMEOUT = 1800000; // 30min.
  // time to wait for the first 2 retries.  this helps page reload
  // speed during dev mode restarts, but doesn't hurt prod too
  // much (due to CONNECT_TIMEOUT)
  var RETRY_MIN_TIMEOUT = 10;

  // fuzz factor to randomize reconnect times by. avoid reconnect
  // storms.
  var RETRY_FUZZ = 0.5; // +- 25%

  ////////// Internals //////////

  var socket;
  var event_callbacks = {}; // name -> [callback]
  var reset_callbacks = [];
  var message_queue = {}; // id -> message
  var next_message_id = 0;
  var server_id;

  //// reactive status stuff
  var status = {
    status: "waiting", connected: false, retry_count: 0
  };

  var status_listeners = {}; // context.id -> context
  var status_changed = function () {
    _.each(status_listeners, function (context) {
      context.invalidate();
    });
  };

  //// retry logic
  var retry_timer;
  var connection_timer;

  var connected = function (welcome_data) {
    if (connection_timer) {
      clearTimeout(connection_timer);
      connection_timer = undefined;
    }

    if (status.connected) {
      // already connected. do nothing. this probably shouldn't happen.
      return;
    }

    // inspect the welcome data and decide if we have to reload
    if (welcome_data && welcome_data.server_id) {
      if (server_id && server_id !== welcome_data.server_id) {
        Meteor._reload.reload();
        // world's about to end, just leave the connection 'connecting'
        // until it does.
        return;
      }
      server_id = welcome_data.server_id;
    } else {
      Meteor._debug("DEBUG: invalid welcome packet", welcome_data);
    }

    // give everyone a chance to munge the message queue.
    var msg_list = _.toArray(message_queue);
    _.each(reset_callbacks, function (callback) {
      msg_list = callback(msg_list);
    });
    message_queue = {};
    _.each(msg_list, function (msg) {
      message_queue[next_message_id++] = msg;
    });

    // send the pending message queue. this should always be in
    // order, since the keys are ordered numerically and they are added
    // in order.
    _.each(message_queue, function (msg, id) {
      socket.json.send(msg, function () {
        delete message_queue[id];
      });
    });

    status.status = "connected";
    status.connected = true;
    status.retry_count = 0;
    status_changed();


  };
  var cleanup_socket = function () {
    if (socket) {

      if (socket.$events) {
        _.each(socket.$events, function (v, k) {
          socket.removeAllListeners(k);
        });
      }
      socket.disconnect();

      var old_socket = socket;
      socket = undefined;

      old_socket.on('connect', function () {
        Meteor._debug("DEBUG: OLD SOCKET RECONNECTED", old_socket);
        old_socket.disconnect();
      });
    }
  };

  var disconnected = function () {
    if (connection_timer) {
      clearTimeout(connection_timer);
      connection_timer = undefined;
    }
    cleanup_socket();
    retry_later(); // sets status. no need to do it here.
  };
  var fake_connect_failed = function () {
    // sometimes socket.io just doesn't tell us when it failed. we
    // detect this with a timer and force failure.
    cleanup_socket();
    disconnected();
  };

  var retry_timeout = function (count) {
    if (count < 2)
      return RETRY_MIN_TIMEOUT;

    var timeout = Math.min(
      RETRY_MAX_TIMEOUT,
      RETRY_BASE_TIMEOUT * Math.pow(RETRY_EXPONENT, count));
    // fuzz the timeout randomly, to avoid reconnect storms when a
    // server goes down.
    timeout = timeout * ((Math.random() * RETRY_FUZZ) + (1 - RETRY_FUZZ/2));

    return timeout;
  };
  var retry_later = function () {
    var timeout = retry_timeout(status.retry_count)
    if (retry_timer) { clearTimeout(retry_timer); }
    retry_timer = setTimeout(retry_now, timeout);

    status.status = "waiting"
    status.connected = false;
    status.retry_time = (new Date()).getTime() + timeout;
    status_changed();
{'fraction_non_alphanumeric': 0.11989484555440803, 'fraction_numerical': 0.009013238193596845, 'mean_word_length': 2.656711294198421, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 9, 'https://': 10, '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': '2341566', 'n_tokens_mistral': 3321, 'n_tokens_neox': 3158, 'n_words': 968}