Attempting threading for long-runing system processes
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import random, string, logging, json, pykka, pylast, urllib, urllib2, os, sys, mopidy_iris, subprocess
|
||||
import random, string, socket, logging, json, pykka, pylast, urllib, urllib2, os, sys, mopidy_iris, subprocess
|
||||
import tornado.web
|
||||
import tornado.websocket
|
||||
import tornado.ioloop
|
||||
@ -14,7 +14,7 @@ from mopidy.core import CoreListener
|
||||
from pkg_resources import parse_version
|
||||
from tornado.escape import json_encode, json_decode
|
||||
|
||||
import socket
|
||||
from .system import IrisSystemActor
|
||||
|
||||
if sys.platform == 'win32':
|
||||
import ctypes
|
||||
@ -22,7 +22,7 @@ if sys.platform == 'win32':
|
||||
# import logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class IrisCore(object):
|
||||
class IrisCore(pykka.ThreadingActor):
|
||||
version = 0
|
||||
spotify_token = False
|
||||
queue_metadata = {}
|
||||
@ -37,15 +37,34 @@ class IrisCore(object):
|
||||
"results": []
|
||||
}
|
||||
snapcast_listener = False
|
||||
system_actor = False
|
||||
|
||||
|
||||
##
|
||||
# Kick off
|
||||
# Mopidy server is starting
|
||||
##
|
||||
def start(self):
|
||||
logger.info('Starting Iris '+self.version)
|
||||
|
||||
# Load our commands from file
|
||||
self.commands = self.load_from_file('commands')
|
||||
|
||||
# Start our system actor
|
||||
self.system_actor = IrisSystemActor()
|
||||
self.system_actor.start()
|
||||
|
||||
|
||||
##
|
||||
# Mopidy is shutting down
|
||||
##
|
||||
def stop(self):
|
||||
logger.info('Stopping Iris')
|
||||
|
||||
self.snapcast_disconnect_listener()
|
||||
|
||||
# Stop our system actor
|
||||
self.system_actor.stop()
|
||||
|
||||
# Load our commands from file
|
||||
self.commands = self.load_from_file('commands')
|
||||
|
||||
|
||||
##
|
||||
@ -1117,18 +1136,27 @@ class IrisCore(object):
|
||||
# Simple test method. Not for use in production for any purposes.
|
||||
##
|
||||
def test(self, *args, **kwargs):
|
||||
callback = kwargs.get('callback', None)
|
||||
data = kwargs.get('data', None)
|
||||
logger.info("Running test")
|
||||
callback = kwargs.get('callback', False)
|
||||
|
||||
self.save_to_file(data,"test")
|
||||
self.broadcast(data={
|
||||
'method': "testing",
|
||||
'params': {}
|
||||
})
|
||||
|
||||
output = self.system_actor.run('test')
|
||||
|
||||
self.broadcast(data={
|
||||
'method': "test_complete",
|
||||
'params': {
|
||||
'output': output
|
||||
}
|
||||
})
|
||||
|
||||
response = {
|
||||
'message': "Saved",
|
||||
'request': data
|
||||
'message': "Running test... please wait"
|
||||
}
|
||||
|
||||
if (callback):
|
||||
callback(response)
|
||||
return
|
||||
else:
|
||||
return response
|
||||
|
||||
@ -17,15 +17,10 @@ class IrisFrontend(pykka.ThreadingActor, CoreListener):
|
||||
mem.iris.config = config
|
||||
|
||||
def on_start(self):
|
||||
logger.info('Starting Iris '+mem.iris.version)
|
||||
mem.iris.start()
|
||||
|
||||
# Create our listening socket for Snapcast event notifications (only if enabled)
|
||||
#if mem.iris.config['iris'].get('snapcast_enabled'):
|
||||
# mem.iris.create_snapcast_listener()
|
||||
|
||||
def on_stop(self):
|
||||
mem.iris.snapcast_disconnect_listener()
|
||||
mem.iris.stop()
|
||||
|
||||
def track_playback_ended(self, tl_track, time_position):
|
||||
mem.iris.check_for_radio_update()
|
||||
|
||||
@ -5652,6 +5652,7 @@ exports.disconnect = disconnect;
|
||||
exports.upgrade = upgrade;
|
||||
exports.reload = reload;
|
||||
exports.restart = restart;
|
||||
exports.runLocalScan = runLocalScan;
|
||||
exports.getConnections = getConnections;
|
||||
exports.connectionAdded = connectionAdded;
|
||||
exports.connectionChanged = connectionChanged;
|
||||
@ -5729,6 +5730,12 @@ function restart() {
|
||||
};
|
||||
}
|
||||
|
||||
function runLocalScan() {
|
||||
return {
|
||||
type: 'PUSHER_RUN_LOCAL_SCAN'
|
||||
};
|
||||
}
|
||||
|
||||
function getConnections() {
|
||||
return {
|
||||
type: 'PUSHER_GET_CONNECTIONS'
|
||||
@ -57985,6 +57992,10 @@ var PusherMiddleware = function () {
|
||||
});
|
||||
break;
|
||||
|
||||
/**
|
||||
* Notifications and alerts
|
||||
**/
|
||||
|
||||
case 'PUSHER_BROWSER_NOTIFICATION':
|
||||
store.dispatch(uiActions.createBrowserNotification(action));
|
||||
break;
|
||||
@ -57996,6 +58007,10 @@ var PusherMiddleware = function () {
|
||||
store.dispatch(uiActions.createNotification(data));
|
||||
break;
|
||||
|
||||
/**
|
||||
* Server actions
|
||||
**/
|
||||
|
||||
case 'PUSHER_RELOAD':
|
||||
// Hard reload. This doesn't strictly clear the cache, but our compiler's
|
||||
// cache buster should handle that
|
||||
@ -58022,6 +58037,17 @@ var PusherMiddleware = function () {
|
||||
});
|
||||
break;
|
||||
|
||||
case 'PUSHER_RUN_LOCAL_SCAN':
|
||||
if (store.getState().ui.allow_reporting) {
|
||||
_reactGa2.default.event({ category: 'Pusher', action: 'Run local scan', label: '' });
|
||||
}
|
||||
request(store, 'run_local_scan').then(function (response) {
|
||||
store.dispatch(mopidyActions.localScanRunning());
|
||||
}, function (error) {
|
||||
store.dispatch(uiActions.createNotification({ content: error.message, description: error.description ? error.description : null, type: 'bad' }));
|
||||
});
|
||||
break;
|
||||
|
||||
case 'PUSHER_VERSION':
|
||||
if (store.getState().ui.allow_reporting) {
|
||||
_reactGa2.default.event({ category: 'Pusher', action: 'Version', label: action.version.current });
|
||||
@ -73171,6 +73197,22 @@ var Settings = function (_React$Component) {
|
||||
var upgrade_button = null;
|
||||
}
|
||||
|
||||
if (this.props.mopidy.local_scan_running) {
|
||||
var local_scan_button = _react2.default.createElement(
|
||||
'button',
|
||||
{ className: 'working' },
|
||||
'Running scan...'
|
||||
);
|
||||
} else {
|
||||
var local_scan_button = _react2.default.createElement(
|
||||
'button',
|
||||
{ onClick: function onClick(e) {
|
||||
return _this3.props.pusherActions.runLocalScan();
|
||||
} },
|
||||
'Run local scan'
|
||||
);
|
||||
}
|
||||
|
||||
return _react2.default.createElement(
|
||||
'div',
|
||||
{ className: 'view settings-view' },
|
||||
@ -73492,29 +73534,6 @@ var Settings = function (_React$Component) {
|
||||
'Advanced',
|
||||
_react2.default.createElement('a', { name: 'advanced' })
|
||||
),
|
||||
_react2.default.createElement(
|
||||
'div',
|
||||
{ className: 'field button-wrapper' },
|
||||
_react2.default.createElement(
|
||||
'div',
|
||||
{ className: 'name' },
|
||||
'Share configuration'
|
||||
),
|
||||
_react2.default.createElement(
|
||||
'div',
|
||||
{ className: 'input' },
|
||||
_react2.default.createElement(
|
||||
_reactRouter.Link,
|
||||
{ className: 'button', to: global.baseURL + "share-configuration" },
|
||||
'Share'
|
||||
),
|
||||
_react2.default.createElement(
|
||||
'div',
|
||||
{ className: 'description' },
|
||||
'Send your authorizations and configuration to another Iris client'
|
||||
)
|
||||
)
|
||||
),
|
||||
_react2.default.createElement(
|
||||
'div',
|
||||
{ className: 'field' },
|
||||
@ -73619,6 +73638,16 @@ var Settings = function (_React$Component) {
|
||||
)
|
||||
)
|
||||
),
|
||||
_react2.default.createElement(
|
||||
'div',
|
||||
{ className: 'field' },
|
||||
local_scan_button,
|
||||
_react2.default.createElement(
|
||||
_reactRouter.Link,
|
||||
{ className: 'button', to: global.baseURL + "share-configuration" },
|
||||
'Share configuration'
|
||||
)
|
||||
),
|
||||
_react2.default.createElement(
|
||||
'div',
|
||||
{ className: 'field' },
|
||||
|
||||
File diff suppressed because one or more lines are too long
19
mopidy_iris/system.py
Executable file
19
mopidy_iris/system.py
Executable file
@ -0,0 +1,19 @@
|
||||
|
||||
import logging, pykka, subprocess, os
|
||||
|
||||
# import logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class IrisSystemActor(pykka.ThreadingActor):
|
||||
|
||||
def __init__(self):
|
||||
super(IrisSystemActor, self).__init__()
|
||||
|
||||
##
|
||||
# Someone is telling us to do something
|
||||
##
|
||||
def run(self, action):
|
||||
path = os.path.dirname(__file__)
|
||||
return subprocess.check_output(["sudo "+path+"/system.sh "+action], shell=True)
|
||||
|
||||
actor_ref = IrisSystemActor.start()
|
||||
@ -11,6 +11,18 @@ elif [[ $1 = "restart" ]]; then
|
||||
|
||||
RESTART="$(service mopidy restart)"
|
||||
echo -e "${RESTART}"
|
||||
|
||||
elif [[ $1 = "scan" ]]; then
|
||||
|
||||
SCAN="$(mopidyctl local scan)"
|
||||
echo -e "${SCAN}"
|
||||
|
||||
elif [[ $1 = "test" ]]; then
|
||||
|
||||
sleep 10
|
||||
|
||||
SCAN="$(echo 'Hello, this is your bash speaking')"
|
||||
echo -e "${SCAN}"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@ -48,6 +48,12 @@ export function restart(){
|
||||
}
|
||||
}
|
||||
|
||||
export function runLocalScan(){
|
||||
return {
|
||||
type: 'PUSHER_RUN_LOCAL_SCAN'
|
||||
}
|
||||
}
|
||||
|
||||
export function getConnections(){
|
||||
return {
|
||||
type: 'PUSHER_GET_CONNECTIONS'
|
||||
|
||||
@ -618,6 +618,11 @@ const PusherMiddleware = (function(){
|
||||
);
|
||||
break
|
||||
|
||||
|
||||
/**
|
||||
* Notifications and alerts
|
||||
**/
|
||||
|
||||
case 'PUSHER_BROWSER_NOTIFICATION':
|
||||
store.dispatch(uiActions.createBrowserNotification(action))
|
||||
break
|
||||
@ -632,6 +637,11 @@ const PusherMiddleware = (function(){
|
||||
store.dispatch(uiActions.createNotification(data));
|
||||
break
|
||||
|
||||
|
||||
/**
|
||||
* Server actions
|
||||
**/
|
||||
|
||||
case 'PUSHER_RELOAD':
|
||||
// Hard reload. This doesn't strictly clear the cache, but our compiler's
|
||||
// cache buster should handle that
|
||||
@ -666,6 +676,21 @@ const PusherMiddleware = (function(){
|
||||
);
|
||||
break;
|
||||
|
||||
case 'PUSHER_RUN_LOCAL_SCAN':
|
||||
if (store.getState().ui.allow_reporting){
|
||||
ReactGA.event({ category: 'Pusher', action: 'Run local scan', label: '' });
|
||||
}
|
||||
request(store, 'run_local_scan')
|
||||
.then(
|
||||
response => {
|
||||
store.dispatch(mopidyActions.localScanRunning());
|
||||
},
|
||||
error => {
|
||||
store.dispatch(uiActions.createNotification({content: error.message, description: (error.description ? error.description : null), type: 'bad'}));
|
||||
}
|
||||
);
|
||||
break;
|
||||
|
||||
case 'PUSHER_VERSION':
|
||||
if (store.getState().ui.allow_reporting){
|
||||
ReactGA.event({ category: 'Pusher', action: 'Version', label: action.version.current });
|
||||
|
||||
@ -202,7 +202,6 @@ class Settings extends React.Component {
|
||||
</a>
|
||||
</span>
|
||||
)
|
||||
|
||||
|
||||
if (this.props.mopidy.upgrading){
|
||||
var upgrade_button = (
|
||||
@ -215,6 +214,16 @@ class Settings extends React.Component {
|
||||
} else {
|
||||
var upgrade_button = null;
|
||||
}
|
||||
|
||||
if (this.props.mopidy.local_scan_running){
|
||||
var local_scan_button = (
|
||||
<button className="working">
|
||||
Running scan...
|
||||
</button>
|
||||
);
|
||||
} else {
|
||||
var local_scan_button = <button onClick={e => this.props.pusherActions.runLocalScan()}>Run local scan</button>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="view settings-view">
|
||||
@ -379,16 +388,6 @@ class Settings extends React.Component {
|
||||
</div>
|
||||
|
||||
<h4 className="underline">Advanced<a name="advanced"></a></h4>
|
||||
|
||||
<div className="field button-wrapper">
|
||||
<div className="name">Share configuration</div>
|
||||
<div className="input">
|
||||
<Link className="button" to={global.baseURL+"share-configuration"}>Share</Link>
|
||||
<div className="description">
|
||||
Send your authorizations and configuration to another Iris client
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field">
|
||||
<div className="name">Artist library URI</div>
|
||||
@ -438,6 +437,11 @@ class Settings extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field">
|
||||
{local_scan_button}
|
||||
<Link className="button" to={global.baseURL+"share-configuration"}>Share configuration</Link>
|
||||
</div>
|
||||
|
||||
<div className="field">
|
||||
{upgrade_button}
|
||||
<button className={"destructive"+(this.props.mopidy.restarting ? ' working' : '')} onClick={e => this.props.pusherActions.restart()}>{this.props.mopidy.restarting ? 'Restarting...' : 'Restart server'}</button>
|
||||
|
||||
Reference in New Issue
Block a user