Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 36 additions & 57 deletions decentralize.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,31 @@ var procure = require('procure');
var Maki = require('maki');
var Soundcloud = require('./lib/Soundcloud');
var Engine = require('./lib/Engine');
var WebSocket = require('ws');

var jsonpatch = require('fast-json-patch');
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 );

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 },
audio: { type: String },
// TODO: replace with a sources list.
youtube: { type: String }
},
names: { get: 'item' },
source: source.proto + '://' + source.authority + '/recordings',
icon: 'sound'
});
var policies = new Policies();
var sessions = new Sessions();

Index = decentralize.define('Index', {
name: 'Index',
routes: { query: '/' },
templates: { query: 'index' },
requires: {
'Show': {
filter: {}
}
},
static: true,
internal: true
});
decentralize.use( sessions );

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);
Expand Down Expand Up @@ -77,6 +62,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' );
});
Expand All @@ -90,38 +94,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();

});

Expand Down
74 changes: 71 additions & 3 deletions lib/Engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,81 @@ 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 ) {
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

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 );
});
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') {
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();
Expand Down Expand Up @@ -90,6 +158,6 @@ Engine.prototype.sync = function( cb ) {
});
});
});
}
};

module.exports = Engine;
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@
"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",
"request": "^2.53.0",
Expand Down
6 changes: 6 additions & 0 deletions public/js/marked.min.js

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions resources/Index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module.exports = {
name: 'Index',
routes: { query: '/' },
templates: { query: 'index' },
requires: {
'Show': {
filter: {}
}
},
static: true,
internal: true
};
17 changes: 17 additions & 0 deletions resources/Show.js
Original file line number Diff line number Diff line change
@@ -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'
}
1 change: 1 addition & 0 deletions views/layouts/default.jade
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
41 changes: 41 additions & 0 deletions views/show-edit.jade
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
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")
input(type="hidden", name="method", value="PATCH")

.field
label Description
textarea(name="description", style="height: 20em;") #{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 &raquo;

block scripts
script.
$('textarea[name=description]').keyup( renderPreview );

function renderPreview() {
var value = this.value;
var rendered = marked( value );
$('.preview').html( rendered );
}