<commit_before>/*jslint node: true */
'use strict';

var winston = require('winston'),
    express = require('express'),
    expressJoi = require('express-joi-validator'),
    expressWinston = require('express-winston'),
    bodyparser = require('body-parser'),
    mqtt = require('mqtt'),
    async = require('async'),
    path = require('path'),
    joi = require('joi'),
    yaml = require('js-yaml'),
    jsonfile = require('jsonfile'),
    fs = require('fs'),
    semver = require('semver'),
    request = require('request');

var CONFIG_DIR = process.env.CONFIG_DIR || process.cwd(),
    CONFIG_FILE = path.join(CONFIG_DIR, 'config.yml'),
    SAMPLE_FILE = path.join(__dirname, '_config.yml'),
    STATE_FILE = path.join(CONFIG_DIR, 'state.json'),
    EVENTS_LOG = path.join(CONFIG_DIR, 'events.log'),
    ACCESS_LOG = path.join(CONFIG_DIR, 'access.log'),
    ERROR_LOG = path.join(CONFIG_DIR, 'error.log'),
    CURRENT_VERSION = require('./package').version;

var app = express(),
    client,
    subscriptions = [],
    callback = '',
    config = {},
    history = {};

// Write all events to disk as well
winston.add(winston.transports.File, {
    filename: EVENTS_LOG,
    json: false
});

/**
 * Load user configuration (or create it)
 * @method loadConfiguration
 * @return {Object} Configuration
 */
function loadConfiguration () {
    if (!fs.existsSync(CONFIG_FILE)) {
        winston.info('No previous configuration found, creating one');
        fs.writeFileSync(CONFIG_FILE, fs.readFileSync(SAMPLE_FILE));
    }

    return yaml.safeLoad(fs.readFileSync(CONFIG_FILE));
}

/**
 * Load the saved previous state from disk
 * @method loadSavedState
 * @return {Object} Configuration
 */
function loadSavedState () {
    var output;
    try {
        output = jsonfile.readFileSync(STATE_FILE);
    } catch (ex) {
        winston.info('No previous state found, continuing');
        output = {
            subscriptions: [],
            callback: '',
            history: {},
            version: '0.0.0'
        };
    }
    return output;
}

/**
 * Resubscribe on a periodic basis
 * @method saveState
 */
function saveState () {
    winston.info('Saving current state');
    jsonfile.writeFileSync(STATE_FILE, {
        subscriptions: subscriptions,
        callback: callback,
        history: history,
        version: CURRENT_VERSION
    }, {
        spaces: 4
    });
}

/**
 * Migrate the configuration from the current version to the latest version
 * @method migrateState
 * @param  {String}     version Version the state was written in before
 */
function migrateState (version) {
    // This is the previous default, but it's totally wrong
    if (config.mqtt && !config.mqtt.preface) {
        config.mqtt.preface = '/smartthings';
    }

    // Stuff was previously in subscription.json, load that and migrate it
    if (semver.lt(version, '1.1.0')) {
        var oldState = jsonfile.readFileSync(path.join(CONFIG_DIR, 'subscription.json'));
        callback = oldState.callback;
        subscriptions = oldState.topics;
    }

    saveState();
}

/**
 * Handle Device Change/Push event from SmartThings
 *
 * @method handlePushEvent
 * @param  {Request} req
 * @param  {Object}  req.body
 * @param  {String}  req.body.name  Device Name (e.g. "Bedroom Light")
 * @param  {String}  req.body.type  Device Property (e.g. "state")
 * @param  {String}  req.body.value Value of device (e.g. "on")
 * @param  {Result}  res            Result Object
 */
