mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
181 lines
6.2 KiB
JavaScript
181 lines
6.2 KiB
JavaScript
var Fiber = require("fibers");
|
|
var _ = require("underscore");
|
|
var os = require("os");
|
|
|
|
var config = require("./config.js");
|
|
var files = require("./files.js");
|
|
var uniload = require("./uniload.js");
|
|
var project = require("./project.js");
|
|
var auth = require("./auth.js");
|
|
var ServiceConnection = require("./service-connection.js");
|
|
var release = require("./release.js");
|
|
var buildmessage = require("./buildmessage.js");
|
|
var httpHelpers = require("./http-helpers.js");
|
|
|
|
// The name of the package that you add to your app to opt out of
|
|
// sending stats.
|
|
var optOutPackageName = "package-stats-opt-out";
|
|
|
|
// Return a list of packages used by this app, both directly and
|
|
// indirectly. Formatted as a list of objects with 'name', 'version'
|
|
// and 'direct', which is how the `recordAppPackages` method on the
|
|
// stats server expects to get this list.
|
|
//
|
|
// In tests, we want to use the same logic to calculate the list of
|
|
// packages for an app created in a sandbox, but we don't want to run
|
|
// the constraint solver, try to load local packages from the catalog,
|
|
// etc. In particular, we don't want to have to repoint project.project
|
|
// at whatever random app we just created in a sandbox and re-initialize
|
|
// the catalog with its local packages (and then have to undo all that
|
|
// after the test is over). So tests can pass a project.Project as an
|
|
// argument, and we'll calculate the list of packages just by looking at
|
|
// .meteor/packages and .meteor/versions, not by doing anything fancy
|
|
// like running the constraint solver.
|
|
// NOTE: This means that if you pass `_currentProjectForTest`, we assume
|
|
// that it is pointing to a root directory with an existing
|
|
// .meteor/versions file.
|
|
var packageList = function (_currentProjectForTest) {
|
|
buildmessage.assertInCapture();
|
|
var directDeps = (_currentProjectForTest || project.project).getConstraints();
|
|
|
|
var versions;
|
|
if (_currentProjectForTest) {
|
|
versions = _currentProjectForTest.dependencies;
|
|
} else {
|
|
versions = project.project.getVersions();
|
|
}
|
|
|
|
return _.map(
|
|
versions,
|
|
function (version, name) {
|
|
return {
|
|
name: name,
|
|
version: version,
|
|
direct: _.has(directDeps, name)
|
|
};
|
|
}
|
|
);
|
|
};
|
|
|
|
// 'what' should be one of "sdk.bundle", "sdk.deploy", "sdk.run".
|
|
// If it's a deploy, 'site' should be the name of the site
|
|
// ("foo.meteor.com") that we're deploying to.
|
|
var recordPackages = function (what, site) {
|
|
buildmessage.assertInCapture();
|
|
// Before doing anything, look at the app's dependencies to see if the
|
|
// opt-out package is there; if present, we don't record any stats.
|
|
var packages = packageList();
|
|
if (_.contains(_.pluck(packages, "name"), optOutPackageName)) {
|
|
// Print some output for the 'report-stats' self-test.
|
|
if (process.env.METEOR_PACKAGE_STATS_TEST_OUTPUT) {
|
|
process.stdout.write("PACKAGE STATS NOT SENT\n");
|
|
}
|
|
return;
|
|
}
|
|
|
|
// We do this inside a new fiber to avoid blocking anything on talking
|
|
// to the package stats server. If we can't connect, for example, we
|
|
// don't care; we'll just miss out on recording these packages.
|
|
// This also gives it its own buildmessage state.
|
|
Fiber(function () {
|
|
|
|
var details = {
|
|
what: what,
|
|
userAgent: httpHelpers.getUserAgent(),
|
|
sessionId: auth.getSessionId(config.getAccountsDomain()),
|
|
site: site
|
|
};
|
|
|
|
try {
|
|
var conn = connectToPackagesStatsServer();
|
|
var accountsConfiguration = auth.getAccountsConfiguration(conn);
|
|
|
|
if (auth.isLoggedIn()) {
|
|
try {
|
|
auth.loginWithTokenOrOAuth(
|
|
conn,
|
|
accountsConfiguration,
|
|
config.getPackageStatsServerUrl(),
|
|
config.getPackageStatsServerDomain(),
|
|
"package-stats-server"
|
|
);
|
|
} catch (err) {
|
|
// Do nothing. If we can't log in, we should continue and report
|
|
// stats anonymously.
|
|
//
|
|
// We log other errors with `logErrorIfInCheckout`, but login
|
|
// errors can happen in normal operation when nothing is wrong
|
|
// (e.g. login token expired or revoked) so we don't log them.
|
|
}
|
|
}
|
|
|
|
var result = conn.call("recordAppPackages",
|
|
project.project.getAppIdentifier(),
|
|
packages,
|
|
details);
|
|
|
|
// If the stats server sent us a new session, save it for use on
|
|
// subsequent requests.
|
|
if (result && result.newSessionId) {
|
|
auth.setSessionId(config.getAccountsDomain(), result.newSessionId);
|
|
}
|
|
|
|
if (process.env.METEOR_PACKAGE_STATS_TEST_OUTPUT) {
|
|
// Print some output for the 'report-stats' self-test.
|
|
process.stdout.write("PACKAGE STATS SENT\n");
|
|
}
|
|
} catch (err) {
|
|
logErrorIfInCheckout(err);
|
|
// Do nothing. A failure to record package stats shouldn't be
|
|
// visible to the end user and shouldn't affect whatever command
|
|
// they are running.
|
|
} finally {
|
|
conn && conn.close();
|
|
}
|
|
}).run();
|
|
};
|
|
|
|
var logErrorIfInCheckout = function (err) {
|
|
if (files.inCheckout()) {
|
|
process.stderr.write("Failed to record package usage.\n");
|
|
process.stderr.write("(This error is hidden when you are not running Meteor from a checkout.)\n");
|
|
process.stderr.write(err.stack || err);
|
|
process.stderr.write("\n\n");
|
|
}
|
|
};
|
|
|
|
// Used in a test (and can only be used against the testing packages
|
|
// server) to fetch one package stats entry for a given application.
|
|
var getPackagesForAppIdInTest = function (currentProject) {
|
|
var conn = connectToPackagesStatsServer();
|
|
var result;
|
|
try {
|
|
result = conn.call(
|
|
"getPackagesForAppId",
|
|
currentProject.getAppIdentifier());
|
|
if (result && result.details) {
|
|
result.details.packages = _.sortBy(result.details.packages, "name");
|
|
}
|
|
} finally {
|
|
conn.close();
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
var connectToPackagesStatsServer = function () {
|
|
var Package = uniload.load({
|
|
packages: ["livedata"]
|
|
});
|
|
var conn = new ServiceConnection(
|
|
Package,
|
|
config.getPackageStatsServerUrl(),
|
|
{_dontPrintErrors: true}
|
|
);
|
|
return conn;
|
|
};
|
|
|
|
exports.recordPackages = recordPackages;
|
|
exports.packageList = packageList; // for use in the "stats" self-test.
|
|
exports.getPackagesForAppIdInTest = getPackagesForAppIdInTest;
|