Browse files

Initial commit

  • Loading branch information...
0 parents commit 38c9b69d1f9d39b21d793ccf77451ebf1e53720c @balor committed May 7, 2011
Showing with 490 additions and 0 deletions.
  1. +3 −0 .gitignore
  2. +4 −0 .npmignore
  3. +10 −0 History.md
  4. +6 −0 Makefile
  5. +60 −0 Readme.md
  6. +263 −0 index.html
  7. +2 −0 index.js
  8. +131 −0 lib/connect-memcached.js
  9. +11 −0 package.json
3 .gitignore
@@ -0,0 +1,3 @@
+.DS_Store
+node_modules
+*.sock
4 .npmignore
@@ -0,0 +1,4 @@
+support
+test
+examples
+*.sock
10 History.md
@@ -0,0 +1,10 @@
+
+0.0.2 / 2010-01-03
+==================
+
+ * Created basic version that actually works
+
+0.0.1 / 2010-01-03
+==================
+
+ * Initial release
6 Makefile
@@ -0,0 +1,6 @@
+index.html: lib/connect-memcached.js
+ dox \
+ --title "connection-memcached" \
+ --desc "Memcached session store for Connect" \
+ --ribbon "https://github.com/balor/connection-memcached" \
+ $< > $@
60 Readme.md
@@ -0,0 +1,60 @@
+
+# connect-memcached
+
+ Memcached session store, using [node-memcached](http://github.com/3rd-Eden/node-memcached) for communication with cache server.
+
+## Installation
+
+ via npm:
+
+ $ npm install connect-memcached
+
+## Example
+
+ var connect = require('connect');
+ var MemcachedStore = require('connect-memcached');
+
+ connect.createServer(
+ connect.cookieParser(),
+ connect.session({
+ store: new MemcachedStore({
+ hosts: [
+ '192.168.1.65:11213',
+ '192.168.1.66:11213',
+ '192.168.1.67:11213'
+ ]
+ }),
+ secret: 'thisissosick'
+ })
+ );
+
+## Options
+
+ - `hosts` Memcached servers locations, can by string, array, hash.
+ - ... Rest of given option will be passed directly to the node-memcached constructor.
+ For details see [node-memcached](http://github.com/3rd-Eden/node-memcached).
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2011 Michał Thoma &lt;michal@balor.pl&gt;
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
263 index.html
@@ -0,0 +1,263 @@
+<a href="https://github.com/balor/hop"><img alt="Fork me on GitHub" id="ribbon" src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"></a><html>
+ <head>
+ <title>connection-memcached</title>
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
+ <style>body {
+ margin: 0;
+ padding: 0;
+ font: 14px/1.5 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
+ color: #252519;
+}
+a {
+ color: #252519;
+}
+a:hover {
+ text-decoration: underline;
+ color: #19469D;
+}
+p {
+ margin: 12px 0;
+}
+h1, h2, h3 {
+ margin: 0;
+ padding: 0;
+}
+table#source {
+ width: 100%;
+ border-collapse: collapse;
+}
+table#source td:first-child {
+ padding: 30px 40px 30px 40px;
+ vertical-align: top;
+}
+table#source td:first-child,
+table#source td:first-child pre {
+ width: 450px;
+}
+table#source td:last-child {
+ padding: 30px 0 30px 40px;
+ border-left: 1px solid #E5E5EE;
+ background: #F5F5FF;
+}
+table#source tr {
+ border-bottom: 1px solid #E5E5EE;
+}
+table#source tr.filename {
+ padding-top: 40px;
+ border-top: 1px solid #E5E5EE;
+}
+table#source tr.filename td:first-child {
+ text-transform: capitalize;
+}
+table#source tr.filename td:last-child {
+ font-size: 12px;
+}
+table#source tr.filename h2 {
+ margin: 0;
+ padding: 0;
+ cursor: pointer;
+}
+table#source tr.code h1,
+table#source tr.code h2,
+table#source tr.code h3 {
+ margin-top: 30px;
+ font-family: "Lucida Grande", "Helvetica Nueue", Arial, sans-serif;
+ font-size: 18px;
+}
+table#source tr.code h2 {
+ font-size: 16px;
+}
+table#source tr.code h3 {
+ font-size: 14px;
+}
+table#source tr.code ul {
+ margin: 15px 0 15px 35px;
+ padding: 0;
+}
+table#source tr.code ul li {
+ margin: 0;
+ padding: 1px 0;
+}
+table#source tr.code ul li p {
+ margin: 0;
+ padding: 0;
+}
+table#source tr.code td:first-child pre {
+ padding: 20px;
+}
+#ribbon {
+ position: fixed;
+ top: 0;
+ right: 0;
+}
+code .string { color: #219161; }
+code .regexp { color: #219161; }
+code .keyword { color: #954121; }
+code .number { color: #19469D; }
+code .comment { color: #bbb; }
+code .this { color: #19469D; }</style>
+ <script>
+ $(function(){
+ $('tr.code').hide();
+ $('tr.filename').toggle(function(){
+ $(this).nextUntil('.filename').fadeIn();
+ }, function(){
+ $(this).nextUntil('.filename').fadeOut();
+ });
+ });
+ </script>
+ </head>
+ <body>
+<table id="source"><tbody><tr><td><h1>connection-memcached</h1><p>Memcached session store for Connect</p></td><td></td></tr><tr class="filename"><td><h2 id="lib/connect-memcached.js"><a href="#">connect-memcached</a></h2></td><td>lib/connect-memcached.js</td></tr><tr class="code">
+<td class="docs">
+<p>Library version.
+ </p>
+</td>
+<td class="code">
+<pre><code><span class="variable">exports</span>.<span class="variable">version</span> = <span class="string">'0.0.2'</span>;</code></pre>
+</td>
+</tr>
+<tr class="code">
+<td class="docs">
+<p>Module dependencies.
+ </p>
+</td>
+<td class="code">
+<pre><code><span class="keyword">var</span> <span class="class">Store</span> = <span class="variable">require</span>(<span class="string">'connect'</span>).<span class="variable">session</span>.<span class="class">Store</span>;
+<span class="keyword">var</span> <span class="class">Memcached</span> = <span class="variable">require</span>(<span class="string">'memcached'</span>);</code></pre>
+</td>
+</tr>
+<tr class="code">
+<td class="docs">
+<p>One day in seconds.
+ </p>
+</td>
+<td class="code">
+<pre><code><span class="keyword">var</span> <span class="variable">oneDay</span> = <span class="number integer">86400</span>;</code></pre>
+</td>
+</tr>
+<tr class="code">
+<td class="docs">
+<p>Initialize MemcachedStore with the given <code>options</code>.</p>
+
+<h2></h2>
+
+<ul><li><p><strong>param</strong>: <em>Object</em> options</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>
+</td>
+<td class="code">
+<pre><code><span class="keyword">var</span> <span class="class">MemcachedStore</span> = <span class="variable">module</span>.<span class="variable">exports</span> = <span class="keyword">function</span> <span class="class">MemcachedStore</span>(<span class="variable">options</span>) {
+ <span class="variable">options</span> = <span class="variable">options</span> || {};
+ <span class="class">Store</span>.<span class="variable">call</span>(<span class="this">this</span>, <span class="variable">options</span>);
+ <span class="keyword">if</span> (!<span class="variable">options</span>.<span class="variable">hosts</span>) {
+ <span class="variable">options</span>.<span class="variable">hosts</span> = <span class="string">'127.0.0.1:11211'</span>;
+ }
+ <span class="this">this</span>.<span class="variable">client</span> = <span class="keyword">new</span> <span class="class">Memcached</span>(<span class="variable">options</span>.<span class="variable">hosts</span>, <span class="variable">options</span>);
+ <span class="variable">console</span>.<span class="variable">log</span>(&<span class="variable">quot</span>;<span class="class">MemcachedStore</span> <span class="variable">initialized</span> <span class="keyword">for</span> <span class="variable">servers</span>: &<span class="variable">quot</span>; + <span class="variable">options</span>.<span class="variable">hosts</span>);
+
+ <span class="this">this</span>.<span class="variable">client</span>.<span class="variable">on</span>(&<span class="variable">quot</span>;<span class="variable">issue</span>&<span class="variable">quot</span>;, <span class="keyword">function</span>(<span class="variable">issue</span>) {
+ <span class="variable">console</span>.<span class="variable">log</span>(&<span class="variable">quot</span>;<span class="class">MemcachedStore</span>::<span class="class">Issue</span> @ &<span class="variable">quot</span>; + <span class="variable">issue</span>.<span class="variable">server</span> + &<span class="variable">quot</span>;: &<span class="variable">quot</span>; +
+ <span class="variable">issue</span>.<span class="variable">messages</span> + &<span class="variable">quot</span>;, &<span class="variable">quot</span>; + <span class="variable">issue</span>.<span class="variable">retries</span> + &<span class="variable">quot</span>; <span class="variable">attempts</span> <span class="variable">left</span>&<span class="variable">quot</span>;);
+ });
+};</code></pre>
+</td>
+</tr>
+<tr class="code">
+<td class="docs">
+<p>Inherit from <code>Store</code>.
+ </p>
+</td>
+<td class="code">
+<pre><code><span class="class">MemcachedStore</span>.<span class="variable">prototype</span>.<span class="variable">__proto__</span> = <span class="class">Store</span>.<span class="variable">prototype</span>;</code></pre>
+</td>
+</tr>
+<tr class="code">
+<td class="docs">
+<p>Attempt to fetch session by the given <code>sid</code>.</p>
+
+<h2></h2>
+
+<ul><li><p><strong>param</strong>: <em>String</em> sid</p></li><li><p><strong>param</strong>: <em>Function</em> fn</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>
+</td>
+<td class="code">
+<pre><code><span class="class">MemcachedStore</span>.<span class="variable">prototype</span>.<span class="variable">get</span> = <span class="keyword">function</span>(<span class="variable">sid</span>, <span class="variable">fn</span>) {
+ <span class="this">this</span>.<span class="variable">client</span>.<span class="variable">get</span>(<span class="variable">sid</span>, <span class="keyword">function</span>(<span class="variable">err</span>, <span class="variable">data</span>) {
+ <span class="keyword">try</span> {
+ <span class="keyword">if</span> (!<span class="variable">data</span>) {
+ <span class="keyword">return</span> <span class="variable">fn</span>();
+ }
+ <span class="variable">fn</span>(<span class="keyword">null</span>, <span class="class">JSON</span>.<span class="variable">parse</span>(<span class="variable">data</span>.<span class="variable">toString</span>()));
+ } <span class="keyword">catch</span> (<span class="variable">err</span>) {
+ <span class="variable">fn</span>(<span class="variable">err</span>);
+ }
+ });
+};</code></pre>
+</td>
+</tr>
+<tr class="code">
+<td class="docs">
+<p>Commit the given <code>sess</code> object associated with the given <code>sid</code>.</p>
+
+<h2></h2>
+
+<ul><li><p><strong>param</strong>: <em>String</em> sid</p></li><li><p><strong>param</strong>: <em>Session</em> sess</p></li><li><p><strong>param</strong>: <em>Function</em> fn</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>
+</td>
+<td class="code">
+<pre><code><span class="class">MemcachedStore</span>.<span class="variable">prototype</span>.<span class="variable">set</span> = <span class="keyword">function</span>(<span class="variable">sid</span>, <span class="variable">sess</span>, <span class="variable">fn</span>) {
+ <span class="keyword">try</span> {
+ <span class="keyword">var</span> <span class="variable">maxAge</span> = <span class="variable">sess</span>.<span class="variable">cookie</span>.<span class="variable">maxAge</span>
+ <span class="keyword">var</span> <span class="variable">ttl</span> = <span class="string">'number'</span> == <span class="keyword">typeof</span> <span class="variable">maxAge</span> ? <span class="variable">maxAge</span> / <span class="number integer">1000</span> | <span class="number integer">0</span> : <span class="variable">oneDay</span>
+ <span class="keyword">var</span> <span class="variable">sess</span> = <span class="class">JSON</span>.<span class="variable">stringify</span>(<span class="variable">sess</span>);
+
+ <span class="this">this</span>.<span class="variable">client</span>.<span class="variable">set</span>(<span class="variable">sid</span>, <span class="variable">sess</span>, <span class="variable">ttl</span>, <span class="keyword">function</span>() {
+ <span class="variable">fn</span> &<span class="variable">amp</span>;&<span class="variable">amp</span>; <span class="variable">fn</span>.<span class="variable">apply</span>(<span class="this">this</span>, <span class="variable">arguments</span>);
+ });
+ } <span class="keyword">catch</span> (<span class="variable">err</span>) {
+ <span class="variable">fn</span> &<span class="variable">amp</span>;&<span class="variable">amp</span>; <span class="variable">fn</span>(<span class="variable">err</span>);
+ }
+};</code></pre>
+</td>
+</tr>
+<tr class="code">
+<td class="docs">
+<p>Destroy the session associated with the given <code>sid</code>.</p>
+
+<h2></h2>
+
+<ul><li><p><strong>param</strong>: <em>String</em> sid</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>
+</td>
+<td class="code">
+<pre><code><span class="class">MemcachedStore</span>.<span class="variable">prototype</span>.<span class="variable">destroy</span> = <span class="keyword">function</span>(<span class="variable">sid</span>, <span class="variable">fn</span>) {
+ <span class="this">this</span>.<span class="variable">client</span>.<span class="variable">del</span>(<span class="variable">sid</span>, <span class="variable">fn</span>);
+};</code></pre>
+</td>
+</tr>
+<tr class="code">
+<td class="docs">
+<p>Fetch number of sessions.</p>
+
+<h2></h2>
+
+<ul><li><p><strong>param</strong>: <em>Function</em> fn</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>
+</td>
+<td class="code">
+<pre><code><span class="class">MemcachedStore</span>.<span class="variable">prototype</span>.<span class="variable">length</span> = <span class="keyword">function</span>(<span class="variable">fn</span>) {
+ <span class="this">this</span>.<span class="variable">client</span>.<span class="variable">items</span>(<span class="variable">fn</span>);
+};</code></pre>
+</td>
+</tr>
+<tr class="code">
+<td class="docs">
+<p>Clear all sessions.</p>
+
+<h2></h2>
+
+<ul><li><p><strong>param</strong>: <em>Function</em> fn</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>
+</td>
+<td class="code">
+<pre><code><span class="class">MemcachedStore</span>.<span class="variable">prototype</span>.<span class="variable">clear</span> = <span class="keyword">function</span>(<span class="variable">fn</span>) {
+ <span class="this">this</span>.<span class="variable">client</span>.<span class="variable">flush</span>(<span class="variable">fn</span>);
+};
+</code></pre>
+</td>
+</tr> </body>
+</html></tbody></table>
2 index.js
@@ -0,0 +1,2 @@
+
+module.exports = require('./lib/connect-memcached');
131 lib/connect-memcached.js
@@ -0,0 +1,131 @@
+
+/*!
+ * connect-memcached
+ * Copyright(c) 2011 Michał Thoma <michal@balor.pl>
+ * MIT Licensed
+ */
+
+/**
+ * Library version.
+ */
+
+exports.version = '0.0.2';
+
+
+/**
+ * Module dependencies.
+ */
+
+var Store = require('connect').session.Store;
+var Memcached = require('memcached');
+
+/**
+ * One day in seconds.
+ */
+
+var oneDay = 86400;
+
+/**
+ * Initialize MemcachedStore with the given `options`.
+ *
+ * @param {Object} options
+ * @api public
+ */
+
+var MemcachedStore = module.exports = function MemcachedStore(options) {
+ options = options || {};
+ Store.call(this, options);
+ if (!options.hosts) {
+ options.hosts = '127.0.0.1:11211';
+ }
+ this.client = new Memcached(options.hosts, options);
+ console.log("MemcachedStore initialized for servers: " + options.hosts);
+
+ this.client.on("issue", function(issue) {
+ console.log("MemcachedStore::Issue @ " + issue.server + ": " +
+ issue.messages + ", " + issue.retries + " attempts left");
+ });
+};
+
+/**
+ * Inherit from `Store`.
+ */
+
+MemcachedStore.prototype.__proto__ = Store.prototype;
+
+/**
+ * Attempt to fetch session by the given `sid`.
+ *
+ * @param {String} sid
+ * @param {Function} fn
+ * @api public
+ */
+
+MemcachedStore.prototype.get = function(sid, fn) {
+ this.client.get(sid, function(err, data) {
+ try {
+ if (!data) {
+ return fn();
+ }
+ fn(null, JSON.parse(data.toString()));
+ } catch (err) {
+ fn(err);
+ }
+ });
+};
+
+/**
+ * Commit the given `sess` object associated with the given `sid`.
+ *
+ * @param {String} sid
+ * @param {Session} sess
+ * @param {Function} fn
+ * @api public
+ */
+
+MemcachedStore.prototype.set = function(sid, sess, fn) {
+ try {
+ var maxAge = sess.cookie.maxAge
+ var ttl = 'number' == typeof maxAge ? maxAge / 1000 | 0 : oneDay
+ var sess = JSON.stringify(sess);
+
+ this.client.set(sid, sess, ttl, function() {
+ fn && fn.apply(this, arguments);
+ });
+ } catch (err) {
+ fn && fn(err);
+ }
+};
+
+/**
+ * Destroy the session associated with the given `sid`.
+ *
+ * @param {String} sid
+ * @api public
+ */
+
+MemcachedStore.prototype.destroy = function(sid, fn) {
+ this.client.del(sid, fn);
+};
+
+/**
+ * Fetch number of sessions.
+ *
+ * @param {Function} fn
+ * @api public
+ */
+
+MemcachedStore.prototype.length = function(fn) {
+ this.client.items(fn);
+};
+
+/**
+ * Clear all sessions.
+ *
+ * @param {Function} fn
+ * @api public
+ */
+
+MemcachedStore.prototype.clear = function(fn) {
+ this.client.flush(fn);
+};
11 package.json
@@ -0,0 +1,11 @@
+{
+ "name": "connect-memcached"
+ , "version": "0.0.2"
+ , "description": "Memcached session store for Connect"
+ , "keywords": ["memcached", "connection", "session", "store", "cache"]
+ , "author": "Michał Thoma <michal@balor.pl>"
+ , "dependencies": { "memcached": ">= 0.0.1" }
+ , "main": "index"
+ , "engines": { "node": "0.4.x" }
+ , "directories": { "lib": "./lib" }
+}

0 comments on commit 38c9b69

Please sign in to comment.