corrade-group-linguistics – Rev 2

Subversion Repositories:
Rev:
#!/usr/bin/env nodejs
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2019 Wizardry and Steamworks - License: CC BY 2.0    //
///////////////////////////////////////////////////////////////////////////

const mqtt = require('mqtt')
const YAML = require('yamljs')
const { createLogger, format, transports } = require('winston')
const path = require('path')
const fs = require('fs')
const Sentiment = require('sentiment')
const db = require('quick.db')
const qs = require('qs')
const lambda = require('was.js').lambda

// Create a new sentiment analyzer.
const sentiment = new Sentiment();

// Load configuration file.
const config = YAML.load('config.yml')

// Set up logger.
const logger = createLogger({
    format: format.combine(
        format.splat(),
        format.simple()
    ),
    transports: [
        new transports.Console({
            timestamp: true
        }),
        new transports.File(
            {
                timestamp: true,
                filename: path.join(path.dirname(fs.realpathSync(__filename)), "log/project.log")
            }
        )
    ]
})

// Subscribe to Corrade MQTT.
const mqttClient = mqtt.connect(config.corrade.mqtt)

mqttClient.on('reconnect', () => {
    logger.info('Reconnecting to Corrade MQTT server...')
})

mqttClient.on('connect', () => {
    logger.info('Connected to Corrade MQTT server.')
    // Subscribe to group message notifications with group name and password.
    mqttClient.subscribe(`${config.corrade.group}/${config.corrade.password}/group`, (error) => {
        if (error) {
            logger.info('Error subscribing to Corrade MQTT group messages.')
            return
        }

        logger.info('Subscribed to Corrade MQTT group messages.')
    })
})

mqttClient.on('error', (error) => {
    logger.error(`Error found while connecting to Corrade MQTT: ${error}`)
})

mqttClient.on('message', (topic, message) => {
    let notification = qs.parse(message.toString())

    // Check the notification parameters for sanity.
    if (notification.type !== 'group')
        return

    // Lambda switch @ WaS!
    lambda.switch(
        notification.message.split(' ')[0],
        (execute) => exeUpdate(notification),
        (execute) => execute === config.sentiment.commands.tokens,
        (execute) => exeTokens(notification),
        (execute) => execute === config.sentiment.commands.sentiment,
        (execute) => exeQuery(notification)
    )
})

/* Performs message analysis and updates the database. */
function exeUpdate(notification) {
    const result = sentiment.analyze(notification.message)

    db.add(`group.${notification.group.toUpperCase()}.${notification.firstname.toUpperCase()} ${notification.lastname.toUpperCase()}.tokens.total`, result.tokens.length)
    db.add(`group.${notification.group.toUpperCase()}.${notification.firstname.toUpperCase()} ${notification.lastname.toUpperCase()}.sentiment.score`, result.comparative)

    db.add(`group.${notification.group.toUpperCase()}.tokens.total`, result.tokens.length)
    db.add(`group.${notification.group.toUpperCase()}.sentiment.score`, result.comparative)
}

/* Returns a cumulative sentiment for either a single avatar or for an entire group. */
function exeQuery(notification) {
    const command = notification.message.split(' ')

    const reply = 1 in command && 2 in command ? 
        `${command[1]} ${command[2]}'s overall sentiment: ${db.get(`group.${notification.group.toUpperCase()}.${command[1].toUpperCase()} ${command[2].toUpperCase()}.sentiment.score`)}` : 
        `Overall group sentiment: ${db.get(`group.${notification.group.toUpperCase()}.sentiment.score`)}`

    // Build the tell command.
    const corradeCommand = qs.stringify({
        'command': 'tell',
        'group': config.corrade.group,
        'password': config.corrade.password,
        'entity': 'group',
        'message': reply
    })

    mqttClient.publish(`${config.corrade.group}/${config.corrade.password}/group`, corradeCommand)
    return true
}

/* Returns counted tokens for either a single avatar or for an entire group. */
function exeTokens(notification) {
    const command = notification.message.split(' ')

    const reply = 1 in command && 2 in command ? 
        `${command[1]} ${command[2]}'s uttered a total number of tokens: ${db.get(`group.${notification.group.toUpperCase()}.${command[1].toUpperCase()} ${command[2].toUpperCase()}.tokens.total`)}` : 
        `Tokens uttered in this group: ${db.get(`group.${notification.group.toUpperCase()}.tokens.total`)}`

    // Build the tell command.
    const corradeCommand = qs.stringify({
        'command': 'tell',
        'group': config.corrade.group,
        'password': config.corrade.password,
        'entity': 'group',
        'message': reply
    })

    mqttClient.publish(`${config.corrade.group}/${config.corrade.password}/group`, corradeCommand)

    return true
}