|
@@ -55,8 +55,6 @@ const typeDefs = `
|
|
|
exitCode: Int
|
|
|
spawnfile: String!
|
|
|
spawnargs: [String]!
|
|
|
- error: [String]!
|
|
|
- data: [String]!
|
|
|
}
|
|
|
|
|
|
type Option {
|
|
@@ -83,7 +81,12 @@ const typeDefs = `
|
|
|
workerProcess: WorkerProcess
|
|
|
}
|
|
|
|
|
|
+ type Interface {
|
|
|
+ name: String!
|
|
|
+ }
|
|
|
+
|
|
|
extend type Query {
|
|
|
+ interfaces: [Interface]!
|
|
|
workers: [Worker]!
|
|
|
worker(id: ID, interfaceName: String): Worker!
|
|
|
ports(interfaceName: String, force: Boolean): [Port]!
|
|
@@ -110,7 +113,9 @@ async function findWorkers () {
|
|
|
|
|
|
// 2. Find all files in ./python_workers that end in _worker.py
|
|
|
const fileNames = await readdir(WORKER_DIR)
|
|
|
- const workerFiles = fileNames.filter(fileName => fileName.includes('_worker.py'))
|
|
|
+ const workerFiles = fileNames.filter(fileName =>
|
|
|
+ fileName.includes('_worker.py')
|
|
|
+ )
|
|
|
|
|
|
// 3. For every worker script
|
|
|
const workerPromises = workerFiles.map(async workerFile => {
|
|
@@ -118,7 +123,9 @@ async function findWorkers () {
|
|
|
const workerScript = `${WORKER_DIR}/${workerFile}`
|
|
|
// a. Find out if it was modified.
|
|
|
const { mtime } = await stat(workerScript)
|
|
|
- const foundWorker = state.workers.find(worker => worker.interfaceName === interfaceName)
|
|
|
+ const foundWorker = state.workers.find(
|
|
|
+ worker => worker.interfaceName === interfaceName
|
|
|
+ )
|
|
|
if (foundWorker) {
|
|
|
// b. If it was modified, save the modification time.
|
|
|
if (foundWorker.mtime < mtime) foundWorker.updated = mtime
|
|
@@ -156,12 +163,37 @@ async function workers (parent, args, context, info) {
|
|
|
async function worker (parent, args, context, info) {
|
|
|
await findWorkers()
|
|
|
const { id, interfaceName } = args
|
|
|
- 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)
|
|
|
- if (!worker) throw new Error(`Worker id=${id}, interfaceName=${interfaceName} not found`)
|
|
|
+ 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
|
|
|
+ )
|
|
|
+ if (!worker) {
|
|
|
+ throw new Error(`Worker id=${id}, interfaceName=${interfaceName} not found`)
|
|
|
+ }
|
|
|
return worker
|
|
|
}
|
|
|
|
|
|
+function workerProcess (parent, args, ctx, info) {
|
|
|
+ const {
|
|
|
+ killed,
|
|
|
+ exitCode,
|
|
|
+ signalCode,
|
|
|
+ spawnargs,
|
|
|
+ spawnfile,
|
|
|
+ pid
|
|
|
+ } = parent.pythonShell
|
|
|
+ return {
|
|
|
+ pid,
|
|
|
+ killed,
|
|
|
+ exitCode,
|
|
|
+ signalCode,
|
|
|
+ spawnfile,
|
|
|
+ spawnargs
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* PORTS SECTION
|
|
|
*/
|
|
@@ -174,13 +206,15 @@ async function findPorts (interfaceName) {
|
|
|
// if (state.lastScan.ports + 1000 > Date.now()) return null
|
|
|
// state.lastScan.ports = Date.now()
|
|
|
|
|
|
- const portsPromises = state.workers.map(worker => {
|
|
|
-
|
|
|
- })
|
|
|
+ const portsPromises = state.workers.map(worker => {})
|
|
|
// Generate all ports for the interface
|
|
|
- const iface = state.interfaces.find(iface => iface.interfaceName === interfaceName)
|
|
|
+ const iface = state.interfaces.find(
|
|
|
+ iface => iface.interfaceName === interfaceName
|
|
|
+ )
|
|
|
|
|
|
- const { data, error, pythonError } = await iface.worker.send({ type: 'ports' })
|
|
|
+ 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)
|
|
@@ -191,7 +225,7 @@ async function findPorts (interfaceName) {
|
|
|
const newPort = {
|
|
|
id,
|
|
|
interfaceName,
|
|
|
- host: os.hostname(),
|
|
|
+ host: HOST,
|
|
|
...port
|
|
|
}
|
|
|
state.ports.push(newPort)
|
|
@@ -215,15 +249,23 @@ async function ports (parent, args, ctx, info) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * OPTIONS SECTION
|
|
|
+ */
|
|
|
async function findOptions (interfaceName) {
|
|
|
- const iface = state.interfaces.find(iface => iface.interfaceName === interfaceName)
|
|
|
- const { data, error, pythonError } = await iface.worker.send({ type: 'options' })
|
|
|
+ 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 options (parent, args, ctx, info) {
|
|
|
+ if (!parent) throw new Error('Parent needed.')
|
|
|
const iface = state.interfaces.find(iface => iface.interfaceName === parent)
|
|
|
|
|
|
// Try to find options if necessary
|
|
@@ -231,40 +273,15 @@ async function options (parent, args, ctx, info) {
|
|
|
return iface.options
|
|
|
}
|
|
|
|
|
|
-function workerProcess (parent, args, ctx, info) {
|
|
|
- const { killed, exitCode, signalCode, spawnargs, spawnfile, pid } = parent.pythonShell
|
|
|
- const { error, data } = parent
|
|
|
- return {
|
|
|
- pid,
|
|
|
- killed,
|
|
|
- exitCode,
|
|
|
- signalCode,
|
|
|
- spawnfile,
|
|
|
- spawnargs,
|
|
|
- error,
|
|
|
- data
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-async function connections (parent, args, ctx, info) {
|
|
|
- if (parent) {
|
|
|
- const iface = state.interfaces.find(iface => iface.interfaceName === parent)
|
|
|
- return iface.connections
|
|
|
- } else {
|
|
|
- return state.connections
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-async function connection (parent, args, context, info) {
|
|
|
- const connection = state.connections.find(connection => connection.id === args.id)
|
|
|
- return connection
|
|
|
-}
|
|
|
-
|
|
|
async function connect (parent, args, ctx, info) {
|
|
|
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)
|
|
|
- if (iface.connections.find(connection => connection.id === id)) throw new Error('already connected.')
|
|
|
+ if (iface.connections.find(connection => connection.id === id)) {
|
|
|
+ throw new Error('already connected.')
|
|
|
+ }
|
|
|
const pythonWorker = new PythonWorker(iface.workerScript)
|
|
|
const spawnData = await pythonWorker.spawn()
|
|
|
if (spawnData.error) throw new Error(spawnData.error)
|
|
@@ -272,11 +289,15 @@ async function connect (parent, args, ctx, info) {
|
|
|
id,
|
|
|
device,
|
|
|
interfaceName,
|
|
|
- host: os.hostname(),
|
|
|
+ host: HOST,
|
|
|
worker: pythonWorker,
|
|
|
- workerProcess: (parent, args, context, info) => workerProcess(pythonWorker, args, context, info)
|
|
|
+ workerProcess: (parent, args, context, info) =>
|
|
|
+ workerProcess(pythonWorker, args, context, info)
|
|
|
}
|
|
|
- const connectionData = await connection.worker.send({ type: 'connect', device })
|
|
|
+ const connectionData = await connection.worker.send({
|
|
|
+ type: 'connect',
|
|
|
+ device
|
|
|
+ })
|
|
|
if (connectionData.error) throw new Error(connectionData.error)
|
|
|
if (connectionData.pythonError) throw new Error(connectionData.pythonError)
|
|
|
iface.connections.push(connection)
|
|
@@ -284,10 +305,32 @@ async function connect (parent, args, ctx, info) {
|
|
|
return connection
|
|
|
}
|
|
|
|
|
|
+async function connections (parent, args, ctx, info) {
|
|
|
+ if (parent) {
|
|
|
+ const iface = state.interfaces.find(iface => iface.interfaceName === parent)
|
|
|
+ return iface.connections
|
|
|
+ } else {
|
|
|
+ return state.connections
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+async function connection (parent, args, context, info) {
|
|
|
+ const connection = state.connections.find(
|
|
|
+ connection => connection.id === args.id
|
|
|
+ )
|
|
|
+ return connection
|
|
|
+}
|
|
|
+
|
|
|
async function connectionCommand (parent, args, ctx, info) {
|
|
|
const { connectionId, type, string, options } = args
|
|
|
- const connection = state.connections.find(connection => connection.id === connectionId)
|
|
|
- const { data, error, pythonError } = await connection.worker.send({ type, string, options })
|
|
|
+ const connection = state.connections.find(
|
|
|
+ connection => connection.id === connectionId
|
|
|
+ )
|
|
|
+ const { data, error, pythonError } = await connection.worker.send({
|
|
|
+ type,
|
|
|
+ string,
|
|
|
+ options
|
|
|
+ })
|
|
|
if (error) throw new Error(JSON.stringify(error))
|
|
|
if (pythonError) throw new Error(JSON.stringify(pythonError))
|
|
|
return data.response
|
|
@@ -310,7 +353,10 @@ async function spawnWorker (parent, args, ctx, info) {
|
|
|
console.log(data, error, pythonError)
|
|
|
if (error) throw new Error(JSON.stringify(error))
|
|
|
if (pythonError) throw new Error(JSON.stringify(pythonError))
|
|
|
- const connectionData = await connection.worker.send({ type: 'connect', device: connection.device })
|
|
|
+ const connectionData = await connection.worker.send({
|
|
|
+ type: 'connect',
|
|
|
+ device: connection.device
|
|
|
+ })
|
|
|
if (connectionData.error) throw new Error(connectionData.error)
|
|
|
if (connectionData.pythonError) throw new Error(connectionData.pythonError)
|
|
|
return connection.workerProcess()
|
|
@@ -328,6 +374,7 @@ async function killWorker (parent, args, ctx, info) {
|
|
|
|
|
|
const resolvers = {
|
|
|
Query: {
|
|
|
+ interfaces: () => [{ name: 'serial' }, { name: 'usbtmc' }],
|
|
|
workers,
|
|
|
worker,
|
|
|
ports,
|