function handlePushEvent (req, res) {
    var topic = getTopicFor(req.body.name, req.body.type),
        value = req.body.value;

    winston.info('Incoming message from SmartThings: %s = %s', topic, value);
    history[topic] = value;

    client.publish(topic, value, {
        retain: true
    }, function () {
        res.send({<commit_msg>HotFix for bug with new users without subscription.json<commit_after>/*jslint node: true */
'use strict';

var winston = require('winston'),
    express = require('express'),
    expressJoi = require('express-joi-validator'),
    expressWinston = require('express-winston'),
    bodyparser = require('body-parser'),
    mqtt = require('mqtt'),
    async = require('async'),
    path = require('path'),
    joi = require('joi'),
    yaml = require('js-yaml'),
    jsonfile = require('jsonfile'),
    fs = require('fs'),
    semver = require('semver'),
    request = require('request');

var CONFIG_DIR = process.env.CONFIG_DIR || process.cwd(),
    CONFIG_FILE = path.join(CONFIG_DIR, 'config.yml'),
    SAMPLE_FILE = path.join(__dirname, '_config.yml'),
    STATE_FILE = path.join(CONFIG_DIR, 'state.json'),
    EVENTS_LOG = path.join(CONFIG_DIR, 'events.log'),
    ACCESS_LOG = path.join(CONFIG_DIR, 'access.log'),
    ERROR_LOG = path.join(CONFIG_DIR, 'error.log'),
    CURRENT_VERSION = require('./package').version;

var app = express(),
    client,
    subscriptions = [],
    callback = '',
    config = {},
    history = {};

// Write all events to disk as well
winston.add(winston.transports.File, {
    filename: EVENTS_LOG,
    json: false
});

/**
 * Load user configuration (or create it)
 * @method loadConfiguration
 * @return {Object} Configuration
 */
function loadConfiguration () {
    if (!fs.existsSync(CONFIG_FILE)) {
        winston.info('No previous configuration found, creating one');
        fs.writeFileSync(CONFIG_FILE, fs.readFileSync(SAMPLE_FILE));
    }

    return yaml.safeLoad(fs.readFileSync(CONFIG_FILE));
}

/**
 * Load the saved previous state from disk
 * @method loadSavedState
 * @return {Object} Configuration
 */
function loadSavedState () {
    var output;
    try {
        output = jsonfile.readFileSync(STATE_FILE);
    } catch (ex) {
        winston.info('No previous state found, continuing');
        output = {
            subscriptions: [],
            callback: '',
            history: {},
            version: '0.0.0'
        };
    }
    return output;
}

/**
 * Resubscribe on a periodic basis
 * @method saveState
 */
function saveState () {
    winston.info('Saving current state');
    jsonfile.writeFileSync(STATE_FILE, {
        subscriptions: subscriptions,
        callback: callback,
        history: history,
        version: CURRENT_VERSION
    }, {
        spaces: 4
    });
}

/**
 * Migrate the configuration from the current version to the latest version
 * @method migrateState
 * @param  {String}     version Version the state was written in before
 */
function migrateState (version) {
    // This is the previous default, but it's totally wrong
    if (config.mqtt && !config.mqtt.preface) {
        config.mqtt.preface = '/smartthings';
    }

    // Stuff was previously in subscription.json, load that and migrate it
    var SUBSCRIPTION_FILE = path.join(CONFIG_DIR, 'subscription.json');
    if (semver.lt(version, '1.1.0') && fs.existsSync(SUBSCRIPTION_FILE)) {
        var oldState = jsonfile.readFileSync(SUBSCRIPTION_FILE);
        callback = oldState.callback;
        subscriptions = oldState.topics;
    }

    saveState();
}

/**
 * Handle Device Change/Push event from SmartThings
 *
 * @method handlePushEvent
 * @param  {Request} req
 * @param  {Object}  req.body
 * @param  {String}  req.body.name  Device Name (e.g. "Bedroom Light")
 * @param  {String}  req.body.type  Device Property (e.g. "state")
 * @param  {String}  req.body.value Value of device (e.g. "on")
 * @param  {Result}  res            Result Object
 */
function handlePushEvent (req, res) {
    var topic = getTopicFor(req.body.name, req.body.type),
        value = req.body.value;

    winston.info('Incoming message from SmartThings: %s = %s', topic, value);
    history[topic] = value;

    client.publish(topic, value, {
        retain: true
    }, function () {
        res.send({
{'fraction_non_alphanumeric': 0.13713107359195773, 'fraction_numerical': 0.001804356231473128, 'mean_word_length': 2.995880535530381, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2293005', 'n_tokens_mistral': 2391, 'n_tokens_neox': 2331, 'n_words': 590}