diff options
-rw-r--r-- | README.markdown | 54 | ||||
-rw-r--r-- | index.js | 106 | ||||
-rw-r--r-- | package.json | 10 |
3 files changed, 170 insertions, 0 deletions
diff --git a/README.markdown b/README.markdown new file mode 100644 index 0000000..22b7c64 --- /dev/null +++ b/README.markdown @@ -0,0 +1,54 @@ +# go - minimalistic uri shortener + +## install dependencies + + npm install + + apparently you can also + + npm install hiredis + + for more awesome. + +## run service + + PORT=80 node . + + if you omit `PORT`, then it's `1337`. + + there's also the possibility to change the Redis key prefix which + defaults to `go:` with + + REDIS_KEY_PREFIX=foobarmyprefix/ + +## add uri + + curl -F uri=https://mywaytoolonguri http://localhost:1337 + + this will give you a shortened uri. + +## resolve uri + + curl -L http://localhost:1337/1 + +## clear database + + redis-cli keys 'go:*' | xargs redis-cli del + + if you have changed `redisPrefix`, then use that instead of `go:`. + +## use systemd + + run + + make install + + to install the systemd service and configuration files. + this will fail if the files are already installed and modified. + + configure `HOSTN` and `PORT` in `/etc/conf.d/go.env` and the user + and/or group in `/etc/systemd/system/go.service`. + + and finally start the service with + + systemctl start go diff --git a/index.js b/index.js new file mode 100644 index 0000000..e9b551c --- /dev/null +++ b/index.js @@ -0,0 +1,106 @@ +// configuration +var httpPort = process.env.PORT; +var redisPrefix = process.env.REDIS_KEY_PREFIX; + + +// automatic configuration +if (!httpPort) { + httpPort = 1337; +} +if (!redisPrefix) { + redisPrefix = 'go:'; +} + + +// load libraries +var http = require('http'); +var url = require('url'); +var formidable = require('formidable'); +var redis = require('redis'); + + +// instantiate components +var redisClient = redis.createClient(); +var httpServer = http.createServer(listener); + + +// setup compoments +redisClient.on('error', function (err) { + console.log('redis made a bubu:', err.message); + process.exit(23); +}); +httpServer.listen(httpPort, function () { + console.log('http server listening on port', httpPort); +}); + + +// http handler +function listener (req, res) { + if (req.method === 'POST' && req.url === '/') { + return create(req, res); + } else if (req.method === 'GET') { + return retrieve(req, res); + } else { + return methodNotAllowed(req, res); + } +} + +function create (req, res) { + redisClient.incr(redisPrefix + 'index', function (err, reply) { + if (err) { + return internalError(err, req, res); + } + + var form = new formidable.IncomingForm(); + + form.parse(req, function(err, fields, files) { + if (err) { + return internalError(err, req, res); + } + + var uri = fields.uri; + // TODO check uri(?) + var shortPath = '/' + reply; + var shortUri = 'http://' + req.headers.host + shortPath; + var key = redisPrefix + shortPath; + + redisClient.set(key, uri, function (error) { + if (error) { + return internalError(err, req, res); + } + + res.writeHead(200, { 'content-type': 'text/plain' }); + return res.end(shortUri + '\r\n'); + }); + }); + }); +} + +function retrieve (req, res) { + var key = redisPrefix + url.parse(req.url).path; + redisClient.get(key, function (error, reply) { + if (error) { + return internalError(err, req, res); + } + + if (typeof reply !== 'string') { + res.writeHead(404, { 'content-type': 'text/plain' }); + return res.end('not found\r\n'); + } + + res.writeHead(302, { + 'content-type': 'text/plain', + 'location': reply, + }); + return res.end(); + }); +} + +function methodNotAllowed (req, res) { + res.writeHead(405, { 'content-type': 'text/plain' }); + return res.end('method not allowed\r\n'); +} +function internalError (error, req, res) { + res.writeHead(500, { 'content-type': 'text/plain' }); + return res.end(error.message + '\r\n'); +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..787f281 --- /dev/null +++ b/package.json @@ -0,0 +1,10 @@ +{ + "name": "go", + "version": "0.0.0", + "description": "minimalistic uri shortener", + "dependencies": { + "formidable": "*", + "redis": "*" + }, + "license": "WTFPL" +} |