utilities/deviceFingerprintUtility.js

'use strict';

const _isNil = require('lodash/isNil');
const _isString = require('lodash/isString');
const _isObject= require('lodash/isObject');

/**
 * @class
 * @description A general-purpose set of utility and helper
 * functions for computing what K4 Device Class a given device belongs to.
 */
class DeviceFingerprintUtility {
    /**
     * @constructor
     * @param {Adapter} adapter
     */
    constructor(adapter) {
        this.adapter = adapter;
    }

    /**
     * @description Based on the supplied identifier field
     * names/types to check against, and a fallback default class name, computes
     * the appropriate device class.
     * @param {String[]} identifierFieldNames A list of accepted field names to
     * use from the device mapping fingerprint against which to compare a supplied
     * set of input candidate values.
     * @param {Object} inputDeviceCandidateValues Key-value pairs of information
     * from the device candidate to investigate and compare against the specified
     * field names from each device fingerprint in the mappings.
     * @param {String} [fallbackClsName] If no device class match is found, use
     * this device class.
     * @returns {String} Returns the matching device class for the candidate values
     * supplied compared against the select fields from the device fingerprint.
     * If no class is found, the fallback class string is returned. If that too
     * is not specified, an empty string is returned.
     */
    calculateDeviceClass(identifierFieldNames, inputDeviceCandidateValues, fallbackClsName) {
        const fallbackClassNameToUse = _isString(fallbackClsName) ? fallbackClsName : '';

        if (!Array.isArray(identifierFieldNames) ||
            identifierFieldNames.length === 0) {
            return fallbackClassNameToUse;
        }

        if (!_isObject(inputDeviceCandidateValues) ||
            Object.keys(inputDeviceCandidateValues).length === 0) {
            return fallbackClassNameToUse;
        }

        const mappingDeviceClassesList = Object.keys(this.adapter.mapping);

        for (let k = 0; k < mappingDeviceClassesList.length; k += 1) {
            const currentDeviceClass = mappingDeviceClassesList[k];
            const currentDeviceMapping = this.adapter.mapping[currentDeviceClass];
            const currentDeviceFingerprint = currentDeviceMapping.fingerprint;
            if (!_isNil(currentDeviceFingerprint) &&
                _isObject(currentDeviceFingerprint)) {
                const isAMatch = Object.keys(currentDeviceFingerprint)
                    .filter(fingerprintField => identifierFieldNames.indexOf(fingerprintField) > -1)
                    .reduce((accumulator, currentFingerprintField) => {
                        return (
                            accumulator &&
                            (currentDeviceFingerprint[currentFingerprintField].indexOf(inputDeviceCandidateValues[currentFingerprintField]) > -1)
                        );
                    }, true);

                if (isAMatch === true) {
                    return currentDeviceClass;
                }
            }
        }

        return fallbackClassNameToUse;
    }
};

module.exports = DeviceFingerprintUtility;