Attempting threading for long-runing system processes

This commit is contained in:
James Barnsley
2018-11-02 10:20:32 +13:00
parent b83043ef4f
commit 4c100a9527
9 changed files with 172 additions and 54 deletions

View File

@ -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

View File

@ -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()

View File

@ -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
View 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()

View File

@ -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

View File

@ -48,6 +48,12 @@ export function restart(){
}
}
export function runLocalScan(){
return {
type: 'PUSHER_RUN_LOCAL_SCAN'
}
}
export function getConnections(){
return {
type: 'PUSHER_GET_CONNECTIONS'

View File

@ -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 });

View File

@ -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>