All main settings for the Expresser platform are set and described on the settings.default.json file. Do not edit it!!! To change settings please create a settings.json file and put your values there.
You can also create specific settings for different runtime environments.
For example to set settings on development, create settings.development.json
and for production a settings.production.json file. These will be parsed
AFTER the main settings.json file.
Please note that the settings.json must ne located on the root of your app!
class Settings
crypto = require "crypto"
fs = require "fs"
lodash = require "lodash"
path = require "path"
utils = require "./utils.coffee"
currentEnv: process.env.NODE_ENVLoad settings from settings.default.json, then settings.json, then environment specific settings.
load: =>
@currentEnv = process.env.NODE_ENV or "development"
@loadFromJson "settings.default.json"
@loadFromJson "settings.json"
@loadFromJson "settings.#{@currentEnv.toString().toLowerCase()}.json"Helper to load values from the specified settings file. @param [String] filename The filename or path to the settings file. @param [Boolean] doNotUpdateSettings If true it won’t update the Settings class, default is false. @return [Object] Returns the JSON representation of the loaded file.
loadFromJson: (filename) =>
filename = utils.getFilePath filename
settingsJson = nullHas json? Load it. Try using UTF8 first, if failed, use ASCII.
if filename?
if process.versions.node.indexOf(".10.") > 0
encUtf8 = {encoding: "utf8"}
encAscii = {encoding: "ascii"}
else
encUtf8 = "utf8"
encAscii = "ascii"Try parsing the file with UTF8 first, if fails, try ASCII.
try
settingsJson = fs.readFileSync filename, encUtf8
settingsJson = utils.minifyJson settingsJson
catch ex
settingsJson = fs.readFileSync filename, encAscii
settingsJson = utils.minifyJson settingsJsonHelper function to overwrite properties.
xtend = (source, target) ->
for prop, value of source
if value?.constructor is Object
target[prop] = {} if not target[prop]?
xtend source[prop], target[prop]
else
target[prop] = source[prop]
xtend settingsJson, this
if @general.debug and @logger.console
console.log "Settings.loadFromJson", filenameReturn the JSON representation of the file (or null if not found / empty).
return settingsJsonReset to default settings.
reset: =>
@instance = new Settings()
@instance.load()Helper to encrypt or decrypt settings files. The default encryption password
defined on the Settings.coffee file is “ExpresserSettings”, which ideally you
should change. The default cipher algorithm is AES 256.
@param [Boolean] encrypt Pass true to encrypt, false to decrypt.
@param [String] filename The file to be encrypted or decrypted.
@param [Object] options Options to be passed to the cipher.
@option options [String] cipher The cipher to be used, default is aes256.
@option options [String] password The default encryption password.
cryptoHelper: (encrypt, filename, options) =>
options = {} if not options?
options = lodash.defaults options, {cipher: "aes256", password: "ExpresserSettings"}
settingsJson = @loadFromJson filename, falseSettings file not found or invalid? Stop here.
if not settingsJson? and @logger.console
console.warn "Settings.cryptoHelper", encrypt, filename, "File not found or invalid, abort!"
return falseIf trying to encrypt and settings property encrypted is true,
abort encryption and log to the console.
if settingsJson.encrypted is true and encrypt
if @logger.console
console.warn "Settings.cryptoHelper", encrypt, filename, "Property 'encrypted' is true, abort!"
return falseHelper to parse and encrypt / decrypt settings data.
parser = (obj) =>
currentValue = null
for prop, value of obj
if value?.constructor is Object
parser obj[prop]
else
try
currentValue = obj[prop]
if encryptCheck the property data type and prefix the new value.
if lodash.isBoolean currentValue
newValue = "bool:"
else if lodash.isNumber currentValue
newValue = "number:"
else
newValue = "string:"Create cipher amd encrypt data.
c = crypto.createCipher options.cipher, options.password
newValue += c.update currentValue.toString(), @general.encoding, "hex"
newValue += c.final "hex"
elseSplit the data as “datatype:encryptedValue”.
arrValue = currentValue.split ":"
newValue = ""Create cipher and decrypt.
c = crypto.createDecipher options.cipher, options.password
newValue += c.update arrValue[1], "hex", @general.encoding
newValue += c.final @general.encodingCast data type (boolean, number or string).
if arrValue[0] is "bool"
if newValue is "true" or newValue is "1"
newValue = true
else
newValue = false
else if arrValue[0] is "number"
newValue = parseFloat newValue
catch ex
if @logger.console
console.error "Settings.cryptoHelper", encrypt, filename, ex, currentValueUpdate settings property value.
obj[prop] = newValueRemove encrypted property prior to decrypting.
if not encrypt
delete settingsJson["encrypted"]Process settings data.
parser settingsJsonAdd encrypted property after file is encrypted.
if encrypt
settingsJson.encrypted = trueStringify and save the new settings file.
newSettingsJson = JSON.stringify settingsJson, null, 4
if process.versions.node.indexOf(".10.") > 0
fs.writeFileSync filename, newSettingsJson, {encoding: @general.encoding}
else
fs.writeFileSync filename, newSettingsJson, @general.encoding
return trueHelper to encrypt the specified settings file. Please see cryptoHelper above.
@param [String] filename The file to be encrypted.
@param [Object] options Options to be passed to the cipher.
@return [Boolean] Returns true if encryption OK, false if something went wrong.
encrypt: (filename, options) =>
@cryptoHelper true, filename, optionsHelper to decrypt the specified settings file. Please see cryptoHelper above.
@param [String] filename The file to be decrypted.
@param [Object] options Options to be passed to the cipher.
@return [Boolean] Returns true if decryption OK, false if something went wrong.
decrypt: (filename, options) =>
@cryptoHelper false, filename, optionsEnable or disable the settings files watcher to auto reload settings when file changes.
The callback is optional in case you want to notify another module about settings updates.
@param [Boolean] enable If enabled is true activate the fs watcher, otherwise deactivate.
@param [Method] callback A function (event, filename) triggered when a settings file changes.
watch: (enable, callback) =>
if callback? and not lodash.isFunction callback
throw new TypeError "The callback must be a valid function, or null/undefined."
logToConsole = @general.debug and @logger.consoleAdd / remove watcher for the @json file if it exists.
filename = utils.getFilePath "settings.json"
if filename?
if enable
fs.watchFile filename, {persistent: true}, (evt, filename) =>
@loadFromJson filename
console.log "Settings.watch", filename, "Reloaded!" if logToConsole
callback(evt, filename) if callback?
else
fs.unwatchFile filename, callbackAdd / remove watcher for the settings.NODE_ENV.json file if it exists.
filename = utils.getFilePath "settings.#{@currentEnv.toString().toLowerCase()}.json"
if filename?
if enable
fs.watchFile filename, {persistent: true}, (evt, filename) =>
@loadFromJson filename
console.log "Settings.watch", filename, "Reloaded!" if logToConsole
callback(evt, filename) if callback?
else
fs.unwatchFile filename, callback
if logToConsole
console.log "Settings.watch", enable, (if callback? then "With callback" else "No callback")Update settings based on Cloud Environmental variables. If a filter is specified,
update only settings that match it, otherwise update everything.
@param [String] filter Filter settings to be updated, for example “mailer” or “database”.
updateFromPaaS: (filter) =>
env = process.env
filter = false if not filter? or filter is ""Update app IP and port (OpenShift, AppFog).
if not filter or filter.indexOf("app") >= 0
ip = env.OPENSHIFT_NODEJS_IP or env.IP
port = env.OPENSHIFT_NODEJS_PORT or env.VCAP_APP_PORT or env.PORT
@app.ip = ip if ip? and ip isnt ""
@app.port = port if port? and port isnt ""Update database settings (AppFog, MongoLab, MongoHQ).
if not filter or filter.indexOf("database") >= 0
vcap = env.VCAP_SERVICES
vcap = JSON.parse vcap if vcap?Check for AppFog MongoDB variables.
if vcap? and vcap isnt ""
mongo = vcap["mongodb-1.8"]
mongo = mongo[0]["credentials"] if mongo?
if mongo?
@database.connString = "mongodb://#{mongo.hostname}:#{mongo.port}/#{mongo.db}"Check for MongoLab variables.
mongoLab = env.MONGOLAB_URI
@database.connString = mongoLab if mongoLab? and mongoLab isnt ""Check for MongoHQ variables.
mongoHq = env.MONGOHQ_URL
@database.connString = mongoHq if mongoHq? and mongoHq isnt ""Update logger settings (Logentries and Loggly).
if not filter or filter.indexOf("logger") >= 0
logentriesToken = env.LOGENTRIES_TOKEN
logglyToken = env.LOGGLY_TOKEN
logglySubdomain = env.LOGGLY_SUBDOMAIN
@logger.logentries.token = logentriesToken if logentriesToken? and logentriesToken isnt ""
@logger.loggly.token = logglyToken if logglyToken? and logglyToken isnt ""
@logger.loggly.subdomain = logglySubdomain if logglySubdomain? and logglySubdomain isnt ""Update mailer settings (SendGrid, Mandrill, Mailgun).
if not filter or filter.indexOf("mail") >= 0
currentSmtpHost = @mailer.smtp.host?.toLowerCase()
currentSmtpHost = "" if not currentSmtpHost?Get and set SendGrid.
smtpUser = env.SENDGRID_USERNAME
smtpPassword = env.SENDGRID_PASSWORD
if currentSmtpHost.indexOf("sendgrid") >= 0
if currentSmtpHost is "sendgrid"
@mailer.smtp.host = "smtp.sendgrid.net"
@mailer.smtp.port = 587
@mailer.smtp.secure = false
if smtpUser? and smtpUser isnt "" and smtpPassword? and smtpPassword isnt ""
@mailer.smtp.user = smtpUser
@mailer.smtp.password = smtpPasswordGet and set Mandrill.
smtpUser = env.MANDRILL_USERNAME
smtpPassword = env.MANDRILL_APIKEY
if currentSmtpHost.indexOf("mandrill") >= 0
if currentSmtpHost is "mandrill"
@mailer.smtp.host = "smtp.mandrillapp.com"
@mailer.smtp.port = 587
@mailer.smtp.secure = false
if smtpUser? and smtpUser isnt "" and smtpPassword? and smtpPassword isnt ""
@mailer.smtp.user = smtpUser
@mailer.smtp.password = smtpPasswordGet and set Mailgun.
smtpHost = env.MAILGUN_SMTP_SERVER
smtpPort = env.MAILGUN_SMTP_PORT
smtpUser = env.MAILGUN_SMTP_LOGIN
smtpPassword = env.MAILGUN_SMTP_PASSWORD
if currentSmtpHost.indexOf("mailgun") >= 0
if smtpHost? and smtpHost isnt "" and smtpPort? and smtpPort isnt ""
@mailer.smtp.host = smtpHost
@mailer.smtp.port = smtpPort
else if currentSmtpHost is "mailgun"
@mailer.smtp.host = "smtp.mailgun.org"
@mailer.smtp.port = 587
@mailer.smtp.secure = false
if smtpUser? and smtpUser isnt "" and smtpPassword? and smtpPassword isnt ""
@mailer.smtp.user = smtpUser
@mailer.smtp.password = smtpPasswordLog to console.
if @general.debug and @logger.console
console.log "Settings.updateFromPaaS", "Updated!", filterSettings.getInstance = ->
if not @instance?
@instance = new Settings()Load default settings and force disable console log on test.
@instance.load()
@instance.logger.console = false if @instance.currentEnv is "test"
return @instance
module.exports = exports = Settings.getInstance()