GT2/GT2-iOS/node_modules/analytics-node/lib/index.js

213 lines
4.9 KiB
JavaScript

var assert = require('assert')
var clone = require('clone')
var debug = require('debug')('analytics-node')
var noop = function () {}
var request = require('superagent')
require('superagent-retry')(request)
var uid = require('crypto-token')
var version = require('../package.json').version
var extend = require('lodash/extend')
var validate = require('@segment/loosely-validate-event')
var removeSlash = require('remove-trailing-slash')
global.setImmediate = global.setImmediate || process.nextTick.bind(process)
/**
* Expose an `Analytics` client.
*/
module.exports = Analytics
/**
* Initialize a new `Analytics` with your Segment project's `writeKey` and an
* optional dictionary of `options`.
*
* @param {String} writeKey
* @param {Object} [options] (optional)
* @property {Number} flushAt (default: 20)
* @property {Number} flushAfter (default: 10000)
* @property {String} host (default: 'https://api.segment.io')
*/
function Analytics (writeKey, options) {
if (!(this instanceof Analytics)) return new Analytics(writeKey, options)
assert(writeKey, 'You must pass your Segment project\'s write key.')
options = options || {}
this.queue = []
this.writeKey = writeKey
this.host = removeSlash(options.host || 'https://api.segment.io')
this.flushAt = Math.max(options.flushAt, 1) || 20
this.flushAfter = options.flushAfter || 10000
}
/**
* Send an identify `message`.
*
* @param {Object} message
* @param {Function} [fn] (optional)
* @return {Analytics}
*/
Analytics.prototype.identify = function (message, fn) {
validate(message, 'identify')
this.enqueue('identify', message, fn)
return this
}
/**
* Send a group `message`.
*
* @param {Object} message
* @param {Function} [fn] (optional)
* @return {Analytics}
*/
Analytics.prototype.group = function (message, fn) {
validate(message, 'group')
this.enqueue('group', message, fn)
return this
}
/**
* Send a track `message`.
*
* @param {Object} message
* @param {Function} [fn] (optional)
* @return {Analytics}
*/
Analytics.prototype.track = function (message, fn) {
validate(message, 'track')
this.enqueue('track', message, fn)
return this
}
/**
* Send a page `message`.
*
* @param {Object} message
* @param {Function} [fn] (optional)
* @return {Analytics}
*/
Analytics.prototype.page = function (message, fn) {
validate(message, 'page')
this.enqueue('page', message, fn)
return this
}
/**
* Send a screen `message`.
*
* @param {Object} message
* @param {Function} fn (optional)
* @return {Analytics}
*/
Analytics.prototype.screen = function (message, fn) {
validate(message, 'screen')
this.enqueue('screen', message, fn)
return this
}
/**
* Send an alias `message`.
*
* @param {Object} message
* @param {Function} [fn] (optional)
* @return {Analytics}
*/
Analytics.prototype.alias = function (message, fn) {
validate(message, 'alias')
this.enqueue('alias', message, fn)
return this
}
/**
* Flush the current queue and callback `fn(err, batch)`.
*
* @param {Function} [fn] (optional)
* @return {Analytics}
*/
Analytics.prototype.flush = function (fn) {
fn = fn || noop
if (!this.queue.length) return setImmediate(fn)
var items = this.queue.splice(0, this.flushAt)
var fns = items.map(function (_) { return _.callback })
var batch = items.map(function (_) { return _.message })
var data = {
batch: batch,
timestamp: new Date(),
sentAt: new Date()
}
debug('flush: %o', data)
request
.post(this.host + '/v1/batch')
.auth(this.writeKey, '')
.retry(3)
.send(data)
.end(function (err, res) {
err = err || error(res)
fns.push(fn)
fns.forEach(function (fn) { fn(err, data) })
debug('flushed: %o', data)
})
}
/**
* Add a `message` of type `type` to the queue and check whether it should be
* flushed.
*
* @param {String} type
* @param {Object} message
* @param {Functino} [fn] (optional)
* @api private
*/
Analytics.prototype.enqueue = function (type, message, fn) {
fn = fn || noop
message = clone(message)
message.type = type
message.context = extend(message.context || {}, {
library: {
name: 'analytics-node',
version: version
}
})
message._metadata = extend(message._metadata || {}, { nodeVersion: process.versions.node })
if (!message.timestamp) message.timestamp = new Date()
if (!message.messageId) message.messageId = 'node-' + uid(32)
debug('%s: %o', type, message)
this.queue.push({
message: message,
callback: fn
})
if (this.queue.length >= this.flushAt) this.flush()
if (this.timer) clearTimeout(this.timer)
if (this.flushAfter) this.timer = setTimeout(this.flush.bind(this), this.flushAfter)
}
/**
* Get an error from a `res`.
*
* @param {Object} res
* @return {String}
*/
function error (res) {
if (!res.error) return
var body = res.body
var msg = (body.error && body.error.message) || res.status + ' ' + res.text
return new Error(msg)
}