expresser
Version:
A ready-to-use platform for Node.js web apps, built on top of Express.
570 lines (311 loc) • 28.3 kB
HTML
<html>
<head>
<title>utils.coffee</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="stylesheet" media="all" href="public/stylesheets/normalize.css" />
<link rel="stylesheet" media="all" href="docco.css" />
</head>
<body>
<div class="container">
<div class="page">
<div class="header">
<h1>utils.coffee</h1>
<div class="toc">
<h3>Table of Contents</h3>
<ol>
<li>
<a class="source" href="index.html">
index.coffee
</a>
</li>
<li>
<a class="source" href="app.html">
app.coffee
</a>
</li>
<li>
<a class="source" href="cron.html">
cron.coffee
</a>
</li>
<li>
<a class="source" href="database.html">
database.coffee
</a>
</li>
<li>
<a class="source" href="downloader.html">
downloader.coffee
</a>
</li>
<li>
<a class="source" href="events.html">
events.coffee
</a>
</li>
<li>
<a class="source" href="firewall.html">
firewall.coffee
</a>
</li>
<li>
<a class="source" href="imaging.html">
imaging.coffee
</a>
</li>
<li>
<a class="source" href="logger.html">
logger.coffee
</a>
</li>
<li>
<a class="source" href="mailer.html">
mailer.coffee
</a>
</li>
<li>
<a class="source" href="settings.html">
settings.coffee
</a>
</li>
<li>
<a class="source" href="sockets.html">
sockets.coffee
</a>
</li>
<li>
<a class="source" href="utils.html">
utils.coffee
</a>
</li>
</ol>
</div>
</div>
<h2 id="expresser-utils">EXPRESSER UTILS</h2>
<p>General network, IO, client and server utilities. As this module can’t reference
any other module but Settings, all its logging will be done to the console only.</p>
<div class='highlight'><pre><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Utils</span></span>
crypto = <span class="hljs-built_in">require</span> <span class="hljs-string">"crypto"</span>
fs = <span class="hljs-built_in">require</span> <span class="hljs-string">"fs"</span>
lodash = <span class="hljs-built_in">require</span> <span class="hljs-string">"lodash"</span>
moment = <span class="hljs-built_in">require</span> <span class="hljs-string">"moment"</span>
os = <span class="hljs-built_in">require</span> <span class="hljs-string">"os"</span>
path = <span class="hljs-built_in">require</span> <span class="hljs-string">"path"</span>
settings = <span class="hljs-built_in">require</span> <span class="hljs-string">"./settings.coffee"</span></pre></div>
<h2 id="server-info-utils">SERVER INFO UTILS</h2>
<p>Helper to get the correct filename for general files. For example
the settings.json file or cron.json for cron jobs. This will look into the current
directory, the running directory and the root directory of the app.
Returns null if no file is found.
@param [String] filename The base filename (with extension) of the config file.
@return [String] The full path to the config file if one was found, or null.</p>
<div class='highlight'><pre> <span class="hljs-attribute">getFilePath</span>: <span class="hljs-function"><span class="hljs-params">(filename)</span> -></span>
originalFilename = <span class="hljs-string">"./"</span> + filename.toString()
<span class="hljs-keyword">if</span> fs.existsSync?
exists = fs.existsSync
<span class="hljs-keyword">else</span>
exists = path.existsSync</pre></div>
<p>Check if file exists.</p>
<div class='highlight'><pre> hasJson = exists filename
<span class="hljs-keyword">return</span> filename <span class="hljs-keyword">if</span> hasJson</pre></div>
<p>Try current path..</p>
<div class='highlight'><pre> filename = path.resolve __dirname, originalFilename
hasJson = exists filename
<span class="hljs-keyword">return</span> filename <span class="hljs-keyword">if</span> hasJson</pre></div>
<p>Try parent path..</p>
<div class='highlight'><pre> filename = path.resolve __dirname, <span class="hljs-string">"../"</span>, originalFilename
hasJson = exists filename
<span class="hljs-keyword">return</span> filename <span class="hljs-keyword">if</span> hasJson</pre></div>
<p>If file does not exist on local path, try application root path.</p>
<div class='highlight'><pre> filename = path.resolve path.dirname(<span class="hljs-built_in">require</span>.main.filename), originalFilename
hasJson = exists filename
<span class="hljs-keyword">return</span> filename <span class="hljs-keyword">if</span> hasJson</pre></div>
<p>Nothing found, so return null.</p>
<div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span></pre></div>
<p>Returns a list of valid server IP addresses. If <code>firstOnly</code> is true it will
return only the very first IP address found.
@param [Boolean] firstOnly Optional, default is false which returns an array with all valid IPs, true returns a String will first valid IP.
@return The server IPv4 address, or null.</p>
<div class='highlight'><pre> <span class="hljs-attribute">getServerIP</span>: <span class="hljs-function"><span class="hljs-params">(firstOnly)</span> -></span>
ifaces = os.networkInterfaces()
result = []</pre></div>
<p>Parse network interfaces and try getting the server IPv4 address.</p>
<div class='highlight'><pre> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">of</span> ifaces
ifaces[i].forEach <span class="hljs-function"><span class="hljs-params">(details)</span> -></span>
<span class="hljs-keyword">if</span> details.family <span class="hljs-keyword">is</span> <span class="hljs-string">"IPv4"</span> <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> details.internal
result.push details.address</pre></div>
<p>Return only first IP or all of them?</p>
<div class='highlight'><pre> <span class="hljs-keyword">if</span> firstOnly
<span class="hljs-keyword">return</span> result[<span class="hljs-number">0</span>]
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">return</span> result</pre></div>
<p>Return an object with general information about the server.
@return [Object] Results with process pid, platform, memory, uptime and IP.</p>
<div class='highlight'><pre> <span class="hljs-attribute">getServerInfo</span>:<span class="hljs-function"> =></span>
result = {}</pre></div>
<p>Save parsed OS info to the result object.</p>
<div class='highlight'><pre> result.uptime = moment.duration(process.uptime, <span class="hljs-string">"s"</span>).humanize()
result.hostname = os.hostname()
result.title = path.basename process.title
result.platform = os.platform() + <span class="hljs-string">" "</span> + os.arch() + <span class="hljs-string">" "</span> + os.release()
result.memoryTotal = (os.totalmem() / <span class="hljs-number">1024</span> / <span class="hljs-number">1024</span>).toFixed(<span class="hljs-number">0</span>) + <span class="hljs-string">" MB"</span>
result.memoryUsage = <span class="hljs-number">100</span> - (os.freemem() / os.totalmem() * <span class="hljs-number">100</span>).toFixed(<span class="hljs-number">0</span>)
result.loadAvg = os.loadavg()
result.ips = <span class="hljs-property">@getServerIP</span>()
result.process = {<span class="hljs-attribute">pid</span>: process.pid, <span class="hljs-attribute">memoryUsage</span>: (process.memoryUsage().rss / <span class="hljs-number">1024</span> / <span class="hljs-number">1024</span>).toFixed(<span class="hljs-number">0</span>) + <span class="hljs-string">" MB"</span>}
<span class="hljs-keyword">return</span> result</pre></div>
<h2 id="client-info-utils">CLIENT INFO UTILS</h2>
<p>Get the client or browser IP. Works for http and socket requests, even when behind a proxy.
@param [Object] reqOrSocket The request or socket object.
@return [String] The client IP address, or null.</p>
<div class='highlight'><pre> <span class="hljs-attribute">getClientIP</span>: <span class="hljs-function"><span class="hljs-params">(reqOrSocket)</span> -></span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> reqOrSocket?</pre></div>
<p>Try getting the xforwarded header first.</p>
<div class='highlight'><pre> <span class="hljs-keyword">if</span> reqOrSocket.header?
xfor = reqOrSocket.header <span class="hljs-string">"X-Forwarded-For"</span>
<span class="hljs-keyword">if</span> xfor? <span class="hljs-keyword">and</span> xfor <span class="hljs-keyword">isnt</span> <span class="hljs-string">""</span>
<span class="hljs-keyword">return</span> xfor.split(<span class="hljs-string">","</span>)[<span class="hljs-number">0</span>]</pre></div>
<p>Get remote address.</p>
<div class='highlight'><pre> <span class="hljs-keyword">if</span> reqOrSocket.connection?
<span class="hljs-keyword">return</span> reqOrSocket.connection.remoteAddress
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">return</span> reqOrSocket.remoteAddress</pre></div>
<p>Get the client’s device. This identifier string is based on the user agent.
@param [Object] req The request object.
@return [String] The client’s device.</p>
<div class='highlight'><pre> <span class="hljs-attribute">getClientDevice</span>: <span class="hljs-function"><span class="hljs-params">(req)</span> -></span>
ua = req.headers[<span class="hljs-string">"user-agent"</span>]</pre></div>
<p>Find mobile devices.</p>
<div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-string">"mobile-wp-8"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"Windows Phone 8"</span>) > <span class="hljs-number">0</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"mobile-wp-7"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"Windows Phone 7"</span>) > <span class="hljs-number">0</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"mobile-wp"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"Windows Phone"</span>) > <span class="hljs-number">0</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"mobile-iphone-5"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"iPhone5"</span>) > <span class="hljs-number">0</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"mobile-iphone-4"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"iPhone4"</span>) > <span class="hljs-number">0</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"mobile-iphone"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"iPhone"</span>) > <span class="hljs-number">0</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"mobile-android-5"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"Android 5"</span>) > <span class="hljs-number">0</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"mobile-android-4"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"Android 4"</span>) > <span class="hljs-number">0</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"mobile-android"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"Android"</span>) > <span class="hljs-number">0</span></pre></div>
<p>Find desktop browsers.</p>
<div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-string">"desktop-chrome"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"Chrome/"</span>) > <span class="hljs-number">0</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"desktop-firefox"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"Firefox/"</span>) > <span class="hljs-number">0</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"desktop-safari"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"Safari/"</span>) > <span class="hljs-number">0</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"desktop-opera"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"Opera/"</span>) > <span class="hljs-number">0</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"desktop-ie-11"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"MSIE 11"</span>) > <span class="hljs-number">0</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"desktop-ie-10"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"MSIE 10"</span>) > <span class="hljs-number">0</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"desktop-ie-9"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"MSIE 9"</span>) > <span class="hljs-number">0</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"desktop-ie"</span> <span class="hljs-keyword">if</span> ua.indexOf(<span class="hljs-string">"MSIE"</span>) > <span class="hljs-number">0</span></pre></div>
<p>Return default desktop value if no specific devices were found on user agent.</p>
<div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-string">"desktop"</span></pre></div>
<h2 id="io-and-datautils">IO AND DATAUTILS</h2>
<p>Copy the <code>src</code> file to the <code>target</code>, both must be the full file path.
@param [String] src The full source file path.
@param [String] target The full target file path.</p>
<div class='highlight'><pre> <span class="hljs-attribute">copyFileSync</span>: <span class="hljs-function"><span class="hljs-params">(src, target)</span> =></span>
srcContents = fs.readFileSync src
fs.writeFileSync target, srcContents</pre></div>
<p>Minify the passed JSON value. Removes comments, unecessary white spaces etc.
@param [String] source The JSON text to be minified.
@param [Boolean] asString If true, return as string instead of JSON object.
@return [String] The minified JSON, or an empty string if there’s an error.</p>
<div class='highlight'><pre> <span class="hljs-attribute">minifyJson</span>: <span class="hljs-function"><span class="hljs-params">(source, asString)</span> -></span>
source = JSON.stringify source <span class="hljs-keyword">if</span> <span class="hljs-keyword">typeof</span> source <span class="hljs-keyword">is</span> <span class="hljs-string">"object"</span>
index = <span class="hljs-number">0</span>
length = source.length
result = <span class="hljs-string">""</span>
symbol = <span class="hljs-literal">undefined</span>
position = <span class="hljs-literal">undefined</span></pre></div>
<p>Main iterator.</p>
<div class='highlight'><pre> <span class="hljs-keyword">while</span> index < length
symbol = source.charAt index
<span class="hljs-keyword">switch</span> symbol</pre></div>
<p>Ignore whitespace tokens. According to ES 5.1 section 15.12.1.1,
whitespace tokens include tabs, carriage returns, line feeds, and
space characters.</p>
<div class='highlight'><pre> <span class="hljs-keyword">when</span> <span class="hljs-string">"\t"</span>, <span class="hljs-string">"\r"</span>
, <span class="hljs-string">"\n"</span>
, <span class="hljs-string">" "</span>
index += <span class="hljs-number">1</span></pre></div>
<p>Ignore line and block comments.</p>
<div class='highlight'><pre> <span class="hljs-keyword">when</span> <span class="hljs-string">"/"</span>
symbol = source.charAt(index += <span class="hljs-number">1</span>)
<span class="hljs-keyword">switch</span> symbol</pre></div>
<p>Line comments.</p>
<div class='highlight'><pre> <span class="hljs-keyword">when</span> <span class="hljs-string">"/"</span>
position = source.indexOf(<span class="hljs-string">"\n"</span>, index)</pre></div>
<p>Check for CR-style line endings.</p>
<div class='highlight'><pre> position = source.indexOf(<span class="hljs-string">"\r"</span>, index) <span class="hljs-keyword">if</span> position < <span class="hljs-number">0</span>
index = (<span class="hljs-keyword">if</span> position > -<span class="hljs-number">1</span> <span class="hljs-keyword">then</span> position <span class="hljs-keyword">else</span> length)</pre></div>
<p>Block comments.</p>
<div class='highlight'><pre> <span class="hljs-keyword">when</span> <span class="hljs-string">"*"</span>
position = source.indexOf(<span class="hljs-string">"*/"</span>, index)
<span class="hljs-keyword">if</span> position > -<span class="hljs-number">1</span></pre></div>
<p>Advance the scanner’s position past the end of the comment.</p>
<div class='highlight'><pre> index = position += <span class="hljs-number">2</span>
<span class="hljs-keyword">break</span>
<span class="hljs-keyword">throw</span> SyntaxError(<span class="hljs-string">"Unterminated block comment."</span>)
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">throw</span> SyntaxError(<span class="hljs-string">"Invalid comment."</span>)</pre></div>
<p>Parse strings separately to ensure that any whitespace characters and
JavaScript-style comments within them are preserved.</p>
<div class='highlight'><pre> <span class="hljs-keyword">when</span> <span class="hljs-string">"\""</span>
position = index
<span class="hljs-keyword">while</span> index < length
symbol = source.charAt(index += <span class="hljs-number">1</span>)
<span class="hljs-keyword">if</span> symbol <span class="hljs-keyword">is</span> <span class="hljs-string">"\\"</span></pre></div>
<p>Skip past escaped characters.</p>
<div class='highlight'><pre> index += <span class="hljs-number">1</span>
<span class="hljs-keyword">else</span> <span class="hljs-keyword">break</span> <span class="hljs-keyword">if</span> symbol <span class="hljs-keyword">is</span> <span class="hljs-string">"\""</span>
<span class="hljs-keyword">if</span> source.charAt(index) <span class="hljs-keyword">is</span> <span class="hljs-string">"\""</span>
result += source.slice(position, index += <span class="hljs-number">1</span>)
<span class="hljs-keyword">break</span>
<span class="hljs-keyword">throw</span> SyntaxError(<span class="hljs-string">"Unterminated string."</span>)</pre></div>
<p>Preserve all other characters.</p>
<div class='highlight'><pre> <span class="hljs-keyword">else</span>
result += symbol
index += <span class="hljs-number">1</span></pre></div>
<p>Check if should return as string or JSON.</p>
<div class='highlight'><pre> <span class="hljs-keyword">if</span> asString
<span class="hljs-keyword">return</span> result
<span class="hljs-keyword">else</span>
<span class="hljs-keyword">return</span> JSON.parse result</pre></div>
<p>Helper to convert HSL colour to HEX. Used by Philips Hue and other colored lights.
@param [Number] h The hue value.
@param [Number] s The saturation value.
@param [Number] l The brightness value.
@return [String] The colour in HEX format.</p>
<div class='highlight'><pre> <span class="hljs-attribute">hslToHex</span>: <span class="hljs-function"><span class="hljs-params">(h, s, l)</span> -></span>
x = h
y = s
z = <span class="hljs-number">1.0</span> - x - y
Y = l
X = (Y / y) * x
Z = (Y / y) * z
r = X * <span class="hljs-number">1.612</span> - Y * <span class="hljs-number">0.203</span> - Z * <span class="hljs-number">0.302</span>
g = -X * <span class="hljs-number">0.509</span> + Y * <span class="hljs-number">1.412</span> + Z * <span class="hljs-number">0.066</span>
b = X * <span class="hljs-number">0.026</span> - Y * <span class="hljs-number">0.072</span> + Z * <span class="hljs-number">0.962</span>
r = (<span class="hljs-keyword">if</span> r <= <span class="hljs-number">0.0031308</span> <span class="hljs-keyword">then</span> <span class="hljs-number">12.92</span> * r <span class="hljs-keyword">else</span> (<span class="hljs-number">1.0</span> + <span class="hljs-number">0.055</span>) * Math.pow(r, (<span class="hljs-number">1.0</span> / <span class="hljs-number">2.4</span>)) - <span class="hljs-number">0.055</span>)
g = (<span class="hljs-keyword">if</span> g <= <span class="hljs-number">0.0031308</span> <span class="hljs-keyword">then</span> <span class="hljs-number">12.92</span> * g <span class="hljs-keyword">else</span> (<span class="hljs-number">1.0</span> + <span class="hljs-number">0.055</span>) * Math.pow(g, (<span class="hljs-number">1.0</span> / <span class="hljs-number">2.4</span>)) - <span class="hljs-number">0.055</span>)
b = (<span class="hljs-keyword">if</span> b <= <span class="hljs-number">0.0031308</span> <span class="hljs-keyword">then</span> <span class="hljs-number">12.92</span> * b <span class="hljs-keyword">else</span> (<span class="hljs-number">1.0</span> + <span class="hljs-number">0.055</span>) * Math.pow(b, (<span class="hljs-number">1.0</span> / <span class="hljs-number">2.4</span>)) - <span class="hljs-number">0.055</span>)
<span class="hljs-function"><span class="hljs-title">cap</span> = <span class="hljs-params">(x)</span> -></span> Math.max <span class="hljs-number">0</span>, Math.min(<span class="hljs-number">1</span>, x)</pre></div>
<p>Helper to convert RGB to hex.</p>
<div class='highlight'><pre> <span class="hljs-function"><span class="hljs-title">rgbhex</span> = <span class="hljs-params">(v)</span> -></span>
v = Math.round(v * <span class="hljs-number">255</span>)
s = <span class="hljs-string">"0"</span> + v.toString(<span class="hljs-number">16</span>)
<span class="hljs-keyword">return</span> s.substr -<span class="hljs-number">2</span></pre></div>
<p>Cap and transform RGB values.</p>
<div class='highlight'><pre> r = rgbhex cap r
g = rgbhex cap g
b = rgbhex cap b</pre></div>
<p>Convert RGB to hex and return result.</p>
<div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-string">"#<span class="hljs-subst">#{r}</span><span class="hljs-subst">#{g}</span><span class="hljs-subst">#{b}</span>"</span></pre></div>
<h2 id="singleton-implementation">Singleton implementation</h2>
<div class='highlight'><pre>Utils.<span class="hljs-function"><span class="hljs-title">getInstance</span> = -></span>
<span class="hljs-property">@instance</span> = <span class="hljs-keyword">new</span> Utils() <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-property">@instance</span>?
<span class="hljs-keyword">return</span> <span class="hljs-property">@instance</span>
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = <span class="hljs-built_in">exports</span> = Utils.getInstance()</pre></div>
<div class="fleur">h</div>
</div>
</div>
</body>
</html>