2016-10-27 16:58:11 +13:00
|
|
|
|
2016-12-20 07:56:42 +13:00
|
|
|
var pusherActions = require('./actions.js')
|
|
|
|
|
var uiActions = require('../ui/actions.js')
|
2016-10-27 21:20:05 +13:00
|
|
|
var helpers = require('../../helpers.js')
|
2016-10-27 16:58:11 +13:00
|
|
|
|
|
|
|
|
const PusherMiddleware = (function(){
|
|
|
|
|
|
|
|
|
|
// container for the actual Mopidy socket
|
|
|
|
|
var socket = null;
|
|
|
|
|
|
|
|
|
|
// handle all manner of socket messages
|
|
|
|
|
const handleMessage = (ws, store, message) => {
|
|
|
|
|
switch( message.action ){
|
|
|
|
|
default:
|
2016-11-21 07:59:52 +13:00
|
|
|
var name = 'unspecified'
|
|
|
|
|
if( message.action ) name = message.action
|
2016-11-29 15:36:01 +13:00
|
|
|
name = name.replace('get_','').toUpperCase()
|
2016-10-27 21:20:05 +13:00
|
|
|
store.dispatch({ type: 'PUSHER_'+name, data: message.data })
|
2016-10-27 16:58:11 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-27 21:20:05 +13:00
|
|
|
const makeRequest = (data) => {
|
|
|
|
|
data.type = 'query';
|
|
|
|
|
data.message_id = helpers.generateGuid();
|
|
|
|
|
socket.send( JSON.stringify(data) );
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-29 15:36:01 +13:00
|
|
|
const broadcast = (data) => {
|
|
|
|
|
data.type = 'broadcast';
|
|
|
|
|
socket.send( JSON.stringify(data) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-10-27 16:58:11 +13:00
|
|
|
/**
|
|
|
|
|
* Middleware
|
|
|
|
|
*
|
|
|
|
|
* This behaves like an action interceptor. We listen for specific actions
|
|
|
|
|
* and handle special functionality. If the action is not in our switch, then
|
|
|
|
|
* it just proceeds to the next middleware, or default functionality
|
|
|
|
|
**/
|
|
|
|
|
return store => next => action => {
|
|
|
|
|
|
|
|
|
|
switch(action.type) {
|
|
|
|
|
|
|
|
|
|
case 'PUSHER_CONNECT':
|
|
|
|
|
|
|
|
|
|
if(socket != null) socket.close();
|
|
|
|
|
store.dispatch({ type: 'PUSHER_CONNECTING' });
|
|
|
|
|
|
|
|
|
|
var state = store.getState();
|
2016-10-28 09:14:29 +13:00
|
|
|
var connection = {
|
|
|
|
|
clientid: Math.random().toString(36).substr(2, 9),
|
|
|
|
|
connectionid: helpers.generateGuid(),
|
|
|
|
|
username: Math.random().toString(36).substr(2, 9)
|
|
|
|
|
}
|
2016-10-28 15:58:07 +13:00
|
|
|
if( state.pusher.username ) connection.username = state.pusher.username;
|
2016-10-27 16:58:11 +13:00
|
|
|
|
|
|
|
|
socket = new WebSocket(
|
2016-10-28 09:14:29 +13:00
|
|
|
'ws://'+state.mopidy.host+':'+state.pusher.port+'/pusher',
|
|
|
|
|
[ connection.clientid, connection.connectionid, connection.username ]
|
2016-10-27 16:58:11 +13:00
|
|
|
);
|
|
|
|
|
|
2016-10-28 09:14:29 +13:00
|
|
|
socket.onopen = () => {
|
|
|
|
|
store.dispatch({ type: 'PUSHER_CONNECTED', connection: connection });
|
2016-10-28 15:58:07 +13:00
|
|
|
store.dispatch({ type: 'PUSHER_SET_USERNAME', username: connection.username });
|
2016-12-20 16:58:20 +13:00
|
|
|
makeRequest({ action: 'get_radio' });
|
2016-10-27 16:58:11 +13:00
|
|
|
};
|
|
|
|
|
|
2016-10-28 09:14:29 +13:00
|
|
|
socket.onmessage = (message) => {
|
2016-10-27 16:58:11 +13:00
|
|
|
var message = JSON.parse(message.data);
|
|
|
|
|
handleMessage( socket, store, message )
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2016-10-27 21:20:05 +13:00
|
|
|
case 'PUSHER_CONNECTED':
|
|
|
|
|
makeRequest({ action: 'get_version' });
|
2016-10-29 22:40:02 +13:00
|
|
|
return next(action);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'PUSHER_UPGRADING':
|
|
|
|
|
makeRequest({ action: 'perform_upgrade' });
|
2016-10-28 09:14:29 +13:00
|
|
|
return next(action);
|
|
|
|
|
break;
|
|
|
|
|
|
2016-10-28 10:48:55 +13:00
|
|
|
case 'PUSHER_CLIENT_CONNECTED':
|
|
|
|
|
makeRequest({ action: 'get_connections' });
|
|
|
|
|
return next(action);
|
|
|
|
|
break;
|
|
|
|
|
|
2016-10-28 09:14:29 +13:00
|
|
|
case 'PUSHER_INSTRUCT':
|
2016-12-12 09:07:47 +13:00
|
|
|
switch( action.message_type ){
|
2016-12-05 10:20:01 +13:00
|
|
|
case 'query':
|
|
|
|
|
makeRequest( action.data )
|
|
|
|
|
break
|
|
|
|
|
case 'broadcast':
|
|
|
|
|
broadcast( action.data )
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'PUSHER_DEBUG':
|
|
|
|
|
switch( action.call ){
|
|
|
|
|
case 'query':
|
|
|
|
|
makeRequest( action.data )
|
|
|
|
|
// THIS DOES NOT RETURN A PROMISE SO CAN'T DETECT RELATED RESPONSES
|
|
|
|
|
/*.then( response => {
|
|
|
|
|
store.dispatch({ type: 'DEBUG', response: response })
|
|
|
|
|
})*/
|
|
|
|
|
break
|
|
|
|
|
case 'broadcast':
|
|
|
|
|
broadcast( action.data )
|
|
|
|
|
/*.then( response => {
|
|
|
|
|
store.dispatch({ type: 'DEBUG', response: response })
|
|
|
|
|
})*/
|
|
|
|
|
break
|
|
|
|
|
default:
|
|
|
|
|
store.dispatch({ type: 'DEBUG', response: '{ "error": "Invalid call" }' })
|
|
|
|
|
break
|
|
|
|
|
}
|
2016-10-27 21:20:05 +13:00
|
|
|
break;
|
|
|
|
|
|
2016-11-29 15:36:01 +13:00
|
|
|
case 'PUSHER_SEND_BROADCAST':
|
|
|
|
|
broadcast({ action: action.action, data: action.data });
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'PUSHER_NOTIFICATION':
|
|
|
|
|
case 'PUSHER_BROADCAST':
|
|
|
|
|
|
|
|
|
|
var notification = window.Notification || window.mozNotification || window.webkitNotification;
|
|
|
|
|
if ('undefined' === typeof notification) return false;
|
|
|
|
|
if ('undefined' !== typeof notification) notification.requestPermission(function(permission){});
|
|
|
|
|
|
|
|
|
|
// handle nested data objects
|
|
|
|
|
var data = {}
|
|
|
|
|
if( typeof(action.data) ) data = action.data
|
|
|
|
|
if( typeof(data.data) ) data = Object.assign({}, data, data.data)
|
|
|
|
|
|
|
|
|
|
// construct our browser notification
|
|
|
|
|
var title = '';
|
|
|
|
|
var options = {
|
|
|
|
|
body: '',
|
|
|
|
|
dir: 'auto',
|
|
|
|
|
lang: 'EN',
|
|
|
|
|
tag: 'iris'
|
|
|
|
|
};
|
|
|
|
|
if( data.title ) title = data.title;
|
|
|
|
|
if( data.body ) options.body = data.body;
|
|
|
|
|
if( data.icon ) options.icon = data.icon;
|
|
|
|
|
|
|
|
|
|
// make it so
|
|
|
|
|
var notification = new notification( title, options );
|
2016-12-20 16:58:20 +13:00
|
|
|
break
|
2016-11-29 15:36:01 +13:00
|
|
|
|
2016-12-12 09:07:47 +13:00
|
|
|
case 'PUSHER_SEND_AUTHORIZATION':
|
|
|
|
|
if( window.confirm('Spotify authorization for user '+action.data.me.id+' received. Do you want to import?') ){
|
|
|
|
|
|
|
|
|
|
// remove any existing authentication
|
|
|
|
|
store.dispatch({ type: 'SPOTIFY_AUTHORIZATION_REVOKED' })
|
|
|
|
|
|
|
|
|
|
// import our new authentication
|
|
|
|
|
store.dispatch({ type: 'SPOTIFY_ME_LOADED', data: action.data.me })
|
|
|
|
|
store.dispatch({ type: 'SPOTIFY_AUTHORIZATION_GRANTED', data: action.data.authorization })
|
|
|
|
|
}else{
|
|
|
|
|
console.log('Authorization ignored')
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
|
2016-12-20 16:58:20 +13:00
|
|
|
case 'PUSHER_START_RADIO':
|
|
|
|
|
|
|
|
|
|
var data = {
|
|
|
|
|
action: 'start_radio',
|
|
|
|
|
seed_artists: [],
|
|
|
|
|
seed_genres: [],
|
|
|
|
|
seed_tracks: []
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for( var i = 0; i < action.uris.length; i++){
|
|
|
|
|
switch( helpers.uriType( action.uris[i] ) ){
|
|
|
|
|
case 'artist':
|
|
|
|
|
data.seed_artists.push( action.uris[i] );
|
|
|
|
|
break;
|
|
|
|
|
case 'track':
|
|
|
|
|
data.seed_tracks.push( action.uris[i] );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
makeRequest( data )
|
|
|
|
|
break
|
|
|
|
|
|
2016-12-20 19:54:19 +13:00
|
|
|
case 'PUSHER_STOP_RADIO':
|
|
|
|
|
var data = {
|
|
|
|
|
action: 'stop_radio',
|
|
|
|
|
seed_artists: [],
|
|
|
|
|
seed_genres: [],
|
|
|
|
|
seed_tracks: []
|
|
|
|
|
}
|
|
|
|
|
makeRequest( data )
|
|
|
|
|
break
|
|
|
|
|
|
2016-10-27 16:58:11 +13:00
|
|
|
// This action is irrelevant to us, pass it on to the next middleware
|
|
|
|
|
default:
|
|
|
|
|
return next(action);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
export default PusherMiddleware
|