Skip to content
Snippets Groups Projects
views.js 8.72 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jake Read's avatar
    Jake Read committed
    // file system to load / look at our available modules / edit them 
    const fs = require('fs')
    
    // express serves files, http makes the connection
    const app = require('express')()
    const http = require('http').Server(app)
    
    // websocket, to share program representations with the client (and back)
    const WebSocket = require('ws')
    
    
    Jake Read's avatar
    Jake Read committed
    const Reps = require('./reps.js')
    
    const Programs = require('./programs.js')
    
    Jake Read's avatar
    Jake Read committed
    SERVER AND WS SETUP --------------------------------------------------
    
    Jake Read's avatar
    Jake Read committed
    var program = null
    
    Jake Read's avatar
    Jake Read committed
    var sckt = null
    
    Jake Read's avatar
    Jake Read committed
    var verbose = false 
    
    Jake Read's avatar
    Jake Read committed
    
    function startHttp() {
        // serving this handful of static files
        app.get('/', (req, res) => {
            console.log('client req /')
            res.sendFile(__dirname + '/client/index.html')
        })
    
        app.get('/:file', (req, res) => {
            console.log('client req', req.params.file)
            res.sendFile(__dirname + '/client/' + req.params.file)
        })
    
    
    Jake Read's avatar
    Jake Read committed
        app.get('/ui/:file', (req, res) => {
            console.log('client req ui', req.params.file)
            res.sendFile(__dirname + '/client/ui/' + req.params.file)
        })
    
    
    Jake Read's avatar
    Jake Read committed
        app.get('/ui/libs/:file', (req, res) => {
            console.log('client req ui lib', req.params.file)
            res.sendFile(__dirname + '/client/ui/libs/' + req.params.file)
        })
    
    
    Jake Read's avatar
    Jake Read committed
        // through this window
        http.listen(8080, () => {
    
    Jake Read's avatar
    Jake Read committed
            console.log('RNDMC is listening on localhost:8080')
    
    Jake Read's avatar
    Jake Read committed
        })
    }
    
    
    function startWs() {
        // and listening for requests here
        const wss = new WebSocket.Server({ port: 8081 })
    
        wss.on('connection', (ws) => {
            sckt = ws
            // say hello
            socketSend('console', 'hello client')
            // send current config as list of all modules
            console.log('socket open on 8081')
            ws.on('message', (evt) => {
                socketRecv(evt)
            })
    
    Jake Read's avatar
    Jake Read committed
        })
    
    Jake Read's avatar
    Jake Read committed
    }
    
    
    Jake Read's avatar
    Jake Read committed
    /*
    
    HOOKUP REF TO TL ------------------------------------------------------
    
    */
    
    function assignProgram(prgm) {
        program = prgm
    }
    
    /*
    
    RECV / SEND PORTALS ---------------------------------------------------
    
    */
    
    
    Jake Read's avatar
    Jake Read committed
    function socketRecv(evt) {
        var recv = JSON.parse(evt)
        var type = recv.type
        var data = recv.data
        //console.log('RECV', recv)
        // bang thru
        switch (type) {
            case 'console':
                console.log('RECV CONSOLE:', data)
                break
    
    Jake Read's avatar
    Jake Read committed
            case 'get current program':
                uiRequestCurrentProgram()
                break
            case 'get module menu':
                uiRequestModuleMenu()
                break
    
            case 'get program menu':
                uiRequestProgramMenu()
                break
    
    Jake Read's avatar
    Jake Read committed
            case 'load program':
    
                uiRequestLoadProgram(data)
    
    Jake Read's avatar
    Jake Read committed
                break
    
            case 'save program':
                uiRequestSaveProgram(data)
    
    Jake Read's avatar
    Jake Read committed
            case 'put module':
                uiRequestNewModule(data)
    
    Jake Read's avatar
    Jake Read committed
                break
    
            case 'remove module':
    
    Jake Read's avatar
    Jake Read committed
                uiRequestRemoveModule(data)
                break
    
            case 'put state change':
    
    Jake Read's avatar
    Jake Read committed
                uiRequestStateChange(data)
    
    Jake Read's avatar
    Jake Read committed
                break
    
            case 'put link change':
    
    Jake Read's avatar
    Jake Read committed
                uiRequestLinkChange(data)
    
    Jake Read's avatar
    Jake Read committed
                // id:output > id:input
                break
    
            case 'put ui change':
    
    Jake Read's avatar
    Jake Read committed
                uiRequestUiChange(data)
    
                break 
            case 'put position change':
                uiRequestMdlPositionChange(data)
    
    Jake Read's avatar
    Jake Read committed
                break
            default:
                console.log('ERR server recv with non recognized type', recv)
                break
        }
    }
    
    function socketSend(type, data) {
    
        if (sckt != null && sckt.readyState === 1) {
    
    Jake Read's avatar
    Jake Read committed
            var msg = {
                type: type,
                data: data
            }
            //console.log('SEND', msg)
            sckt.send(JSON.stringify(msg))
    
        } else {
    
            console.log('on socketSend, ws not ready')
    
    Jake Read's avatar
    Jake Read committed
        }
    }
    
    
    Jake Read's avatar
    Jake Read committed
    /*
    
    HEAP -> UI HANDLES ---------------------------------------------------
    
    */
    
    Jake Read's avatar
    Jake Read committed
    
    // runs when browser first loads
    
    Jake Read's avatar
    Jake Read committed
    function uiRequestCurrentProgram() {
    
    Jake Read's avatar
    Jake Read committed
        // make reps from program and send the list 
    
    Jake Read's avatar
    Jake Read committed
        console.log('SEND PROGRAMS TO UI')
        var prgRep = {
            description: {
                name: program.description.name,
                id: program.description.id,
                path: program.description.path
            },
            modules: {}
        }
        for (mdlName in program.modules) {
            var mdlRep = Reps.makeFromModule(program.modules[mdlName])
            prgRep.modules[mdlName] = mdlRep
        }
        socketSend('put program', prgRep)
    }
    
    
    
    // TODO: proper heirarchy, with both of these ... 
    
    
    Jake Read's avatar
    Jake Read committed
    function uiRequestModuleMenu() {
        var availableSourceRep = {}
    
    Jake Read's avatar
    Jake Read committed
        var dir = fs.readdirSync('./modules')
    
    Jake Read's avatar
    Jake Read committed
        for (i in dir) {
            availableSourceRep[dir[i]] = {}
    
    Jake Read's avatar
    Jake Read committed
            var subdir = fs.readdirSync('./modules/' + dir[i])
    
    Jake Read's avatar
    Jake Read committed
            for (j in subdir) {
                // find js files
                if (subdir[j].slice(-3) === '.js') {
                    var obj = {}
    
    Jake Read's avatar
    Jake Read committed
                    obj.path = './modules/' + dir[i] + '/' + subdir[j]
    
    Jake Read's avatar
    Jake Read committed
                    availableSourceRep[dir[i]][subdir[j].slice(0, -3)] = obj
                }
            }
        }
        socketSend('put module menu', availableSourceRep)
    
    Jake Read's avatar
    Jake Read committed
    }
    
    
    function uiRequestProgramMenu() {
        var availableProgramRep = {}
        var paths = fs.readdirSync('./programs')
        for (i in paths) {
            if (paths[i].slice(-5) === '.json') {
                var name = paths[i].slice(0, -5)
                var path = './programs/' + paths[i]
                availableProgramRep[paths[i]] = {
                    name: name,
                    path: path
                }
            }
        }
        socketSend('put program menu', availableProgramRep)
    }
    
    
    Jake Read's avatar
    Jake Read committed
    /*
    
    UI -> HEAP HANDLES ---------------------------------------------------
    
    */
    
    
    function uiRequestLoadProgram(data) {
    
    Jake Read's avatar
    Jake Read committed
        console.log('UI REQUEST TO OPEN NEW PROGRAM', data)
    
        // gonna tear it doooown, maybe just kick page afterwards to restart it?
        program = null
        program = Programs.open(data)
    
        socketSend('restart', '')
    
    Jake Read's avatar
    Jake Read committed
    }
    
    Jake Read's avatar
    Jake Read committed
    
    
    function uiRequestSaveProgram(data) {
    
        console.log('UI REQUEST TO SAVE PROGRAM', data)
        // is data a path? add .json ? 
    
        if (data) {
            if (!data.includes('.json')) {
                data = data + '.json'
            }
            path = 'programs/' + data
            Programs.save(program, path)
            socketSend('console', ('saved program at' + path))
    
    Jake Read's avatar
    Jake Read committed
    function uiRequestNewModule(data) {
        console.log('UI REQUEST ADD MODULE TO PROGRAM', data)
    
        Programs.loadModuleFromSource(program, data)
        // bit of a mess to pick out the last entered module 
        var keys = Object.keys(program.modules)
    
    Jake Read's avatar
    Jake Read committed
        var latest = keys[keys.length - 1]
    
    Jake Read's avatar
    Jake Read committed
        if (program.modules[latest].description.isLink && data != './modules/hardware/atkseriallink.js') {
    
    Jake Read's avatar
    Jake Read committed
            // we just added hardware, so added a link, so we've added two 
            // just burn it down 
            socketSend('restart', '')
        }
    
        // TODO: questionable init - here and in loadProgram, should be better handled across board 
    
    Jake Read's avatar
    Jake Read committed
        if (program.modules[latest].init != null) {
    
            program.modules[latest].init()
        }
    
        socketSend('put module', Reps.makeFromModule(program.modules[keys[keys.length - 1]]))
    
    Jake Read's avatar
    Jake Read committed
    function uiRequestRemoveModule(data) {
    
        console.log('UI REQUEST TO REMOVE MODULE', data.id)
    
    Jake Read's avatar
    Jake Read committed
        Programs.removeModule(program, data.id)
        socketSend('restart', '')
    
    Jake Read's avatar
    Jake Read committed
    function uiRequestStateChange(data) {
        console.log('UI REQUEST CHANGE STATE IN MODULE', data)
    
    
        var mdlState = program.modules[data.id].state
    
    
    Jake Read's avatar
    Jake Read committed
        if (mdlState[data.key] != null) {
            mdlState[data.key] = data.val
            mdlState.emitUIChange(data.key)
    
        } else {
    
    Jake Read's avatar
    Jake Read committed
            console.log("ERR no state key,", data.key, "found here", data)
            console.log("THE KEY", data.key)
            console.log("THE MDL", mdlState)
            console.log("THE STATE", mdlState[data.key])
    
    Jake Read's avatar
    Jake Read committed
    }
    
    function uiRequestLinkChange(data) {
        console.log('UI REQUEST ADD EVENT LINK', data)
    
        var fromId = data.from.id
        var outputName = data.from.output
        var toId = data.to.id
        var inputName = data.to.input
    
        var fromMdl = program.modules[fromId]
        var toMdl = program.modules[toId]
    
    
        // if it's already attached, we rm
    
    Jake Read's avatar
    Jake Read committed
        if (fromMdl.outputs[outputName].isLinked(toMdl.inputs[inputName])) {
    
            fromMdl.outputs[outputName].remove(toMdl.inputs[inputName])
        } else {
            fromMdl.outputs[outputName].attach(toMdl.inputs[inputName])
        }
    
        var nRep = Reps.makeFromModule(fromMdl)
    
        socketSend('put module change', nRep)
    
    function uiRequestUiChange(data){
    
    Jake Read's avatar
    Jake Read committed
        if(verbose) console.log('UI PUSH UI DATA DOWN', data)
    
        var mdlUiElem = program.modules[data.id].ui[data.key]
        mdlUiElem.onMessage(data.msg)
    }
    
    function uiRequestMdlPositionChange(data) {
    
    Jake Read's avatar
    Jake Read committed
        if(verbose) console.log('UI REQUEST ADD / CHANGE UI INFO TO MODULE', data)
    
        var mod = program.modules[data.description.id]
        mod.description.position = data.description.position
    
    Jake Read's avatar
    Jake Read committed
    }
    
    /*
    
    EXPORTS --------------------------------------------------------------
    
    */
    
    Jake Read's avatar
    Jake Read committed
    module.exports = {
        startHttp: startHttp,
        startWs: startWs,
        uiSocket: {
            send: socketSend
        },
        assignProgram: assignProgram
    }