Source: Analytics/Analytics.js

/*
 * Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
 * the License. A copy of the License is located at
 *
 *     http://aws.amazon.com/apache2.0/
 *
 * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
 * and limitations under the License.
 */

import {
    AWS,
    AMA,
    Pinpoint,
    ClientDevice,
    ConsoleLogger as Logger,
    Constants
} from '../Common';

import Auth from '../Auth';

const logger = new Logger('AnalyticsClass');
const ama_logger = new Logger('AMA');
ama_logger.log = ama_logger.verbose;

/**
* Provide mobile analytics client functions
*/
class AnalyticsClass {
    /**
     * Initialize an Analytics class with configuration
     * @param config - Configuration of the Analytics
     */
    constructor(config) {
        this.configure(config);
        logger.debug('Analytics Config', this._config);

        const client_info = ClientDevice.clientInfo();
        if (client_info.platform) { this._config.platform = client_info.platform; }

        this._buffer = [];
    } 

    /**
     * @param {Object} config - The configuration object
     * @return {Object} - Current configuration
     */
    configure(config) {
        logger.debug('configure Analytics');
        let conf = config? config.Analytics || config : {};

        if (conf['aws_mobile_analytics_app_id']) {
            conf = {
                appId: conf['aws_mobile_analytics_app_id'],
                platform: 'other',
                region: conf['aws_project_region']
            }
        }

        this._config = Object.assign({}, this._config, conf);

        this._initClients();

        return this._config;
    }

    /**
     * Record session start
     */
    startSession() {
        if (this.amaClient) {
            this.amaClient.startSession();
        }
    }

    /**
     * Record session stop
     */
    stopSession() {
        if (this.amaClient) {
            this.amaClient.stopSession();
        }
    }

    /**
     * Restart Analytics client with credentials provided
     * @param {Object} credentials - Cognito Credentials
     */
    restart(credentials) {
        try {
            this.stopSession();
            this._config.credentials = credentials;
            this._initClients();
        } catch(e) {
            logger.error(e);
        }
    }

    /**
     * Record one analytic event and send it to Pinpoint
     * @param {String} name - The name of the event
     * @param {Object} [attributs] - Attributes of the event
     * @param {Object} [metrics] - Event metrics
     */
    record(name, attributes, metrics) {
        logger.debug('record event ' + name);
        if (!this.amaClient) {
            logger.debug('amaClient not ready, put in buffer');
            this._buffer.push({
                name: name,
                attribtues: attributes,
                metrics: metrics
            });
            return;
        }
        this.amaClient.recordEvent(name, attributes, metrics);
    }

    /**
     * Record one analytic event
     * @param {Object} event - Event object
     * @param {Object} [attributes] - Attributes of the event
     * @param {Object} [metrics] - Event metrics
     */
    recordMonetization(event, attributes, metrics) {
        this.amaClient.recordMonetizationEvent(event, attributes, metrics);
    }

    /**
     * @private
     */
    _ensureCredentials() {
        const conf = this._config;
        if (conf.credentials) { return Promise.resolve(true); }

        return Auth.currentCredentials()
            .then(credentials => {
                const cred = Auth.essentialCredentials(credentials);
                logger.debug('set credentials for analytics', cred);
                conf.credentials = cred;

                if (!conf.clientId && conf.credentials) {
                    conf.clientId = conf.credentials.identityId;
                }

                return true;
            })
            .catch(err => {
                logger.error(err)
                return false;
            });
    }

    /**
     * @private
     */
    _checkConfig() {
        return !!this._config.appId;
    }

    /**
     * @private
     */
    async _initClients() {
        if (!this._checkConfig()) { return false; }

        const credentialsOK = await this._ensureCredentials();
        if (!credentialsOK) { return false; }

        this._initAMA();
        this._initPinpoint();
        this.startSession();

        return true;
    }

    /**
     * @private
     */
    _initAMA() {
        logger.debug('init AMA');
        const { appId, platform, clientId, region, credentials } = this._config;
        this.amaClient = new AMA.Manager({
            appId: appId,
            platform: platform,
            clientId: clientId,
            logger: ama_logger,
            clientOptions: {
                region: region,
                credentials: credentials
            }
        });

        if (this._buffer.length > 0) {
            logger.debug('something in buffer, flush it');
            const buffer = this._buffer;
            this._buffer = [];
            buffer.forEach(event => {
                this.amaClient.recordEvent(event.name, event.attributes, event.metrics);
            });
        }
    }

    /**
     * @private
     */
    _initPinpoint() {
        logger.debug('init Pinpoint');
        const { region, appId, clientId, credentials } = this._config;
        this.pinpointClient = new Pinpoint({
            region: region,
            credentials: credentials
        });

        const request = this._endpointRequest();
        const update_params = {
            ApplicationId: appId,
            EndpointId: clientId,
            EndpointRequest: request
        };
        logger.debug(update_params);

        this.pinpointClient.updateEndpoint(update_params, function(err, data) {
            if (err) {
                logger.debug('Pinpoint ERROR', err);
            } else {
                logger.debug('Pinpoint SUCCESS', data);
            }
        });
    }

    /**
     * @private
     */
    _endpointRequest() {
        const client_info = ClientDevice.clientInfo();
        const credentials = this._config.credentials;
        const user_id = credentials.authenticated? credentials.identityId : null;
        logger.debug('demographic user id: ' + user_id);
        return {
            Demographic: {
                AppVersion: this._config.appVersion || client_info.appVersion,
                Make: client_info.make,
                Model: client_info.model,
                ModelVersion: client_info.version,
                Platform: client_info.platform
            },
            User: { UserId: user_id }
        };
    }
}

export default AnalyticsClass;