diff options
Diffstat (limited to 'app')
25 files changed, 375 insertions, 91 deletions
diff --git a/app/client/auth/auth.gate.js b/app/client/auth/auth.gate.js index 6df1238..076ec54 100644 --- a/app/client/auth/auth.gate.js +++ b/app/client/auth/auth.gate.js @@ -46,11 +46,11 @@ class AuthRouter extends Component { class AuthGate extends Component { render(){ - if (!this.props.auth.initialized) { + if (true && !this.props.auth.initialized) { console.log('loading auth') return <div className='loading'>Loading</div> } - if (this.props.auth.isAuthenticated) { + if (true || this.props.auth.isAuthenticated) { console.log('authenticated...') if (this.props.auth.returnTo) { let { returnTo } = this.props.auth diff --git a/app/client/common/browser.component.js b/app/client/common/browser.component.js new file mode 100644 index 0000000..50b31cf --- /dev/null +++ b/app/client/common/browser.component.js @@ -0,0 +1,89 @@ +import { h, Component } from 'preact' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' +import { Route, Link } from 'react-router-dom' + +import { Loading, FileList, FileViewer } from '../common' + +import actions from '../actions' + +class Browser extends Component { + state = { + dir: '/', + files: [], + loading: true + } + componentDidMount() { + this.fetch(this.state.dir) + } + handlePick(file) { + console.log(file) + if (file.dir) { + this.fetch([this.state.dir, file.name].join('/').replace('//','/')) + } else { + this.fetchFile([this.state.dir, file.name].join('/').replace('//','/')) + } + } + fetch(dir) { + console.log('fetch', dir) + const { tool: module } = this.props.app + this.setState({ dir, file: null, loading: true }) + actions.socket.list_directory({ module, dir }).then(files => { + console.log(files) + this.setState({ dir, files, loading: false }) + }) + } + fetchFile(fn) { + console.log('fetch file', fn) + const { tool: module } = this.props.app + this.setState({ file: null, loadingFile: true }) + actions.socket.read_file({ module, fn }).then(file => { + console.log(file) + this.setState({ file, loadingFile: false }) + }) + } + render() { + const { app } = this.props + const { + loading, dir, files, + loadingFile, file, + } = this.state + console.log(this.props, this.state) + return ( + <div className='app browser'> + <h1>{dir}{dir[dir.length-1] !== '/' && '/'}</h1> + {app.tool}<br/> + {loading && <Loading />} + <FileList + files={files} + groupDirectories + parentDirectory={dir !== '/'} + orderBy='name asc' + fields={'name datetime size'} + onClick={(file, e) => { + e.preventDefault() + e.stopPropagation() + console.log('picked a result', file) + this.handlePick(file) + }} + onClickParent={e => { + console.log('navigate up') + this.fetch(this.state.dir.split('/').slice(0, -1).join('/') || '/') + }} + /> + {loadingFile && <Loading />} + {file && <FileViewer file={file} />} + </div> + ) + } +} + +const mapStateToProps = state => ({ + app: state.system.app, +}) + +const mapDispatchToProps = (dispatch, ownProps) => ({ + actions: bindActionCreators({}, dispatch), +}) + +export default connect(mapStateToProps, mapDispatchToProps)(Browser) diff --git a/app/client/common/currentTask.component.js b/app/client/common/currentTask.component.js index 3c71a88..ef976bc 100644 --- a/app/client/common/currentTask.component.js +++ b/app/client/common/currentTask.component.js @@ -31,7 +31,7 @@ function CurrentTask ({ cpu, gpu, processor }) { ? <span>(currently #{epoch})</span> : ""} <br/><br/> - <div class='quiet'>{last_message}</div> + <div className='quiet'>{last_message}</div> </div> ) } diff --git a/app/client/common/fileList.component.js b/app/client/common/fileList.component.js index b71faae..f932274 100644 --- a/app/client/common/fileList.component.js +++ b/app/client/common/fileList.component.js @@ -11,18 +11,24 @@ export const FileList = props => { const { files, fields, sort, title, - linkFiles, onClick, onDelete, + linkFiles, + onClick, onClickParent, onDelete, + groupDirectories, parentDirectory, orderBy='name asc', className='', fileListClassName='filelist', rowClassName='row file' } = props const { mapFn, sortFn } = util.sort.orderByFn(orderBy) - const fileList = (files || []) + let sortedFiles = (files || []) .filter(f => !!f) .map(mapFn) .sort(sortFn) - .map(pair => { + if (groupDirectories) { + const groupedFiles = sortedFiles.reduce((a,b) => { a[b[1].dir].push(b); return a }, { true: [], false: [] }) + sortedFiles = groupedFiles.true.concat(groupedFiles.false) + } + const fileList = sortedFiles.map(pair => { return <FileRow file={pair[1]} fields={fieldSet(fields)} @@ -35,8 +41,8 @@ export const FileList = props => { if (!fileList || !fileList.length) { return ( <div className={'rows ' + className}> - <div class='row heading'> - <h4 class='noFiles'>No files</h4> + <div className='row heading'> + <h4 className='noFiles'>No files</h4> </div> </div> ) @@ -45,12 +51,21 @@ export const FileList = props => { return ( <div className={'rows ' + className}> {title && - <div class='row heading'> + <div className='row heading'> <h3>{title}</h3>} </div> } <div className={'rows ' + fileListClassName}> + {parentDirectory && + <div className={rowClassName + ' parent'}> + <div className="filename" title="Parent Directory"> + <span className='link' onClick={(e) => onClickParent && onClickParent(e)}> + <i>Parent Directory</i> + </span> + </div> + </div> + } {fileList} </div> </div> @@ -83,14 +98,14 @@ export const FileRow = props => { } return ( - <div class={className} key={key}> + <div className={className} key={key}> {fields.has('name') && <div className="filename" title={file.name || file.url}> {file.persisted === false ? <span className='unpersisted'>{name}</span> : (linkFiles && file.url) ? <a target='_blank' onClick={(e) => { if (!(e.metaKey || e.ctrlKey || e.altKey) && onClick) { e.preventDefault(); onClick && onClick(file, e) }}} href={file.url}>{name}</a> - : <span class='link' onClick={(e) => onClick && onClick(file, e)}>{name}</span> + : <span className='link' onClick={(e) => onClick && onClick(file, e)}>{name}</span> } </div> } diff --git a/app/client/common/fileViewer.component.js b/app/client/common/fileViewer.component.js new file mode 100644 index 0000000..bc71f20 --- /dev/null +++ b/app/client/common/fileViewer.component.js @@ -0,0 +1,57 @@ +import { h, Component } from 'preact' + +const image_types = { + 'jpg': 'image/jpeg', + 'jpeg': 'image/jpeg', + 'png': 'image/png', + 'gif': 'image/gif', +} + +const audio_types = { + 'wav': 'audio/wav', + 'mp3': 'audio/mp3', + 'flac': 'audio/flac', + 'aiff': 'audio/aiff', +} + +const video_types = { + 'mp4': 'video/mp4', +} + +export default function FileViewer({ file }) { + const { + error, + name, path, + date, size, + buf, + } = file + if (error) { + return <div className='fileViewer'>{error}</div> + } + if (!buf) { + return <div className='fileViewer'>File empty</div> + } + const ext = name.split('.').slice(-1)[0].toLowerCase() + let tag; + if (ext in image_types) { + tag = <img src={getURLFor(buf, image_types[ext])} /> + } else if (ext in audio_types) { + tag = <audio src={getURLFor(buf, audio_types[ext])} controls autoplay /> + } else if (ext in video_types) { + tag = <video src={getURLFor(buf, audio_types[ext])} controls autoplay /> + } else { + tag = <div className='text'>{ab2str(buf)}</div> + } + return ( + <div className='fileViewer'>{tag}</div> + ) +} + +const getURLFor = (buf, type) => { + const arrayBufferView = new Uint8Array(buf) + const blob = new Blob([arrayBufferView], { type }) + const urlCreator = window.URL || window.webkitURL + return urlCreator.createObjectURL(blob) +} + +const ab2str = buf => String.fromCharCode.apply(null, new Uint8Array(buf)) diff --git a/app/client/common/folderList.component.js b/app/client/common/folderList.component.js index a6c6ae5..91d0bff 100644 --- a/app/client/common/folderList.component.js +++ b/app/client/common/folderList.component.js @@ -12,7 +12,7 @@ export default function FolderList ({ db, path, emptyText, activity }) { if (! db) return null if (db.loading || !db.data) { return ( - <div class='col folderList'> + <div className='col folderList'> <Loading progress={db.progress} /> </div> ) @@ -23,7 +23,7 @@ export default function FolderList ({ db, path, emptyText, activity }) { } if (! folderList.length && emptyText) { return ( - <div class='col folderList'> + <div className='col folderList'> {emptyText} </div> ) @@ -41,7 +41,7 @@ export default function FolderList ({ db, path, emptyText, activity }) { }) return ( - <div class='col folderList'> + <div className='col folderList'> <Group title='Projects'> {folders} </Group> diff --git a/app/client/common/index.js b/app/client/common/index.js index e6baafc..e120597 100644 --- a/app/client/common/index.js +++ b/app/client/common/index.js @@ -1,11 +1,13 @@ import AudioPlayer from './audioPlayer/audioPlayer.component' import AugmentationGrid from './augmentationGrid.component' +import Browser from './browser.component' import Button from './button.component' import ButtonGrid from './buttonGrid.component' import Checkbox from './checkbox.component' import CurrentTask from './currentTask.component' import { FileList, FileRow } from './fileList.component' import FileUpload from './fileUpload.component' +import FileViewer from './fileViewer.component' import FolderList from './folderList.component' import Gallery from './gallery.component' import Group from './group.component' @@ -26,8 +28,8 @@ import * as Views from './views' export { Views, Loading, Progress, Header, AudioPlayer, - FolderList, FileList, FileRow, FileUpload, - Gallery, Player, + FolderList, FileList, FileRow, FileUpload, FileViewer, + Gallery, Player, Browser, Group, ParamGroup, Param, TextInput, NumberInput, Slider, Select, SelectGroup, Button, Checkbox, diff --git a/app/client/common/slider.component.js b/app/client/common/slider.component.js index 7252ca3..9dba730 100644 --- a/app/client/common/slider.component.js +++ b/app/client/common/slider.component.js @@ -81,7 +81,7 @@ class Slider extends Component { text_value = parseFloat(value).toFixed(2) } return ( - <div class='slider param'> + <div className='slider param'> <label> <span>{title || name.replace(/_/g, ' ')}</span> <input type='text' value={text_value} onBlur={this.handleInput} /> diff --git a/app/client/common/taskList.component.js b/app/client/common/taskList.component.js index c1ed38a..272ff80 100644 --- a/app/client/common/taskList.component.js +++ b/app/client/common/taskList.component.js @@ -56,18 +56,18 @@ class TaskList extends Component { dataset_link = label } return ( - <div class='row'> - <div class='activity'>{task.activity} {task.module}</div> - <div class='dataset'>{dataset_link}</div> + <div className='row'> + <div className='activity'>{task.activity} {task.module}</div> + <div className='dataset'>{dataset_link}</div> <div className={"age " + util.carbon_date(task.updated_at)}>{util.get_age(task.updated_at)}</div> - <div class='options'> - <span class='destroy' onClick={() => this.handleDestroy(task)}>x</span> + <div className='options'> + <span className='destroy' onClick={() => this.handleDestroy(task)}>x</span> </div> </div> ) }) return ( - <div class='tasklist rows'> + <div className='tasklist rows'> {taskList} </div> ) diff --git a/app/client/common/views/new.view.js b/app/client/common/views/new.view.js index a6ab3b1..a417bfc 100644 --- a/app/client/common/views/new.view.js +++ b/app/client/common/views/new.view.js @@ -22,11 +22,11 @@ export default class NewView extends Component { render(){ const { module, history, db, path } = this.props return ( - <div class={'app new-view ' + module.name}> - <div class='heading'> + <div className={'app new-view ' + module.name}> + <div className='heading'> <h1>{module.displayName || module.name}</h1> </div> - <div class='col narrow'> + <div className='col narrow'> <NewDatasetForm module={module} history={history} diff --git a/app/client/dashboard/dashboardHeader.component.js b/app/client/dashboard/dashboardHeader.component.js index 063cd47..45e9914 100644 --- a/app/client/dashboard/dashboardHeader.component.js +++ b/app/client/dashboard/dashboardHeader.component.js @@ -15,7 +15,7 @@ class DashboardHeader extends Component { render() { const { site, runner } = this.props return ( - <div class='dashboardHeader heading'> + <div className='dashboardHeader heading'> <h1>{site.name} cortex</h1> {this.renderStatus("GPU", runner.gpu)} {this.renderStatus("CPU", runner.cpu)} diff --git a/app/client/dataset/dataset.component.js b/app/client/dataset/dataset.component.js index 7df1b9c..af48ef4 100644 --- a/app/client/dataset/dataset.component.js +++ b/app/client/dataset/dataset.component.js @@ -23,19 +23,19 @@ class DatasetComponent extends Component { if (!folder || !folder.name) return fields = fieldSet(fields) return ( - <div class='rows params datasets'> - <div class='row row-heading dataset'> + <div className='rows params datasets'> + <div className='row row-heading dataset'> {fields.has('input') && - <div class='col'>input</div> + <div className='col'>input</div> } {fields.has('status') && - <div class='col'>status</div> + <div className='col'>status</div> } {fields.has('checkpoint') && - <div class='col'>checkpoint</div> + <div className='col'>checkpoint</div> } {fields.has('output') && - <div class='col'>output</div> + <div className='col'>output</div> } </div> {this.renderGroups()} diff --git a/app/client/dataset/dataset.new.js b/app/client/dataset/dataset.new.js index 1b0df86..19f479a 100644 --- a/app/client/dataset/dataset.new.js +++ b/app/client/dataset/dataset.new.js @@ -12,11 +12,11 @@ function NewDatasetForm (props) { if (loading) return <Loading /> console.log(props) return ( - <div class='opaque'> - <div class='heading'> + <div className='opaque'> + <div className='heading'> <h2>Create a new {module.displayName} project</h2> </div> - <div class='params'> + <div className='params'> <TextInput autofocus title={'Name your project'} diff --git a/app/client/dataset/upload.status.js b/app/client/dataset/upload.status.js index 3fce4fa..3437019 100644 --- a/app/client/dataset/upload.status.js +++ b/app/client/dataset/upload.status.js @@ -6,7 +6,7 @@ import Loading from '../common/loading.component' function UploadStatus (props) { return ( - <div class='status'> + <div className='status'> {props.status} </div> ) diff --git a/app/client/index.jsx b/app/client/index.jsx index 0b0ed05..cda528c 100644 --- a/app/client/index.jsx +++ b/app/client/index.jsx @@ -7,7 +7,7 @@ import * as socket from './socket' import util from './util' import Auth from './auth' -import { Header, AudioPlayer } from './common' +import { Header, Browser, AudioPlayer } from './common' import System from './system/system.component' import Dashboard from './dashboard/dashboard.component' import modules from './modules' @@ -33,9 +33,10 @@ const app = ( <Route path='/' children={(props) => <div>{console.log(props.location.pathname)}</div>} /> <Route exact path='/system' component={System} /> <Route exact path='/dashboard' component={Dashboard} /> + <Route exact path='/browse' component={Browser} /> <Route exact path='/logout' component={Auth.Logout} /> - <Route exact path='/login' component={() => { console.log('pziss'); <Redirect to='/' /> }} /> - <Route exact path='/signup' component={() => { console.log('pziss'); <Redirect to='/' /> }} /> + <Route exact path='/login' component={() => { <Redirect to='/' /> }} /> + <Route exact path='/signup' component={() => { <Redirect to='/' /> }} /> {module_list} <Route exact path='/' component={Dashboard} /> <Route path='/' component={Header} /> diff --git a/app/client/modules/morph/views/morph.app.js b/app/client/modules/morph/views/morph.app.js index 153fe2b..bd049c4 100644 --- a/app/client/modules/morph/views/morph.app.js +++ b/app/client/modules/morph/views/morph.app.js @@ -66,8 +66,8 @@ class MorphResults extends Component { <div className='heading row middle'> <h1>Morph</h1> </div> - <div class='rows params renders'> - <div class='column'> + <div className='rows params renders'> + <div className='column'> <Group title="From"> <Select title="Starting sequence" diff --git a/app/client/modules/pix2pix/views/pix2pix.live.js b/app/client/modules/pix2pix/views/pix2pix.live.js index b6765ed..2b59656 100644 --- a/app/client/modules/pix2pix/views/pix2pix.live.js +++ b/app/client/modules/pix2pix/views/pix2pix.live.js @@ -151,7 +151,7 @@ class Pix2PixLive extends Component { > </ParamGroup> - <p class='last_message'>{this.props.last_message}</p> + <p className='last_message'>{this.props.last_message}</p> </ParamGroup> </div> <div className='column'> diff --git a/app/client/modules/pix2pix/views/pix2pix.show.js b/app/client/modules/pix2pix/views/pix2pix.show.js index 02a009e..4f57fac 100644 --- a/app/client/modules/pix2pix/views/pix2pix.show.js +++ b/app/client/modules/pix2pix/views/pix2pix.show.js @@ -41,8 +41,8 @@ class Pix2pixShow extends Component { return ( <div className='app pix2pix'> - <div class='heading'> - <div class='spaced'> + <div className='heading'> + <div className='spaced'> <h1>{folder ? folder.name : <Loading />}</h1> <UploadStatus /> </div> @@ -89,24 +89,24 @@ class Pix2pixShow extends Component { console.log(dataset) return ( <div> - <div class={'actions'}> - <span class='link' onClick={() => remote.train_task(dataset, pix2pix.folder_id, 1)}>train</span> - <span class='link' onClick={() => remote.train_task(dataset, pix2pix.folder_id, 5)}>5x</span> - <span class='link' onClick={() => remote.train_task(dataset, pix2pix.folder_id, 10)}>10x</span> - <span class='link' onClick={() => remote.train_task(dataset, pix2pix.folder_id, 20)}>20x</span> - <span class='link' onClick={() => remote.train_task(dataset, pix2pix.folder_id, 50)}>50x</span> + <div className={'actions'}> + <span className='link' onClick={() => remote.train_task(dataset, pix2pix.folder_id, 1)}>train</span> + <span className='link' onClick={() => remote.train_task(dataset, pix2pix.folder_id, 5)}>5x</span> + <span className='link' onClick={() => remote.train_task(dataset, pix2pix.folder_id, 10)}>10x</span> + <span className='link' onClick={() => remote.train_task(dataset, pix2pix.folder_id, 20)}>20x</span> + <span className='link' onClick={() => remote.train_task(dataset, pix2pix.folder_id, 50)}>50x</span> </div> {dataset.isBuilt - ? <div class='subtext'> + ? <div className='subtext'> {'fetched '} - <span class='link' onClick={() => remote.clear_cache_task(dataset)}>rm</span> + <span className='link' onClick={() => remote.clear_cache_task(dataset)}>rm</span> </div> : isFetching - ? <div class='subtext'> + ? <div className='subtext'> {'fetching'} </div> - : <div class='subtext'> - <span class='link' onClick={() => remote.fetch_task(input.url, input.id, dataset.name)}>fetch</span> + : <div className='subtext'> + <span className='link' onClick={() => remote.fetch_task(input.url, input.id, dataset.name)}>fetch</span> </div> } </div> diff --git a/app/client/modules/pix2pixhd/views/pix2pixhd.train.js b/app/client/modules/pix2pixhd/views/pix2pixhd.train.js index 06caa5a..957b068 100644 --- a/app/client/modules/pix2pixhd/views/pix2pixhd.train.js +++ b/app/client/modules/pix2pixhd/views/pix2pixhd.train.js @@ -114,6 +114,33 @@ class Pix2PixHDTrain extends Component { value={this.state.epoch} /> </Group> + <Group title='Augmentation Grid'> + <AugmentationGrid + checkpoint={this.props.pix2pixhd.checkpoint} + take={[1,2,3,4,5,10,15,20,25,50,75,100,200,300,400,500,1000]} + make={[1,2,3,4,5,10,15,20,25,50,75,100,200,]} + onAugment={(augment_take, augment_make) => { + this.props.remote.augment_task(this.state.checkpoint_name, { + ...this.state, + augment_take, + augment_make, + }) + }} + onTrain={() => { + this.props.remote.train_task(this.state.checkpoint_name, pix2pixhd.folder_id, 1) + setTimeout(() => { // auto-generate epoch demo + this.props.remote.augment_task(this.state.checkpoint_name, { + ...this.state, + augment_take: 10, + augment_make: 150, + no_symlinks: true, + mov: true, + folder_id: this.props.pix2pixhd.data.resultsFolder.id + }) + }, 250) + }} + /> + </Group> <Group title='Augment'> <NumberInput name="augment_take" @@ -151,33 +178,6 @@ class Pix2PixHDTrain extends Component { }} /> </Group> - <Group title='Augmentation Grid'> - <AugmentationGrid - checkpoint={this.props.pix2pixhd.checkpoint} - take={[1,2,3,4,5,10,15,20,25,50,75,100,200,300,400,500,1000]} - make={[1,2,3,4,5,10,15,20,25,50,75,100,200,]} - onAugment={(augment_take, augment_make) => { - this.props.remote.augment_task(this.state.checkpoint_name, { - ...this.state, - augment_take, - augment_make, - }) - }} - onTrain={() => { - this.props.remote.train_task(this.state.checkpoint_name, pix2pixhd.folder_id, 1) - setTimeout(() => { // auto-generate epoch demo - this.props.remote.augment_task(this.state.checkpoint_name, { - ...this.state, - augment_take: 10, - augment_make: 150, - no_symlinks: true, - mov: true, - folder_id: this.props.pix2pixhd.data.resultsFolder.id - }) - }, 250) - }} - /> - </Group> <Group title='Status'> <Button diff --git a/app/client/modules/pix2pixhd/views/sequence.editor.js b/app/client/modules/pix2pixhd/views/sequence.editor.js new file mode 100644 index 0000000..9693805 --- /dev/null +++ b/app/client/modules/pix2pixhd/views/sequence.editor.js @@ -0,0 +1,89 @@ +import { h, Component } from 'preact' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' +import { Route, Link } from 'react-router-dom' + +import { Loading, FileList, FileViewer } from '../../common' + +import actions from '../actions' + +class SequenceEditor extends Component { + state = { + dir: '/', + files: [], + loading: true + } + componentDidMount() { + this.fetch(this.state.dir) + } + handlePick(file) { + console.log(file) + if (file.dir) { + this.fetch([this.state.dir, file.name].join('/').replace('//','/')) + } else { + this.fetchFile([this.state.dir, file.name].join('/').replace('//','/')) + } + } + fetch(dir) { + console.log('fetch', dir) + const { tool: module } = this.props.app + this.setState({ dir, file: null, loading: true }) + actions.socket.list_directory({ module, dir }).then(files => { + console.log(files) + this.setState({ dir, files, loading: false }) + }) + } + fetchFile(fn) { + console.log('fetch file', fn) + const { tool: module } = this.props.app + this.setState({ file: null, loadingFile: true }) + actions.socket.read_file({ module, fn }).then(file => { + console.log(file) + this.setState({ file, loadingFile: false }) + }) + } + render() { + const { app } = this.props + const { + loading, dir, files, + loadingFile, file, + } = this.state + console.log(this.props, this.state) + // return ( + // <div className='app browser'> + // <h1>{dir}{dir[dir.length-1] !== '/' && '/'}</h1> + // {app.tool}<br/> + // {loading && <Loading />} + // <FileList + // files={files} + // groupDirectories + // parentDirectory={dir !== '/'} + // orderBy='name asc' + // fields={'name datetime size'} + // onClick={(file, e) => { + // e.preventDefault() + // e.stopPropagation() + // console.log('picked a result', file) + // this.handlePick(file) + // }} + // onClickParent={e => { + // console.log('navigate up') + // this.fetch(this.state.dir.split('/').slice(0, -1).join('/') || '/') + // }} + // /> + // {loadingFile && <Loading />} + // {file && <FileViewer file={file} />} + // </div> + // ) + } +} + +const mapStateToProps = state => ({ + app: state.system.app, +}) + +const mapDispatchToProps = (dispatch, ownProps) => ({ + actions: bindActionCreators({}, dispatch), +}) + +export default connect(mapStateToProps, mapDispatchToProps)(SequenceEditor) diff --git a/app/client/socket/socket.actions.js b/app/client/socket/socket.actions.js index b80a0fa..31d73cc 100644 --- a/app/client/socket/socket.actions.js +++ b/app/client/socket/socket.actions.js @@ -8,6 +8,7 @@ export const count_directory = opt => syscall_async('count_directory', opt).t export const list_sequences = opt => syscall_async('list_sequences', opt).then(res => res.sequences) export const run_script = opt => syscall_async('run_script', opt) export const upload_file = opt => syscall_async('upload_file', opt) +export const read_file = opt => syscall_async('read_file', opt).then(res => res.file) export const syscall_async = (tag, payload, ttl=10000) => { ttl = payload.ttl || ttl diff --git a/app/client/store.js b/app/client/store.js index 654b22d..2b71e75 100644 --- a/app/client/store.js +++ b/app/client/store.js @@ -7,24 +7,24 @@ import { routerReducer } from 'react-router-redux' // import navReducer from './nav.reducer' import authReducer from './auth/auth.reducer' -import systemReducer from './system/system.reducer' -import dashboardReducer from './dashboard/dashboard.reducer' import liveReducer from './live/live.reducer' -import uploadReducer from './dataset/upload.reducer' import queueReducer from './queue/queue.reducer' +import systemReducer from './system/system.reducer' +import uploadReducer from './dataset/upload.reducer' +import dashboardReducer from './dashboard/dashboard.reducer' import audioPlayerReducer from './common/audioPlayer/audioPlayer.reducer' import { moduleReducer } from './modules/module.reducer' const appReducer = combineReducers({ + router: routerReducer, auth: authReducer, - system: systemReducer, - dashboard: dashboardReducer, live: liveReducer, - upload: uploadReducer, queue: queueReducer, - router: routerReducer, - module: moduleReducer, + system: systemReducer, + upload: uploadReducer, + dashboard: dashboardReducer, audioPlayer: audioPlayerReducer, + module: moduleReducer, }) export const history = createHistory() diff --git a/app/relay/remote.js b/app/relay/remote.js index 1c9875f..a0639a5 100644 --- a/app/relay/remote.js +++ b/app/relay/remote.js @@ -146,6 +146,16 @@ remote.on('system', (data) => { }) }) break + case 'read_file': + runner.read_file(data.payload, (file) => { + remote.emit('system_res', { + type: 'read_file', + query: data.payload, + uuid: data.uuid, + file, + }) + }) + break case 'get_status': remote.emit('system_res', { type: 'relay_status', diff --git a/app/relay/runner.js b/app/relay/runner.js index 44f2554..f1e3497 100644 --- a/app/relay/runner.js +++ b/app/relay/runner.js @@ -11,6 +11,7 @@ import readdir from 'fs-readdir-promise' import * as q from './queue' +const MAX_TRANSFER_SIZE = 1024 * 1024 * 2.5 const idle_state = { status: 'IDLE', task: {} } export const state = { @@ -169,6 +170,24 @@ export function module_dir(opt, dir){ return path.join(module.cwd, dir.replace(/\.\.?\//g, '')) } +export function read_file(opt, cb) { + const fn = module_dir(opt, opt.fn) + if (!fn) return cb([]) + stat_promise(fn).then(stat => { + if (stat.size > MAX_TRANSFER_SIZE) { + return cb({ error: 'file too large'}) + } + fs.readFile(fn, (err, buf) => cb({ + error: err, + name: opt.fn, + path: fn, + date: stat.ctime, + size: stat.size, + buf + })) + }).catch(() => cb({ error: 'error reading file' })) +} + export function list_directory(opt, cb) { const dir = module_dir(opt, opt.dir) if (!dir) return cb([]) diff --git a/app/server/site.js b/app/server/site.js index 717e42b..24f6ff0 100644 --- a/app/server/site.js +++ b/app/server/site.js @@ -133,6 +133,7 @@ function serve_index(req, res) { res.sendFile(path.join(__dirname, '../../public app.get('/:module/:mode/:id/', serve_index) app.get('/:module/:mode/', serve_index) +app.get('/browse/', serve_index) app.get('/system/', serve_index) app.get('/dashboard/', serve_index) app.get('/', serve_index) |
