146 lines
3.9 KiB
JavaScript
146 lines
3.9 KiB
JavaScript
/**
|
|
* A Node.js wrapper for the Matomo (http://matomo.org) tracking HTTP API
|
|
* https://github.com/matomo-org/matomo-tracker
|
|
*
|
|
* @author Frederic Hemberger, Matomo Team
|
|
* @license MIT
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const assert = require('assert');
|
|
const events = require('events');
|
|
const util = require('util');
|
|
const qs = require('querystring');
|
|
const url = require('url');
|
|
|
|
|
|
/**
|
|
* @constructor
|
|
* @param {Number} siteId Id of the site you want to track
|
|
* @param {String} trackerUrl URL of your Matomo instance
|
|
* @param {Boolean} [true] noURLValidation Set to true if the `piwik.php` has been renamed
|
|
*/
|
|
function MatomoTracker (siteId, trackerUrl, noURLValidation) {
|
|
if (!(this instanceof MatomoTracker)) {
|
|
return new MatomoTracker(siteId, trackerUrl, noURLValidation);
|
|
}
|
|
events.EventEmitter.call(this);
|
|
|
|
assert.ok(siteId && (typeof siteId === 'number' || typeof siteId === 'string'), 'Matomo siteId required.');
|
|
assert.ok(trackerUrl && typeof trackerUrl === 'string', 'Matomo tracker URL required, e.g. http://example.com/matomo.php');
|
|
if (!noURLValidation) {
|
|
assert.ok(trackerUrl.endsWith('matomo.php') || trackerUrl.endsWith('piwik.php'), 'A tracker URL must end with "matomo.php" or "piwik.php"');
|
|
}
|
|
|
|
this.siteId = siteId;
|
|
this.trackerUrl = trackerUrl;
|
|
|
|
// Use either HTTPS or HTTP agent according to Matomo tracker URL
|
|
this.agent = require(trackerUrl.startsWith('https') ? 'https' : 'http');
|
|
}
|
|
|
|
util.inherits(MatomoTracker, events.EventEmitter);
|
|
|
|
|
|
/**
|
|
* Executes the call to the Matomo tracking API
|
|
*
|
|
* For a list of tracking option parameters see
|
|
* https://developer.matomo.org/api-reference/tracking-api
|
|
*
|
|
* @param {(String|Object)} options URL to track or options (must contain URL as well)
|
|
*/
|
|
MatomoTracker.prototype.track = function track (options) {
|
|
var hasErrorListeners = this.listeners('error').length;
|
|
|
|
if (typeof options === 'string') {
|
|
options = {
|
|
url: options
|
|
};
|
|
}
|
|
|
|
// Set mandatory options
|
|
options = options || {};
|
|
options.idsite = this.siteId;
|
|
options.rec = 1;
|
|
|
|
assert.ok(options.url, 'URL to be tracked must be specified.');
|
|
|
|
var requestUrl = this.trackerUrl + '?' + qs.stringify(options);
|
|
var self = this;
|
|
var req = this.agent.get(requestUrl, function (res) {
|
|
// Check HTTP statuscode for 200 and 30x
|
|
if (!/^(200|30[12478])$/.test(res.statusCode)) {
|
|
if (hasErrorListeners) {
|
|
self.emit('error', res.statusCode);
|
|
}
|
|
}
|
|
});
|
|
|
|
req.on('error', function (err) {
|
|
hasErrorListeners && self.emit('error', err.message);
|
|
});
|
|
|
|
req.end();
|
|
};
|
|
|
|
|
|
MatomoTracker.prototype.trackBulk = function trackBulk (events, callback) {
|
|
var hasErrorListeners = this.listeners('error').length;
|
|
|
|
assert.ok(events && (events.length > 0), 'Events require at least one.');
|
|
assert.ok(this.siteId !== undefined && this.siteId !== null, 'siteId must be specified.');
|
|
|
|
var body = JSON.stringify({
|
|
requests: events.map(query => {
|
|
query.idsite = this.siteId;
|
|
query.rec = 1;
|
|
return '?' + qs.stringify(query);
|
|
})
|
|
});
|
|
|
|
var uri = url.parse(this.trackerUrl);
|
|
|
|
const requestOptions = {
|
|
protocol: uri.protocol,
|
|
hostname: uri.hostname,
|
|
port: uri.port,
|
|
path: uri.path,
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Content-Length': Buffer.byteLength(body),
|
|
}
|
|
};
|
|
|
|
const req = this.agent.request(requestOptions, res => {
|
|
if (!/^(200|30[12478])$/.test(res.statusCode)) {
|
|
if (hasErrorListeners) {
|
|
this.emit('error', res.statusCode);
|
|
}
|
|
}
|
|
|
|
let data = [];
|
|
|
|
res.on('data', chunk => {
|
|
data.push(chunk);
|
|
});
|
|
|
|
res.on('end', () => {
|
|
data = Buffer.concat(data).toString();
|
|
typeof callback === 'function' && callback(data);
|
|
});
|
|
});
|
|
|
|
req.on('error', (err) => {
|
|
hasErrorListeners && this.emit('error', err.message);
|
|
}
|
|
);
|
|
|
|
req.write(body);
|
|
req.end();
|
|
};
|
|
|
|
module.exports = MatomoTracker;
|