Skip to content
Browse files

[0.2.0] Initial commit to github

  • Loading branch information...
0 parents commit e907b3b0f6fec8c6ed50e0318dc978d3e07b607c @alejandro committed Nov 12, 2011
Showing with 455 additions and 0 deletions.
  1. +35 −0 app.js
  2. +2 −0 bdd/dotcloud.yml
  3. +231 −0 lib/comments.js
  4. +6 −0 lib/options.js
  5. +18 −0 lib/redis.js
  6. +42 −0 lib/utils.js
  7. +9 −0 package.json
  8. +89 −0 public/index.html
  9. +8 −0 public/stylesheets/style.css
  10. +7 −0 routes/index.js
  11. +2 −0 views/index.jade
  12. +6 −0 views/layout.jade
35 app.js
@@ -0,0 +1,35 @@
+
+/**
+ * Module dependencies.
+ */
+
+var express = require('express')
+ , routes = require('./routes')
+
+var app = module.exports = express.createServer();
+
+// Configuration
+
+app.configure(function(){
+ app.set('views', __dirname + '/views');
+ app.set('view engine', 'jade');
+ app.use(express.bodyParser());
+ app.use(express.methodOverride());
+ app.use(app.router);
+ app.use(express.static(__dirname + '/public'));
+});
+
+app.configure('development', function(){
+ app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
+});
+
+app.configure('production', function(){
+ app.use(express.errorHandler());
+});
+
+// Routes
+
+app.get('/', routes.index);
+
+app.listen(3000);
+console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
2 bdd/dotcloud.yml
@@ -0,0 +1,2 @@
+node-comm:
+ type: redis
231 lib/comments.js
@@ -0,0 +1,231 @@
+/*
+ * node-comm
+ * Copyright (c) 2011 Alejandro Morales <vamg008@gmail.com>
+ * MIT Licensed
+ */
+
+/* Change this for your own namespace */
+const NAMESPACE = 'ncomm';
+var redis = require('./redis').redis,
+ url = require('url').parse,
+ util = require('./utils.js').util;
+
+
+/* threadKey
+ * Defining the mask for process. Receive two arguments:
+ * @id that is the page identifier for example: http://test.com/d/i/r/topath the id would be dirtopath
+ * @parent is the hostname for of the page: i.e test.com
+*/
+var threadKey = module.exports.newComment = function(id,parent) {
+ return NAMESPACE + ':' + parent + ':' + id;
+}
+
+/* shortTKeys
+ * Defining the mask for a site. Receive one argument:
+ * @parent is the hostname for the page: i.e test.com
+ * In redis is a hash
+*/
+var shortTKeys = module.exports.urlThreadKey = function(parent) {
+ return NAMESPACE + ':' + parent;
+}
+/* convertURL(ur)
+ * Convert url to only alphanumeric chars for redis key string support
+ */
+var convertURL = function(_url) {
+ var host = url(_url).hostname,
+ slug = url(_url).pathname;
+ /* We don't want to make a key with a protocol that is not browser based (?) */
+ return { host: host, slug: slug.replace(/[^\w \xC0-\xFF]/g,'') };
+}
+var slOff = function(_url){
+ return _url.replace(/[^\w \xC0-\xFF]/g,'') ;
+}
+
+/* Delete duplicate members */
+Array.prototype.unique = function () {
+ var r = new Array();
+ o:for(var i = 0, n = this.length; i < n; i++){
+ for(var x = 0, y = r.length; x < y; x++) {
+ if(r[x]==this[i]) {
+ continue o;
+ }
+ }
+ r[r.length] = this[i];
+ }
+ return r;
+}
+/*
+ * A new Comment has these params:
+ * @url: Has the asociate url for the comment Box
+ * @username: The username that post the comment
+ * @reply: an Array that contains two values, a bolean that define if the comment is a reply and a commentId or null(by default)
+ * @comment: the comment.
+ * @id: Comment # id like 1,2,3,4
+*/
+/*
+* A valid comment looks like this:
+ { url:'http://numbus.co:8080/f/prueba/h',
+ comment: { authorId: "4ebef2c27f21bd298a000000", comment: "YOUR COMMENT",time: Date.now(),
+ parent: "URL parent or comment parent as reply" } }
+*/
+var newComment = module.exports.newComment = function(Object,res) {
+ var O = Object;
+ /* the RegExp was a const but everytwo presented a bug */
+ if (/^(http:\/\/)([\w]+\.){1,}[A-Z]{2,}\b/gi.test(O.url)) {
+ var threadId = convertURL(O.url).slug,
+ parent = convertURL(O.url).host;
+ thread = threadKey(threadId,parent),
+ toJSONString = function(val){val.comment = util.toStaticHTML(val.comment);return JSON.stringify(val)};
+ redis.exists(thread, function(e,d){
+ if (e) res('No ok: ' + e,null);
+ redis.hincrby(thread,'id',1,function(e4,d4){
+ redis.hincrby('u:' + O.comment.authorId, 'id',1, function(error, data){
+ O.comment.lid = data, O.comment.id = d4; /* Setting up floating points */
+ redis.multi()
+ .HSET('u:' + O.comment.authorId, data, toJSONString(O.comment))
+ .HSET(thread,d4, toJSONString(O.comment))
+ .lpush(shortTKeys(parent),url(O.url).pathname)
+ .exec(function(e2,d2){
+ if (e2) res('No ok: ' + err, null)
+ res(null, d2)
+ });
+ });
+ });
+ })
+ } else {
+ res('I need an url', null)
+ }
+}
+var deleteComment = exports.deleteComment = function(Object,res){
+ var nO = Object;
+ if (/^(http:\/\/)([\w]+\.){1,}[A-Z]{2,}\b/gi.test(nO.url)) {
+ var threadId = convertURL(nO.url).slug,
+ parent = convertURL(nO.url).host;
+ thread = threadKey(threadId,parent),
+ comment = nO.comment;
+ redis.multi()
+ .HDEL(thread, comment.id)
+ .HDEL('u:'+ comment.authorId, comment.lid)
+ .exec(function(e,d2){
+ if (e) {
+ res('No ok: ' + e, null)
+ } else {
+ res(null, 'ok')
+ }
+ });
+ } else {
+ res('I need an url', null)
+ }
+}
+
+var fetchByThread = module.exports.fetch = function(Object,res){
+ var nO = Object,
+ threadId = convertURL(nO.url).slug,
+ parent = convertURL(nO.url).host,
+ thread = threadKey(threadId,parent);
+ redis.hgetall(thread, function(e,d){
+ if (e){
+ res(e,null);
+ } else {
+ res(null,d);
+ }
+ });
+}
+var fetchByUser = module.exports.fetchByUser = function(Object, res) {
+ redis.hgetall('u:' + Object.comment.authorId, function(e,d){
+ if (!e) {
+ res(null, d);
+ } else {
+ res(e,null);
+ }
+ });
+}
+var fetchBySite = module.exports.fetchBySite = function(site,res){
+ redis.lrange(shortTKeys(site), 0, -1, function(e,d){
+ if (e) {
+ res(e, null);
+ } else {
+ var d = d.unique();
+ var r = [];
+ var i = 0;
+ d.forEach(function(u){
+ var threadId = slOff(u),
+ parent = site,
+ thread = threadKey(threadId,parent);
+ redis.hgetall(thread, function(e,dd){
+ i++;
+ r.push({"path": u, "comments": dd});
+ if (i === d.length) {
+ res(null, JSON.stringify(r));
+ }
+ });
+
+ });
+
+ }
+ });
+}
+var merge = module.exports.merge = function (obj1, obj2) {
+ for (var p in obj2) {
+ try {
+ if ( obj2[p].constructor===Object ) {
+ obj1[p] = merge(obj2[p], obj1[p]);
+ } else {
+ if (typeof parseFloat(p) != 'number') {
+ obj1[p] = obj2[p];
+ }
+ }
+ } catch(e) {
+ obj1[p] = obj2[p];
+ }
+ }
+ return obj1;
+}
+var edit = module.exports.edit = function(obj, res){
+ var nO = obj,
+ threadId = convertURL(nO.url).slug,
+ parent = convertURL(nO.url).host,
+ thread = threadKey(threadId,parent);
+ redis.hget(thread, nO.comment.id, function(e,d){
+ if (d) {
+ d = JSON.parse(d);
+ d.comment = nO.comment.comment;
+ d.time = Date.now();
+ redis.hset(thread, nO.comment.id, JSON.stringify(d), function(e,d){
+ if (d===0) d ='ok';
+ res(e,d);
+ });
+ }
+ });
+}
+
+/*
+var test = {url:'http://numbus.co:8080/f/pruebas/h/hsas', comment: { authorId: "4ebef2c27f21bd298a000000", comment: "He SIDO EDITADO 2 veces",time: Date.now(), parent: "URL parent or comment parent as reply sistema",id:2,lid:1 } };
+edit(test, function(e,d){
+ console.log(d);
+});
+*/
+/* Pruebas */
+/*
+* All the methods are asyncronous...
+* for example for a new comment just do:
+
+ var test = { url:'http://numbus.co:8080/f/pruebas/h', comment: { authorId: "4ebef2c27f21bd298a000000", comment: "YOUR PROBANDO",time: Date.now(), parent: "URL parent or comment parent as reply sistema" } };
+
+ newComment(test, function(e,d){
+ console.log(d);
+ });
+
+ * for delete a comment do:
+ var dtest ={url:'http://numbus.co:8080/f/pruebas/h',comment:{authorId: "4ebef2c27f21bd298a000000",lid:1,id:1}}
+ deleteComment(dtest, function(e,d){
+ console.log(d);
+ });
+*/
+/*
+for (var i=0;i<1; i++) {
+ comment= { authorId: "4ebef2c27f21bd298a000000", comment: "YOUR PROBANDO" +i,time: Date.now(), parent: "URL parent or comment parent as reply sistema" } ;
+ newComment({ url:'http://numbus.co/f/pruebas/h/hsas', comment:comment}, function(e,d){
+ });
+}
+*/
6 lib/options.js
@@ -0,0 +1,6 @@
+exports.codeName = 'node-com';
+exports.ver = '0.3.1';
+exports.port = '8100';
+exports.type = 'env';
+exports.env = process.env.NODE_ENV || 'DEV';
+exports.processDate = Date.now();
18 lib/redis.js
@@ -0,0 +1,18 @@
+var options = require('./options');
+var redis = require('redis');
+if (options.env == 'production') {
+ var createRedisClient = function() {
+ var db = redis.createClient(9034, 'carp.redistogo.com');
+ var dbAuth=function() { db.auth('2ac23e223b531f90263935c0f6ff4a1e');};
+ db.addListener('connected',dbAuth);
+ db.addListener('reconnected',dbAuth);
+ db.on("error", function (err) {
+ console.log((err).red);
+ });
+ dbAuth();
+ return db;
+ };
+ exports.redis = createRedisClient();
+} else {
+ exports.redis = redis.createClient();
+}
42 lib/utils.js
@@ -0,0 +1,42 @@
+var util= exports.util = {
+ urlRE: /https?:\/\/([-\w\.]+)+(:\d+)?(\/([^\s]*(\?\S+)?)?)?/g,
+
+ // html sanitizer
+ toStaticHTML: function(inputHtml) {
+ inputHtml = inputHtml.toString();
+ return inputHtml.replace(/&/g, "&amp;")
+ .replace(/</g, "&lt;")
+ .replace(/>/g, "&gt;");
+ },
+
+ //pads n with zeros on the left,
+ //digits is minimum length of output
+ //zeroPad(3, 5); returns "005"
+ //zeroPad(2, 500); returns "500"
+ zeroPad: function (digits, n) {
+ n = n.toString();
+ while (n.length < digits)
+ n = '0' + n;
+ return n;
+ },
+
+ //it is almost 8 o'clock PM here
+ //timeString(new Date); returns "19:49"
+ timeString: function (date) {
+ var minutes = date.getMinutes().toString();
+ var hours = date.getHours().toString();
+ return this.zeroPad(2, hours) + ":" + this.zeroPad(2, minutes);
+ },
+
+ //does the argument only contain whitespace?
+ isBlank: function(text) {
+ var blank = /^\s*$/;
+ return (text.match(blank) !== null);
+ }
+};
+
+//used to keep the most recent messages visible
+function scrollDown () {
+ window.scrollBy(0, 100000000000000000);
+ $("#entry").focus();
+}
9 package.json
@@ -0,0 +1,9 @@
+{
+ "name": "application-name"
+ , "version": "0.0.1"
+ , "private": true
+ , "dependencies": {
+ "express": "2.5.0"
+ , "jade": ">= 0.0.1"
+ }
+}
89 public/index.html
@@ -0,0 +1,89 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+
+<title>Index</title>
+</head>
+
+<body>
+<div id="container"></div>
+
+<script src="http://code.jquery.com/jquery.js"></script>
+<script src="https://github.com/BorisMoore/jsrender/raw/master/jsrender.js"></script>
+<!-- What your data should look like -->
+<script id="data" type="data">
+[
+{ lol: 0, data: "hi0" , date: Date.now() },
+{ lol: 1, data: "hi1" , date: Date.now() },
+{ lol: 2, data: "hi2" , date: Date.now() },
+{ lol: 3, data: "hi3" , date: Date.now() },
+{ lol: 4, data: "hi4" , date: Date.now() },
+{ lol: 5, data: "hi5" , date: Date.now() },
+{ lol: 6, data: "hi6" , date: Date.now() },
+{ lol: 7, data: "hi7" , date: Date.now() },
+{ lol: 8, data: "hi8" , date: Date.now() },
+{ lol: 9, data: "hi9" , date: Date.now() },
+{ lol: 10, data: "hi10", date: Date.now() },
+{ lol: 11, data: "hi11", date: Date.now() },
+{ lol: 12, data: "hi12", date: Date.now() },
+{ lol: 13, data: "hi13", date: Date.now() },
+{ lol: 14, data: "hi14", date: Date.now() },
+{ lol: 15, data: "hi15", date: Date.now() }
+]
+</script>
+
+<script id="tmpl" type="template">
+ <table>
+ {{#each data}}
+ <tr>
+ <td><b>{{=lol}}</b></td>
+ <td>{{=data}}</td>
+ <td>{{=date}}</td>
+ <td>
+ {{#if inner.length}}
+ {{#each inner}}
+ {{=i}},
+ {{/each}}
+ {{/if}}
+ </td>
+ </tr>
+ {{/each}}
+ </table>
+</script>
+
+<script>
+ jQuery(function($) {
+ var tmpl = $("#tmpl");
+ var container = $("#container");
+ $.views.allowCode = true;
+ function render() {
+ // Generate *fake* data
+ var data = function() {
+ var _data = [];
+ var obj, rand;
+ for (var i=0; i<100; i++) {
+ _data.push(obj = { lol: i, data: "hi"+i, date: (new Date).toString() });
+ rand = Math.floor(Math.random()*50);
+ obj.inner = [];
+ for (var j=0; j<rand; j++) {
+ obj.inner.push(j);
+ }
+ }
+ return _data;
+ }();
+ var start = +new Date();
+ container.html(
+ tmpl.render({ data: data })
+ );
+ var end = +new Date();
+ console.log( end-start, "ms" );
+ }
+ window.setInterval(render, 1000);
+ render();
+ });
+</script>
+
+</body>
+</html>
8 public/stylesheets/style.css
@@ -0,0 +1,8 @@
+body {
+ padding: 50px;
+ font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
+}
+
+a {
+ color: #00B7FF;
+}
7 routes/index.js
@@ -0,0 +1,7 @@
+/*
+ * GET home page.
+ */
+
+exports.index = function(req, res){
+ res.render('index', { title: 'Express' })
+};
2 views/index.jade
@@ -0,0 +1,2 @@
+h1= title
+p Welcome to #{title}
6 views/layout.jade
@@ -0,0 +1,6 @@
+!!!
+html
+ head
+ title= title
+ link(rel='stylesheet', href='/stylesheets/style.css')
+ body!= body

0 comments on commit e907b3b

Please sign in to comment.
Something went wrong with that request. Please try again.