<commit_before>var Future = require('fibers/future');
var files = require('./files.js');
var config = require('./config.js');
var path = require('path');
var fs = require('fs');
var unipackage = require('./unipackage.js');
var fiberHelpers = require('./fiber-helpers.js');
var Fiber = require('fibers');
var httpHelpers = require('./http-helpers.js');
var auth = require('./auth.js');
var release = require('./release.js');
var url = require('url');
var _ = require('underscore');

// a bit of a hack
var getPackage = _.once(function () {
  return unipackage.load({
    library: release.current.library,
    packages: [ 'meteor', 'livedata' ],
    release: release.current.name
  });
});

// If 'error' is an exception that we know how to report in a
// user-friendly way, print an approprite message to stderr and return
// an appropriate exit status for a command. Else rethrow error.
//
// galaxyName should be the name of the galaxy that we're talking to.
// If messages is provided, it is a map from DDP error names to
// human-readable explanation to use.
var handleError = function (error, galaxyName, messages) {
  var Package = getPackage();
  messages = messages || {};

  if (e instanceof Package.meteor.Meteor.Error) {
    var msg = messages[error.error];
    if (msg)
      process.stderr.write(msg + "\n");
    else if (error.message)
      process.stderr.write("Denied: " + error.message + "\n");
    return 1;
  } else if (e instanceof ConnectionTimeoutError) {
    // If we have an http/https URL for a galaxyName instead of a
    // proper galaxyName (which is what the code in this file
    // currently passes), strip off the scheme and trailing slash.
    var m = galaxyName.match(/^https?:\/\/(.*[^\/])\/?$/);
    if (m)
      galaxyName = m[1];

    process.stderr.write(galaxyName + ": connection failed");
    return 1;
  } else {
    throw error;
  }
};

// Wrapper to manage a DDP connection to a service within a
// Galaxy. Provides (1) authentication from the credential cache, (2)
// failing method calls and subscriptions if, after 10 seconds, we're
// not connected. This functionality should eventually end up in the
// DDP client in one form or other.
//
// - galaxy: the name of the galaxy to connect to, as returned by
//   discoverGalaxy (as described there, should probably be a galaxy
//   name, but currently is a https or http URL)
// - service: the service to connect to within the Galaxy, such as
//   'ultraworld' or 'log-reader'.
var ConnectionTimeoutError = function () {};
var ServiceConnection = function (galaxy, service) {
  var self = this;
  var Package = getPackage();
  var endpointUrl = galaxy + "/" + service;
  var parsedEndpoint = url.parse(endpointUrl);
  var authToken = auth.getSessionToken(parsedEndpoint.hostname);

  // XXX XXX higher up on the stack, we need to get the galaxy name
  // from the hostname of endpointUrl, and run the login command for
  // that galaxy.
  if (! authToken)
    throw new Error("not logged in to galaxy?")

  self.connection = Package.livedata.DDP.connect(endpointUrl, {
    headers: {
      cookie: "GALAXY_AUTH=" + authToken
    }
  });

  self.connectionTimeoutCallbacks = [];
  self.connectionTimer = Package.meteor.Meteor.setTimeout(function () {
    if (self.connection.status().status !== "connected") {
      self.connection = null;
      _.each(self.connectionTimeoutCallbacks, function (f) {
        f();
      });
      self.connectionTimeoutCallbacks = [];
    }
  }, 10*1000);
};

_.extend(ServiceConnection.prototype, {
  _onConnectionTimeout: function (f) {
    var self = this;
    if (! self.connection)
      f();
    else
      self.connectionTimeoutCallbacks.push(f);
  },

  call: function (/* arguments */) {
    var self = this;
    var fut = new Future;
    self._onConnectionTimeout(function () {
      fut['throw'](new ConnectionTimeoutError);
    });

    var args = _.toArray(arguments);
    var name = args.shift();
    self.connection.apply(name, args, function (err, result) {
      if (err)
        fut['throw'](err);
      else
        fut['return'](result);
    });

    return fut.wait();
  },

  // XXX derived from _subscribeAndWait in livedata_connection.js
  // -- but with a different signature..
  subscribeAndWait: function (/* arguments */) {
    var self = this;

    var fut = new Future();
    self._onConnectionTimeout(function () {
      fut['throw'](new ConnectionTimeoutError);
    });

    var ready = false;
    var args = _.toArray(arguments);
    args.push({
      onReady: function () {
        ready = true;
        fut['return']();
      },
      onError: function (e) {
        if (! ready)
          fut['throw'](e);
        else
          /* XXX handle post-ready error */;
      }
    });

    self.subscribe.apply(self, args);
    return fut.wait();
  },

  close: function () {
    var self = this;
    if (self.connection) {
      self.connection.close();
      self.connection = null;
    }
    if (self.connectionTimer) {
      // Clean up the timer so that Node can exit cleanly
      var Package = getPackage();
      Package.meteor.Meteor.clearTimeout(self.connectionTimer);
      self.connectionTimer = null;
    }
  }
});


// Determine if a particular site is hosted by Galaxy, and if so, by
// which Galaxy. 'app' should be a hostname, like 'myapp.meteor.com'
// or 'mysite.com'. Returns the base URL for the Galaxy
// (https://[galaxyname], or possibly http://[galaxyname] if running
// locally). The URL will not have a trailing slash. Returns null if
// the site is not hosted by Galaxy.
//
// The result is cached, so there is no penality for calling this
// function multiple times (during the same run of the
// tool). (Assuming you wait for the first call to complete before
// making the subsequent calls. The caching doesn't kick in until the
// first call returns.)<commit_msg>fixed for 'meteor logs' on a galaxy<commit_after>var Future = require('fibers/future');
var files = require('./files.js');
var config = require('./config.js');
var path = require('path');
var fs = require('fs');
var unipackage = require('./unipackage.js');
var fiberHelpers = require('./fiber-helpers.js');
var Fiber = require('fibers');
var httpHelpers = require('./http-helpers.js');
var auth = require('./auth.js');
var release = require('./release.js');
var url = require('url');
var _ = require('underscore');

