Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

improved server directory structure

 * modified session ttl handling
  • Loading branch information...
commit 304129f7f92cfd7950cd96e18a8ea0d75c23cee8 1 parent 1842316
Tim Schindler authored
View
1  .gitignore
@@ -0,0 +1 @@
+node_modules/
View
54 Readme.md
@@ -13,15 +13,14 @@
## Installation:
- $ git clone git@github.com:zyndiecate/sayndo.git
- $ cd sayndo/
$ npm install
For session support the redis server is required. The redis
client for node gets installed on "npm install", but you have
- to install the redis server by yourself on your mashine.
+ to install the redis server by yourself on your mashine. Linux
+ user do:
@@ -43,7 +42,17 @@
## Configuration:
- See lib/config/config.js. It´s well commented.
+ You have to structure your directories like this:
+
+ app -
+ |- config -
+ | |- config.js
+ | |- app_locals.js
+ |
+ |- node_modules
+
+ For detailed information see example/config/config.js.
+ It´s well commented.
@@ -99,6 +108,8 @@
The session object by default is just an empty object
literal. You can access the current session like that.
+ How to write sessions and their properties, see the
+ lines below.
res.session
@@ -111,27 +122,14 @@
- Session specific messages can be written to the session object.
- Give a user just that session property and the message will be
- available like that. How to write sessions and their properties,
- see the lines below.
-
- res.session.message
-
-
-
- **Note that the session message by default is just displayed
- one time.** To change that just modify the behaviour in the
- lib/app/app_local.js.
-
-
-
Create a new session with the authType "admin" for only
10 minutes. **To create a new valid session you need to define
the "authType" attribute, related to the auth types in your
- config.js.**
+ config.js.** You can set the "time to life" explicity. If it
+ is not provided by you, the "ttl" property of your config file
+ is used. Otherwise the default "ttl" is to 1 year.
- res.session.write({authType: 'admin', user: 'John'}, 10);
+ res.session.write({authType: 'admin', user: 'John', ttl: 10} [, cb]);
@@ -194,7 +192,7 @@
To redirect clients just do that:
- res.redirect('/redirect');
+ res.view.redirect('/redirect');
@@ -203,6 +201,14 @@
+## Sending Data:
+
+ Just to send Json or string data do:
+
+ res.view.send(stringOrObject);
+
+
+
## Locals:
Locals are placeholder in views to insert data from the
@@ -248,7 +254,7 @@
app.js
app.guest.GET['/'] = function(req, res) {
- res.render('/index.html', {msg: 'hello world'});
+ res.view.render('/index.html', {msg: 'hello world'});
};
@@ -304,7 +310,7 @@
Tests are implemented with https://github.com/cloudhead/vows.
$ sudo npm install vows -g
- $ vows lib/sayndo/tests/* --spec
+ $ vows node_modules/sayndo/test/* --spec
View
11 app_locals.js
@@ -1,11 +0,0 @@
-/*
- *
- * Server site app locals module.
- *
- */
-
-/*
- * Just require the module and export it.
- */
-module.exports = require('../../config/app_locals.js');
-
View
11 config.js
@@ -1,11 +0,0 @@
-/*
- *
- * Server site config module.
- *
- */
-
-/*
- * Just require the module and export it.
- */
-module.exports = require('../../config/config.js');
-
View
11 config/app_locals.js
@@ -0,0 +1,11 @@
+/*
+ *
+ * Server site app locals.
+ *
+ */
+
+/*
+ * Just require the module and export it.
+ */
+module.exports = require('../../../config/app_locals.js');
+
View
11 config/config.js
@@ -0,0 +1,11 @@
+/*
+ *
+ * Server site config.
+ *
+ */
+
+/*
+ * Just require the module and export it.
+ */
+module.exports = require('../../../config/config.js');
+
View
30 example/config/app_locals.js
@@ -9,37 +9,11 @@
*/
var appLocals = {
/*
- * Set the app title globaly.
*
- * @return string, of the app name.
*/
- title: function() {
+ title: function(req, res) {
return 'Sayndo';
- },
-
- /*
- * Get the session message html for each view.
- *
- * @param req, nodes request object.
- * @param res, nodes response object.
- *
- * @return concatinated html string containing the session message.
- */
- message: function(req, res) {
- var message = '<div class="message">'
- , sessionMessage = res.session.message;
-
- if(typeof sessionMessage === 'string'
- && sessionMessage.length != 0) {
- message += sessionMessage;
-
- res.session.update({message: ''});
- }
-
- message += '</div>';
-
- return message;
- },
+ }
};
module.exports = appLocals;
View
16 example/config/config.js
@@ -55,6 +55,11 @@ var config = {
dependencies: [],
/*
+ * Session lifetime in minutes.
+ */
+ ttl: 60 * 24 * 365, // 1 year
+
+ /*
* Array of request methods the server have to support.
* This request methods are also supported for the view
* route functions.
@@ -83,7 +88,16 @@ var config = {
* String of random character to create save hashes. The
* security salt is a dependency for the session support.
*/
- securitySalt: '2RFD6jDdrdmpp9790kjIhug76ZG76hoiUkjg',
+ securitySalt: 'jsdhh2hi3d237d89JKH78jhHIPP=00JKJnjn',
+
+ /*
+ *
+ */
+ mysql: {
+ user: 'user',
+ password: 'password',
+ database: 'database'
+ },
/*
* Array containing strings to ignore unwanted files and
View
2  index.js
@@ -1,4 +1,4 @@
/*
* Just require the server.
*/
-module.exports = require('./server.js');
+module.exports = require('./lib/server.js');
View
4 cache.js → lib/cache.js
@@ -5,7 +5,7 @@ var fs = require('fs')
, path = require('path')
, file = require('./file.js')
, view = require('./view.js')
- , config = require('./config.js')
+ , config = require('../config/config.js')
, layoutPattern = /layout/g;
@@ -59,7 +59,7 @@ var cache = {
view.parseLocals(layoutHtml, {view: viewHtml}, function(html) {
var rawPath = filePath.replace(config.viewPath, '');
- view.cache[rawPath] = viewHtml;
+ view.cache['none' + rawPath] = viewHtml;
view.cache[type + rawPath] = html;
});
});
View
21 cookie.js → lib/cookie.js
@@ -59,6 +59,27 @@ var cookie = {
);
}
});
+ },
+
+ /*
+ *
+ */
+ init: function init(req, res, cb) {
+ res.cookie = {};
+
+ res.cookie.read = function(key, cb) {
+ cookie.read(req.headers.cookie, key, cb);
+ };
+
+ res.cookie.write = function(key, value, properties, minutes) {
+ cookie.write(res, key, value, properties, minutes);
+ };
+
+ res.cookie.remove = function(key) {
+ cookie.remove(req.headers.cookie, res, key);
+ };
+
+ cb();
}
};
View
2  file.js → lib/file.js
@@ -3,7 +3,7 @@
*/
var fs = require('fs')
, view = require('./view.js')
- , config = require('./config.js');
+ , config = require('../config/config.js');
/*
* File module.
View
0  redis.js → lib/redis.js
File renamed without changes
View
0  route.js → lib/route.js
File renamed without changes
View
104 server.js → lib/server.js
@@ -1,9 +1,11 @@
/*
* Dependencies
*/
-var http = require('http')
+var url = require('url')
+ , http = require('http')
, log = require('logerize')
, qs = require('querystring')
+ , CallbackQueue = require('callbackQueue')
, file = require('./file.js')
, view = require('./view.js')
@@ -12,12 +14,7 @@ var http = require('http')
, route = require('./route.js')
, cookie = require('./cookie.js')
, session = require('./session.js')
- , config = require('./config.js');
-
-var fileExt = file.ext
- , httpServer = http.Server()
- , fileTypes = config.fileTypes
- , defaultAuthType = config.defaultAuthType;
+ , config = require('../config/config.js');
/*
* Server module. A request controller for node http server.
@@ -31,87 +28,40 @@ var server = {
* @param res, object of a server response.
*/
requestHandler: function serverRequestHandler(app, req, res) {
- var reqFile = fileTypes[fileExt(req.url)];
+ var url = req.url.pathname
+ , reqFile = config.fileTypes[file.ext(url)];
// Send cached static files as fast as possible.
if(typeof reqFile !== 'undefined') {
res.writeHead(200, reqFile.header);
- return res.end(file.cache[req.url], reqFile.encoding);
+ return res.end(file.cache[url], reqFile.encoding);
}
- var reqCookies = req.headers.cookie;
-
- // Get the current session and authType to render requested view.
- session.readByCookie(reqCookies, function(err, properties, authType) {
- /*
- * Init session support.
- */
- res.session = properties;
-
- res.session.write = function(properties, minutes, cb) {
- properties.ip = req.connection.remoteAddress;
-
- session.write(res, properties, minutes, cb);
- };
-
- res.session.update = function(properties, cb) {
- session.update(res.session.id, properties, cb);
- }
-
- res.session.remove = function(cb) {
- session.remove(res.session.id, cb);
- };
-
- /*
- * Init cookie support.
- */
- res.cookie = {};
-
- res.cookie.read = function(key, cb) {
- cookie.read(reqCookies, key, cb);
- };
-
- res.cookie.write = function(key, value, properties, minutes) {
- cookie.write(res, key, value, properties, minutes);
- };
-
- res.cookie.remove = function(key) {
- cookie.remove(reqCookies, res, key);
- };
-
- /*
- * Init redirect support.
- */
- res.redirect = function(url) {
- res.writeHead(301, {'Location': url});
- res.end();
- };
-
- /*
- * Init sending of plain data.
- */
- res.send = function(data) {
- res.writeHead(200, {'Content-Type': 'text/plain'});
- res.end(data);
- };
-
- /*
- * Init view rendering with reqest and response.
- */
- res.render = function(viewPath, data) {
- view.render(req, res, viewPath, data);
- };
-
+ var modules = ['session', 'cookie', 'view'];
+ var callbackQueue = CallbackQueue(modules, function() {
// Render requested view if it exists.
- var requestedView = app[authType][req.method][req.url];
+ var requestedView = app[res.session.authType][req.method][url];
if(typeof requestedView === 'function') return requestedView(req, res);
// Render default view if it exists.
- var defaultView = app[defaultAuthType][req.method][req.url];
+ var defaultView = app[config.defaultAuthType][req.method][url];
if(typeof defaultView === 'function') return defaultView(req, res);
// Render the error view if no other view match.
- app[defaultAuthType].GET.errors(req, res);
+ app[config.defaultAuthType].GET.errors(req, res);
+ });
+
+ session.init(req, res, function() {
+ callbackQueue.register('session');
+ });
+
+ cookie.init(req, res, function() {
+ callbackQueue.register('cookie');
+
+ });
+
+ view.init(req, res, function() {
+ callbackQueue.register('view');
});
},
@@ -144,8 +94,12 @@ var server = {
* @return object, of an http server instance.
*/
node: function serverNode(app) {
+ var httpServer = http.Server();
+
// Listen on requests.
httpServer.on('request', function (req, res) {
+ req.url = url.parse(req.url, true);
+
if(req.method === 'POST') server.getRequestBody(app, req, res);
else server.requestHandler(app, req, res);
});
View
77 session.js → lib/session.js
@@ -1,13 +1,18 @@
/*
- * Dependencies.
+ * Session module.
+ */
+
+/*
+ * Module variables.
*/
var crypto = require('crypto')
, cookie = require('./cookie.js')
- , config = require('./config.js')
+ , config = require('../config/config.js')
, redis = require('./redis.js').init();
-var sessionPrefix = config.sessionCookie;
+var sessionPrefix = config.sessionCookie
+ , ttl = config.ttl || (60 * 24 * 365); // minutes
/*
* Server site session helper.
@@ -34,11 +39,12 @@ var session = {
readByCookie: function(reqCookies, cb) {
cookie.read(reqCookies, sessionPrefix, function(sessionCookie) {
if(sessionCookie === null) {
- return cb(null, {}, config.defaultAuthType);
+ return cb(undefined, {
+ authType: config.defaultAuthType
+ });
}
var sessionId = sessionCookie.replace(sessionPrefix + '=', '');
-
session.read(sessionId, cb);
});
},
@@ -51,9 +57,13 @@ var session = {
*/
read: function(id, cb) {
redis.client.hgetall(sessionPrefix + id, function(err, session) {
- if(typeof session.authType === 'string') return cb(err, session, session.authType);
+ if(typeof session.authType === 'string') {
+ return cb(err, session);
+ }
- cb(err, {}, config.defaultAuthType);
+ cb(err, {
+ authType: config.defaultAuthType
+ });
});
},
@@ -65,19 +75,20 @@ var session = {
* @param minutes, number of minutes a session have to be active.
* @param cb, function to execute with new session id.
*/
- write: function(res, properties, minutes, cb) {
- var id = this.createHash();
-
+ write: function(res, properties, cb) {
if(typeof res.session === 'object' && typeof res.session.id === 'string') {
redis.client.del(sessionPrefix + res.session.id);
}
- properties.id = id;
+ properties.id = this.createHash();
+ properties.ttl = properties.ttl || ttl;
- redis.client.hmset(sessionPrefix + id, properties, function(err) {
- cookie.write(res, sessionPrefix, id, 'path=/;', minutes);
+ redis.client.hmset(sessionPrefix + properties.id, properties, function(err) {
+ cookie.write(res, sessionPrefix, properties.id, 'path=/;', properties.ttl);
- if(typeof cb === 'function') cb(err, id);
+ if(typeof cb === 'function') {
+ cb(err, properties);
+ }
});
},
@@ -89,11 +100,15 @@ var session = {
* @param cb, function to execute.
*/
update: function(id, properties, cb) {
- if(typeof id === 'string') {
- redis.client.hmset(sessionPrefix + id, properties, function(err, result) {
- if(typeof cb === 'function') cb(err, result);
- });
+ if(typeof id === 'undefined') {
+ return;
}
+
+ redis.client.hmset(sessionPrefix + id, properties, function(err, result) {
+ if(typeof cb === 'function') {
+ cb(err, result);
+ }
+ });
},
/*
@@ -105,16 +120,36 @@ var session = {
remove: function(id, cb) {
cookie.remove(sessionPrefix);
redis.client.del(sessionPrefix + id, function(err) {
- if(typeof cb === 'function') cb(err);
+ if(typeof cb === 'function') {
+ cb(err);
+ }
});
},
/*
* Initialize the session module.
*/
- init: function() {
- return session;
+ init: function(req, res, cb) {
+ this.readByCookie(req.headers.cookie, function(err, properties) {
+ res.session = properties;
+
+ res.session.write = function(properties, cb) {
+ properties.ip = req.connection.remoteAddress;
+ session.write(res, properties, cb);
+ };
+
+ res.session.update = function(properties, cb) {
+ session.update(res.session.id, properties, cb);
+ }
+
+ res.session.remove = function(cb) {
+ session.remove(res.session.id, cb);
+ };
+
+ cb();
+ });
},
};
module.exports = session;
+
View
41 view.js → lib/view.js
@@ -1,8 +1,8 @@
/*
* Depenedencies
*/
-var config = require('./config.js')
- , appLocals = require('./app_locals.js');
+var config = require('../config/config.js')
+ , appLocals = require('../config/app_locals.js');
/*
* View module.
@@ -91,18 +91,47 @@ var view = {
* @param locals, object of locals to parse into a view.
*/
render: function(req, res, viewPath, locals) {
- if(typeof locals !== 'object') locals = {};
- if(locals.layout === false) locals.layout = '';
- else if(typeof locals.layout !== 'string') locals.layout = 'default';
+ locals = locals || {};
+ locals.layout = req.url.query.layout || locals.layout || 'default';
view.combineLocals(req, res, locals, function(combinedLocals) {
- var cachedView = view.cache[locals.layout + viewPath];
+ var cachedView = view.cache[combinedLocals.layout + viewPath];
view.parseLocals(cachedView, combinedLocals, function(html) {
res.writeHead(200, view.contentType);
res.end(html);
});
});
+ },
+
+ /*
+ *
+ */
+ init: function init(req, res, cb) {
+ res.view = {};
+
+ res.view.redirect = function redirect(url) {
+ res.writeHead(301, {'Location': url});
+ res.end();
+ };
+
+ res.view.send = function send(data) {
+ var contentType = 'text/html';
+
+ if(typeof data === 'object') {
+ data = JSON.stringify(data);
+ contentType = 'application/json';
+ }
+
+ res.writeHead(200, {'Content-Type': contentType});
+ res.end(data);
+ };
+
+ res.view.render = function render(viewPath, locals) {
+ view.render(req, res, viewPath, locals);
+ };
+
+ cb();
}
};
View
2  package.json
@@ -2,7 +2,7 @@
"name": "sayndo",
"author": "Tim Schindler <tim.schindler@adcloud.com>",
"description": "Fast and flexible web server with customized routing and authorization.",
- "version": "0.0.4",
+ "version": "0.0.5",
"repository": {
"type": "git",
"url": "git://github.com/zyndiecate/sayndo.git"
View
192 riak.js
@@ -1,192 +0,0 @@
-/*
- *
- * Server site riak module.
- *
- */
-
-/*
- * Dependencies.
- */
-var log = require('logerize')
- , tools = require('./tools.js');
-
-var riak = {
- /*
- * Flush the whole riak data.
- */
- flushAll: function() {
- var riak = this;
-
- riak.buckets(function(err, data, meta) {
- if(err) {
- log.error('Could not flush all buckets: ' + err.message);
-
- return;
- }
-
- var buckets = data.buckets
- , i = 0
- , ii = buckets.length;
-
- function getKeys(bucket, bucketNumber, cb) {
- riak.keys(bucket, function(err, keys) {
- var i = 0
- , ii = keys.length;
-
- for(i; i < ii; i++) {
- var key = keys[i];
- cb(bucket, key);
- }
-
- log.info(
- 'Flushed ' + ii + ' keys from ' +
- (bucketNumber + 1) + '. bucket "' + bucket + '".'
- );
- });
- }
-
- for(i; i < ii; i++) {
- var bucket = buckets[i];
-
- getKeys(bucket, i, function(bucket, key) {
- riak.remove(bucket, key);
- });
- }
-
- if(buckets.length > 0) {
- log.info('Flush all riak keys from ' + buckets.length + ' buckets.');
- }
- });
- },
-
- /*
- * Add an item to an array inside a session object.
- *
- * @param id, string of the session id to modify.
- * @param key, string of the list name to modify.
- * @param value, string of the item to add.
- */
- push: function(bucket, key, value, cb) {
- var riak = this;
-
- riak.get(bucket, key, function(err, data, meta) {
- if(tools.inArray(key, data)) {
- return;
- }
-
- if(data.notFound) {
- data = [];
- }
-
- data.push(value);
-
- riak.save(bucket, key, data, function(err) {
- if(typeof cb === 'function') {
- cb();
- }
- });
- });
- },
-
- /*
- * Remove an item from an array inside a session object.
- *
- * @param id, string of the session id to modify.
- * @param key, string of the list name to modify.
- * @param value, string of the item to remove.
- */
- pop: function(bucket, key, value, cb) {
- var riak = this;
-
- riak.get(bucket, key, function(err, data, meta) {
- if(data.notFound) {
- data = [];
- }
-
- // Remove the item if it exists in the list.
- var i = 0
- , ii = data.length;
-
- for(i; i < ii; i++) {
- if(data[i] === value) {
- data.splice(i, 1);
- }
- }
-
- // Remove the list if it is empty.
- if(data.length == 0) {
- riak.remove(bucket, key);
-
- return;
- }
-
- // Save the new list.
- riak.save(bucket, key, data, function(err) {
- if(typeof cb === 'function') {
- cb();
- }
- });
- });
- },
-
- /*
- * Log stored data using an expression for possible keys.
- *
- * @param expression, string of an expression that match possible keys.
- */
- keys: function(expression) {
- var client = require('riak-js').getClient(riak.proConfig);
-
- client.keys(expression, function(err, data, meta) {
- console.log(data);
- });
- },
-
- /*
- * Log stored data using bucket and data key.
- *
- * @param type, string of the riak environment (either "dev" or "pro").
- * @param bucket, string of a riak bucket where data is stored.
- * @param key, string of the data key.
- */
- log: function(bucket, key) {
- var client = require('riak-js').getClient(riak.proConfig);
-
- client.getAll(bucket, key, function(err, data, meta) {
- console.log(data);
- });
- },
-
- /*
- * Set the riak server configuration.
- */
- proConfig: {
- host: '127.0.0.1',
- port: '8091',
- debug: false
- },
-
- /*
- * Set the riak server configuration.
- */
- devConfig: {
- host: '127.0.0.1',
- port: '8092'
- },
-
- /*
- * Initialize the riak helper module.
- */
- init: function() {
- this.riak = require('riak-js').getClient(riak.proConfig);
-
- this.riak.flushAll = riak.flushAll;
- this.riak.push = riak.push;
- this.riak.pop = riak.pop;
-
- return this.riak;
- }
-};
-
-module.exports = riak;
-
View
35 tools.js
@@ -1,35 +0,0 @@
-/*
- *
- * Server site tools module.
- *
- */
-
-/*
- * Dependencies.
- */
-
-var tools = {
- /*
- * Check if an item exists in an array.
- *
- * @param item, the item to check against an array.
- * @param array, the array to check against the item.
- *
- * @return booloean, if the item exists in the array or not.
- */
- inArray: function(item, array) {
- var i = 0
- , ii = array.length;
-
- for(i; i < ii; i++) {
- if(array[i] === item) {
- return true;
- }
- }
-
- return false;
- },
-};
-
-module.exports = tools;
-
Please sign in to comment.
Something went wrong with that request. Please try again.