Ver código fonte

improved ports in interfaces.

Tomi Cvetic 6 anos atrás
pai
commit
2b58dbf73c
1 arquivos alterados com 80 adições e 49 exclusões
  1. 80 49
      backend/src/interfaces.js

+ 80 - 49
backend/src/interfaces.js

@@ -25,7 +25,6 @@ const HOST = os.hostname()
 
 const state = {
   workers: [],
-  interfaces: [],
   ports: [],
   connections: [],
   lastScan: {
@@ -103,7 +102,7 @@ const typeDefs = `
 /**
  * WORKER SECTION
  */
-async function findWorkers () {
+async function findWorkers() {
   // 1. Don't check more frequently than once per second.
   // if (state.lastScan.workers + 1000 > Date.now()) return null
   // state.lastScan.workers = Date.now()
@@ -129,7 +128,7 @@ async function findWorkers () {
     const { data, error, pythonError } = await workerProcess.spawn()
     if (error) throw new Error(error)
     if (pythonError) throw new Error(pythonError)
-    // c. Save the worker in the state.
+    // d. Save the worker in the state.
     state.workers.push({
       id: md5(`${interfaceName}${workerScript}${mtime}`),
       interfaceName,
@@ -145,27 +144,33 @@ async function findWorkers () {
   await Promise.all(workerPromises)
 }
 
-async function workers (parent, args, context, info) {
+async function workers(parent, args, context, info) {
   await findWorkers()
   return state.workers.map(worker => ({
     ...worker,
+    // Find ports
+    ports: ports(worker.interfaceName, args, context, info),
+    // Serialize worker process
     workerProcess: workerProcess(worker.workerProcess, args, context, info)
   }))
 }
 
-async function worker (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`)
-  return worker
+  return {
+    ...worker,
+    workerProcess: workerProcess(worker.workerProcess, args, context, info)
+  }
 }
 
 /**
  * PORTS SECTION
  */
-async function findPorts (interfaceName) {
+async function findPorts() {
   console.log('find ports.')
   // 1. Make sure, workers are updated.
   await findWorkers()
@@ -174,56 +179,74 @@ async function findPorts (interfaceName) {
   // if (state.lastScan.ports + 1000 > Date.now()) return null
   // 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.')
 }
 
-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
 
+  console.log(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
   } else {
     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)
 
   // Try to find options if necessary
@@ -231,7 +254,15 @@ async function options (parent, args, ctx, info) {
   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 { error, data } = parent
   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) {
     const iface = state.interfaces.find(iface => iface.interfaceName === parent)
     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)
   return connection
 }
 
-async function connect (parent, args, ctx, info) {
+async function connect(parent, args, ctx, info) {
   const { interfaceName, device } = args
   const iface = state.interfaces.find(iface => iface.interfaceName === interfaceName)
   const id = md5(interfaceName + device)
@@ -284,7 +315,7 @@ async function connect (parent, args, ctx, info) {
   return connection
 }
 
-async function connectionCommand (parent, args, ctx, info) {
+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 })
@@ -294,7 +325,7 @@ async function connectionCommand (parent, args, ctx, info) {
 }
 
 // TODO Also find connections in interfaces.
-async function endWorker (parent, args, ctx, info) {
+async function endWorker(parent, args, ctx, info) {
   const { id } = args
   const connection = state.connections.find(connection => connection.id === id)
   const { data, error, pythonError } = await connection.worker.end()
@@ -303,7 +334,7 @@ async function endWorker (parent, args, ctx, info) {
   return connection.workerProcess()
 }
 
-async function spawnWorker (parent, args, ctx, info) {
+async function spawnWorker(parent, args, ctx, info) {
   const { id } = args
   const connection = state.connections.find(connection => connection.id === id)
   const { data, error, pythonError } = await connection.worker.spawn()
@@ -316,7 +347,7 @@ async function spawnWorker (parent, args, ctx, info) {
   return connection.workerProcess()
 }
 
-async function killWorker (parent, args, ctx, info) {
+async function killWorker(parent, args, ctx, info) {
   const { id } = args
   const connection = state.connections.find(connection => connection.id === id)
   const { data, error, pythonError } = await connection.worker.kill()