summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/client/dashboard/gallery.component.js1
-rw-r--r--app/client/index.jsx11
-rw-r--r--app/client/live/player.js4
-rw-r--r--app/client/pix2pix/index.js255
-rw-r--r--app/client/pix2pix/live.component.js252
-rw-r--r--app/client/socket.js20
-rw-r--r--app/client/system/system.actions.js7
-rw-r--r--app/client/system/system.component.js68
-rw-r--r--app/client/system/system.reducer.js37
-rw-r--r--app/client/types.js4
-rw-r--r--app/relay/index.js23
-rw-r--r--app/relay/interpreters.js24
-rw-r--r--app/relay/runner.js26
-rw-r--r--app/server/index.js16
14 files changed, 471 insertions, 277 deletions
diff --git a/app/client/dashboard/gallery.component.js b/app/client/dashboard/gallery.component.js
index 0b13cfe..8db7032 100644
--- a/app/client/dashboard/gallery.component.js
+++ b/app/client/dashboard/gallery.component.js
@@ -15,7 +15,6 @@ class Gallery extends Component {
</div>
)
})
- imageList.push(imageList[0])
return (
<div class='gallery'>
{imageList}
diff --git a/app/client/index.jsx b/app/client/index.jsx
index 45a1b94..fba38df 100644
--- a/app/client/index.jsx
+++ b/app/client/index.jsx
@@ -8,15 +8,20 @@ import socket from './socket'
import Header from './common/header.component'
import Dashboard from './dashboard/dashboard.component'
-import LivePix2Pix from './pix2pix'
+import System from './system/system.component'
+import Pix2Pix from './pix2pix'
const app = (
<Provider store={store}>
<BrowserRouter>
<div>
<Route exact path='/' component={Dashboard} />
- <Route exact path='/live/' component={LivePix2Pix} />
- <Route exact path='/dashboard/' component={Dashboard} />
+ <Route path='/datasets/' component={Dashboard} />
+ <Route path='/checkpoints/' component={Dashboard} />
+ <Route path='/results/' component={Dashboard} />
+ <Route path='/live/' component={Pix2Pix.Live} />
+ <Route path='/system/' component={System} />
+ <Route path='/dashboard/' component={Dashboard} />
<Header />
</div>
</BrowserRouter>
diff --git a/app/client/live/player.js b/app/client/live/player.js
index ac5f0c8..808e79e 100644
--- a/app/client/live/player.js
+++ b/app/client/live/player.js
@@ -37,7 +37,7 @@ export function onFrame (data) {
const blob = new Blob([data.frame], { type: 'image/jpg' })
const url = URL.createObjectURL(blob)
const img = new Image ()
- img.onload = function() {
+ img.onload = () => {
img.onload = null
last_frame = data.meta
URL.revokeObjectURL(url)
@@ -54,7 +54,7 @@ export function onFrame (data) {
}
if (saving) {
saving = false
- canvas.toBlob(function(blob) {
+ canvas.toBlob(blob => {
store.dispatch({
type: types.player.save_frame,
blob: blob,
diff --git a/app/client/pix2pix/index.js b/app/client/pix2pix/index.js
index 9d41fbc..282868f 100644
--- a/app/client/pix2pix/index.js
+++ b/app/client/pix2pix/index.js
@@ -1,252 +1,5 @@
-import { h, Component } from 'preact'
-import { bindActionCreators } from 'redux'
-import { connect } from 'react-redux'
+import Pix2PixLive from './live.component'
-import Player from '../common/player.component'
-import ParamGroup from '../common/paramGroup.component'
-import Slider from '../common/slider.component'
-import Select from '../common/select.component'
-import Button from '../common/button.component'
-
-import { startRecording, stopRecording, saveFrame } from '../live/player'
-
-import * as liveActions from '../live/actions'
-
-class LivePix2Pix extends Component {
- constructor(props){
- super()
- props.actions.get_params()
- props.actions.list_checkpoints()
- props.actions.list_sequences()
- this.changeCheckpoint = this.changeCheckpoint.bind(this)
- this.changeEpoch = this.changeEpoch.bind(this)
- this.changeSequence = this.changeSequence.bind(this)
- this.seek = this.seek.bind(this)
- this.togglePlaying = this.togglePlaying.bind(this)
- this.toggleRecording = this.toggleRecording.bind(this)
- }
- componentWillUpdate(nextProps) {
- if (nextProps.opt.checkpoint_name && nextProps.opt.checkpoint_name !== this.props.opt.checkpoint_name) {
- this.props.actions.list_epochs(nextProps.opt.checkpoint_name)
- }
- }
- changeCheckpoint(checkpoint_name){
- this.props.actions.load_epoch(checkpoint_name, 'latest')
- }
- changeEpoch(epoch_name){
- this.props.actions.load_epoch(this.props.opt.checkpoint_name, epoch_name)
- }
- changeSequence(sequence){
- console.log('got sequence', sequence)
- this.props.actions.load_sequence(sequence)
- }
- seek(percentage){
- const frame = Math.floor(percentage * (parseInt(this.props.frame.sequence_len) || 1) + 1)
- this.props.actions.seek(frame)
- }
- togglePlaying(){
- if (this.props.opt.processing) {
- this.props.actions.pause()
- } else {
- this.props.actions.play()
- }
- }
- toggleRecording(){
- if (this.props.opt.recording){
- stopRecording()
- this.props.actions.pause()
- } else {
- startRecording()
- }
- }
- render(){
- return (
- <div className='app'>
- <Player width={424} height={256} />
- <div className='params'>
- <div className='column'>
- <ParamGroup
- title='Playback'
- noToggle
- >
- <Select
- name='send_image'
- title='view mode'
- options={['a','b','sequence','recursive']}
- />
- <Select
- name='sequence_name'
- title='sequence'
- options={this.props.sequences}
- onChange={this.changeSequence}
- />
- <Select
- name='checkpoint_name'
- title='checkpoint'
- options={this.props.checkpoints}
- onChange={this.changeCheckpoint}
- />
- <Select
- name='epoch'
- title='epoch'
- options={this.props.epochs}
- onChange={this.changeEpoch}
- />
- <Slider
- name='position'
- min={0.0} max={1.0} type='float'
- value={(this.props.frame.sequence_i || 0) / (this.props.frame.sequence_len || 1)}
- onChange={this.seek}
- />
- <Button
- title={'Processing: ' + (this.props.opt.processing ? 'yes' : 'no')}
- onClick={this.togglePlaying}
- >
- {this.props.opt.processing ? 'Pause' : 'Restart'}
- </Button>
- <Button
- title={
- this.props.opt.savingVideo
- ? 'Saving video...'
- : this.props.opt.recording
- ? 'Recording (' + timeInSeconds(this.props.opt.recordFrames) +')'
- : 'Record video'
- }
- onClick={this.toggleRecording}
- >
- {this.props.opt.savingVideo ? 'Saving' : this.props.opt.recording ? 'Recording' : 'Record'}
- </Button>
- <Button
- title={'Save frame'}
- onClick={saveFrame}
- >
- Save
- </Button>
- </ParamGroup>
- </div>
- <div className='column'>
- <ParamGroup
- title='Transition'
- name='transition'
- >
- <Slider
- name='transition_period'
- min={10} max={5000} type='int'
- />
- <Slider
- name='transition_min'
- min={0.001} max={0.2} type='float'
- />
- <Slider
- name='transition_max'
- min={0.1} max={1.0} type='float'
- />
- </ParamGroup>
-
- <ParamGroup
- title='Recursion'
- name='recursive'
- >
- <Slider
- name='recursive_frac'
- min={0.0} max={0.5} type='float'
- />
- <Slider
- name='recurse_roll'
- min={-64} max={64} type='int'
- />
- <Slider
- name='recurse_roll_axis'
- min={0} max={1} type='int'
- />
- </ParamGroup>
-
- <ParamGroup
- title='Sequence'
- name='sequence'
- >
- <Slider
- name='sequence_frac'
- min={0.0} max={0.5} type='float'
- />
- <Slider
- name='process_frac'
- min={0} max={1} type='float'
- />
- </ParamGroup>
- </div>
- <div className='column'>
- <ParamGroup
- title='Clahe'
- name='clahe'
- >
- <Slider
- name='clip_limit'
- min={1.0} max={4.0} type='float'
- />
- </ParamGroup>
-
- <ParamGroup
- title='Posterize'
- name='posterize'
- >
- <Slider
- name='spatial_window'
- min={2} max={128} type='int'
- />
- <Slider
- name='color_window'
- min={2} max={128} type='int'
- />
- </ParamGroup>
-
- <ParamGroup
- title='Blur'
- name='blur'
- >
- <Slider
- name='blur_radius'
- min={3} max={7} type='odd'
- />
- <Slider
- name='blur_sigma'
- min={0} max={2} type='float'
- />
- </ParamGroup>
-
- <ParamGroup
- title='Canny Edge Detection'
- name='canny'
- >
- <Slider
- name='canny_lo'
- min={10} max={200} type='int'
- />
- <Slider
- name='canny_hi'
- min={10} max={200} type='int'
- />
- </ParamGroup>
-
- </div>
- </div>
- </div>
- )
- }
-}
-function timeInSeconds(n){
- return (n / 10).toFixed(1) + ' s.'
-}
-const mapStateToProps = state => ({
- opt: state.live.opt,
- frame: state.live.frame,
- checkpoints: state.live.checkpoints,
- epochs: state.live.epochs,
- sequences: state.live.sequences,
-})
-
-const mapDispatchToProps = (dispatch, ownProps) => ({
- actions: bindActionCreators(liveActions, dispatch)
-})
-
-export default connect(mapStateToProps, mapDispatchToProps)(LivePix2Pix)
+export default {
+ Live: Pix2PixLive,
+} \ No newline at end of file
diff --git a/app/client/pix2pix/live.component.js b/app/client/pix2pix/live.component.js
new file mode 100644
index 0000000..9d41fbc
--- /dev/null
+++ b/app/client/pix2pix/live.component.js
@@ -0,0 +1,252 @@
+import { h, Component } from 'preact'
+import { bindActionCreators } from 'redux'
+import { connect } from 'react-redux'
+
+import Player from '../common/player.component'
+import ParamGroup from '../common/paramGroup.component'
+import Slider from '../common/slider.component'
+import Select from '../common/select.component'
+import Button from '../common/button.component'
+
+import { startRecording, stopRecording, saveFrame } from '../live/player'
+
+import * as liveActions from '../live/actions'
+
+class LivePix2Pix extends Component {
+ constructor(props){
+ super()
+ props.actions.get_params()
+ props.actions.list_checkpoints()
+ props.actions.list_sequences()
+ this.changeCheckpoint = this.changeCheckpoint.bind(this)
+ this.changeEpoch = this.changeEpoch.bind(this)
+ this.changeSequence = this.changeSequence.bind(this)
+ this.seek = this.seek.bind(this)
+ this.togglePlaying = this.togglePlaying.bind(this)
+ this.toggleRecording = this.toggleRecording.bind(this)
+ }
+ componentWillUpdate(nextProps) {
+ if (nextProps.opt.checkpoint_name && nextProps.opt.checkpoint_name !== this.props.opt.checkpoint_name) {
+ this.props.actions.list_epochs(nextProps.opt.checkpoint_name)
+ }
+ }
+ changeCheckpoint(checkpoint_name){
+ this.props.actions.load_epoch(checkpoint_name, 'latest')
+ }
+ changeEpoch(epoch_name){
+ this.props.actions.load_epoch(this.props.opt.checkpoint_name, epoch_name)
+ }
+ changeSequence(sequence){
+ console.log('got sequence', sequence)
+ this.props.actions.load_sequence(sequence)
+ }
+ seek(percentage){
+ const frame = Math.floor(percentage * (parseInt(this.props.frame.sequence_len) || 1) + 1)
+ this.props.actions.seek(frame)
+ }
+ togglePlaying(){
+ if (this.props.opt.processing) {
+ this.props.actions.pause()
+ } else {
+ this.props.actions.play()
+ }
+ }
+ toggleRecording(){
+ if (this.props.opt.recording){
+ stopRecording()
+ this.props.actions.pause()
+ } else {
+ startRecording()
+ }
+ }
+ render(){
+ return (
+ <div className='app'>
+ <Player width={424} height={256} />
+ <div className='params'>
+ <div className='column'>
+ <ParamGroup
+ title='Playback'
+ noToggle
+ >
+ <Select
+ name='send_image'
+ title='view mode'
+ options={['a','b','sequence','recursive']}
+ />
+ <Select
+ name='sequence_name'
+ title='sequence'
+ options={this.props.sequences}
+ onChange={this.changeSequence}
+ />
+ <Select
+ name='checkpoint_name'
+ title='checkpoint'
+ options={this.props.checkpoints}
+ onChange={this.changeCheckpoint}
+ />
+ <Select
+ name='epoch'
+ title='epoch'
+ options={this.props.epochs}
+ onChange={this.changeEpoch}
+ />
+ <Slider
+ name='position'
+ min={0.0} max={1.0} type='float'
+ value={(this.props.frame.sequence_i || 0) / (this.props.frame.sequence_len || 1)}
+ onChange={this.seek}
+ />
+ <Button
+ title={'Processing: ' + (this.props.opt.processing ? 'yes' : 'no')}
+ onClick={this.togglePlaying}
+ >
+ {this.props.opt.processing ? 'Pause' : 'Restart'}
+ </Button>
+ <Button
+ title={
+ this.props.opt.savingVideo
+ ? 'Saving video...'
+ : this.props.opt.recording
+ ? 'Recording (' + timeInSeconds(this.props.opt.recordFrames) +')'
+ : 'Record video'
+ }
+ onClick={this.toggleRecording}
+ >
+ {this.props.opt.savingVideo ? 'Saving' : this.props.opt.recording ? 'Recording' : 'Record'}
+ </Button>
+ <Button
+ title={'Save frame'}
+ onClick={saveFrame}
+ >
+ Save
+ </Button>
+ </ParamGroup>
+ </div>
+ <div className='column'>
+ <ParamGroup
+ title='Transition'
+ name='transition'
+ >
+ <Slider
+ name='transition_period'
+ min={10} max={5000} type='int'
+ />
+ <Slider
+ name='transition_min'
+ min={0.001} max={0.2} type='float'
+ />
+ <Slider
+ name='transition_max'
+ min={0.1} max={1.0} type='float'
+ />
+ </ParamGroup>
+
+ <ParamGroup
+ title='Recursion'
+ name='recursive'
+ >
+ <Slider
+ name='recursive_frac'
+ min={0.0} max={0.5} type='float'
+ />
+ <Slider
+ name='recurse_roll'
+ min={-64} max={64} type='int'
+ />
+ <Slider
+ name='recurse_roll_axis'
+ min={0} max={1} type='int'
+ />
+ </ParamGroup>
+
+ <ParamGroup
+ title='Sequence'
+ name='sequence'
+ >
+ <Slider
+ name='sequence_frac'
+ min={0.0} max={0.5} type='float'
+ />
+ <Slider
+ name='process_frac'
+ min={0} max={1} type='float'
+ />
+ </ParamGroup>
+ </div>
+ <div className='column'>
+ <ParamGroup
+ title='Clahe'
+ name='clahe'
+ >
+ <Slider
+ name='clip_limit'
+ min={1.0} max={4.0} type='float'
+ />
+ </ParamGroup>
+
+ <ParamGroup
+ title='Posterize'
+ name='posterize'
+ >
+ <Slider
+ name='spatial_window'
+ min={2} max={128} type='int'
+ />
+ <Slider
+ name='color_window'
+ min={2} max={128} type='int'
+ />
+ </ParamGroup>
+
+ <ParamGroup
+ title='Blur'
+ name='blur'
+ >
+ <Slider
+ name='blur_radius'
+ min={3} max={7} type='odd'
+ />
+ <Slider
+ name='blur_sigma'
+ min={0} max={2} type='float'
+ />
+ </ParamGroup>
+
+ <ParamGroup
+ title='Canny Edge Detection'
+ name='canny'
+ >
+ <Slider
+ name='canny_lo'
+ min={10} max={200} type='int'
+ />
+ <Slider
+ name='canny_hi'
+ min={10} max={200} type='int'
+ />
+ </ParamGroup>
+
+ </div>
+ </div>
+ </div>
+ )
+ }
+}
+function timeInSeconds(n){
+ return (n / 10).toFixed(1) + ' s.'
+}
+const mapStateToProps = state => ({
+ opt: state.live.opt,
+ frame: state.live.frame,
+ checkpoints: state.live.checkpoints,
+ epochs: state.live.epochs,
+ sequences: state.live.sequences,
+})
+
+const mapDispatchToProps = (dispatch, ownProps) => ({
+ actions: bindActionCreators(liveActions, dispatch)
+})
+
+export default connect(mapStateToProps, mapDispatchToProps)(LivePix2Pix)
diff --git a/app/client/socket.js b/app/client/socket.js
index ea6f380..3f008ef 100644
--- a/app/client/socket.js
+++ b/app/client/socket.js
@@ -1,4 +1,5 @@
import { store } from './store'
+import types from './types'
import * as player from './live/player'
let socket = io.connect('/client')
@@ -45,6 +46,18 @@ socket.on('res', (data) => {
console.log(data)
})
+socket.on('system_res', (data) => {
+ console.log('system response', data)
+ switch (data.type) {
+ case 'command_output':
+ store.dispatch({
+ type: types.system.command_output,
+ data: data,
+ })
+ break
+ }
+})
+
socket.on('frame', player.onFrame)
socket.on('status', (data) => {
@@ -121,4 +134,11 @@ export function set_param(key, value) {
}
})
}
+export function run_system_command(cmd) {
+ socket.emit('system', {
+ cmd: 'run_system_command',
+ payload: cmd,
+ })
+}
+
export { socket }
diff --git a/app/client/system/system.actions.js b/app/client/system/system.actions.js
new file mode 100644
index 0000000..1732179
--- /dev/null
+++ b/app/client/system/system.actions.js
@@ -0,0 +1,7 @@
+import * as socket from '../socket'
+import types from '../types'
+
+export const run = (cmd) => {
+ socket.run_system_command(cmd)
+ return { type: types.system.running_command, cmd }
+}
diff --git a/app/client/system/system.component.js b/app/client/system/system.component.js
new file mode 100644
index 0000000..0819c2f
--- /dev/null
+++ b/app/client/system/system.component.js
@@ -0,0 +1,68 @@
+import { h, Component } from 'preact'
+import { bindActionCreators } from 'redux'
+import { connect } from 'react-redux'
+
+import Group from '../common/group.component'
+import Slider from '../common/slider.component'
+import Select from '../common/select.component'
+import Button from '../common/button.component'
+
+import * as systemActions from './system.actions'
+
+class System extends Component {
+ constructor(props){
+ super()
+ }
+ render(){
+ const { site, actions } = this.props
+ return (
+ <div className='dashboard'>
+ <div className='heading'>
+ <h2>{site.name} System</h2>
+ </div>
+
+ <div className='column'>
+ <Group title="Diagnostics">
+ <button onClick={() => actions.run('nvidia-smi')}>nvidia-smi</button>
+ <button onClick={() => actions.run('ps')}>ps</button>
+ <button onClick={() => actions.run('w')}>w</button>
+ </Group>
+ {this.renderCommandOutput()}
+ </div>
+ </div>
+ )
+ }
+ renderCommandOutput(){
+ const { cmd } = this.props
+ let output
+ if (cmd.loading) {
+ output = 'Loading: ' + cmd.name
+ }
+ else if (cmd.loaded) {
+ if (cmd.error) {
+ output = 'Error: ' + cmd.name + '\n\n' + JSON.stringify(cmd.error, null, 2)
+ } else {
+ output = cmd.stdout
+ if (cmd.stderr) {
+ output += '\n\n_________________________________\n\n'
+ output += cmd.stderr
+ }
+ }
+ }
+ return (
+ <div>
+ <div className='screen'>{output}</div>
+ </div>
+ )
+ }
+}
+const mapStateToProps = state => ({
+ site: state.system.site,
+ cmd: state.system.cmd,
+})
+
+const mapDispatchToProps = (dispatch, ownProps) => ({
+ actions: bindActionCreators(systemActions, dispatch)
+})
+
+export default connect(mapStateToProps, mapDispatchToProps)(System)
diff --git a/app/client/system/system.reducer.js b/app/client/system/system.reducer.js
index bc19fd1..e581813 100644
--- a/app/client/system/system.reducer.js
+++ b/app/client/system/system.reducer.js
@@ -1,3 +1,4 @@
+import types from '../types'
import moment from 'moment'
let FileSaver = require('file-saver')
@@ -8,6 +9,15 @@ const systemInitialState = {
site: {
name: 'Lens Cortex',
},
+ cmd: {
+ loading: false,
+ loaded: false,
+ name: null,
+ error: null,
+ stdout: null,
+ stderr: null,
+ },
+
currentTask: {
id: 1072,
activity: 'train',
@@ -29,6 +39,9 @@ const systemInitialState = {
{
url: 'https://s3.amazonaws.com/i.asdf.us/bucky/data/4282/woodscaled_4_true_20180521_2150.png',
},
+ {
+ url: 'https://s3.amazonaws.com/i.asdf.us/bucky/data/4282/woodscaled_4_true_20180521_2146%20(1).png',
+ },
],
tasks: [
{
@@ -98,6 +111,30 @@ const systemInitialState = {
const systemReducer = (state = systemInitialState, action) => {
switch(action.type) {
+ case types.system.running_command:
+ return {
+ ...state,
+ cmd: {
+ loading: true,
+ loaded: false,
+ name: action.cmd,
+ error: null,
+ stdout: null,
+ stderr: null,
+ }
+ }
+ case types.system.command_output:
+ return {
+ ...state,
+ cmd: {
+ loading: false,
+ loaded: true,
+ name: action.data.cmd,
+ error: action.data.error,
+ stdout: action.data.stdout,
+ stderr: action.data.stderr,
+ }
+ }
default:
return state
}
diff --git a/app/client/types.js b/app/client/types.js
index 782a225..fe22465 100644
--- a/app/client/types.js
+++ b/app/client/types.js
@@ -1,4 +1,8 @@
export default {
+ system: {
+ running_command: 'SYSTEM_RUNNING_COMMAND',
+ command_output: 'SYSTEM_COMMAND_OUTPUT',
+ },
socket: {
load_params: 'LOAD_PARAMS',
list_sequences: 'LIST_SEQUENCES',
diff --git a/app/relay/index.js b/app/relay/index.js
index d43f221..2f93644 100644
--- a/app/relay/index.js
+++ b/app/relay/index.js
@@ -9,10 +9,7 @@ let remote = io.connect(process.env.SOCKETIO_REMOTE)
remote.on('cmd', (data) => {
console.log('cmd data', data)
- if (! data.cmd) {
- console.log('malformed param...?')
- return
- }
+ if (! data.cmd) return console.log('malformed param...?')
console.log('got', data.cmd)
switch (data.cmd) {
case 'set_param':
@@ -43,6 +40,24 @@ remote.on('cmd', (data) => {
}
})
+remote.on('system', (data) => {
+ console.log('system:', data.cmd)
+ switch(data.cmd) {
+ case 'run_system_command':
+ runner.run_system_command(data.payload, (error, stdout, stderr) => {
+ remote.emit('system_res', {
+ type: 'command_output',
+ cmd: data.payload,
+ error, stdout, stderr
+ })
+ })
+ break
+ default:
+ remote.emit('system_res', { error: 'unknown system command' })
+ break
+ }
+})
+
let rpc = new zerorpc.Client()
rpc.connect('tcp://127.0.0.1:' + process.env.RPC_PORT)
rpc.on('error', function(error) {
diff --git a/app/relay/interpreters.js b/app/relay/interpreters.js
index 1adb95e..c276f94 100644
--- a/app/relay/interpreters.js
+++ b/app/relay/interpreters.js
@@ -1,4 +1,16 @@
export default {
+ bash: {
+ cmd: process.env.BASH_BIN || '/bin/bash',
+ gpu: false,
+ },
+ perl: {
+ cmd: process.env.PERL_BIN || '/usr/bin/perl',
+ gpu: false,
+ },
+ python: {
+ cmd: process.env.PYTHON_BIN,
+ gpu: false,
+ },
pytorch: {
cmd: process.env.PYTORCH_BIN,
gpu: true,
@@ -7,16 +19,4 @@ export default {
cmd: process.env.TENSORFLOW_BIN,
gpu: true,
},
- python: {
- cmd: process.env.PYTHON_BIN,
- gpu: false,
- },
- bash: {
- cmd: process.env.BASH_BIN || '/bin/bash',
- gpu: false,
- }
- perl: {
- cmd: process.env.PERL_BIN || '/usr/bin/perl',
- gpu: false,
- }
} \ No newline at end of file
diff --git a/app/relay/runner.js b/app/relay/runner.js
index caa2ded..715be7b 100644
--- a/app/relay/runner.js
+++ b/app/relay/runner.js
@@ -1,7 +1,7 @@
// monitors which process is currently running
// kills it if need be.... murder
-import { spawn } from 'child_process'
+import { execFile, spawn } from 'child_process'
import interpreters from './interpreters'
import modules from './modules'
import { kill } from 'tree-kill'
@@ -43,6 +43,21 @@ export function build_params(module, task) {
}
}
+export function run_system_command(cmd, cb) {
+ console.log('running system command:', cmd)
+ switch(cmd) {
+ case 'nvidia-smi':
+ case 'ps':
+ case 'uptime':
+ case 'w':
+ execFile(cmd, cb)
+ break
+ default:
+ cb({ error: 'no such command' })
+ break
+ }
+}
+
export function run_task(module_name, task){
const module = modules['module_name']
if (! module) throw new Error("No such module")
@@ -52,9 +67,16 @@ export function run_task(module_name, task){
const subprocess = spawn(activity.interpreter, params)
if (activity.gpu) {
state.current_gpu_task = subprocess
- } else {
+ }
+ else {
state.current_cpu_task = subprocess
}
+ subprocess.stdout.on('data', data => {
+ console.log('stdout', subprocess.pid, data)
+ })
+ subprocess.stderr.on('data', data => {
+ console.log('stderr', subprocess.pid, data)
+ })
subprocess.on('error', (err) => {
console.log('process error', subprocess.pid, err)
})
diff --git a/app/server/index.js b/app/server/index.js
index 3104a98..c3b0763 100644
--- a/app/server/index.js
+++ b/app/server/index.js
@@ -9,8 +9,9 @@ app.use(express.static('public', { extensions: ['html'] }))
function serve_index(req, res) { res.sendFile(path.join(__dirname, '../../public', 'index.html')) }
app.get('/dashboard/', serve_index)
-app.get('/checkpoint/', serve_index)
-app.get('/dataset/', serve_index)
+app.get('/system/', serve_index)
+app.get('/checkpoints/', serve_index)
+app.get('/datasets/', serve_index)
app.get('/live/', serve_index)
app.get('/', serve_index)
// app.get('/images', site.images)
@@ -49,6 +50,11 @@ function bind_relay(socket) {
client.emit('status', data)
})
+ socket.on('system_res', data => {
+ console.log('System responded', data.cmd)
+ client.emit('system_res', data)
+ })
+
socket.on('frame', (data) => {
client.volatile.emit('frame', data)
})
@@ -64,6 +70,12 @@ function bind_client(socket){
console.log('Client sent command', data)
relay.emit('cmd', data)
})
+
+ socket.on('system', data => {
+ console.log('Client sent system command', data)
+ relay.emit('system', data)
+ })
+
socket.on('disconnect', () => {
console.log('Client disconnected')
})