Files
Iris/src/js/services/pusher/middleware.js
2017-01-09 12:54:34 +13:00

270 lines
9.7 KiB
JavaScript
Executable File

var pusherActions = require('./actions.js')
var uiActions = require('../ui/actions.js')
var helpers = require('../../helpers.js')
const PusherMiddleware = (function(){
// container for the actual Mopidy socket
var socket = null;
var deferredRequests = [];
const resolveRequest = (requestId, message ) => {
var response = JSON.parse( message );
deferredRequests[request_id].resolve( response );
delete deferredRequests[request_id];
}
const rejectRequest = (requestId, message) => {
deferredRequests[requestId].reject( message );
}
// handle all manner of socket messages
const handleMessage = (ws, store, message) => {
switch (message.action){
case 'response':
if (typeof( deferredRequests[ message.request_id ]) !== 'undefined' ){
deferredRequests[ message.request_id ].resolve( message )
} else {
console.error('Pusher: Response with no matching request', message);
}
break
case 'broadcast':
if (message.type ){
var type = message.type.toUpperCase()
} else if (message.data.type ){
var type = message.data.type.toUpperCase()
} else {
var type = 'UNRECOGNISED_BROADCAST'
}
store.dispatch({ type: type, data: message.data })
break
}
}
const request = (data) => {
return new Promise( (resolve, reject) => {
// send the payload
data.request_id = helpers.generateGuid()
socket.send( JSON.stringify(data) )
// add query to our deferred responses
deferredRequests[ data.request_id ] = {
resolve: resolve,
reject: reject
}
})
}
/**
* 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_INSTRUCT':
request( action.data )
.then(
response => {
store.dispatch({ type: 'PUSHER_INSTRUCT', data: response.data })
}
)
break
case 'PUSHER_CONNECT':
if(socket != null) socket.close();
store.dispatch({ type: 'PUSHER_CONNECTING' });
var state = store.getState();
var connection = {
clientid: Math.random().toString(36).substr(2, 9),
connectionid: helpers.generateGuid(),
username: Math.random().toString(36).substr(2, 9)
}
if( state.pusher.username ) connection.username = state.pusher.username;
socket = new WebSocket(
'ws://'+state.mopidy.host+':'+state.pusher.port+'/pusher',
[ connection.clientid, connection.connectionid, connection.username ]
);
socket.onopen = () => {
store.dispatch({ type: 'PUSHER_CONNECTED', connection: connection });
store.dispatch({ type: 'PUSHER_SET_USERNAME', username: connection.username });
request({ action: 'get_radio' })
.then(
response => {
store.dispatch({ type: 'RADIO', data: response.data })
}
)
};
socket.onmessage = (message) => {
var message = JSON.parse(message.data);
handleMessage( socket, store, message )
};
break;
case 'PUSHER_CONNECTED':
request({ action: 'get_version' })
.then(
response => {
store.dispatch({ type: 'PUSHER_VERSION', data: response.data })
}
)
return next(action);
break;
case 'PUSHER_UPGRADING':
request({ action: 'perform_upgrade' })
.then(
response => {
store.dispatch({ type: 'PUSHER_UPGRADE', data: response.data })
}
)
return next(action);
break;
case 'PUSHER_SET_USERNAME':
request({ action: 'set_username', username: action.username })
.then(
response => {
store.dispatch({ type: 'PUSHER_USERNAME', data: { username: response.data.username }})
}
)
return next(action);
break;
case 'PUSHER_GET_CONNECTIONS':
case 'PUSHER_CLIENT_CONNECTED':
request({ action: 'get_connections' })
.then(
response => {
store.dispatch({ type: 'PUSHER_CONNECTIONS', data: response.data })
}
)
return next(action);
break
case 'PUSHER_DEBUG':
request( action.data )
.then(
response => {
store.dispatch({ type: 'DEBUG', response: response.data })
}
)
break;
case 'PUSHER_SEND_AUTHORIZATION':
request({
action: 'send_authorization',
recipient_connectionid: action.recipient_connectionid,
authorization: action.authorization,
me: action.me
})
.then(
response => {
uiActions.createNotification('Authorization sent')
}
)
break;
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
case 'START_RADIO':
request({
action: 'broadcast',
data: {
type: 'browser_notification',
title: 'Radio started',
body: store.getState().pusher.username +' started radio mode',
icon: ''
}
})
.then(
response => {
uiActions.createNotification('Starting 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;
}
}
request( data )
break
case 'STOP_RADIO':
request({
action: 'broadcast',
data: {
type: 'browser_notification',
title: 'Radio stopped',
body: store.getState().pusher.username +' stopped radio mode',
icon: ''
}
})
.then(
response => {
uiActions.createNotification('Stopping radio')
}
)
store.dispatch( uiActions.createNotification('Stopping radio') )
var data = {
action: 'stop_radio',
seed_artists: [],
seed_genres: [],
seed_tracks: []
}
request( data )
break
// This action is irrelevant to us, pass it on to the next middleware
default:
return next(action);
}
}
})();
export default PusherMiddleware