From 43b65dd066588ddeab729ad0160c8d6ced7da9b1 Mon Sep 17 00:00:00 2001 From: Eric Martindale Date: Sun, 5 Apr 2015 19:51:37 -0400 Subject: [PATCH 1/9] Add support for editing shows. --- decentralize.js | 57 +++++++++++++++++++++++-------------------------- lib/Engine.js | 37 +++++++++++++++++++++++++++++--- package.json | 1 + 3 files changed, 62 insertions(+), 33 deletions(-) diff --git a/decentralize.js b/decentralize.js index 15c98a6..8a767fc 100644 --- a/decentralize.js +++ b/decentralize.js @@ -6,9 +6,9 @@ var procure = require('procure'); var Maki = require('maki'); var Soundcloud = require('./lib/Soundcloud'); var Engine = require('./lib/Engine'); -var WebSocket = require('ws'); +var Sessions = require('maki-sessions'); -var jsonpatch = require('fast-json-patch'); +var rest = require('restler'); var home = 'https://' + config.service.authority; @@ -18,13 +18,16 @@ source.authority = source.host + (([80, 443].indexOf( parseInt(source.port) ) == var decentralize = new Maki( config ); var soundcloud = new Soundcloud( config.soundcloud ); +var sessions = new Sessions(); +decentralize.use( sessions ); + Show = decentralize.define('Show', { attributes: { title: { type: String , slug: true }, slug: { type: String }, recorded: { type: Date }, released: { type: Date , default: Date.now , required: true }, - description: { type: String }, + description: { type: String , format: 'markdown' }, audio: { type: String }, // TODO: replace with a sources list. youtube: { type: String } @@ -77,6 +80,25 @@ procure( source.proto + '://' + source.authority + '/shows/decentralize', functi return next(); } }); + decentralize.app.get('/shows/:showSlug/edit', function(req, res, next) { + Show.get({ slug: req.param('showSlug') }, function(err, show) { + return res.render('show-edit', { + item: show + }); + }); + }); + decentralize.app.post('/shows/:showSlug', function(req, res, next) { + rest.patch( source.proto + '://' + source.authority + '/recordings/' + req.param('showSlug') , { + headers: { + Accept: 'application/json' + }, + data: req.body + }).on('complete', function(data, request) { + if (request.statusCode !== 200) return res.error('Editing failed'); + req.flash('success', 'Content edited successfully!'); + return res.redirect('/shows/' + req.param('showSlug')); + }); + }); decentralize.app.get('/rss', function(req, res, next) { res.redirect( 301 , '/feed' ); }); @@ -90,38 +112,13 @@ procure( source.proto + '://' + source.authority + '/shows/decentralize', functi }); }); - // subscribe to updates to important things. - // mainly, recordings - var ws = new WebSocket(source.sockets + source.authority + '/recordings'); - ws.on('error', function(err) { - console.error( err ); - }); - ws.on('message', function(data) { - console.log('DATAGRAM:' , data ); - var msg = JSON.parse( data ); - if (msg.method === 'patch') { - if (msg.params.channel === '/recordings') { - jsonpatch.apply( decentralize.resources['Show'].data , msg.params.ops ); - } - - if (msg.params.channel.match(/\/recordings\/(.*)/)) { - var recordings = decentralize.resources['Show'].data; - for (var i = 0; i < recordings.length; i++) { - if (msg.params.channel === '/recordings/' + recordings[ i ].slug ) { - jsonpatch.apply( recordings[ i ] , msg.params.ops ); - } - } - } - - } - }); - - var engine = new Engine( config ); + var engine = new Engine( config , decentralize ); setInterval(function() { engine.sync(); }, /*/ 2500 /*/ 1 * 3600 * 1000 /**/ ); engine.sync(); + engine.subscribe(); }); diff --git a/lib/Engine.js b/lib/Engine.js index a4638c4..64d0cea 100644 --- a/lib/Engine.js +++ b/lib/Engine.js @@ -4,13 +4,44 @@ var request = require('request'); var jsonpatch = require('fast-json-patch'); var contentDisposition = require('content-disposition'); +var WebSocket = require('ws'); var Soundcloud = require('./Soundcloud'); var Form = require('form-data'); -function Engine( config ) { +function Engine( config , decentralize ) { this.config = config; + this.decentralize = decentralize; this.soundcloud = new Soundcloud( config.soundcloud ); -} +}; + +Engine.prototype.subscribe = function( cb ) { + var self = this; + // subscribe to updates to important things. + // mainly, recordings + var ws = new WebSocket( self.config.source.sockets + self.config.source.authority + '/recordings'); + ws.on('error', function(err) { + console.error( err ); + }); + ws.on('message', function(data) { + console.log('DATAGRAM:' , data ); + var msg = JSON.parse( data ); + if (msg.method === 'patch') { + if (msg.params.channel === '/recordings') { + jsonpatch.apply( self.decentralize.resources['Show'].data , msg.params.ops ); + } + + if (msg.params.channel.match(/\/recordings\/(.*)/)) { + var recordings = self.decentralize.resources['Show'].data; + for (var i = 0; i < recordings.length; i++) { + if (msg.params.channel === '/recordings/' + recordings[ i ].slug ) { + jsonpatch.apply( recordings[ i ] , msg.params.ops ); + } + } + } + + } + }); +}; Engine.prototype.sync = function( cb ) { if (!cb) var cb = new Function(); @@ -90,6 +121,6 @@ Engine.prototype.sync = function( cb ) { }); }); }); -} +}; module.exports = Engine; diff --git a/package.json b/package.json index 25aa7e0..47d5fdb 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "form-data": "^0.2.0", "lodash": "^3.3.0", "maki": "git://github.com/martindale/maki", + "maki-sessions": "^0.1.0", "node-torrent-stream": "git://github.com/unusualbob/node-torrent-stream", "procure": "^0.1.3", "request": "^2.53.0", From 938bd4097bcd05fd18a6ff99fe7caebdc9a18e2f Mon Sep 17 00:00:00 2001 From: Eric Martindale Date: Sun, 5 Apr 2015 20:00:51 -0400 Subject: [PATCH 2/9] Move resources into dedicated folder. --- decentralize.js | 30 ++---------------------------- resources/Index.js | 12 ++++++++++++ resources/Show.js | 17 +++++++++++++++++ 3 files changed, 31 insertions(+), 28 deletions(-) create mode 100644 resources/Index.js create mode 100644 resources/Show.js diff --git a/decentralize.js b/decentralize.js index 8a767fc..c24a6e8 100644 --- a/decentralize.js +++ b/decentralize.js @@ -21,34 +21,8 @@ var soundcloud = new Soundcloud( config.soundcloud ); var sessions = new Sessions(); decentralize.use( sessions ); -Show = decentralize.define('Show', { - attributes: { - title: { type: String , slug: true }, - slug: { type: String }, - recorded: { type: Date }, - released: { type: Date , default: Date.now , required: true }, - description: { type: String , format: 'markdown' }, - audio: { type: String }, - // TODO: replace with a sources list. - youtube: { type: String } - }, - names: { get: 'item' }, - source: source.proto + '://' + source.authority + '/recordings', - icon: 'sound' -}); - -Index = decentralize.define('Index', { - name: 'Index', - routes: { query: '/' }, - templates: { query: 'index' }, - requires: { - 'Show': { - filter: {} - } - }, - static: true, - internal: true -}); +Show = decentralize.define('Show', require('./resources/Show') ); +Index = decentralize.define('Index', require('./resources/Index') ); procure( source.proto + '://' + source.authority + '/shows/decentralize', function(err, show) { if (err) return console.error(err); diff --git a/resources/Index.js b/resources/Index.js new file mode 100644 index 0000000..a56349b --- /dev/null +++ b/resources/Index.js @@ -0,0 +1,12 @@ +module.exports = { + name: 'Index', + routes: { query: '/' }, + templates: { query: 'index' }, + requires: { + 'Show': { + filter: {} + } + }, + static: true, + internal: true +}; diff --git a/resources/Show.js b/resources/Show.js new file mode 100644 index 0000000..5996214 --- /dev/null +++ b/resources/Show.js @@ -0,0 +1,17 @@ +var source = require('../config').source; + +module.exports = { + attributes: { + title: { type: String , slug: true }, + slug: { type: String }, + recorded: { type: Date }, + released: { type: Date , default: Date.now , required: true }, + description: { type: String , format: 'markdown' }, + audio: { type: String }, + // TODO: replace with a sources list. + youtube: { type: String } + }, + names: { get: 'item' }, + source: source.proto + '://' + source.authority + '/recordings', + icon: 'sound' +} From 8d428194c5acc8ad32e6334ab1bf833fe4c80810 Mon Sep 17 00:00:00 2001 From: Eric Martindale Date: Sun, 5 Apr 2015 21:54:17 -0400 Subject: [PATCH 3/9] Begin to add various auth items. --- decentralize.js | 10 +++++++++- package.json | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/decentralize.js b/decentralize.js index c24a6e8..b77b3e9 100644 --- a/decentralize.js +++ b/decentralize.js @@ -6,19 +6,27 @@ var procure = require('procure'); var Maki = require('maki'); var Soundcloud = require('./lib/Soundcloud'); var Engine = require('./lib/Engine'); + var Sessions = require('maki-sessions'); +var ProxAuth = require('maki-auth-proxy'); +var Policies = require('maki-auth-tokens'); var rest = require('restler'); var home = 'https://' + config.service.authority; var source = config.source; -source.authority = source.host + (([80, 443].indexOf( parseInt(source.port) ) === -1) ? ':' + source.port : ''); +source.authority = source.host; +if ([80, 443].indexOf( parseInt(source.port) ) === -1) { + source.authority += ':' + source.port; +} var decentralize = new Maki( config ); var soundcloud = new Soundcloud( config.soundcloud ); +var policies = new Policies(); var sessions = new Sessions(); + decentralize.use( sessions ); Show = decentralize.define('Show', require('./resources/Show') ); diff --git a/package.json b/package.json index 47d5fdb..a39400b 100644 --- a/package.json +++ b/package.json @@ -23,10 +23,11 @@ "dependencies": { "async": "^0.9.0", "content-disposition": "^0.5.0", - "fast-json-patch": "^0.5.1", + "fast-json-patch": "^0.5.2", "form-data": "^0.2.0", "lodash": "^3.3.0", "maki": "git://github.com/martindale/maki", + "maki-auth-proxy": "0.0.0", "maki-sessions": "^0.1.0", "node-torrent-stream": "git://github.com/unusualbob/node-torrent-stream", "procure": "^0.1.3", From 4539b4acd770a845764396b4bbf55655026ebf58 Mon Sep 17 00:00:00 2001 From: Eric Martindale Date: Sun, 5 Apr 2015 22:43:26 -0400 Subject: [PATCH 4/9] Add form for editing shows. --- views/show-edit.jade | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 views/show-edit.jade diff --git a/views/show-edit.jade b/views/show-edit.jade new file mode 100644 index 0000000..7e87b2b --- /dev/null +++ b/views/show-edit.jade @@ -0,0 +1,25 @@ +extends layouts/default + +block content + h2 Edit + + form.ui.form(action="/shows/#{item.slug}", method="POST") + input(type="hidden", name="method", value="PATCH") + + .field + label Description + textarea(name="description", rows="50") #{item.description} + + .field + label YouTube Video ID + input(type="text", name="youtube", value="#{item.youtube || ''}") + + .two.fields + .field + label decentral.fm Username + input(type="text", name="username") + .field + label decentral.fm Password + input(type="password", name="password") + + button.ui.submit.button(type="submit") Edit » From 6c2d19b64c883fd3014cf72697361f413f8e15a8 Mon Sep 17 00:00:00 2001 From: Eric Martindale Date: Sun, 5 Apr 2015 23:03:57 -0400 Subject: [PATCH 5/9] Add support for markdown editing and preview. --- public/js/marked.min.js | 6 ++++++ views/layouts/default.jade | 1 + views/show-edit.jade | 18 +++++++++++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 public/js/marked.min.js diff --git a/public/js/marked.min.js b/public/js/marked.min.js new file mode 100644 index 0000000..a5164c4 --- /dev/null +++ b/public/js/marked.min.js @@ -0,0 +1,6 @@ +/** + * marked - a markdown parser + * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) + * https://github.com/chjj/marked + */ +(function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,def:/^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:cap[1]==="pre"||cap[1]==="script"||cap[1]==="style",text:cap[0]});continue}if(!bq&&top&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else if(this.options.pedantic){this.rules=inline.pedantic}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^/i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=escape(this.smartypants(cap[0]));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/--/g,"—").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){var out="",l=text.length,i=0,ch;for(;i.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"
"+(escaped?code:escape(code,true))+"\n
"}return'
'+(escaped?code:escape(code,true))+"\n
\n"};Renderer.prototype.blockquote=function(quote){return"
\n"+quote+"
\n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"'+text+"\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"
\n":"
\n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"\n"};Renderer.prototype.listitem=function(text){return"
  • "+text+"
  • \n"};Renderer.prototype.paragraph=function(text){return"

    "+text+"

    \n"};Renderer.prototype.table=function(header,body){return"\n"+"\n"+header+"\n"+"\n"+body+"\n"+"
    \n"};Renderer.prototype.tablerow=function(content){return"\n"+content+"\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"\n"};Renderer.prototype.strong=function(text){return""+text+""};Renderer.prototype.em=function(text){return""+text+""};Renderer.prototype.codespan=function(text){return""+text+""};Renderer.prototype.br=function(){return this.options.xhtml?"
    ":"
    "};Renderer.prototype.del=function(text){return""+text+""};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0){return""}}var out='
    ";return out};Renderer.prototype.image=function(href,title,text){var out=''+text+'":">";return out};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i/g,">").replace(/"/g,""").replace(/'/g,"'")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon")return":";if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;iAn error occured:

    "+escape(e.message+"",true)+"
    "}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof module!=="undefined"&&typeof exports==="object"){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return this||(typeof window!=="undefined"?window:global)}()); \ No newline at end of file diff --git a/views/layouts/default.jade b/views/layouts/default.jade index 1a638ce..07d09f1 100644 --- a/views/layouts/default.jade +++ b/views/layouts/default.jade @@ -36,6 +36,7 @@ html.no-js script(src="/js/highlight.pack.js") script(src="/js/uuid.js") script(src="/js/jsonrpc.js") + script(src="/js/marked.min.js") script(src="/js/maki.js") diff --git a/views/show-edit.jade b/views/show-edit.jade index 7e87b2b..2d2a1a1 100644 --- a/views/show-edit.jade +++ b/views/show-edit.jade @@ -1,6 +1,12 @@ extends layouts/default block content + + h1 #{item.title} + + h2 Preview + .preview !{ markdown( item.description ) } + h2 Edit form.ui.form(action="/shows/#{item.slug}", method="POST") @@ -8,7 +14,7 @@ block content .field label Description - textarea(name="description", rows="50") #{item.description} + textarea(name="description", style="height: 20em;") #{item.description} .field label YouTube Video ID @@ -23,3 +29,13 @@ block content input(type="password", name="password") button.ui.submit.button(type="submit") Edit » + +block scripts + script. + $('textarea[name=description]').keyup( renderPreview ); + + function renderPreview() { + var value = this.value; + var rendered = marked( value ); + $('.preview').html( rendered ); + } From 662a42ed03185d7912215ac3cc7755fae90c966e Mon Sep 17 00:00:00 2001 From: Eric Martindale Date: Sun, 5 Apr 2015 23:41:29 -0400 Subject: [PATCH 6/9] More robust socket handler. --- lib/Engine.js | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/lib/Engine.js b/lib/Engine.js index 64d0cea..e437b74 100644 --- a/lib/Engine.js +++ b/lib/Engine.js @@ -8,21 +8,58 @@ var WebSocket = require('ws'); var Soundcloud = require('./Soundcloud'); var Form = require('form-data'); +var TRY_TIMES = [ 100 , 250 , 2500 , 10000 , 60 * 1000 , 5 * 60 * 1000 , 10 * 60 * 1000 , 60 * 60 * 1000 ]; + function Engine( config , decentralize ) { this.config = config; this.decentralize = decentralize; this.soundcloud = new Soundcloud( config.soundcloud ); + + this.tries = 0; + }; Engine.prototype.subscribe = function( cb ) { var self = this; // subscribe to updates to important things. // mainly, recordings - var ws = new WebSocket( self.config.source.sockets + self.config.source.authority + '/recordings'); - ws.on('error', function(err) { + + console.log('initializing socket...'); + + try { + self.ws = new WebSocket( self.config.source.sockets + self.config.source.authority + '/recordings'); + } catch (e) { + console.log('exception connecting'); + } + + self.ws.on('error', function(err) { console.error( err ); }); - ws.on('message', function(data) { + self.ws.on('open', function() { + self.tries = 0; + console.log('socket now open.'); + }); + self.ws.on('close', function() { + console.log('socket closed wat'); + + function attemptReconnect() { + self.ws.removeAllListeners('open'); + self.ws.removeAllListeners('close'); + self.ws.removeAllListeners('error'); + self.ws.removeAllListeners('message'); + + delete self.ws; + + self.subscribe(); + + setTimeout( attemptReconnect , TRY_TIMES[ self.tries++ ] ); + + }; + + attemptReconnect(); + + }); + self.ws.on('message', function(data) { console.log('DATAGRAM:' , data ); var msg = JSON.parse( data ); if (msg.method === 'patch') { From c5cf5e5cd4e74ec0f13223ca2d78f4b74468f920 Mon Sep 17 00:00:00 2001 From: Eric Martindale Date: Mon, 30 Oct 2017 14:39:19 -0700 Subject: [PATCH 7/9] Upgrade to Maki 0.3, add tests --- .coveralls.yml | 1 + .travis.yml | 7 + config/index.js | 7 +- decentralize:web.js | 5 + lib/decentralize.js | 214 +++++++++++++++++++++++++++++++ package.json | 11 +- test/decentralize.integration.js | 18 +++ 7 files changed, 255 insertions(+), 8 deletions(-) create mode 100644 .coveralls.yml create mode 100644 .travis.yml create mode 100644 decentralize:web.js create mode 100644 lib/decentralize.js create mode 100644 test/decentralize.integration.js diff --git a/.coveralls.yml b/.coveralls.yml new file mode 100644 index 0000000..9160059 --- /dev/null +++ b/.coveralls.yml @@ -0,0 +1 @@ +service_name: travis-ci diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..a3ffa8d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,7 @@ +language: node_js +node_js: +- '6' +services: + - mongodb + - redis-server +after_script: istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage diff --git a/config/index.js b/config/index.js index cce2fd8..a6ca9b2 100644 --- a/config/index.js +++ b/config/index.js @@ -12,13 +12,14 @@ module.exports = { mission: 'the podcast', description: 'The best place for learning about what\'s going on with the latest decentralized tech.', source: 'https://github.com/martindale/decentralize', - points: [] + points: [], + dependencies: ['decentral'] }, source: { sockets: 'ws://', proto: 'http', - host: 'localhost', - port: '15005' + host: process.env.DECENTRAL_HOST || 'localhost', + port: process.env.DECENTRAL_PORT || '15005' }, soundcloud: { clientID: '98ce66124fabdff2f33beb2f810a0a25', diff --git a/decentralize:web.js b/decentralize:web.js new file mode 100644 index 0000000..c091707 --- /dev/null +++ b/decentralize:web.js @@ -0,0 +1,5 @@ +var config = require('./config'); +var DECENTRALIZE = require('./lib/decentralize'); +var decentralize = new DECENTRALIZE(config); + +decentralize.start(); diff --git a/lib/decentralize.js b/lib/decentralize.js new file mode 100644 index 0000000..33601d7 --- /dev/null +++ b/lib/decentralize.js @@ -0,0 +1,214 @@ +process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'; + +var procure = require('procure'); + +var Maki = require('maki'); +var Soundcloud = require('./Soundcloud'); +var Engine = require('./Engine'); +var Remote = require('maki-remote'); +var WebSocket = require('ws'); + +var jsonpatch = require('fast-json-patch'); + +function DECENTRALIZE (config) { + if (!config) config = require('../config'); + + var self = this; + + self.config = config; + self.home = 'https://' + config.service.authority; + + self.source = config.source; + self.source.authority = self.source.host; + if (!~[80, 443].indexOf( parseInt(self.source.port) )) { + self.source.authority += ':' + self.source.port; + } + self.source.base = self.source.proto + '://' + self.source.authority; + + self.app = new Maki( config ); + var soundcloud = new Soundcloud( config.soundcloud ); + + var Sessions = require('maki-sessions'); + var sessions = new Sessions(); + + self.app.use(sessions); + + // setup of various remotes, subservices on another Maki namespace + var MailPimpSubscription = new Remote('http://localhost:2525/subscriptions'); + var MailPimpTask = new Remote('http://localhost:2525/tasks'); + + Show = self.app.define('Show', { + attributes: { + title: { type: String , slug: true }, + slug: { type: String }, + recorded: { type: Date }, + released: { type: Date , default: Date.now , required: true }, + description: { type: String }, + audio: { type: String }, + filename: { type: String }, + // TODO: replace with a sources list. + youtube: { type: String }, + soundcloud: { type: String }, + }, + names: { get: 'item' }, + source: self.source.proto + '://' + self.source.authority + '/recordings', + icon: 'sound' + }); + + var Subscription = self.app.define('Subscription', { + attributes: { + email: { type: String , required: true , validator: function(value) { + // see HTML spec: https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address + // this should mirror HTML5's "type=email", as per the above link + return /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test( value ); + } }, + status: { type: String , enum: ['requested', 'pending', 'validated'], default: 'requested' }, + created: { type: Date , default: Date.now }, + }, + handlers: { + html: { + create: function(req, res, next) { + req.flash('info', 'Successfully subscribed! Check your inbox for a confirmation.'); + res.redirect('/'); + } + } + } + }); + + Subscription.post('create', function(done) { + var subscription = this; + MailPimpSubscription.create({ + email: subscription.email, + // TODO: place in config, or auto-create-and-collect + _list: '55d490d83e5a3dcf5287129e' + }, function(err, data) { + // TODO: retry, error handling, etc. + if (!data._id) return done('no subscription created'); + Subscription.patch({ _id: subscription._id }, [ + { op: 'replace', path: '/status', value: 'pending' } + ], function(err) { + if (err) console.error(err); + done(err); + }); + }); + }); + + Index = self.app.define('Index', { + name: 'Index', + routes: { query: '/' }, + templates: { query: 'index' }, + requires: { + 'Show': { + filter: {} + } + }, + static: true, + internal: true + }); + +} + +DECENTRALIZE.prototype.start = function (done) { + var self = this; + if (!done) done = Function(); + + console.log('starting:', self.source.base); + + procure( self.source.base + '/shows/decentralize' , function(err, show) { + if (err || !show) return console.error(err || 'no such show: decentralize'); + + console.log('came back:', err, show); + + // TODO: catch error + try { + self.config.show = JSON.parse( show ); + } catch (e) { + console.error(e); + return done(e); + } + + self.config.show.source = self.source; + self.config.show.home = self.home; + + console.log('maki starting...'); + + self.app.start(function() { + console.log('maki started!'); + + self.app.app.locals.show = self.config.show; + + self.app.app.get('/about', function(req, res, next) { + res.render('about'); + }); + self.app.app.get('/contact', function(req, res, next) { + res.render('contact'); + }); + self.app.app.post('/contact', function(req, res, next) { + MailPimpTask.create({ + subject: 'DECENTRALIZE Contact Form', + recipient: 'eric@self.app.fm', + sender: req.param('from'), + content: req.param('message') + }, function(err, task) { + req.flash('info', 'Mail sent successfully! We\'ll get in touch shortly.'); + res.redirect('/'); + }); + }); + self.app.app.get('/team', function(req, res, next) { + res.render('team'); + }); + self.app.app.get('/subscribe', function(req, res, next) { + res.render('subscribe'); + }); + + // redirect an erroneous lengthy tag + self.app.app.get('/shows/episode-26-nick-sullivan-on-changetip-and-the-future-of-bitcoin-microtransactions', function(req, res, next) { + res.redirect( 301 , '/shows/episode-25-nick-sullivan'); + }); + self.app.app.get('/shows/episode-29-susanne-tempelhof-and-dan-metcalf-on-blockchain-applications-and-bitcoin-2-0', function(req, res, next) { + res.redirect( 301 , '/shows/episode-29-susanne-tempelhof-and-dan-metcalf'); + }); + + self.app.app.get('/:somePath', function(req, res, next) { + Show.get({ slug: req.param('somePath') }, function(err, show) { + if (show) return res.redirect('/shows/' + show.slug ); + next(); + }); + }); + self.app.app.get('/shows', function(req, res, next) { + if (req.accepts('application/rss+xml')) { + return res.redirect('/feed'); + } else { + return next(); + } + }); + self.app.app.get('/rss', function(req, res, next) { + res.redirect( 301 , '/feed' ); + }); + self.app.app.get('/feed', function(req, res, next) { + Show.query({}, function(err, shows) { + res.set('Content-Type', 'application/rss+xml'); + res.render('feed', { + resource: Show, + collection: shows + }); + }); + }); + + var engine = new Engine( self.config , self.app ); + + setInterval(function() { + //engine.sync(); + }, /*/ 2500 /*/ 1 * 3600 * 1000 /**/ ); + + engine.subscribe(); + engine.sync(); + + return done(); + + }); + + }); +} + +module.exports = DECENTRALIZE; diff --git a/package.json b/package.json index e6ff217..6235bc6 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "decentralize", "version": "0.0.0", "description": "decentralize the podcast", - "main": "decentralize.js", + "main": "lib/decentralize.js", "scripts": { "test": "mocha" }, @@ -26,18 +26,19 @@ "fast-json-patch": "^0.5.1", "form-data": "^0.2.0", "lodash": "^3.3.0", - "maki": "git://github.com/martindale/maki#6be8e8d5949e00f79abf348a406e3369c883051d", + "maki": "github:martindale/maki#v0.2.1", "maki-remote": "0.0.1", "maki-sessions": "^0.1.0", "node-torrent-stream": "git://github.com/unusualbob/node-torrent-stream", - "procure": "^0.1.3", + "procure": "^0.1.4", "request": "^2.53.0", "restler": "^3.2.2", "ws": "^0.7.1" }, "devDependencies": { - "coveralls": "^2.11.2", - "istanbul": "^0.3.6", + "chai": "^4.1.2", + "coveralls": "^2.13.3", + "istanbul": "^0.3.22", "mocha": "^2.1.0" } } diff --git a/test/decentralize.integration.js b/test/decentralize.integration.js new file mode 100644 index 0000000..7d1f04b --- /dev/null +++ b/test/decentralize.integration.js @@ -0,0 +1,18 @@ +var assert = require('assert'); +var expect = require('chai').expect; + +var DECENTRALIZE = require('../'); +var config = require('../config'); + +describe('DECENTRALIZE', function() { + this.timeout(20000); + + it('should expose a constructor', function(){ + assert(typeof DECENTRALIZE, 'function'); + }); + + it('should start successfully', function (done) { + var app = new DECENTRALIZE(config); + app.start(done); + }); +}); From c4eed271d5408993e7ccc458128f9a07f7a7d317 Mon Sep 17 00:00:00 2001 From: Eric Martindale Date: Mon, 30 Oct 2017 15:49:50 -0700 Subject: [PATCH 8/9] Improve handling, messaging, onboarding --- .travis.yml | 2 +- config/index.js | 8 ++++---- lib/Engine.js | 3 +++ lib/decentralize.js | 7 +------ package.json | 7 +++++-- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index a3ffa8d..6b3066e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: -- '6' +- '8' services: - mongodb - redis-server diff --git a/config/index.js b/config/index.js index a6ca9b2..0f2948a 100644 --- a/config/index.js +++ b/config/index.js @@ -16,10 +16,10 @@ module.exports = { dependencies: ['decentral'] }, source: { - sockets: 'ws://', - proto: 'http', - host: process.env.DECENTRAL_HOST || 'localhost', - port: process.env.DECENTRAL_PORT || '15005' + sockets: 'wss://', + proto: 'https', + host: process.env.DECENTRAL_HOST || 'decentral.fm', + port: process.env.DECENTRAL_PORT || '443' }, soundcloud: { clientID: '98ce66124fabdff2f33beb2f810a0a25', diff --git a/lib/Engine.js b/lib/Engine.js index 6f5a60c..8015ca9 100644 --- a/lib/Engine.js +++ b/lib/Engine.js @@ -56,6 +56,9 @@ Engine.prototype.subscribe = function( cb ) { attemptReconnect(); }); + + // TODO: port to Fabric + // TODO: add Router self.ws.on('message', function(data) { console.log('DATAGRAM:' , data ); var msg = JSON.parse( data ); diff --git a/lib/decentralize.js b/lib/decentralize.js index 33601d7..d0e479d 100644 --- a/lib/decentralize.js +++ b/lib/decentralize.js @@ -111,15 +111,10 @@ function DECENTRALIZE (config) { DECENTRALIZE.prototype.start = function (done) { var self = this; if (!done) done = Function(); - - console.log('starting:', self.source.base); - + procure( self.source.base + '/shows/decentralize' , function(err, show) { if (err || !show) return console.error(err || 'no such show: decentralize'); - - console.log('came back:', err, show); - // TODO: catch error try { self.config.show = JSON.parse( show ); } catch (e) { diff --git a/package.json b/package.json index 6235bc6..4022398 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,11 @@ "version": "0.0.0", "description": "decentralize the podcast", "main": "lib/decentralize.js", + "engine": "node >= 8.0.0", "scripts": { - "test": "mocha" + "test": "mocha", + "coverage": "NODE_ENV=test istanbul cover _mocha -- --recursive", + "start": "node decentralize:web.js" }, "repository": { "type": "git", @@ -26,7 +29,7 @@ "fast-json-patch": "^0.5.1", "form-data": "^0.2.0", "lodash": "^3.3.0", - "maki": "github:martindale/maki#v0.2.1", + "maki": "github:martindale/maki#tatami", "maki-remote": "0.0.1", "maki-sessions": "^0.1.0", "node-torrent-stream": "git://github.com/unusualbob/node-torrent-stream", From 92a3cbe50bbf5798d78c9318e04d21172b00e073 Mon Sep 17 00:00:00 2001 From: Eric Martindale Date: Mon, 30 Oct 2017 17:35:29 -0700 Subject: [PATCH 9/9] Improve test structures --- README.md | 3 +++ lib/Engine.js | 37 +------------------------------- lib/decentralize.js | 32 ++------------------------- test/decentralize.integration.js | 12 ++++++++--- 4 files changed, 15 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 945add7..2e1a532 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ decentralize ============ +[![Build Status](https://img.shields.io/travis/FabricLabs/decentralize.svg?branch=master&style=flat-square)](https://travis-ci.org/FabricLabs/decentralize) +[![Coverage Status](https://img.shields.io/coveralls/FabricLabs/decentralize.svg?style=flat-square)](https://coveralls.io/r/FabricLabs/decentralize) +[![Total Contributors](https://img.shields.io/github/contributors/FabricLabs/decentralize.svg?style=flat-square)](https://github.com/FabricLabs/decentralize/contributors) podcast diff --git a/lib/Engine.js b/lib/Engine.js index 4add712..a4015e1 100644 --- a/lib/Engine.js +++ b/lib/Engine.js @@ -14,20 +14,13 @@ function Engine( config , decentralize ) { this.config = config; this.decentralize = decentralize; this.soundcloud = new Soundcloud( config.soundcloud ); -<<<<<<< HEAD this.tries = 0; -======= - - this.tries = 0; - ->>>>>>> edit-shows }; Engine.prototype.subscribe = function( cb ) { var self = this; // subscribe to updates to important things. // mainly, recordings -<<<<<<< HEAD console.log('initializing socket...'); try { @@ -36,17 +29,6 @@ Engine.prototype.subscribe = function( cb ) { throw new Error( e ); } -======= - - console.log('initializing socket...'); - - try { - self.ws = new WebSocket( self.config.source.sockets + self.config.source.authority + '/recordings'); - } catch (e) { - console.log('exception connecting'); - } - ->>>>>>> edit-shows self.ws.on('error', function(err) { console.error( err ); }); @@ -56,11 +38,7 @@ Engine.prototype.subscribe = function( cb ) { }); self.ws.on('close', function() { console.log('socket closed wat'); -<<<<<<< HEAD -======= - ->>>>>>> edit-shows function attemptReconnect() { self.ws.removeAllListeners('open'); self.ws.removeAllListeners('close'); @@ -68,7 +46,6 @@ Engine.prototype.subscribe = function( cb ) { self.ws.removeAllListeners('message'); delete self.ws; -<<<<<<< HEAD self.subscribe(); @@ -79,21 +56,9 @@ Engine.prototype.subscribe = function( cb ) { attemptReconnect(); }); - + // TODO: port to Fabric // TODO: add Router -======= - - self.subscribe(); - - setTimeout( attemptReconnect , TRY_TIMES[ self.tries++ ] ); - - }; - - attemptReconnect(); - - }); ->>>>>>> edit-shows self.ws.on('message', function(data) { console.log('DATAGRAM:' , data ); var msg = JSON.parse( data ); diff --git a/lib/decentralize.js b/lib/decentralize.js index d0e479d..824b60c 100644 --- a/lib/decentralize.js +++ b/lib/decentralize.js @@ -37,24 +37,6 @@ function DECENTRALIZE (config) { var MailPimpSubscription = new Remote('http://localhost:2525/subscriptions'); var MailPimpTask = new Remote('http://localhost:2525/tasks'); - Show = self.app.define('Show', { - attributes: { - title: { type: String , slug: true }, - slug: { type: String }, - recorded: { type: Date }, - released: { type: Date , default: Date.now , required: true }, - description: { type: String }, - audio: { type: String }, - filename: { type: String }, - // TODO: replace with a sources list. - youtube: { type: String }, - soundcloud: { type: String }, - }, - names: { get: 'item' }, - source: self.source.proto + '://' + self.source.authority + '/recordings', - icon: 'sound' - }); - var Subscription = self.app.define('Subscription', { attributes: { email: { type: String , required: true , validator: function(value) { @@ -93,18 +75,8 @@ function DECENTRALIZE (config) { }); }); - Index = self.app.define('Index', { - name: 'Index', - routes: { query: '/' }, - templates: { query: 'index' }, - requires: { - 'Show': { - filter: {} - } - }, - static: true, - internal: true - }); + Show = self.app.define('Show', require('../resources/Show')); + Index = self.app.define('Index', require('../resources/Index')); } diff --git a/test/decentralize.integration.js b/test/decentralize.integration.js index 7d1f04b..14d11c7 100644 --- a/test/decentralize.integration.js +++ b/test/decentralize.integration.js @@ -4,15 +4,21 @@ var expect = require('chai').expect; var DECENTRALIZE = require('../'); var config = require('../config'); -describe('DECENTRALIZE', function() { +describe('DECENTRALIZE', function () { this.timeout(20000); - it('should expose a constructor', function(){ + it('should expose a constructor', function () { assert(typeof DECENTRALIZE, 'function'); }); it('should start successfully', function (done) { var app = new DECENTRALIZE(config); - app.start(done); + app.start(function () { + app.destroy(done); + }); + }); + + it('can create a local recording', function (done) { + done(); }); });