UNPKG

lisb-hubot

Version:

A simple helpful robot for your Company

247 lines (211 loc) 6.32 kB
'use strict' const EventEmitter = require('events').EventEmitter const User = require('./user') class Brain extends EventEmitter { // Represents somewhat persistent storage for the robot. Extend this. // // Returns a new Brain with no external storage. constructor (robot) { super() this.data = { users: {}, talks: {}, domains: {}, _private: {} } this.getRobot = function () { return robot } this.autoSave = true robot.on('running', () => { this.resetSaveInterval(5) }) } // Public: Store key-value pair under the private namespace and extend // existing @data before emitting the 'loaded' event. // // Returns the instance for chaining. set (key, value) { let pair if (key === Object(key)) { pair = key } else { pair = {} pair[key] = value } Object.keys(pair).forEach((key) => { this.data._private[key] = pair[key] }) this.emit('loaded', this.data) return this } // Public: Get value by key from the private namespace in @data // or return null if not found. // // Returns the value. get (key) { return this.data._private[key] != null ? this.data._private[key] : null } // Public: Remove value by key from the private namespace in @data // if it exists // // Returns the instance for chaining. remove (key) { if (this.data._private[key] != null) { delete this.data._private[key] } return this } // Public: Emits the 'save' event so that 'brain' scripts can handle // persisting. // // Returns nothing. save () { this.emit('save', this.data) } // Public: Emits the 'close' event so that 'brain' scripts can handle closing. // // Returns nothing. close () { clearInterval(this.saveInterval) this.save() this.emit('close') } // Public: Enable or disable the automatic saving // // enabled - A boolean whether to autosave or not // // Returns nothing setAutoSave (enabled) { this.autoSave = enabled } // Public: Reset the interval between save function calls. // // seconds - An Integer of seconds between saves. // // Returns nothing. resetSaveInterval (seconds) { if (this.saveInterval) { clearInterval(this.saveInterval) } this.saveInterval = setInterval(() => { if (this.autoSave) { this.save() } }, seconds * 1000) } // Public: Merge keys loaded from a DB against the in memory representation. // // Returns nothing. // // Caveats: Deeply nested structures don't merge well. mergeData (data) { for (const k in data || {}) { this.data[k] = data[k] } // for old daab versions. ['users', 'talks', 'domains'] .filter(m => this.data[m] && Object.keys(this.data[m]).length > 0) .forEach(m => { console.warn(`Please use brain.${m}().`) this.data[m] = {} }) this.emit('loaded', this.data) } // Public: Get an Array of User objects stored in the brain. // // Returns an Array of User objects. users (domainId) { const adapter = this.getRobot().adapter const delegateToMe = require('./adapter').prototype.users if (adapter && adapter.users !== delegateToMe) { return adapter.users(domainId) } return this.data.users } // Public: Get a User object given a unique identifier. // // Returns a User instance of the specified user. userForId (id, options) { let domainId if (typeof options === 'string') { domainId = options options = undefined } const users = this.users(domainId) let user = users[id] if (!options) { options = {} } options.robot = this.getRobot() if (!user) { user = new User(id, options) users[id] = user } if (options && options.room && (!user.room || user.room !== options.room)) { user = new User(id, options) users[id] = user } delete options.robot return user } // Public: Get a User object given a name. // // Returns a User instance for the user with the specified name. userForName (name, domainId) { let result = null const lowerName = name.toLowerCase() const users = this.users(domainId) for (const k in users || {}) { const userName = users[k].name if (userName != null && userName.toString().toLowerCase() === lowerName) { result = users[k] } } return result } // Public: Get all users whose names match fuzzyName. Currently, match // means 'starts with', but this could be extended to match initials, // nicknames, etc. // // Returns an Array of User instances matching the fuzzy name. usersForRawFuzzyName (fuzzyName, domainId) { const lowerFuzzyName = fuzzyName.toLowerCase() const users = this.users(domainId) || {} return Object.keys(users).reduce((result, key) => { const user = users[key] if (user.name.toLowerCase().lastIndexOf(lowerFuzzyName, 0) === 0) { result.push(user) } return result }, []) } // Public: If fuzzyName is an exact match for a user, returns an array with // just that user. Otherwise, returns an array of all users for which // fuzzyName is a raw fuzzy match (see usersForRawFuzzyName). // // Returns an Array of User instances matching the fuzzy name. usersForFuzzyName (fuzzyName, domainId) { const matchedUsers = this.usersForRawFuzzyName(fuzzyName, domainId) const lowerFuzzyName = fuzzyName.toLowerCase() const fuzzyMatchedUsers = matchedUsers.filter(user => user.name.toLowerCase() === lowerFuzzyName) return fuzzyMatchedUsers.length > 0 ? fuzzyMatchedUsers : matchedUsers } // Public: Get an Array of Talk objects stored in the brain. // // Returns an Array of Talk objects. rooms () { const adapter = this.getRobot().adapter if (adapter && typeof adapter.talks === 'function') return adapter.talks() return this.data.talks } // Public: Get an Array of Domain objects stored in the brain. // // Returns an Array of Domain objects. domains () { const adapter = this.getRobot().adapter if (adapter && typeof adapter.domains === 'function') return adapter.domains() return this.data.domains } } module.exports = Brain