|
@@ -25,7 +25,6 @@ const HOST = os.hostname()
|
|
|
|
|
|
const state = {
|
|
const state = {
|
|
workers: [],
|
|
workers: [],
|
|
- interfaces: [],
|
|
|
|
ports: [],
|
|
ports: [],
|
|
connections: [],
|
|
connections: [],
|
|
lastScan: {
|
|
lastScan: {
|
|
@@ -103,7 +102,7 @@ const typeDefs = `
|
|
/**
|
|
/**
|
|
* WORKER SECTION
|
|
* WORKER SECTION
|
|
*/
|
|
*/
|
|
-async function findWorkers () {
|
|
|
|
|
|
+async function findWorkers() {
|
|
// 1. Don't check more frequently than once per second.
|
|
// 1. Don't check more frequently than once per second.
|
|
// if (state.lastScan.workers + 1000 > Date.now()) return null
|
|
// if (state.lastScan.workers + 1000 > Date.now()) return null
|
|
// state.lastScan.workers = Date.now()
|
|
// state.lastScan.workers = Date.now()
|
|
@@ -129,7 +128,7 @@ async function findWorkers () {
|
|
const { data, error, pythonError } = await workerProcess.spawn()
|
|
const { data, error, pythonError } = await workerProcess.spawn()
|
|
if (error) throw new Error(error)
|
|
if (error) throw new Error(error)
|
|
if (pythonError) throw new Error(pythonError)
|
|
if (pythonError) throw new Error(pythonError)
|
|
- // c. Save the worker in the state.
|
|
|
|
|
|
+ // d. Save the worker in the state.
|
|
state.workers.push({
|
|
state.workers.push({
|
|
id: md5(`${interfaceName}${workerScript}${mtime}`),
|
|
id: md5(`${interfaceName}${workerScript}${mtime}`),
|
|
interfaceName,
|
|
interfaceName,
|
|
@@ -145,27 +144,33 @@ async function findWorkers () {
|
|
await Promise.all(workerPromises)
|
|
await Promise.all(workerPromises)
|
|
}
|
|
}
|
|
|
|
|
|
-async function workers (parent, args, context, info) {
|
|
|
|
|
|
+async function workers(parent, args, context, info) {
|
|
await findWorkers()
|
|
await findWorkers()
|
|
return state.workers.map(worker => ({
|
|
return state.workers.map(worker => ({
|
|
...worker,
|
|
...worker,
|
|
|
|
+ // Find ports
|
|
|
|
+ ports: ports(worker.interfaceName, args, context, info),
|
|
|
|
+ // Serialize worker process
|
|
workerProcess: workerProcess(worker.workerProcess, args, context, info)
|
|
workerProcess: workerProcess(worker.workerProcess, args, context, info)
|
|
}))
|
|
}))
|
|
}
|
|
}
|
|
|
|
|
|
-async function worker (parent, args, context, info) {
|
|
|
|
|
|
+async function worker(parent, args, context, info) {
|
|
await findWorkers()
|
|
await findWorkers()
|
|
const { id, interfaceName } = args
|
|
const { id, interfaceName } = args
|
|
if (!id && !interfaceName) throw new Error('Either id or interfaceName needs to be provided!')
|
|
if (!id && !interfaceName) throw new Error('Either id or interfaceName needs to be provided!')
|
|
const worker = state.workers.find(worker => worker.id === id || worker.interfaceName === interfaceName)
|
|
const worker = state.workers.find(worker => worker.id === id || worker.interfaceName === interfaceName)
|
|
if (!worker) throw new Error(`Worker id=${id}, interfaceName=${interfaceName} not found`)
|
|
if (!worker) throw new Error(`Worker id=${id}, interfaceName=${interfaceName} not found`)
|
|
- return worker
|
|
|
|
|
|
+ return {
|
|
|
|
+ ...worker,
|
|
|
|
+ workerProcess: workerProcess(worker.workerProcess, args, context, info)
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
* PORTS SECTION
|
|
* PORTS SECTION
|
|
*/
|
|
*/
|
|
-async function findPorts (interfaceName) {
|
|
|
|
|
|
+async function findPorts() {
|
|
console.log('find ports.')
|
|
console.log('find ports.')
|
|
// 1. Make sure, workers are updated.
|
|
// 1. Make sure, workers are updated.
|
|
await findWorkers()
|
|
await findWorkers()
|
|
@@ -174,56 +179,74 @@ async function findPorts (interfaceName) {
|
|
// if (state.lastScan.ports + 1000 > Date.now()) return null
|
|
// if (state.lastScan.ports + 1000 > Date.now()) return null
|
|
// state.lastScan.ports = Date.now()
|
|
// state.lastScan.ports = Date.now()
|
|
|
|
|
|
- const portsPromises = state.workers.map(worker => {
|
|
|
|
-
|
|
|
|
|
|
+ // 3. Loop through all workers to find available ports.
|
|
|
|
+ const portsPromises = state.workers.map(async worker => {
|
|
|
|
+ // a) Ask worker for ports.
|
|
|
|
+ const { data, error, pythonError } = await worker.workerProcess.send({ type: 'ports' })
|
|
|
|
+ if (error) throw new Error(error)
|
|
|
|
+ if (pythonError) throw new Error(pythonError)
|
|
|
|
+ console.log(data)
|
|
|
|
+ // b) Add all ports that are not in the list.
|
|
|
|
+ data.forEach(port => {
|
|
|
|
+ const id = port.name || port.device
|
|
|
|
+ if (state.ports.find(port => port.id === id)) return null
|
|
|
|
+ const newPort = {
|
|
|
|
+ id,
|
|
|
|
+ interfaceName: worker.interfaceName,
|
|
|
|
+ host: os.hostname(),
|
|
|
|
+ ...port
|
|
|
|
+ }
|
|
|
|
+ state.ports.push(newPort)
|
|
|
|
+ worker.ports.push(newPort)
|
|
|
|
+ })
|
|
})
|
|
})
|
|
- // Generate all ports for the interface
|
|
|
|
- const iface = state.interfaces.find(iface => iface.interfaceName === interfaceName)
|
|
|
|
|
|
+ await Promise.all(portsPromises)
|
|
|
|
|
|
- const { data, error, pythonError } = await iface.worker.send({ type: 'ports' })
|
|
|
|
- if (error) throw new Error(error)
|
|
|
|
- if (pythonError) throw new Error(pythonError)
|
|
|
|
- console.log(data)
|
|
|
|
- data.forEach(port => {
|
|
|
|
- const id = port.name || port.device
|
|
|
|
- // Skip existing ports
|
|
|
|
- if (state.ports.find(port => port.id === id)) return null
|
|
|
|
- const newPort = {
|
|
|
|
- id,
|
|
|
|
- interfaceName,
|
|
|
|
- host: os.hostname(),
|
|
|
|
- ...port
|
|
|
|
- }
|
|
|
|
- state.ports.push(newPort)
|
|
|
|
- iface.ports.push(newPort)
|
|
|
|
- })
|
|
|
|
console.log('found ports.')
|
|
console.log('found ports.')
|
|
}
|
|
}
|
|
|
|
|
|
-async function ports (parent, args, ctx, info) {
|
|
|
|
- const { force, interfaceName } = args
|
|
|
|
|
|
+async function ports(parent, args, ctx, info) {
|
|
|
|
+ await findPorts()
|
|
|
|
+ const { interfaceName } = args
|
|
const ifName = interfaceName || parent
|
|
const ifName = interfaceName || parent
|
|
|
|
|
|
|
|
+ console.log(ifName)
|
|
if (ifName) {
|
|
if (ifName) {
|
|
- const iface = state.interfaces.find(iface => iface.interfaceName === ifName)
|
|
|
|
-
|
|
|
|
- // Try to find ports if necessary
|
|
|
|
- if (!iface.ports.length || force) await findPorts(ifName)
|
|
|
|
|
|
+ const iface = state.workers.find(iface => iface.interfaceName === ifName)
|
|
|
|
+ if (!iface) throw new Error(`Interface ${ifName} not found.`)
|
|
return iface.ports
|
|
return iface.ports
|
|
} else {
|
|
} else {
|
|
return state.ports
|
|
return state.ports
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-async function findOptions (interfaceName) {
|
|
|
|
- const iface = state.interfaces.find(iface => iface.interfaceName === interfaceName)
|
|
|
|
- const { data, error, pythonError } = await iface.worker.send({ type: 'options' })
|
|
|
|
- if (error) throw new Error(error)
|
|
|
|
- if (pythonError) throw new Error(pythonError)
|
|
|
|
- iface.options.push(...data)
|
|
|
|
|
|
+async function port(parent, args, ctx, info) {
|
|
|
|
+ await findPorts()
|
|
|
|
+ const { id } = args
|
|
|
|
+ if (!id) throw new Error('Need an id.')
|
|
|
|
+ const port = state.ports.find(port => port.id === id)
|
|
|
|
+ return port
|
|
}
|
|
}
|
|
|
|
|
|
-async function options (parent, args, ctx, info) {
|
|
|
|
|
|
+async function findOptions() {
|
|
|
|
+ // 1. Make sure, workers are updated.
|
|
|
|
+ await findWorkers()
|
|
|
|
+
|
|
|
|
+ // 2. Don't check more frequently than once per second.
|
|
|
|
+ // if (state.lastScan.options + 1000 > Date.now()) return null
|
|
|
|
+ // state.lastScan.options = Date.now()
|
|
|
|
+
|
|
|
|
+ const optionPromises = state.workers.map(async worker => {
|
|
|
|
+ const { data, error, pythonError } = await worker.workerProcess.pythonShell.send({ type: 'options' })
|
|
|
|
+ if (error) throw new Error(error)
|
|
|
|
+ if (pythonError) throw new Error(pythonError)
|
|
|
|
+ iface.options.push(...data)
|
|
|
|
+ })
|
|
|
|
+ await Promise.all(optionPromises)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+async function options(parent, args, ctx, info) {
|
|
|
|
+ if (!parent) throw new Error('Need a parent.')
|
|
const iface = state.interfaces.find(iface => iface.interfaceName === parent)
|
|
const iface = state.interfaces.find(iface => iface.interfaceName === parent)
|
|
|
|
|
|
// Try to find options if necessary
|
|
// Try to find options if necessary
|
|
@@ -231,7 +254,15 @@ async function options (parent, args, ctx, info) {
|
|
return iface.options
|
|
return iface.options
|
|
}
|
|
}
|
|
|
|
|
|
-function workerProcess (parent, args, ctx, info) {
|
|
|
|
|
|
+function workerProcess(parent, args, ctx, info) {
|
|
|
|
+ let worker
|
|
|
|
+ const { id } = args
|
|
|
|
+ if (!id && !parent) throw new Error('Need either id or parent of worker.')
|
|
|
|
+ if (parent) {
|
|
|
|
+ worker = parent
|
|
|
|
+ } else {
|
|
|
|
+ worker = state.workers.find(worker => worker.id === id).workerProcess
|
|
|
|
+ }
|
|
const { killed, exitCode, signalCode, spawnargs, spawnfile, pid } = parent.pythonShell
|
|
const { killed, exitCode, signalCode, spawnargs, spawnfile, pid } = parent.pythonShell
|
|
const { error, data } = parent
|
|
const { error, data } = parent
|
|
return {
|
|
return {
|
|
@@ -246,7 +277,7 @@ function workerProcess (parent, args, ctx, info) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-async function connections (parent, args, ctx, info) {
|
|
|
|
|
|
+async function connections(parent, args, ctx, info) {
|
|
if (parent) {
|
|
if (parent) {
|
|
const iface = state.interfaces.find(iface => iface.interfaceName === parent)
|
|
const iface = state.interfaces.find(iface => iface.interfaceName === parent)
|
|
return iface.connections
|
|
return iface.connections
|
|
@@ -255,12 +286,12 @@ async function connections (parent, args, ctx, info) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-async function connection (parent, args, context, info) {
|
|
|
|
|
|
+async function connection(parent, args, context, info) {
|
|
const connection = state.connections.find(connection => connection.id === args.id)
|
|
const connection = state.connections.find(connection => connection.id === args.id)
|
|
return connection
|
|
return connection
|
|
}
|
|
}
|
|
|
|
|
|
-async function connect (parent, args, ctx, info) {
|
|
|
|
|
|
+async function connect(parent, args, ctx, info) {
|
|
const { interfaceName, device } = args
|
|
const { interfaceName, device } = args
|
|
const iface = state.interfaces.find(iface => iface.interfaceName === interfaceName)
|
|
const iface = state.interfaces.find(iface => iface.interfaceName === interfaceName)
|
|
const id = md5(interfaceName + device)
|
|
const id = md5(interfaceName + device)
|
|
@@ -284,7 +315,7 @@ async function connect (parent, args, ctx, info) {
|
|
return connection
|
|
return connection
|
|
}
|
|
}
|
|
|
|
|
|
-async function connectionCommand (parent, args, ctx, info) {
|
|
|
|
|
|
+async function connectionCommand(parent, args, ctx, info) {
|
|
const { connectionId, type, string, options } = args
|
|
const { connectionId, type, string, options } = args
|
|
const connection = state.connections.find(connection => connection.id === connectionId)
|
|
const connection = state.connections.find(connection => connection.id === connectionId)
|
|
const { data, error, pythonError } = await connection.worker.send({ type, string, options })
|
|
const { data, error, pythonError } = await connection.worker.send({ type, string, options })
|
|
@@ -294,7 +325,7 @@ async function connectionCommand (parent, args, ctx, info) {
|
|
}
|
|
}
|
|
|
|
|
|
// TODO Also find connections in interfaces.
|
|
// TODO Also find connections in interfaces.
|
|
-async function endWorker (parent, args, ctx, info) {
|
|
|
|
|
|
+async function endWorker(parent, args, ctx, info) {
|
|
const { id } = args
|
|
const { id } = args
|
|
const connection = state.connections.find(connection => connection.id === id)
|
|
const connection = state.connections.find(connection => connection.id === id)
|
|
const { data, error, pythonError } = await connection.worker.end()
|
|
const { data, error, pythonError } = await connection.worker.end()
|
|
@@ -303,7 +334,7 @@ async function endWorker (parent, args, ctx, info) {
|
|
return connection.workerProcess()
|
|
return connection.workerProcess()
|
|
}
|
|
}
|
|
|
|
|
|
-async function spawnWorker (parent, args, ctx, info) {
|
|
|
|
|
|
+async function spawnWorker(parent, args, ctx, info) {
|
|
const { id } = args
|
|
const { id } = args
|
|
const connection = state.connections.find(connection => connection.id === id)
|
|
const connection = state.connections.find(connection => connection.id === id)
|
|
const { data, error, pythonError } = await connection.worker.spawn()
|
|
const { data, error, pythonError } = await connection.worker.spawn()
|
|
@@ -316,7 +347,7 @@ async function spawnWorker (parent, args, ctx, info) {
|
|
return connection.workerProcess()
|
|
return connection.workerProcess()
|
|
}
|
|
}
|
|
|
|
|
|
-async function killWorker (parent, args, ctx, info) {
|
|
|
|
|
|
+async function killWorker(parent, args, ctx, info) {
|
|
const { id } = args
|
|
const { id } = args
|
|
const connection = state.connections.find(connection => connection.id === id)
|
|
const connection = state.connections.find(connection => connection.id === id)
|
|
const { data, error, pythonError } = await connection.worker.kill()
|
|
const { data, error, pythonError } = await connection.worker.kill()
|