Pusher username management; Spotify vs mopidy middleware glitching
This commit is contained in:
7
src/js/bootstrap.js
vendored
7
src/js/bootstrap.js
vendored
@ -22,17 +22,22 @@ let reducers = combineReducers({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// set application defaults
|
// set application defaults
|
||||||
|
// TODO: Look at using propTypes in the component for these falsy initial states
|
||||||
var initialState = {
|
var initialState = {
|
||||||
mopidy: {
|
mopidy: {
|
||||||
|
connected: false,
|
||||||
host: window.location.hostname,
|
host: window.location.hostname,
|
||||||
port: 6680,
|
port: 6680,
|
||||||
volume: 0,
|
volume: 0,
|
||||||
progress: 0
|
progress: 0
|
||||||
},
|
},
|
||||||
pusher: {
|
pusher: {
|
||||||
|
connections: [],
|
||||||
|
connected: false,
|
||||||
port: 6681
|
port: 6681
|
||||||
},
|
},
|
||||||
spotify: {
|
spotify: {
|
||||||
|
connected: false,
|
||||||
country: 'NZ',
|
country: 'NZ',
|
||||||
locale: 'en_NZ',
|
locale: 'en_NZ',
|
||||||
me: false
|
me: false
|
||||||
@ -65,7 +70,7 @@ if( localStorage.getItem('spotify') ){
|
|||||||
let store = createStore(
|
let store = createStore(
|
||||||
reducers,
|
reducers,
|
||||||
initialState,
|
initialState,
|
||||||
applyMiddleware( thunk, localstorageMiddleware, pusherMiddleware, mopidyMiddleware, spotifyMiddleware )
|
applyMiddleware( thunk, localstorageMiddleware, mopidyMiddleware, pusherMiddleware, spotifyMiddleware )
|
||||||
);
|
);
|
||||||
|
|
||||||
export default store;
|
export default store;
|
||||||
|
|||||||
61
src/js/components/PusherConnectionList.js
Executable file
61
src/js/components/PusherConnectionList.js
Executable file
@ -0,0 +1,61 @@
|
|||||||
|
|
||||||
|
import React, { PropTypes } from 'react'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { Link } from 'react-router'
|
||||||
|
import { createStore, bindActionCreators } from 'redux'
|
||||||
|
|
||||||
|
import FontAwesome from 'react-fontawesome'
|
||||||
|
|
||||||
|
import * as pusherActions from '../services/pusher/actions'
|
||||||
|
|
||||||
|
class PusherConnectionList extends React.Component{
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount(){
|
||||||
|
if( this.props.pusher.connected ){
|
||||||
|
this.props.pusherActions.getConnectionList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(newProps){
|
||||||
|
if( !this.props.pusher.connected && newProps.pusher.connected ){
|
||||||
|
this.props.pusherActions.getConnectionList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(){
|
||||||
|
if( !this.props.pusher.connected ) return null;
|
||||||
|
if( typeof(this.props.pusher.connections) == 'undefined' || this.props.pusher.connections.length <= 0 ) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="pusher-connection-list">
|
||||||
|
{
|
||||||
|
this.props.pusher.connections.map( (connection, index) => {
|
||||||
|
return (
|
||||||
|
<div className="connection cf" key={connection.connectionid}>
|
||||||
|
<div className="col w20 one-liner">{ connection.username }</div>
|
||||||
|
<div className="col w20 one-liner">{ connection.ip }</div>
|
||||||
|
<div className="col w20 one-liner">{ connection.connectionid }</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = (state, ownProps) => {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => {
|
||||||
|
return {
|
||||||
|
pusherActions: bindActionCreators(pusherActions, dispatch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(PusherConnectionList)
|
||||||
@ -6,7 +6,7 @@ const localstorageMiddleware = (function(){
|
|||||||
**/
|
**/
|
||||||
return store => next => action => {
|
return store => next => action => {
|
||||||
|
|
||||||
console.log(action)
|
console.log(action, store.getState())
|
||||||
|
|
||||||
// proceed as normal first
|
// proceed as normal first
|
||||||
// this way, any reducers and middleware do their thing BEFORE we store our new state
|
// this way, any reducers and middleware do their thing BEFORE we store our new state
|
||||||
@ -14,6 +14,25 @@ const localstorageMiddleware = (function(){
|
|||||||
|
|
||||||
switch( action.type ){
|
switch( action.type ){
|
||||||
|
|
||||||
|
case 'PUSHER_SET_CONFIG':
|
||||||
|
var pusher = {
|
||||||
|
username: action.config.username,
|
||||||
|
port: action.config.port
|
||||||
|
};
|
||||||
|
localStorage.setItem('pusher', JSON.stringify(pusher));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'PUSHER_CONNECTED':
|
||||||
|
var pusher = JSON.parse( localStorage.getItem('pusher') );
|
||||||
|
if( !pusher ) pusher = {};
|
||||||
|
Object.assign(
|
||||||
|
pusher,{
|
||||||
|
connectionid: action.connection.connectionid
|
||||||
|
}
|
||||||
|
);
|
||||||
|
localStorage.setItem('pusher', JSON.stringify(pusher));
|
||||||
|
break;
|
||||||
|
|
||||||
case 'MOPIDY_SET_CONFIG':
|
case 'MOPIDY_SET_CONFIG':
|
||||||
var mopidy = {
|
var mopidy = {
|
||||||
host: action.config.host,
|
host: action.config.host,
|
||||||
|
|||||||
@ -10,6 +10,14 @@ export function setConfig( config ){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setUsername( username ){
|
||||||
|
return {
|
||||||
|
type: 'PUSHER_INSTRUCT',
|
||||||
|
action: 'set_username',
|
||||||
|
data: { username: username }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function connect(){
|
export function connect(){
|
||||||
return {
|
return {
|
||||||
type: 'PUSHER_CONNECT'
|
type: 'PUSHER_CONNECT'
|
||||||
@ -22,10 +30,17 @@ export function disconnect(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function instruct( call, value ){
|
export function getConnectionList(){
|
||||||
return {
|
return {
|
||||||
type: 'PUSHER_INSTRUCT',
|
type: 'PUSHER_INSTRUCT',
|
||||||
call: call,
|
action: 'get_connections'
|
||||||
value: value
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function instruct( action, data = null ){
|
||||||
|
return {
|
||||||
|
type: 'PUSHER_INSTRUCT',
|
||||||
|
action: action,
|
||||||
|
data: data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,16 +40,23 @@ const PusherMiddleware = (function(){
|
|||||||
store.dispatch({ type: 'PUSHER_CONNECTING' });
|
store.dispatch({ type: 'PUSHER_CONNECTING' });
|
||||||
|
|
||||||
var state = store.getState();
|
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(
|
socket = new WebSocket(
|
||||||
'ws://'+state.mopidy.host+':'+state.pusher.port+'/pusher'
|
'ws://'+state.mopidy.host+':'+state.pusher.port+'/pusher',
|
||||||
|
[ connection.clientid, connection.connectionid, connection.username ]
|
||||||
);
|
);
|
||||||
|
|
||||||
socket.onopen = function(){
|
socket.onopen = () => {
|
||||||
store.dispatch({ type: 'PUSHER_CONNECTED' });
|
store.dispatch({ type: 'PUSHER_CONNECTED', connection: connection });
|
||||||
};
|
};
|
||||||
|
|
||||||
socket.onmessage = function(message){
|
socket.onmessage = (message) => {
|
||||||
var message = JSON.parse(message.data);
|
var message = JSON.parse(message.data);
|
||||||
handleMessage( socket, store, message )
|
handleMessage( socket, store, message )
|
||||||
};
|
};
|
||||||
@ -58,6 +65,11 @@ const PusherMiddleware = (function(){
|
|||||||
|
|
||||||
case 'PUSHER_CONNECTED':
|
case 'PUSHER_CONNECTED':
|
||||||
makeRequest({ action: 'get_version' });
|
makeRequest({ action: 'get_version' });
|
||||||
|
return next(action);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'PUSHER_INSTRUCT':
|
||||||
|
makeRequest({ action: action.action, data: action.data });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// This action is irrelevant to us, pass it on to the next middleware
|
// This action is irrelevant to us, pass it on to the next middleware
|
||||||
|
|||||||
@ -3,19 +3,22 @@ export default function reducer(pusher = {}, action){
|
|||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
|
||||||
case 'PUSHER_CONNECTED':
|
case 'PUSHER_CONNECTED':
|
||||||
return Object.assign({}, pusher, { connected: true, connecting: false });
|
return Object.assign({}, pusher, { connected: true, connecting: false, connectionid: action.connection.connectionid });
|
||||||
|
|
||||||
case 'PUSHER_DISCONNECTED':
|
case 'PUSHER_DISCONNECTED':
|
||||||
return Object.assign({}, pusher, { connected: false, connecting: false });
|
return Object.assign({}, pusher, { connected: false, connecting: false });
|
||||||
|
|
||||||
case 'PUSHER_SET_PORT':
|
case 'PUSHER_SET_CONFIG':
|
||||||
return Object.assign({}, pusher, { port: action.port });
|
return Object.assign({}, pusher, {
|
||||||
|
username: action.username,
|
||||||
|
port: action.port
|
||||||
|
});
|
||||||
|
|
||||||
case 'PUSHER_CLIENT_CONNECTED':
|
case 'PUSHER_CLIENT_CONNECTED':
|
||||||
return Object.assign({}, pusher, { connections: action.data });
|
return Object.assign({}, pusher, { connection: action.data });
|
||||||
|
|
||||||
case 'PUSHER_CONNECTIONS_LOADED':
|
case 'PUSHER_CONNECTIONS':
|
||||||
return Object.assign({}, pusher, { connections: action.data });
|
return Object.assign({}, pusher, { connections: action.data.connections });
|
||||||
|
|
||||||
case 'PUSHER_VERSION':
|
case 'PUSHER_VERSION':
|
||||||
return Object.assign({}, pusher, { version: action.data });
|
return Object.assign({}, pusher, { version: action.data });
|
||||||
|
|||||||
@ -12,7 +12,8 @@ const SpotifyMiddleware = (function(){
|
|||||||
switch(action.type){
|
switch(action.type){
|
||||||
|
|
||||||
// when our mopidy server current track changes
|
// when our mopidy server current track changes
|
||||||
case 'MOPIDY_CURRENTTLTRACK':
|
case 'MOPIDY_CURRENTTLTRACK_XX':
|
||||||
|
// DISABLED AS IT CAUSES ISSUE
|
||||||
|
|
||||||
// proceed as usual so we don't inhibit default functionality
|
// proceed as usual so we don't inhibit default functionality
|
||||||
next(action)
|
next(action)
|
||||||
|
|||||||
@ -6,8 +6,10 @@ import { bindActionCreators } from 'redux'
|
|||||||
import FontAwesome from 'react-fontawesome'
|
import FontAwesome from 'react-fontawesome'
|
||||||
import SpotifyAuthenticationFrame from '../components/SpotifyAuthenticationFrame'
|
import SpotifyAuthenticationFrame from '../components/SpotifyAuthenticationFrame'
|
||||||
import ConfirmationButton from '../components/ConfirmationButton'
|
import ConfirmationButton from '../components/ConfirmationButton'
|
||||||
|
import PusherConnectionList from '../components/PusherConnectionList'
|
||||||
import Header from '../components/Header'
|
import Header from '../components/Header'
|
||||||
|
|
||||||
|
import * as pusherActions from '../services/pusher/actions'
|
||||||
import * as mopidyActions from '../services/mopidy/actions'
|
import * as mopidyActions from '../services/mopidy/actions'
|
||||||
import * as spotifyActions from '../services/spotify/actions'
|
import * as spotifyActions from '../services/spotify/actions'
|
||||||
|
|
||||||
@ -15,16 +17,27 @@ class Settings extends React.Component{
|
|||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
mopidy_host: this.props.mopidy.host,
|
mopidy_host: this.props.mopidy.host,
|
||||||
mopidy_port: this.props.mopidy.port,
|
mopidy_port: this.props.mopidy.port,
|
||||||
|
pusher_username: '',
|
||||||
pusher_port: this.props.pusher.port,
|
pusher_port: this.props.pusher.port,
|
||||||
spotify_country: this.props.spotify.country,
|
spotify_country: this.props.spotify.country,
|
||||||
spotify_locale: this.props.spotify.locale
|
spotify_locale: this.props.spotify.locale
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps( newProps ){
|
||||||
|
if( this.props.pusher.connectionid != newProps.pusher.connectionid ){
|
||||||
|
|
||||||
|
function isCurrentConnection(connection){
|
||||||
|
return connection.connectionid == newProps.pusher.connectionid;
|
||||||
|
}
|
||||||
|
var currentConnection = newProps.pusher.connections.find(isCurrentConnection);
|
||||||
|
this.setState({ pusher_username: currentConnection.username })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resetAllSettings(){
|
resetAllSettings(){
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
window.location.reload(true);
|
window.location.reload(true);
|
||||||
@ -35,12 +48,13 @@ class Settings extends React.Component{
|
|||||||
window.location.reload(true);
|
window.location.reload(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
setSpotifyConfig(){
|
|
||||||
this.props.spotifyActions.setConfig({ country: this.state.spotify_country, locale: this.state.spotify_locale });
|
|
||||||
}
|
|
||||||
|
|
||||||
setPusherConfig(){
|
setPusherConfig(){
|
||||||
this.props.pusherActions.setConfig({ port: this.state.pusher_port });
|
this.props.pusherActions.setConfig({ port: this.state.pusher_port });
|
||||||
|
this.props.pusherActions.setUsername( this.state.pusher_username );
|
||||||
|
}
|
||||||
|
|
||||||
|
setSpotifyConfig(){
|
||||||
|
this.props.spotifyActions.setConfig({ country: this.state.spotify_country, locale: this.state.spotify_locale });
|
||||||
}
|
}
|
||||||
|
|
||||||
render(){
|
render(){
|
||||||
@ -56,18 +70,22 @@ class Settings extends React.Component{
|
|||||||
<h3 className="underline">Mopidy</h3>
|
<h3 className="underline">Mopidy</h3>
|
||||||
<form onSubmit={() => this.setMopidyConfig()}>
|
<form onSubmit={() => this.setMopidyConfig()}>
|
||||||
<label>
|
<label>
|
||||||
<span className="label">Host</span>
|
<div className="label">Host</div>
|
||||||
|
<div className="input">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
onChange={ e => this.setState({ mopidy_host: e.target.value })}
|
onChange={ e => this.setState({ mopidy_host: e.target.value })}
|
||||||
value={ this.state.mopidy_host } />
|
value={ this.state.mopidy_host } />
|
||||||
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<span className="label">Port</span>
|
<div className="label">Port</div>
|
||||||
|
<div className="input">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
onChange={ e => this.setState({ mopidy_port: e.target.value })}
|
onChange={ e => this.setState({ mopidy_port: e.target.value })}
|
||||||
value={ this.state.mopidy_port } />
|
value={ this.state.mopidy_port } />
|
||||||
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<button type="submit" className="secondary">Apply</button>
|
<button type="submit" className="secondary">Apply</button>
|
||||||
</form>
|
</form>
|
||||||
@ -75,11 +93,22 @@ class Settings extends React.Component{
|
|||||||
<h3 className="underline">Pusher</h3>
|
<h3 className="underline">Pusher</h3>
|
||||||
<form onSubmit={() => this.setPusherConfig()}>
|
<form onSubmit={() => this.setPusherConfig()}>
|
||||||
<label>
|
<label>
|
||||||
<span className="label">Port</span>
|
<div className="label">Username</div>
|
||||||
|
<div className="input">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
onChange={ e => this.setState({ pusher_username: e.target.value })}
|
||||||
|
value={ this.state.pusher_username } />
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<div className="label">Port</div>
|
||||||
|
<div className="input">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
onChange={ e => this.setState({ pusher_port: e.target.value })}
|
onChange={ e => this.setState({ pusher_port: e.target.value })}
|
||||||
value={ this.state.pusher_port } />
|
value={ this.state.pusher_port } />
|
||||||
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<button type="submit" className="secondary">Apply</button>
|
<button type="submit" className="secondary">Apply</button>
|
||||||
</form>
|
</form>
|
||||||
@ -87,18 +116,22 @@ class Settings extends React.Component{
|
|||||||
<h3 className="underline">Spotify</h3>
|
<h3 className="underline">Spotify</h3>
|
||||||
<form onSubmit={() => this.setSpotifyConfig()}>
|
<form onSubmit={() => this.setSpotifyConfig()}>
|
||||||
<label>
|
<label>
|
||||||
<span className="label">Country</span>
|
<div className="label">Country</div>
|
||||||
|
<div className="input">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
onChange={ e => this.setState({ spotify_country: e.target.value })}
|
onChange={ e => this.setState({ spotify_country: e.target.value })}
|
||||||
value={ this.state.spotify_country } />
|
value={ this.state.spotify_country } />
|
||||||
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<span className="label">Locale</span>
|
<div className="label">Locale</div>
|
||||||
<input
|
<div className="input">
|
||||||
type="text"
|
<input
|
||||||
onChange={ e => this.setState({ spotify_locale: e.target.value })}
|
type="text"
|
||||||
value={ this.state.spotify_locale } />
|
onChange={ e => this.setState({ spotify_locale: e.target.value })}
|
||||||
|
value={ this.state.spotify_locale } />
|
||||||
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<button type="submit" className="secondary">Apply</button>
|
<button type="submit" className="secondary">Apply</button>
|
||||||
</form>
|
</form>
|
||||||
@ -107,6 +140,14 @@ class Settings extends React.Component{
|
|||||||
|
|
||||||
<ConfirmationButton content="Reset all settings" confirmingContent="Are you sure?" onConfirm={() => this.resetAllSettings()} />
|
<ConfirmationButton content="Reset all settings" confirmingContent="Are you sure?" onConfirm={() => this.resetAllSettings()} />
|
||||||
|
|
||||||
|
<h3 className="underline">Advanced</h3>
|
||||||
|
<label>
|
||||||
|
<div className="label">Connections</div>
|
||||||
|
<div className="input">
|
||||||
|
<PusherConnectionList />
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -126,6 +167,7 @@ const mapStateToProps = (state, ownProps) => {
|
|||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => {
|
const mapDispatchToProps = (dispatch) => {
|
||||||
return {
|
return {
|
||||||
|
pusherActions: bindActionCreators(pusherActions, dispatch),
|
||||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||||
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -91,4 +91,8 @@ main {
|
|||||||
|
|
||||||
.cf{
|
.cf{
|
||||||
@include clearfix;
|
@include clearfix;
|
||||||
|
}
|
||||||
|
|
||||||
|
.one-liner{
|
||||||
|
@include one_line_text;
|
||||||
}
|
}
|
||||||
@ -87,8 +87,13 @@ label {
|
|||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
.input {
|
||||||
width: 60%;
|
width: 85%;
|
||||||
|
float: left;
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user