Newer
Older
// 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')
const Programs = require('./programs.js')
SERVER AND WS SETUP --------------------------------------------------
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)
})
app.get('/ui/:file', (req, res) => {
console.log('client req ui', req.params.file)
res.sendFile(__dirname + '/client/ui/' + req.params.file)
})
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)
})
})
}
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)
})
/*
HOOKUP REF TO TL ------------------------------------------------------
*/
function assignProgram(prgm) {
program = prgm
}
/*
RECV / SEND PORTALS ---------------------------------------------------
*/
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
case 'get current program':
uiRequestCurrentProgram()
break
case 'get module menu':
uiRequestModuleMenu()
break
case 'get program menu':
uiRequestProgramMenu()
break
case 'save program':
uiRequestSaveProgram(data)
break
case 'put position change':
uiRequestMdlPositionChange(data)
break
default:
console.log('ERR server recv with non recognized type', recv)
break
}
}
function socketSend(type, data) {
if (sckt != null && sckt.readyState === 1) {
var msg = {
type: type,
data: data
}
//console.log('SEND', msg)
sckt.send(JSON.stringify(msg))
console.log('on socketSend, ws not ready')
/*
HEAP -> UI HANDLES ---------------------------------------------------
*/
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 ...
function uiRequestModuleMenu() {
var availableSourceRep = {}
for (i in dir) {
availableSourceRep[dir[i]] = {}
var subdir = fs.readdirSync('./modules/' + dir[i])
for (j in subdir) {
// find js files
if (subdir[j].slice(-3) === '.js') {
var obj = {}
obj.path = './modules/' + dir[i] + '/' + subdir[j]
availableSourceRep[dir[i]][subdir[j].slice(0, -3)] = obj
}
}
}
socketSend('put module menu', availableSourceRep)
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)
}
/*
UI -> HEAP HANDLES ---------------------------------------------------
*/
// gonna tear it doooown, maybe just kick page afterwards to restart it?
program = null
program = Programs.open(data)
socketSend('restart', '')
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))
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)
if (program.modules[latest].description.isLink && data != './modules/hardware/atkseriallink.js') {
// 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
program.modules[latest].init()
}
socketSend('put module', Reps.makeFromModule(program.modules[keys[keys.length - 1]]))
console.log('UI REQUEST TO REMOVE MODULE', data.id)
Programs.removeModule(program, data.id)
socketSend('restart', '')
function uiRequestStateChange(data) {
console.log('UI REQUEST CHANGE STATE IN MODULE', data)
var mdlState = program.modules[data.id].state
if (mdlState[data.key] != null) {
mdlState[data.key] = data.val
mdlState.emitUIChange(data.key)
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])
}
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 (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)
function uiRequestUiChange(data){
var mdlUiElem = program.modules[data.id].ui[data.key]
mdlUiElem.onMessage(data.msg)
}
function uiRequestMdlPositionChange(data) {
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
}
/*
EXPORTS --------------------------------------------------------------
*/