/** * Copyright© 2016, Oracle and/or its affiliates. All rights reserved. */ /** * Callback invoked after successfully flushing analytics events. * @callback Analytics~successCallback * @deprecated Use promises instead */ /** * Callback invoked on error. * @callback Analytics~errorCallback * @param statusCode {Number} Any HTTP status code returned from the server, if available. * @param message {String} The HTTP payload from the server, if available, or an error message. * @deprecated Use promises instead */ /** * * Class that provides analytics capabilities. Callers should use * MobileBackend's [analytics]{@link MobileBackend#analytics} property. * @constructor * @global */ function Analytics(backend, platform, utils, logger) { var _sessionId = null; var _events = []; /** * Returns session ID for current session. * @returns {String} */ this.getSessionId = function(){ return _sessionId; }; this._getEvents = function(){ return _events; }; /** * Starts a new session. If one is in progress, then a new session will not be created. */ this.startSession = function () { if (_sessionId === null) { if(locationEnabled()){ platform.initGPSLocation(); } _sessionId = utils.uuid(); this.logNamedEvent('sessionStart').type = 'system'; } }; /** * Ends a session if one exists. * @param [successCallback] {Analytics~successCallback} Callback invoked on success (deprecated use promises instead). * @param [errorCallback] {Analytics~errorCallback} Callback invoked on error (deprecated use promises instead). * @return {Promise.<Undefined|NetworkResponse>} */ this.endSession = function (successCallback, errorCallback) { if (_sessionId !== null) { var _this = this; _this.logNamedEvent("sessionEnd").type = "system"; logger.verbose('Deactivate a default session'); return this.flush().then(flushSuccess, flushError); } else { if(errorCallback){ errorCallback(500, 'Session ID is null'); return undefined; } else { return Promise.reject(new NetworkResponse(500, 'Session ID is null')); } } function flushSuccess(){ _sessionId = null; if(successCallback){ successCallback(); } } function flushError(exception){ if(errorCallback){ errorCallback(exception.statusCode, exception.data); } else { return Promise.reject(exception); } } }; /** * Creates a new analytics event with the given name. * @param name {String} The name of the event. * @returns {AnalyticsEvent} The [AnalyticsEvent]{@link AnalyticsEvent} instance that was logged. */ this.logNamedEvent = function (name) { var event = new AnalyticsEvent(name); this.logEvent(event); return event; }; /** * Writes out an analytics event. It will implicitly call startSession(), * which will add a new event to the list of events for Oracle Mobile Cloud Service to consume * @param event {AnalyticsEvent} The event to log. * @example event: "GettingStartedJSEvent" * @returns {AnalyticsEvent} The [AnalyticsEvent]{@link AnalyticsEvent} instance that was logged. */ this.logEvent = function (event) { if (_events.length === 0) { _events[0] = this._createContextEvent(); } this.startSession(); _events[_events.length] = event; event.sessionID = _sessionId; return event; }; function locationEnabled(){ if(backend._config.analytics && typeof backend._config.analytics.location !== 'undefined'){ return backend._config.analytics.location; } else { return true; } } /** * Uploads all events to the service if the device is online or caches them locally until the device goes online, at * which point they will be uploaded. If a session is in progress it will end. * @param [successCallback] {Analytics~successCallback} Callback invoked on success (deprecated use promises instead). * @param [errorCallback] {Analytics~errorCallback} Callback invoked on error (deprecated use promises instead). * @return {Promise.<Object|NetworkResponse>} */ this.flush = function (successCallback, errorCallback) { for (var i = 0; i < _events.length; i++) { if (locationEnabled() && _events[i].name == "context") { var gpsLocation = platform.getGPSLocation(); if (gpsLocation != null && gpsLocation.latitude != null) { _events[i].properties.latitude = gpsLocation.latitude; } if (gpsLocation != null && gpsLocation.longitude != null) { _events[i].properties.longitude = gpsLocation.longitude; } } } var eventsString = JSON.stringify(_events); var headers = backend.getHttpHeaders(utils.MODULE_NAMES.MCS_ANALYTICS); headers[utils.HEADERS.CONTENT_TYPE] = utils.ACCEPT_TYPES.APPLICATION_JSON; return platform.invokeService({ method: utils.HTTP_METHODS.POST, url: backend.getPlatformUrl("analytics/events"), headers: headers, data: eventsString }).then(invokeServiceSuccess, invokeServiceError); function invokeServiceSuccess() { logger.verbose('Analytics events flushed.'); _events = []; if (successCallback) { successCallback(); } } function invokeServiceError(response) { logger.error('Failed to flush analytics events.'); if (errorCallback) { errorCallback(response.statusCode, response.data); } else { return Promise.reject(response); } } }; this._createContextEvent = function () { var contextEvent = new AnalyticsEvent("context"); contextEvent.type = "system"; contextEvent.properties.timezone = "" + new Date().getTimezoneOffset() * 60; var deviceInformation = platform.getDeviceInformation(); contextEvent.properties.model = deviceInformation.model; contextEvent.properties.manufacturer = deviceInformation.manufacturer; contextEvent.properties.osName = deviceInformation.osName; contextEvent.properties.osVersion = deviceInformation.osVersion; contextEvent.properties.osBuild = deviceInformation.osBuild; contextEvent.properties.carrier = deviceInformation.carrier; return contextEvent; }; }