// a bit of a hack
var getPackage = _.once(function () {
  return unipackage.load({
    library: release.current.library,
    packages: [ 'meteor', 'livedata' ],
    release: release.current.name
  });
});

// If 'error' is an exception that we know how to report in a
// user-friendly way, print an approprite message to stderr and return
// an appropriate exit status for a command. Else rethrow error.
//
// galaxyName should be the name of the galaxy that we're talking to.
// If messages is provided, it is a map from DDP error names to
// human-readable explanation to use.
var handleError = function (error, galaxyName, messages) {
  var Package = getPackage();
  messages = messages || {};

  if (error instanceof Package.meteor.Meteor.Error) {
    var msg = messages[error.error];
    if (msg)
      process.stderr.write(msg + "\n");
    else if (error.message)
      process.stderr.write("Denied: " + error.message + "\n");
    return 1;
  } else if (error instanceof ConnectionTimeoutError) {
    // If we have an http/https URL for a galaxyName instead of a
    // proper galaxyName (which is what the code in this file
    // currently passes), strip off the scheme and trailing slash.
    var m = galaxyName.match(/^https?:\/\/(.*[^\/])\/?$/);
    if (m)
      galaxyName = m[1];

    process.stderr.write(galaxyName + ": connection failed");
    return 1;
  } else {
    throw error;
  }
};

// Wrapper to manage a DDP connection to a service within a
// Galaxy. Provides (1) authentication from the credential cache, (2)
// failing method calls and subscriptions if, after 10 seconds, we're
// not connected. This functionality should eventually end up in the
// DDP client in one form or other.
//
// - galaxy: the name of the galaxy to connect to, as returned by
//   discoverGalaxy (as described there, should probably be a galaxy
//   name, but currently is a https or http URL)
// - service: the service to connect to within the Galaxy, such as
//   'ultraworld' or 'log-reader'.
var ConnectionTimeoutError = function () {};
var ServiceConnection = function (galaxy, service) {
  var self = this;
  var Package = getPackage();
  var endpointUrl = galaxy + "/" + service;
  var parsedEndpoint = url.parse(endpointUrl);
  var authToken = auth.getSessionToken(parsedEndpoint.hostname);

  // XXX XXX higher up on the stack, we need to get the galaxy name
  // from the hostname of endpointUrl, and run the login command for
  // that galaxy.
  if (! authToken)
    throw new Error("not logged in to galaxy?")

  self.connection = Package.livedata.DDP.connect(endpointUrl, {
    headers: {
      cookie: "GALAXY_AUTH=" + authToken
    }
  });

  self.connectionTimeoutCallbacks = [];
  self.connectionTimer = Package.meteor.Meteor.setTimeout(function () {
    if (self.connection.status().status !== "connected") {
      self.connection = null;
      _.each(self.connectionTimeoutCallbacks, function (f) {
        f();
      });
      self.connectionTimeoutCallbacks = [];
    }
  }, 10*1000);
};

_.extend(ServiceConnection.prototype, {
  _onConnectionTimeout: function (f) {
    var self = this;
    if (! self.connection)
      f();
    else
      self.connectionTimeoutCallbacks.push(f);
  },

  call: function (/* arguments */) {
    var self = this;
    var fut = new Future;
    self._onConnectionTimeout(function () {
      fut['throw'](new ConnectionTimeoutError);
    });

    var args = _.toArray(arguments);
    var name = args.shift();
    self.connection.apply(name, args, function (err, result) {
      if (err)
        fut['throw'](err);
      else
        fut['return'](result);
    });

    return fut.wait();
  },

  // XXX derived from _subscribeAndWait in livedata_connection.js
  // -- but with a different signature..
  subscribeAndWait: function (/* arguments */) {
    var self = this;

    var fut = new Future();
    self._onConnectionTimeout(function () {
      fut['throw'](new ConnectionTimeoutError);
    });

    var ready = false;
    var args = _.toArray(arguments);
    args.push({
      onReady: function () {
        ready = true;
        fut['return']();
      },
      onError: function (e) {
        if (! ready)
          fut['throw'](e);
        else
          /* XXX handle post-ready error */;
      }
    });

    self.connection.subscribe.apply(self.connection, args);
    return fut.wait();
  },

  close: function () {
    var self = this;
    if (self.connection) {
      self.connection.close();
      self.connection = null;
    }
    if (self.connectionTimer) {
      // Clean up the timer so that Node can exit cleanly
      var Package = getPackage();
      Package.meteor.Meteor.clearTimeout(self.connectionTimer);
      self.connectionTimer = null;
    }
  }
});


// Determine if a particular site is hosted by Galaxy, and if so, by
// which Galaxy. 'app' should be a hostname, like 'myapp.meteor.com'
// or 'mysite.com'. Returns the base URL for the Galaxy
// (https://[galaxyname], or possibly http://[galaxyname] if running
// locally). The URL will not have a trailing slash. Returns null if
// the site is not hosted by Galaxy.
//
// The result is cached, so there is no penality for calling this
// function multiple times (during the same run of the
// tool). (Assuming you wait for the first call to complete before
// making the subsequent calls. The caching doesn't kick in until the
// first call returns.)
{'fraction_non_alphanumeric': 0.12973984016323756, 'fraction_numerical': 0.0022105084169358954, 'mean_word_length': 2.9433456252095205, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, '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': '6502830', 'n_tokens_mistral': 3445, 'n_tokens_neox': 3365, 'n_words': 1191}