-
Notifications
You must be signed in to change notification settings - Fork 42
/
index.js
145 lines (116 loc) · 3.87 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
* A Node.js wrapper for the Matomo (http://matomo.org) tracking HTTP API
* https://github.com/matomo-org/matomo-nodejs-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 (!/^(20[04]|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 (!/^(20[04]|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;