Files
Iris/src/js/services/pusher/middleware.js

348 lines
13 KiB
JavaScript
Raw Normal View History

2016-10-27 16:58:11 +13:00
2016-10-27 21:20:05 +13:00
var helpers = require('../../helpers.js')
2017-02-06 17:02:43 +13:00
var uiActions = require('../ui/actions.js')
var pusherActions = require('./actions.js')
var spotifyActions = require('../spotify/actions.js')
2016-10-27 16:58:11 +13:00
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 );
}
2016-10-27 16:58:11 +13:00
// handle all manner of socket messages
const handleMessage = (ws, store, message) => {
2017-02-19 21:27:43 +13:00
// if debug enabled
if (store.getState().ui.log_pusher) console.log('Pusher', message)
2017-02-18 22:04:05 +13:00
// response to a request [we] made
if (typeof(message.request_id) !== 'undefined' && message.request_id){
if (typeof( deferredRequests[ message.request_id ]) !== 'undefined' ){
deferredRequests[ message.request_id ].resolve( message )
} else {
console.error('Pusher: Response with no matching request', message);
}
2016-10-27 16:58:11 +13:00
2017-02-18 22:04:05 +13:00
// general message
// this can be client-client, server-client or a broadcast to many clients
} else {
2017-02-19 21:27:43 +13:00
message.type = 'PUSHER_'+message.type.toUpperCase()
2017-02-18 22:04:05 +13:00
store.dispatch(message)
}
2016-10-27 21:20:05 +13:00
}
2017-02-18 22:04:05 +13:00
const request = (method, data = {}) => {
return new Promise( (resolve, reject) => {
2017-02-18 22:04:05 +13:00
var request_id = helpers.generateGuid()
var message = {
method: method,
data: data,
request_id: request_id
}
socket.send( JSON.stringify(message) )
// add query to our deferred responses
2017-02-18 22:04:05 +13:00
deferredRequests[request_id] = {
resolve: resolve,
reject: reject
}
})
}
2016-10-27 16:58:11 +13:00
return store => next => action => {
switch(action.type) {
case 'PUSHER_CONNECT':
if(socket != null) socket.close();
store.dispatch({ type: 'PUSHER_CONNECTING' });
var state = store.getState();
var connection = {
2017-02-17 21:36:31 +13:00
clientid: helpers.generateGuid(),
2017-02-18 22:04:05 +13:00
connection_id: helpers.generateGuid(),
2017-02-17 21:36:31 +13:00
username: 'Anonymous'
}
2016-10-28 15:58:07 +13:00
if( state.pusher.username ) connection.username = state.pusher.username;
2017-02-17 21:36:31 +13:00
connection.username = connection.username.replace(/\W/g, '')
2017-02-16 19:51:49 +13:00
2016-10-27 16:58:11 +13:00
socket = new WebSocket(
2017-02-16 19:51:49 +13:00
'ws://'+state.mopidy.host+':'+state.mopidy.port+'/iris/ws',
2017-02-18 22:04:05 +13:00
[ connection.clientid, connection.connection_id, connection.username ]
2016-10-27 16:58:11 +13:00
);
socket.onmessage = (message) => {
2016-10-27 16:58:11 +13:00
var message = JSON.parse(message.data);
handleMessage( socket, store, message )
};
2017-02-21 20:04:45 +13:00
socket.onclose = () => {
store.dispatch({
type: 'PUSHER_DISCONNECTED'
})
2017-02-21 21:56:40 +13:00
// attempt to reconnect ever 5 seconds
2017-02-21 20:04:45 +13:00
setTimeout(() => {
store.dispatch(pusherActions.connect())
}, 5000);
};
2016-10-27 16:58:11 +13:00
break;
2016-10-27 21:20:05 +13:00
case 'PUSHER_CONNECTED':
2017-02-18 22:04:05 +13:00
request('get_config')
.then(
response => {
2017-02-18 22:04:05 +13:00
if (response.error){
console.error(response.error)
2017-02-07 10:21:20 +13:00
return false
}
response.type = 'PUSHER_CONFIG'
2017-02-18 22:04:05 +13:00
store.dispatch(response)
if (response.config.spotify_username){
store.dispatch(spotifyActions.getUser('spotify:user:'+response.config.spotify_username))
2017-02-06 17:02:43 +13:00
}
var spotify = store.getState().spotify
if (!spotify.country || !spotify.locale){
2017-02-18 22:04:05 +13:00
store.dispatch({ type: 'SPOTIFY_SET_CONFIG', config: response.config })
}
}
)
2017-02-18 22:04:05 +13:00
request('get_version')
.then(
response => {
2017-02-18 22:04:05 +13:00
if (response.error){
console.error(response.error)
2017-02-07 10:21:20 +13:00
return false
}
response.type = 'PUSHER_VERSION'
2017-02-18 22:04:05 +13:00
store.dispatch(response)
}
)
2017-02-18 22:04:05 +13:00
request('get_radio')
.then(
response => {
2017-02-18 22:04:05 +13:00
if (response.error){
console.error(response.error)
2017-02-07 10:21:20 +13:00
return false
}
response.type = 'PUSHER_RADIO'
2017-02-18 22:04:05 +13:00
store.dispatch(response)
}
)
2017-02-14 21:41:13 +13:00
store.dispatch(pusherActions.getQueueMetadata())
return next(action);
break;
case 'PUSHER_INSTRUCT':
request( action )
.then(
response => {
store.dispatch({ type: 'PUSHER_INSTRUCT', data: response.data })
}
)
break
case 'PUSHER_DELIVER_MESSAGE':
2017-03-09 08:04:23 +13:00
request('deliver_message', action.data)
.then(
response => {
2017-02-21 19:54:00 +13:00
store.dispatch( uiActions.createNotification('Message delivered') )
}
)
break
2017-03-09 08:04:23 +13:00
case 'PUSHER_DELIVER_BROADCAST':
request('broadcast', action.data)
break
2017-02-14 12:13:07 +13:00
case 'PUSHER_GET_QUEUE_METADATA':
2017-02-18 22:04:05 +13:00
request('get_queue_metadata')
2017-02-14 12:13:07 +13:00
.then(
response => {
response.type = 'PUSHER_QUEUE_METADATA'
2017-02-18 22:04:05 +13:00
store.dispatch(response)
2017-02-14 12:13:07 +13:00
}
)
break;
case 'PUSHER_ADD_QUEUE_METADATA':
2017-02-18 22:04:05 +13:00
request('add_queue_metadata', {
tlids: action.tlids,
added_from: action.from_uri,
added_by: store.getState().pusher.username
})
2017-02-14 12:13:07 +13:00
break;
2017-02-19 21:27:43 +13:00
case 'PUSHER_START_UPGRADE':
2017-02-18 22:04:05 +13:00
request('upgrade')
.then(
response => {
if (response.error){
console.error(response.error)
return false
}
2017-02-07 10:21:20 +13:00
2017-02-18 22:04:05 +13:00
if (response.upgrade_successful){
store.dispatch( uiActions.createNotification('Upgrade complete') )
}else{
store.dispatch( uiActions.createNotification('Upgrade failed, please upgrade manually','bad') )
}
2017-02-18 22:04:05 +13:00
response.type = 'PUSHER_VERSION'
2017-02-18 22:04:05 +13:00
store.dispatch(response)
}
)
return next(action);
break;
case 'PUSHER_SET_USERNAME':
2017-02-18 22:04:05 +13:00
request('set_username', {
username: action.username
})
.then(
response => {
if (response.error){
console.error(response.error)
return false
}
2017-02-19 21:27:43 +13:00
response.type = 'PUSHER_USERNAME_CHANGED'
store.dispatch(response)
2017-02-18 22:04:05 +13:00
}
)
2016-10-28 10:48:55 +13:00
return next(action);
break;
2017-02-19 21:27:43 +13:00
case 'PUSHER_GET_CONNECTIONS':
2017-02-18 22:04:05 +13:00
request('get_connections')
.then(
response => {
if (response.error){
console.error(response.error)
return false
}
2017-02-19 21:27:43 +13:00
response.type = 'PUSHER_CONNECTIONS'
2017-02-18 22:04:05 +13:00
store.dispatch(response)
}
)
return next(action);
break
2017-02-21 19:54:00 +13:00
case 'PUSHER_SPOTIFY_AUTHORIZATION':
2017-02-18 22:04:05 +13:00
if( window.confirm('Spotify authorization for user '+action.me.id+' received. Do you want to import?') ){
// remove any existing authentication
store.dispatch({ type: 'SPOTIFY_AUTHORIZATION_REVOKED' })
// import our new authentication
2017-02-18 22:04:05 +13:00
store.dispatch({ type: 'SPOTIFY_ME_LOADED', data: action.me })
store.dispatch({ type: 'SPOTIFY_AUTHORIZATION_GRANTED', data: action.authorization })
}else{
console.log('Authorization ignored')
}
break
case 'PUSHER_START_RADIO':
store.dispatch(uiActions.createNotification('Starting radio...'))
2017-01-05 13:49:38 +13:00
2016-12-20 16:58:20 +13:00
var data = {
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;
case 'genre':
data.seed_genres.push( action.uris[i] );
break;
2016-12-20 16:58:20 +13:00
}
}
2017-03-09 08:04:23 +13:00
// we don't need to wait for response, as change will be broadcast
request( 'start_radio', data )
2017-03-09 08:04:23 +13:00
break
case 'PUSHER_RADIO_STARTED':
var data = {
type: 'browser_notification',
title: 'Radio',
body: 'Radio mode started',
icon: (store.getState().ui.current_track ? helpers.getTrackIcon( store.getState().ui.current_track ) : false)
}
store.dispatch( pusherActions.deliverBroadcast(data) )
2016-12-20 16:58:20 +13:00
break
case 'PUSHER_STOP_RADIO':
store.dispatch(uiActions.createNotification('Stopping radio'))
2017-01-05 13:49:38 +13:00
2016-12-20 19:54:19 +13:00
var data = {
seed_artists: [],
seed_genres: [],
seed_tracks: []
}
2017-03-09 08:04:23 +13:00
// we don't need to wait for response, as change will be broadcast
request( 'stop_radio', data )
break
2017-03-09 08:04:23 +13:00
case 'PUSHER_RADIO_STOPPED':
var data = {
type: 'browser_notification',
title: 'Radio',
body: 'Radio mode stopped',
icon: (store.getState().ui.current_track ? helpers.getTrackIcon( store.getState().ui.current_track ) : false)
}
store.dispatch( pusherActions.deliverBroadcast(data) )
break
case 'PUSHER_BROWSER_NOTIFICATION':
store.dispatch(uiActions.createBrowserNotification(action))
2016-12-20 19:54:19 +13:00
break
case 'PUSHER_RESTART':
// Hard reload. This doesn't strictly clear the cache, but our compiler's
// cache buster should handle that
window.location.reload(true);
break
case 'PUSHER_DEBUG':
request( action.message.method, action.message.data )
.then(
response => {
store.dispatch({type: 'DEBUG', response: response})
}
)
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