diff --git a/README.md b/README.md index 39baab8..0e49e10 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ STDOUT. Check the README there for more details and usages. * `host` - the host the server runs on (default localhost) * `port` - the port the server runs on (default 7777) * `keyLength` - the length of the keys to user (default 10) -* `maxLength` - maximum length of a paste (default none) +* `maxLength` - maximum length of a paste (default 400000) * `staticMaxAge` - max age for static assets (86400) * `recompressStaticAssets` - whether or not to compile static js assets (true) * `documents` - static documents to serve (ex: http://hastebin.com/about.com) @@ -156,9 +156,9 @@ All of which are optional except `type` with very logical default values. ### Memcached -To use memcached storage you must install the `memcache` package via npm +To use memcache storage you must install the `memcached` package via npm -`npm install memcache` +`npm install memcached` Once you've done that, your config section should look like: diff --git a/config.js.example b/config.js.example index 52ad004..4b33e28 100644 --- a/config.js.example +++ b/config.js.example @@ -33,10 +33,9 @@ }, "storage": { - "type": "redis", - "host": "0.0.0.0", - "port": 6379, - "db": 2, + "type": "memcached", + "host": "127.0.0.1", + "port": 11211, "expire": 2592000 }, diff --git a/lib/document_handler.js b/lib/document_handler.js index 68985ec..83eb141 100644 --- a/lib/document_handler.js +++ b/lib/document_handler.js @@ -36,7 +36,7 @@ DocumentHandler.prototype.handleRawGet = function(key, response, skipExpire) { this.store.get(key, function(ret) { if (ret) { winston.verbose('retrieved raw document', { key: key }); - response.writeHead(200, { 'content-type': 'text/plain' }); + response.writeHead(200, { 'content-type': 'text/plain; charset=UTF-8' }); response.end(ret); } else { @@ -123,7 +123,7 @@ DocumentHandler.prototype.chooseKey = function(callback) { } else { callback(key); } - }); + }, true); // Don't bump expirations when key searching }; DocumentHandler.prototype.acceptableKey = function() { diff --git a/lib/document_stores/memcached.js b/lib/document_stores/memcached.js index 2771886..be10db6 100644 --- a/lib/document_stores/memcached.js +++ b/lib/document_stores/memcached.js @@ -1,45 +1,52 @@ -var memcached = require('memcache'); -var winston = require('winston'); +const memcached = require('memcached'); +const winston = require('winston'); -// Create a new store with options -var MemcachedDocumentStore = function(options) { - this.expire = options.expire; - if (!MemcachedDocumentStore.client) { - MemcachedDocumentStore.connect(options); +class MemcachedDocumentStore { + + // Create a new store with options + constructor(options) { + this.expire = options.expire; + + const host = options.host || '127.0.0.1'; + const port = options.port || 11211; + const url = `${host}:${port}`; + this.connect(url); } -}; -// Create a connection -MemcachedDocumentStore.connect = function(options) { - var host = options.host || '127.0.0.1'; - var port = options.port || 11211; - this.client = new memcached.Client(port, host); - this.client.connect(); - this.client.on('connect', function() { - winston.info('connected to memcached on ' + host + ':' + port); - }); - this.client.on('error', function(e) { - winston.info('error connecting to memcached', { error: e }); - }); -}; + // Create a connection + connect(url) { + this.client = new memcached(url); -// Save file in a key -MemcachedDocumentStore.prototype.set = -function(key, data, callback, skipExpire) { - MemcachedDocumentStore.client.set(key, data, function(err) { - err ? callback(false) : callback(true); - }, skipExpire ? 0 : this.expire); -}; + winston.info(`connecting to memcached on ${url}`); -// Get a file from a key -MemcachedDocumentStore.prototype.get = function(key, callback, skipExpire) { - var _this = this; - MemcachedDocumentStore.client.get(key, function(err, reply) { - callback(err ? false : reply); - if (_this.expire && !skipExpire) { - winston.warn('store does not currently push forward expirations on GET'); - } - }); -}; + this.client.on('failure', function(error) { + winston.info('error connecting to memcached', {error}); + }); + } + + // Save file in a key + set(key, data, callback, skipExpire) { + this.client.set(key, data, skipExpire ? 0 : this.expire, (error) => { + callback(!error); + }); + } + + // Get a file from a key + get(key, callback, skipExpire) { + this.client.get(key, (error, data) => { + callback(error ? false : data); + + // Update the key so that the expiration is pushed forward + if (!skipExpire) { + this.set(key, data, (updateSucceeded) => { + if (!updateSucceeded) { + winston.error('failed to update expiration on GET', {key}); + } + }, skipExpire); + } + }); + } + +} module.exports = MemcachedDocumentStore; diff --git a/lib/document_stores/redis.js b/lib/document_stores/redis.js index 7edbaf0..eed07e7 100644 --- a/lib/document_stores/redis.js +++ b/lib/document_stores/redis.js @@ -29,6 +29,11 @@ RedisDocumentStore.connect = function(options) { if (options.password) { RedisDocumentStore.client.auth(options.password); } + + RedisDocumentStore.client.on('error', function(err) { + winston.error('redis disconnected', err); + }); + RedisDocumentStore.client.select(index, function(err) { if (err) { winston.error( diff --git a/lib/document_stores/rethinkdb.js b/lib/document_stores/rethinkdb.js index b7ee7ae..ca825af 100644 --- a/lib/document_stores/rethinkdb.js +++ b/lib/document_stores/rethinkdb.js @@ -1,39 +1,46 @@ const crypto = require('crypto'); const rethink = require('rethinkdbdash'); +const winston = require('winston'); -var RethinkDBStore = (options) => { - this.client = rethink({ - silent: true, - host: options.host || '127.0.0.1', - port: options.port || 28015, - db: options.db || 'haste', - user: options.user || 'admin', - password: options.password || '' - }); -}; - -RethinkDBStore.md5 = (str) => { +const md5 = (str) => { const md5sum = crypto.createHash('md5'); md5sum.update(str); return md5sum.digest('hex'); }; -RethinkDBStore.prototype.set = (key, data, callback) => { - try { - this.client.table('uploads').insert({ id: RethinkDBStore.md5(key), data: data }).run((error) => { - if (error) return callback(false); +class RethinkDBStore { + constructor(options) { + this.client = rethink({ + silent: true, + host: options.host || '127.0.0.1', + port: options.port || 28015, + db: options.db || 'haste', + user: options.user || 'admin', + password: options.password || '' + }); + } + + set(key, data, callback) { + this.client.table('uploads').insert({ id: md5(key), data: data }).run((error) => { + if (error) { + callback(false); + winston.error('failed to insert to table', error); + return; + } callback(true); }); - } catch (err) { - callback(false); } -}; -RethinkDBStore.prototype.get = (key, callback) => { - this.client.table('uploads').get(RethinkDBStore.md5(key)).run((error, result) => { - if (error || !result) return callback(false); - callback(result.data); - }); -}; + get(key, callback) { + this.client.table('uploads').get(md5(key)).run((error, result) => { + if (error || !result) { + callback(false); + if (error) winston.error('failed to insert to table', error); + return; + } + callback(result.data); + }); + } +} module.exports = RethinkDBStore;