summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSuchita Lad2025-04-08 12:57:02 +0530
committerSuchita Lad2025-04-08 12:57:02 +0530
commit530c70390f2b399321a1b796de409351ad3ff1e2 (patch)
tree3449cb7defaf86f00e182599544ca9220e57fd38
parent4b50b816c8cd6bbd39927b57b99a8499897b57fb (diff)
parent8ea1cdadc8f9488e973785bff6381183e02be846 (diff)
downloadCommon-Interface-Project-530c70390f2b399321a1b796de409351ad3ff1e2.tar.gz
Common-Interface-Project-530c70390f2b399321a1b796de409351ad3ff1e2.tar.bz2
Common-Interface-Project-530c70390f2b399321a1b796de409351ad3ff1e2.zip
Merged scripts with xcosblocks
-rw-r--r--blocks/eda-frontend/src/components/SchematicEditor/SchematicToolbar.js39
-rw-r--r--blocks/eda-frontend/src/components/SchematicEditor/SimulationProperties.js17
-rw-r--r--blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js209
-rw-r--r--blocks/eda-frontend/src/redux/saveSchematicSlice.js10
-rw-r--r--blocks/simulationAPI/helpers/config.py7
-rw-r--r--blocks/simulationAPI/helpers/ngspice_helper.py105
-rw-r--r--blocks/simulationAPI/helpers/scilab_manager.py462
-rw-r--r--blocks/simulationAPI/tasks.py31
-rw-r--r--blocks/simulationAPI/urls.py1
-rw-r--r--blocks/simulationAPI/views.py36
10 files changed, 727 insertions, 190 deletions
diff --git a/blocks/eda-frontend/src/components/SchematicEditor/SchematicToolbar.js b/blocks/eda-frontend/src/components/SchematicEditor/SchematicToolbar.js
index 8dcbf739..259803b4 100644
--- a/blocks/eda-frontend/src/components/SchematicEditor/SchematicToolbar.js
+++ b/blocks/eda-frontend/src/components/SchematicEditor/SchematicToolbar.js
@@ -103,6 +103,7 @@ export default function SchematicToolbar ({ mobileClose, gridRef }) {
const title2 = useSelector(state => state.saveSchematic.title)
const scriptDump = useSelector(state => state.saveSchematic.scriptDump)
+ const showDot = useSelector(state => state.saveSchematic.showDot)
const dispatch = useDispatch()
const isMobile = useMediaQuery('(max-width:600px)')
@@ -433,7 +434,43 @@ export default function SchematicToolbar ({ mobileClose, gridRef }) {
{ icon: <ImageOutlinedIcon fontSize='small' />, label: 'Image Export', action: handleImgClickOpen },
{ icon: <PrintOutlinedIcon fontSize='small' />, label: 'Print Preview', action: PrintPreview },
'pipe',
- { icon: <DescriptionIcon fontSize='small' style={{ color: scriptDump ? 'red' : 'inherit' }} />, label: 'Show Script', action: handleSchWinOpen },
+ {
+ icon: (
+ <div style={{ position: 'relative', display: 'inline-block', cursor: 'pointer' }} onClick={handleSchWinOpen}>
+ <DescriptionIcon fontSize="small" style={{ color: scriptDump ? 'red' : 'inherit' }} />
+
+ {/* Blinking Dot */}
+ {showDot && (
+ <div
+ style={{
+ position: 'absolute',
+ top: '-3px', // Adjust position to be visible
+ right: '-3px',
+ width: '5px',
+ height: '5px',
+ borderRadius: '50%',
+ backgroundColor: 'green',
+ animation: 'blink-animation 1s infinite alternate',
+ zIndex: 10 // Ensure visibility
+ }}
+ />
+ )}
+
+ {/* CSS for blinking effect */}
+ <style>
+ {`
+ @keyframes blink-animation {
+ 0% { opacity: 1; }
+ 50% { opacity: 0.3; }
+ 100% { opacity: 1; }
+ }
+ `}
+ </style>
+ </div>
+ ),
+ label: 'Show Script',
+ action: handleSchWinOpen
+ },
{ icon: <PlayCircleOutlineIcon fontSize='small' />, label: 'Simulate', action: handleNetlistOpen },
'pipe',
{ icon: <UndoIcon fontSize='small' />, label: 'Undo', action: editorUndo },
diff --git a/blocks/eda-frontend/src/components/SchematicEditor/SimulationProperties.js b/blocks/eda-frontend/src/components/SchematicEditor/SimulationProperties.js
index cd3a1704..fbfecbac 100644
--- a/blocks/eda-frontend/src/components/SchematicEditor/SimulationProperties.js
+++ b/blocks/eda-frontend/src/components/SchematicEditor/SimulationProperties.js
@@ -44,6 +44,7 @@ const useStyles = makeStyles((theme) => ({
export default function SimulationProperties () {
const title = useSelector(state => state.saveSchematic.title)
const isSimRes = useSelector(state => state.simulation.isSimRes)
+ const scriptTaskId = useSelector(state => state.simulation.scriptTaskId)
const dispatch = useDispatch()
const classes = useStyles()
const [transientAnalysisControlLine, setTransientAnalysisControlLine] = useState({
@@ -81,16 +82,17 @@ export default function SimulationProperties () {
// Prepare Netlist to file
const prepareNetlist = (netlist) => {
- const titleA = title.split(' ')[1]
+ const titleA = title
const myblob = new Blob([netlist], {
type: 'text/plain'
})
const file = new File([myblob], `${titleA}.xml`, { type: 'text/xml', lastModified: Date.now() })
- sendNetlist(file)
+ const type = 'XCOS'
+ sendNetlist(file, type)
}
- function sendNetlist (file) {
- netlistConfig(file)
+ function sendNetlist (file, type) {
+ netlistConfig(file, type)
.then((response) => {
const res = response.data
const taskId = res.details.task_id
@@ -102,10 +104,15 @@ export default function SimulationProperties () {
}
// Upload the nelist
- async function netlistConfig (file) {
+ async function netlistConfig (file, type) {
const formData = new FormData()
formData.append('app_name', process.env.REACT_APP_NAME)
formData.append('file', file)
+ formData.append('type', type)
+ if (scriptTaskId) {
+ formData.append('script_task_id', scriptTaskId)
+ }
+
for (const [key, value] of Object.entries(transientAnalysisControlLine)) {
formData.append(key, value)
}
diff --git a/blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js b/blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js
index 371f19d3..83c8ce15 100644
--- a/blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js
+++ b/blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js
@@ -36,7 +36,7 @@ import {
import { makeStyles } from '@material-ui/core/styles'
import CloseIcon from '@material-ui/icons/Close'
import { useSelector, useDispatch } from 'react-redux'
-import { fetchSchematic, fetchDiagram, setSchScriptDump } from '../../redux/saveSchematicSlice'
+import { fetchSchematic, fetchDiagram, setSchScriptDump, setShowDot } from '../../redux/saveSchematicSlice'
import { fetchSchematics, fetchGallery } from '../../redux/dashboardSlice'
import { setScriptTaskId } from '../../redux/simulationSlice'
import { blue } from '@material-ui/core/colors'
@@ -341,15 +341,18 @@ HelpScreen.propTypes = {
export function ScriptScreen ({ isOpen, onClose }) {
const scriptDump = useSelector(state => state.saveSchematic.scriptDump)
const title = useSelector(state => state.saveSchematic.title)
+ const showDot = useSelector(state => state.saveSchematic.showDot)
const dispatch = useDispatch()
+ const [result, setResult] = useState('No output yet...')
+ const [variables, setVariables] = useState([])
const scriptHandler = (e) => {
dispatch(setSchScriptDump(e.target.value))
+ dispatch(setShowDot(true))
}
- const [result, setResult] = useState('')
const prepareScriptNetlist = (scriptDump) => {
- const titleA = title.split(' ')[1]
+ const titleA = title
const myblob = new Blob([scriptDump], {
type: 'text/plain'
})
@@ -361,9 +364,14 @@ export function ScriptScreen ({ isOpen, onClose }) {
function sendSriptNetlist (file, type) {
netlistConfig(file, type)
.then((response) => {
- const res = response.data
- const taskId = res.details.task_id
+ const data = response.data
+ const taskId = data.task_id
dispatch(setScriptTaskId(taskId))
+
+ console.log('taskId2:', taskId)
+ setResult(data.output || 'No output available.')
+ setVariables(data.variables)
+
})
.catch(function (error) {
console.error(error)
@@ -388,11 +396,16 @@ export function ScriptScreen ({ isOpen, onClose }) {
const executeScript = () => {
dispatch(setScriptTaskId(''))
prepareScriptNetlist(scriptDump)
+ dispatch(setShowDot(false))
}
const resetCode = () => {
dispatch(setSchScriptDump(''))
- setResult('')
+ dispatch(setShowDot(false))
+ dispatch(setScriptTaskId(''))
+ setResult('No output yet...')
+ setVariables('')
+
}
return (
@@ -413,50 +426,190 @@ export function ScriptScreen ({ isOpen, onClose }) {
<Box sx={{ p: 4 }}>
{/* Code and Result Sections */}
- <Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', md: '1fr 1fr' }, gap: 4, alignItems: 'stretch' }}>
- {/* Scilab Code Input */}
- <Box sx={{ p: 2, bgcolor: 'white', boxShadow: 2, borderRadius: 2, display: 'flex', flexDirection: 'column', height: '100%' }}>
- <Typography variant='subtitle1' sx={{ fontWeight: 'bold', mb: 1 }}>
+ <Box
+ sx={{
+ display: 'grid',
+ gridTemplateColumns: { xs: '1fr', md: '1fr 1fr' },
+ gap: 4,
+ alignItems: 'stretch',
+ }}
+ >
+ <Box
+ sx={{
+ p: 2,
+ boxShadow: 2,
+ borderRadius: 2,
+ display: 'flex',
+ flexDirection: 'column',
+ flexGrow: 1,
+ }}
+ >
+ <Typography variant="subtitle1" style={{ fontWeight: 'bold', mb: 1 }}>
Scilab Code:
</Typography>
- <TextField
- value={scriptDump}
- onChange={scriptHandler}
- multiline
- minRows={12}
- variant='outlined'
- fullWidth
- sx={{ fontFamily: 'Courier New, monospace', fontSize: '14px', flexGrow: 1 }}
- />
+
+ <Box
+ sx={{
+ height: '500px',
+ overflowY: 'scroll',
+ border: '1px solid #ccc',
+ borderRadius: 1,
+ '&::-webkit-scrollbar': {
+ width: '8px',
+ },
+ '&::-webkit-scrollbar-track': {
+ backgroundColor: '#f1f1f1',
+ },
+ '&::-webkit-scrollbar-thumb': {
+ backgroundColor: '#888',
+ borderRadius: '4px',
+ },
+ '&::-webkit-scrollbar-thumb:hover': {
+ backgroundColor: '#555',
+ },
+ }}
+ >
+ <TextField
+ value={scriptDump}
+ onChange={scriptHandler}
+ multiline
+ variant="outlined"
+ fullWidth
+ InputProps={{
+ disableUnderline: true,
+ sx: {
+ fontFamily: 'Courier New, monospace',
+ fontSize: '14px',
+ },
+ }}
+ />
+ </Box>
</Box>
- {/* Execution Result */}
- <Box sx={{ p: 2, bgcolor: 'white', boxShadow: 2, borderRadius: 2, display: 'flex', flexDirection: 'column', height: '100%' }}>
- <Typography variant='subtitle1' sx={{ fontWeight: 'bold', mb: 1 }}>
+ <Box
+ sx={{
+ p: 2,
+ boxShadow: 2,
+ borderRadius: 2,
+ display: 'flex',
+ flexDirection: 'column',
+ height: '100%',
+ }}
+ >
+ <Typography variant="subtitle1" style={{ fontWeight: 'bold', mb: 1 }}>
Result:
</Typography>
<Box
sx={{
flexGrow: 1,
width: '100%',
- height: '200px',
p: 2,
border: '1px solid gray',
borderRadius: 1,
overflowY: 'auto',
display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- minHeight: '200px'
+ height: '500px',
+ whiteSpace: 'pre-wrap', // Keep line breaks
+ '&::-webkit-scrollbar': {
+ width: '8px',
+ },
+ '&::-webkit-scrollbar-track': {
+ backgroundColor: '#f1f1f1',
+ },
+ '&::-webkit-scrollbar-thumb': {
+ backgroundColor: '#888',
+ borderRadius: '4px',
+ },
+ '&::-webkit-scrollbar-thumb:hover': {
+ backgroundColor: '#555',
+ },
}}
>
- {result || 'No output yet...'}
+ {result}
+ </Box>
+
+ <Typography variant="subtitle1" style={{ fontWeight: "bold", marginTop: 16 }}>
+ Variable Browser :
+ </Typography>
+ <Box
+ style={{
+ flexGrow: 1,
+ padding: 8,
+ border: "1px solid gray",
+ borderRadius: 4
+ }}
+ >
+ <TableContainer
+ component={Paper}
+ elevation={0}
+ style={{ maxHeight: 150 }}
+ >
+ <Table size="small" stickyHeader>
+ <TableHead>
+ <TableRow style={{ backgroundColor: "#e0e0e0" }}>
+ <TableCell
+ style={{
+ border: "1px solid gray",
+ fontWeight: "bold",
+ padding: "4px 8px",
+ }}
+ >
+ Name
+ </TableCell>
+ <TableCell
+ style={{
+ border: "1px solid gray",
+ fontWeight: "bold",
+ padding: "4px 8px",
+ }}
+ >
+ Value
+ </TableCell>
+ <TableCell
+ style={{
+ border: "1px solid gray",
+ fontWeight: "bold",
+ padding: "4px 8px",
+ }}
+ >
+ Type
+ </TableCell>
+ </TableRow>
+ </TableHead>
+ <TableBody>
+ {variables.length > 0 ? (
+ variables.map((variable, index) => (
+ <TableRow key={index}>
+ <TableCell style={{ border: "1px solid gray", padding: "4px 8px" }}>
+ {variable.name}
+ </TableCell>
+ <TableCell style={{ border: "1px solid gray", padding: "4px 8px" }}>
+ {variable.value}
+ </TableCell>
+ <TableCell style={{ border: "1px solid gray", padding: "4px 8px" }}>
+ {variable.type}
+ </TableCell>
+ </TableRow>
+ ))
+ ) : (
+ <TableRow>
+ <TableCell colSpan={3} align="center">
+ No variables available.
+ </TableCell>
+ </TableRow>
+ )}
+ </TableBody>
+ </Table>
+ </TableContainer>
</Box>
</Box>
+
</Box>
+
+
{/* Action Buttons */}
- <Box sx={{ mt: 4, display: 'flex', gap: 2 }}>
+ <Box sx={{ mt: 4, display: 'flex', gap: 4 }}>
<Button onClick={executeScript} color='primary' variant='contained'>
Execute
</Button>
diff --git a/blocks/eda-frontend/src/redux/saveSchematicSlice.js b/blocks/eda-frontend/src/redux/saveSchematicSlice.js
index 639e130b..7cfdcf3c 100644
--- a/blocks/eda-frontend/src/redux/saveSchematicSlice.js
+++ b/blocks/eda-frontend/src/redux/saveSchematicSlice.js
@@ -8,6 +8,7 @@ const initialState = {
description: '',
xmlData: null,
scriptDump: '',
+ showDot: false,
details: {},
isLoading: false,
isSaved: null,
@@ -186,6 +187,9 @@ const saveSchematicSlice = createSlice({
},
setSchScriptDump: (state, action) => {
state.scriptDump = action.payload
+ },
+ setShowDot: (state, action) => {
+ state.showDot = action.payload
}
},
extraReducers: (builder) => {
@@ -214,6 +218,7 @@ const saveSchematicSlice = createSlice({
state.title = action.payload.name
state.xmlData = action.payload.data_dump
state.scriptDump = action.payload.script_dump
+ state.showDot = action.payload.script_dump !== ''
})
.addCase(fetchSchematic.rejected, (state) => {
state.isLoading = false
@@ -230,6 +235,7 @@ const saveSchematicSlice = createSlice({
state.title = action.payload.name
state.xmlData = action.payload.data_dump
state.scriptDump = action.payload.script_dump
+ state.showDot = action.payload.script_dump !== ''
})
.addCase(fetchDiagram.rejected, (state) => {
state.isLoading = false
@@ -257,6 +263,7 @@ const saveSchematicSlice = createSlice({
state.title = action.payload.name
state.xmlData = action.payload.data_dump
state.scriptDump = action.payload.script_dump
+ state.showDot = action.payload.script_dump !== ''
})
.addCase(openLocalSch.rejected, (state) => {
state.isLoading = false
@@ -269,7 +276,8 @@ export const {
setSchTitle,
setSchDescription,
setSchXmlData,
- setSchScriptDump
+ setSchScriptDump,
+ setShowDot
} = saveSchematicSlice.actions
export default saveSchematicSlice.reducer
diff --git a/blocks/simulationAPI/helpers/config.py b/blocks/simulationAPI/helpers/config.py
index 9bc8bce3..0db1da84 100644
--- a/blocks/simulationAPI/helpers/config.py
+++ b/blocks/simulationAPI/helpers/config.py
@@ -11,6 +11,8 @@ SCILAB_START_INSTANCES = int(os.environ.get('SCILAB_START_INSTANCES', '2'))
SCILAB_MAX_INSTANCES = int(os.environ.get('SCILAB_MAX_INSTANCES', '3'))
SCILAB_INSTANCE_RETRY_INTERVAL = int(os.environ.get('SCILAB_INSTANCE_RETRY_INTERVAL', '5'))
+SCILAB_INSTANCE_TIMEOUT_INTERVAL = 300
+
# Following are system command which are not permitted in sci files
# (Reference scilab-on-cloud project)
SYSTEM_COMMANDS = (
@@ -21,3 +23,8 @@ SPECIAL_CHARACTERS = r'["\'\\]'
# The directory where images are created
IMAGEDIR = 'images'
+
+# Set CREATEIMAGE to True to create img_test.jpg in IMAGEDIR
+CREATEIMAGE = False
+
+REMOVEFILE = True
diff --git a/blocks/simulationAPI/helpers/ngspice_helper.py b/blocks/simulationAPI/helpers/ngspice_helper.py
index c5eb8e71..3b466760 100644
--- a/blocks/simulationAPI/helpers/ngspice_helper.py
+++ b/blocks/simulationAPI/helpers/ngspice_helper.py
@@ -13,6 +13,7 @@ from django.db.models import Case, F, Value, When
from django.utils.timezone import now
from simulationAPI.models import Task
+from simulationAPI.helpers.scilab_manager import start_scilab, upload
logger = get_task_logger(__name__)
XmlToXcos = join(settings.BASE_DIR, 'Xcos/XmlToXcos.sh')
@@ -50,8 +51,13 @@ class CannotRunParser(Exception):
def update_task_status(task_id, status, meta=None):
+ print("status:", status, task_id)
# Update Celery backend state
- current_task.update_state(state=status, meta=meta or {})
+ if current_task is not None:
+ try:
+ current_task.update_state(state=status, meta=meta or {})
+ except Exception as e:
+ print(f"Error updating Celery task state: {e}")
# Update Django database
Task.objects.filter(task_id=task_id).update(
@@ -110,74 +116,47 @@ def CreateXcos(file_path, parameters, task_id):
return xcosfile
-def ExecXml(task, task_name):
+def ExecXml(task, task_name, workspace_file):
task_id = task.task_id
file_path = task.file.path
+
current_dir = settings.MEDIA_ROOT + '/' + str(task_id)
try:
+ # Create xcos file
xcosfile = CreateXml(file_path, task.parameters, task_id)
- (logfilefd, log_name) = mkstemp(prefix=datetime.now().strftime(
- 'scilab-log-%Y%m%d-'), suffix='.txt', dir=current_dir)
-
- if logfilefd != LOGFILEFD:
- os.dup2(logfilefd, LOGFILEFD)
- os.close(logfilefd)
-
- task.log_name = log_name
- task.save()
-
- logger.info('will run %s %s> %s', SCILAB_CMD[0], LOGFILEFD, log_name)
- logger.info('running command %s', SCILAB_CMD[-1])
- proc = subprocess.Popen(
- SCILAB_CMD,
- stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- start_new_session=True, universal_newlines=True, cwd=current_dir,
- pass_fds=(LOGFILEFD, ))
-
- os.close(LOGFILEFD)
-
- update_task_status(task_id, 'STREAMING',
- meta={'current_process': 'Processed Xml, Streaming Output'})
-
- cmd = "try;"
- cmd += "chdir('%s');" % current_dir
- cmd += "loadXcosLibs();"
- cmd += "importXcosDiagram('%s');" % xcosfile
- cmd += "xcos_simulate(scs_m,4);"
- cmd += SCILAB_END
-
- logger.info('running command %s', cmd)
- proc.stdin.write(cmd)
-
- (out, err) = proc.communicate()
-
- maxlines = 15
- logger.info('Ran %s', SCILAB_CMD[0])
- if out:
- out = out.strip()
- if out:
- out = '\n'.join(re.split(r'\n+', out, maxlines + 1)[:maxlines])
- logger.info('out=%s', out)
- if err:
- err = re.sub(r'Undefined variable: helpbrowser_update', '', err)
- err = err.strip()
- if err:
- err = '\n'.join(re.split(r'\n+', err, maxlines + 1)[:maxlines])
- logger.info('err=%s', err)
-
- task.returncode = proc.returncode
- task.save()
-
- return 'Streaming'
+
+ upload(task.session, task, xcosfile)
+ result = start_scilab(task.session, task, xcosfile)
+
+ if result == "":
+ logger.info('Simulation completed successfully for task %s', task_id)
+ update_task_status(task_id, 'SUCCESS',
+ meta={'current_process': 'Simulation Completed'})
+ return 'Streaming'
+ else:
+ logger.warning('Simulation failed for task %s: %s', task_id, result)
+ update_task_status(task_id, 'FAILURE',
+ meta={'current_process': result})
+ return 'Failure'
+
except BaseException as e:
- logger.exception('Encountered Exception:')
- logger.info('removing %s', file_path)
- os.remove(file_path)
+ logger.exception('Encountered Exception during XML Execution:')
+ logger.info('Cleaning up files for task %s', task_id)
+ # Cleanup
+ try:
+ os.remove(file_path)
+ except FileNotFoundError:
+ pass
target = os.listdir(current_dir)
for item in target:
- logger.info('removing %s', item)
- os.remove(join(current_dir, item))
- logger.info('removing %s', current_dir)
- os.rmdir(current_dir)
- logger.info('Deleted Files')
+ try:
+ os.remove(join(current_dir, item))
+ except FileNotFoundError:
+ continue
+ try:
+ os.rmdir(current_dir)
+ except OSError:
+ pass
+ logger.info('Deleted Files and Directory for task %s', task_id)
raise e
+
diff --git a/blocks/simulationAPI/helpers/scilab_manager.py b/blocks/simulationAPI/helpers/scilab_manager.py
index 79000d91..fb693167 100644
--- a/blocks/simulationAPI/helpers/scilab_manager.py
+++ b/blocks/simulationAPI/helpers/scilab_manager.py
@@ -7,8 +7,9 @@ from gevent.event import Event
from gevent.lock import RLock
import glob
import json
+import fileinput
import os
-from os.path import abspath, exists, isfile, join
+from os.path import abspath, exists, isfile, join, splitext
import re
import signal
import subprocess
@@ -17,13 +18,18 @@ from threading import current_thread
from time import time
import unicodedata
import uuid
+import logging
+from xml.dom import minidom
+import shutil
from simulationAPI.helpers import config
+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'blocks.settings')
# Scilab dir
SCILAB_DIR = abspath(settings.SCILAB_DIR)
+READCONTENTFILE = abspath("resources/Read_Content.txt")
SCILAB = join(SCILAB_DIR, 'bin', 'scilab-adv-cli')
BASEDIR = abspath('src/static')
IMAGEDIR = join(BASEDIR, config.IMAGEDIR)
@@ -66,7 +72,8 @@ SCILAB_CMD = [SCILAB,
"-nouserstartup",
"-nb",
"-nw",
- "-e", SCILAB_START]
+ "-e", SCILAB_START
+ ]
USER_DATA = {}
@@ -222,7 +229,7 @@ class UserData:
def __init__(self):
self.sessiondir = mkdtemp(
prefix=datetime.now().strftime('%Y%m%d.'), dir=SESSIONDIR)
- self.diagrams = []
+ self.diagrams = {}
self.datafiles = []
self.scripts = {}
self.scriptcount = 0
@@ -230,6 +237,18 @@ class UserData:
self.diagramlock = RLock()
self.timestamp = time()
+ def __str__(self):
+ return (f"UserData(sessiondir={self.sessiondir}, "
+ f"diagrams={len(self.diagrams)}, "
+ f"datafiles={len(self.datafiles)}, "
+ f"scripts={list(self.scripts.keys())}, "
+ f"scriptcount={self.scriptcount}, "
+ f"scifile={self.scifile}, "
+ f"timestamp={self.timestamp})")
+
+ def __repr__(self):
+ return self.__str__()
+
def getscriptcount(self):
with self.diagramlock:
rv = self.scriptcount
@@ -238,7 +257,7 @@ class UserData:
return str(rv)
def clean(self):
- for diagram in self.diagrams:
+ for diagram in self.diagrams.values():
diagram.clean()
self.diagrams = None
for script in self.scripts:
@@ -615,15 +634,22 @@ def prestart_scilab():
return (proc, log_name)
-def run_scilab(command, base, createlogfile=False, timeout=70):
+def run_scilab(command, base, createlogfile=False, timeout=1800):
instance = get_scilab_instance()
if instance is None:
logger.error('cannot run command %s', command)
return None
- cmd = command + SCILAB_END
+ logger.info('Scilab instance log file: %s', instance.log_name)
+ cmd = 'try;' + command + SCILAB_END + '\n'
logger.info('running command %s', cmd)
instance.proc.stdin.write(cmd)
+ instance.proc.stdin.flush()
+
+ # output, error = instance.proc.communicate(timeout=timeout)
+ # with open(instance.log_name, 'a') as log:
+ # log.write(output if output else '')
+ # log.write(error if error else '')
if not createlogfile:
remove(instance.log_name)
@@ -673,17 +699,20 @@ def uploadscript(session, task):
'''
Below route is called for uploading script file.
'''
- (script, sessiondir) = add_script(session)
+ (script, sessiondir) = add_script(session, task)
- file = task.file.name
+ file = task.file
if not file:
msg = "Upload Error\n"
rv = {'msg': msg}
- return JsonResponse(rv)
+ return rv
fname = join(sessiondir, SCRIPT_FILES_FOLDER,
- script.script_id + '_script.sce')
- file.save(fname)
+ f"{script.script_id}_script.sce")
+ # file.save(fname)
+ with open(fname, 'wb+') as destination:
+ for chunk in file.chunks():
+ destination.write(chunk)
script.filename = fname
if is_unsafe_script(fname):
@@ -691,25 +720,30 @@ def uploadscript(session, task):
"Please edit the script again.\n")
script.status = -1
rv = {'status': script.status, 'msg': msg}
- return JsonResponse(rv)
+ return rv
- wfname = join(sessiondir, SCRIPT_FILES_FOLDER,
- script.script_id + '_script_workspace.dat')
+ wfname = join(sessiondir, WORKSPACE_FILES_FOLDER,
+ f"{script.script_id}_script_workspace.dat")
script.workspace_filename = wfname
command = "exec('%s');save('%s');" % (fname, wfname)
script.instance = run_scilab(command, script)
+
if script.instance is None:
msg = "Resource not available"
script.status = -2
rv = {'status': script.status, 'msg': msg}
- return JsonResponse(rv)
+ return rv
+
+ # Save workspace file in task model
+ task.workspace_file = wfname
+ task.save()
msg = ''
script.status = 1
- rv = {'script_id': script.script_id, 'status': script.status, 'msg': msg}
- return JsonResponse(rv)
+ rv = {'task_id': task.task_id, 'script_id': script.script_id, 'status': script.status, 'msg': msg}
+ return rv
def clean_output(s):
@@ -724,24 +758,24 @@ def clean_output(s):
return s
-def getscriptoutput(session):
+def getscriptoutput(session, task):
'''
Below route is called for uploading script file.
'''
- script = get_script(session, get_script_id())
+ script = get_script(session, task)
if script is None:
# when called with same script_id again or with incorrect script_id
logger.warning('no script')
msg = "no script"
rv = {'msg': msg}
- return JsonResponse(rv)
+ return rv
instance = script.instance
if instance is None:
logger.warning('no instance')
msg = "no instance"
rv = {'msg': msg}
- return JsonResponse(rv)
+ return rv
proc = instance.proc
@@ -758,7 +792,7 @@ def getscriptoutput(session):
msg = 'Script stopped'
script.status = -5
rv = {'status': script.status, 'msg': msg, 'output': output}
- return JsonResponse(rv)
+ return rv
if returncode > 0:
logger.info('return code is %s', returncode)
if output:
@@ -771,7 +805,7 @@ def getscriptoutput(session):
"Please edit the script and execute again.\n")
script.status = -3
rv = {'status': script.status, 'msg': msg, 'output': output}
- return JsonResponse(rv)
+ return rv
logger.info('workspace for %s saved in %s',
script.script_id, script.workspace_filename)
@@ -786,7 +820,7 @@ def getscriptoutput(session):
msg = "Resource not available"
script.status = -2
rv = {'status': script.status, 'msg': msg}
- return JsonResponse(rv)
+ return rv
proc = instance.proc
listoutput = proc.communicate(timeout=10)[0]
@@ -799,7 +833,7 @@ def getscriptoutput(session):
msg = 'Script stopped'
script.status = -5
rv = {'status': script.status, 'msg': msg, 'output': listoutput}
- return JsonResponse(rv)
+ return rv
if returncode > 0:
logger.info('return code is %s', returncode)
if listoutput:
@@ -815,26 +849,26 @@ def getscriptoutput(session):
rv = {'script_id': script.script_id, 'status': script.status,
'msg': msg, 'output': output, 'returncode': returncode,
'variables': variables}
- return JsonResponse(rv)
+ return rv
except subprocess.TimeoutExpired:
kill_script(script)
msg = 'Timeout'
script.status = -4
rv = {'status': script.status, 'msg': msg}
- return JsonResponse(rv)
+ return rv
except UnicodeDecodeError:
kill_script(script)
msg = 'Unicode Decode Error'
script.status = -6
rv = {'status': script.status, 'msg': msg}
- return JsonResponse(rv)
+ return rv
-def sendfile(session):
+def sendfile(session, task):
'''
This route is used in chart.js for sending image filename
'''
- diagram = get_diagram(session, get_request_id())
+ diagram = get_diagram(session, task)
if diagram is None:
logger.warning('no diagram')
return ''
@@ -916,12 +950,12 @@ def load_variables(filename):
return command
-def start_scilab(session):
+def start_scilab(session, task, xcosfile):
'''
function to execute xcos file using scilab (scilab-adv-cli), access log
file written by scilab
'''
- diagram = get_diagram(session, get_request_id())
+ diagram = get_diagram(session, task)
if diagram is None:
logger.warning('no diagram')
return "error"
@@ -1001,6 +1035,8 @@ def start_scilab(session):
instance = diagram.instance
logger.info('log_name=%s', instance.log_name)
+ task.log_name = instance.log_name
+ task.save()
# Start sending log to chart function for creating chart
try:
@@ -1069,15 +1105,313 @@ def stopDetailsThread(diagram):
remove(fn)
-def get_diagram(session, xcos_file_id, remove=False):
- if not xcos_file_id:
+def upload(session, task, xcosfile):
+ '''Route that will process the file upload'''
+ # Get the file
+ file = xcosfile
+ # Check if the file is not null
+ if not file:
+ return "error"
+ # flags to check if both TOWS_c and FROMWSB are present
+ flag1 = 0
+ flag2 = 0
+ list1 = []
+ list2 = []
+ # Make the filename safe, remove unsupported chars
+ (diagram, scripts, sessiondir) = add_diagram(session, task)
+
+ script = get_script(session, task, scripts=scripts)
+ if script is not None:
+ diagram.workspace_filename = script.workspace_filename
+ # Save the file in xml extension and using it for further modification
+ # by using xml parser
+ temp_file_xml_name = diagram.diagram_id + ".xml"
+ shutil.copy(xcosfile, temp_file_xml_name)
+ # file.save(temp_file_xml_name)
+ new_xml = minidom.parse(temp_file_xml_name)
+
+ # to identify if we have to load or save to workspace or neither #0 if
+ # neither TOWS_c or FROMWSB found
+ blocks = new_xml.getElementsByTagName("BasicBlock")
+ tk_is_present = False
+ pattern = re.compile(r"<SplitBlock")
+ for i, line in enumerate(open(temp_file_xml_name)):
+ for match in re.finditer(pattern, line):
+ list1.append(i + 1)
+ pattern1 = re.compile(r"<ControlPort")
+ for i, line in enumerate(open(temp_file_xml_name)):
+ for match in re.finditer(pattern1, line):
+ list2.append(i + 1)
+ pattern2 = re.compile(r"<ImplicitInputPort")
+ count1 = 0
+
+ for i, line in enumerate(open(temp_file_xml_name)):
+ for match in re.finditer(pattern2, line):
+ count1 += 1
+ if count1 >= 1:
+ splitline = []
+ count = 0
+ for i in range(len(list1)):
+ for j in range(len(list2)):
+ if list2[j] == list1[i] + 3:
+ count += 1
+ splitline.append(list1[i])
+ blocksplit = new_xml.getElementsByTagName("SplitBlock")
+ block_ids = [] # this stores the id of split blocks
+ for block in blocksplit:
+ if block.getAttribute("style") == "SPLIT_f":
+ block_ids.append(int(block.getAttribute("id")))
+ compsplit = []
+ for i in range(len(splitline)):
+ for j in range(len(list1)):
+ if splitline[i] == list1[j]:
+ compsplit.append(j)
+
+ finalsplit = []
+ for i in range(len(compsplit)):
+ finalsplit.append(block_ids[compsplit[i]])
+
+ blockcontrol = new_xml.getElementsByTagName("ControlPort")
+ for block in blockcontrol:
+ for i in range(len(finalsplit)):
+ # match the lines with the parent of our spliblocks which
+ # we need to change
+ if block.getAttribute("parent") == str(finalsplit[i]):
+ block.setAttribute('id', '-1')
+
+ blockcommand = new_xml.getElementsByTagName("CommandPort")
+ for block in blockcommand:
+ for i in range(len(finalsplit)):
+ if block.getAttribute("parent") == str(finalsplit[i]):
+ block.setAttribute('id', '-1')
+
+ # here we take the ids of command controllink which we will search
+ # and change
+ finalchangeid = []
+ for i in range(len(finalsplit)):
+ finalchangeid.append(finalsplit[i] + 4)
+ finalchangeid.append(finalsplit[i] + 5)
+
+ # here we save the contents
+ with open(temp_file_xml_name, 'w') as f:
+ f.write(new_xml.toxml())
+
+ with open(temp_file_xml_name, "r") as f:
+ newline = []
+ i = 0
+ for word in f.readlines():
+
+ if "<CommandControlLink id=" in word:
+ temp_word = ""
+ for i in range(len(finalchangeid)):
+ fcid = str(finalchangeid[i])
+ srch = '<CommandControlLink id="' + fcid + '"'
+ if srch in word:
+ rplc = '<ImplicitLink id="' + fcid + '"'
+ temp_word = word.replace(srch, rplc)
+ i += 1
+ if temp_word != "":
+ newline.append(temp_word)
+ else:
+ newline.append(word)
+ else:
+ newline.append(word)
+ with open(temp_file_xml_name, "w") as f:
+ for line in newline:
+ f.writelines(line)
+ with open(temp_file_xml_name, "r") as in_file:
+ buf = in_file.readlines()
+ # length=len(finalsplit)
+ # return finalsplit
+ with open(temp_file_xml_name, "w") as out_file:
+ for line in buf:
+ for i in range(len(finalsplit)):
+ fs = str(finalsplit[i])
+ srch = ('<ControlPort connectable="0" '
+ 'dataType="UNKNOW_TYPE" id="-1" ordering="1" '
+ 'parent="' + fs + '"')
+ if srch in line:
+ line = (
+ '\t <ImplicitInputPort connectable="0" '
+ 'dataType="UNKNOW_TYPE" '
+ 'id="' + str(finalsplit[i] + 1) + '" '
+ 'ordering="1" parent="' + fs + '" '
+ 'style="ImplicitInputPort">\n'
+ '\t\t<mxGeometry as="geometry" height="10" '
+ 'relative="1" width="10" y="0.5000">\n'
+ '\t\t</mxGeometry>\n'
+ '\t </ImplicitInputPort>\n'
+ '\t <ImplicitOutputPort connectable="0" '
+ 'dataType="UNKNOW_TYPE" '
+ 'id="' + str(finalsplit[i] + 2) + '" '
+ 'ordering="1" parent="' + fs + '" '
+ 'style="ImplicitOutputPort">\n'
+ '\t\t<mxGeometry as="geometry" height="10" '
+ 'relative="1" width="10" y="0.5000">\n'
+ '\t\t</mxGeometry>\n'
+ '\t </ImplicitOutputPort>\n'
+ '\t <ImplicitOutputPort connectable="0" '
+ 'dataType="UNKNOW_TYPE" '
+ 'id="' + str(finalsplit[i] + 3) + '" '
+ 'ordering="1" parent="' + fs + '" '
+ 'style="ImplicitOutputPort">\n'
+ '\t\t<mxGeometry as="geometry" height="10" '
+ 'relative="1" width="10" y="0.5000">\n'
+ '\t\t</mxGeometry>\n'
+ '\t </ImplicitOutputPort>\n' + line)
+
+ out_file.write(line)
+ list3 = []
+ implitdetect = []
+ # return temp_file_xml_name
+ for i in range(len(finalsplit)):
+ implitdetect.append(finalsplit[i] + 5)
+ implitdetect.append(finalsplit[i] + 6)
+ for i in range(len(implitdetect)):
+ pattern3 = re.compile(
+ "<ImplicitLink id=\"" + str(implitdetect[i]) + "\"")
+ for i, line in enumerate(open(temp_file_xml_name)):
+ for match in re.finditer(pattern3, line):
+ list3.append(i - 1)
+ with open(temp_file_xml_name, 'r+') as f:
+ data = f.read().splitlines()
+ replace = list3
+ for i in replace:
+ data[i] = '\t </ImplicitLink>'
+ f.seek(0)
+ f.write('\n'.join(data))
+ f.truncate()
+ fname = join(sessiondir, UPLOAD_FOLDER,
+ splitext(temp_file_xml_name)[0] + ".xcos")
+ os.rename(temp_file_xml_name, fname)
+ diagram.xcos_file_name = fname
+ return diagram.diagram_id
+
+ # List to contain all affich blocks
+ blockaffich = new_xml.getElementsByTagName("AfficheBlock")
+ for block in blockaffich:
+ interfaceFunctionName = block.getAttribute("interfaceFunctionName")
+ if interfaceFunctionName == "AFFICH_m":
+ diagram.workspace_counter = 4
+
+ # List to contain all the block IDs of tkscales so that we can create
+ # read blocks with these IDs
+ block_id = []
+ for block in blocks:
+ interfaceFunctionName = block.getAttribute("interfaceFunctionName")
+ if interfaceFunctionName == "TKSCALE":
+ block_id.append(block.getAttribute("id"))
+ block.setAttribute('id', '-1')
+ tk_is_present = True
+ # Changed the ID of tkscales to -1 so that virtually the
+ # tkscale blocks get disconnected from diagram at the backend
+ # Taking workspace_counter 1 for TOWS_c and 2 for FROMWSB
+ elif interfaceFunctionName == "scifunc_block_m":
+ diagram.workspace_counter = 5
+ elif interfaceFunctionName == "TOWS_c":
+ if block.childNodes:
+ for node in block.childNodes:
+ if not isinstance(node, minidom.Element):
+ continue
+ if node.getAttribute("as") != "exprs":
+ continue
+ if node.childNodes is None:
+ continue
+ childCount = 0
+ for childChildNode in node.childNodes:
+ if not isinstance(childChildNode, minidom.Element):
+ continue
+ childCount += 1
+ if childCount != 2:
+ continue
+ value = childChildNode.getAttribute("value")
+ if value is not None:
+ diagram.save_variables.add(value)
+ break
+ diagram.workspace_counter = 1
+ flag1 = 1
+ elif interfaceFunctionName == "FROMWSB":
+ diagram.workspace_counter = 2
+ flag2 = 1
+ if diagram.save_variables:
+ logger.info("save variables = %s", diagram.save_variables)
+ if flag1 and flag2:
+ # Both TOWS_c and FROMWSB are present
+ diagram.workspace_counter = 3
+ # Hardcoded the real time scaling to 1.0 (i.e., no scaling of time
+ # occurs) only if tkscale is present
+ if tk_is_present:
+ for dia in new_xml.getElementsByTagName("XcosDiagram"):
+ dia.setAttribute('realTimeScaling', '1.0')
+
+ # Save the changes made by parser
+ with open(temp_file_xml_name, 'w') as f:
+ f.write(new_xml.toxml())
+
+ # In front of block tkscale printing the block corresponding to read
+ # function and assigning corresponding values
+ skipblock = False
+ for line in fileinput.input(temp_file_xml_name, inplace=1):
+
+ if 'interfaceFunctionName=\"TKSCALE\"' in line:
+ # change the block ID
+ i = diagram.tk_count
+ print('<BasicBlock blockType="d" id="', block_id[i], '" '
+ 'interfaceFunctionName="RFILE_f" parent="1" '
+ 'simulationFunctionName="readf" '
+ 'simulationFunctionType="DEFAULT" style="RFILE_f">',
+ sep='')
+ print('<ScilabString as="exprs" height="5" width="1">')
+ print('<data column="0" line="0" value="1"/>')
+ # Value equal to 1 implies take readings from first column in
+ # the file
+ print('<data column="0" line="1" value="2"/>')
+ # Path to the file from which read block obtains the values
+ fname = join(diagram.sessiondir, VALUES_FOLDER,
+ diagram.diagram_id + "_tk" + str(i + 1) + ".txt")
+ print('<data column="0" line="2" value="', fname, '"/>',
+ sep='')
+ print('<data column="0" line="3" value="(2(e10.3,1x))"/>')
+ # (2(e10.3,1x)) The format in which numbers are written
+ # Two columns with base 10 and 3 digits after decimal and 1x
+ # represents 1 unit space between two columns.
+ print('<data column="0" line="4" value="2"/>')
+ print('</ScilabString>')
+ print('<ScilabDouble as="realParameters" '
+ 'height="0" width="0"/>')
+ print('<ScilabDouble as="integerParameters" '
+ 'height="105" width="1">')
+ diagram.tk_count += 1
+ # The remaining part of the block is read from the
+ # Read_Content.txt file and written to the xml file
+ with open(READCONTENTFILE, "r") as read_file:
+ for line_content in read_file:
+ print(line_content, end='')
+ skipblock = True
+ elif skipblock:
+ if '</BasicBlock>' in line:
+ skipblock = False
+ else:
+ print(line, end='')
+
+ # Changing the file extension from xml to xcos
+ fname = join(sessiondir, UPLOAD_FOLDER,
+ splitext(temp_file_xml_name)[0] + ".xcos")
+ # Move the xcos file to uploads directory
+ os.rename(temp_file_xml_name, fname)
+ diagram.xcos_file_name = fname
+ return diagram.diagram_id
+
+
+def get_diagram(session, task, remove=False):
+ if not task:
logger.warning('no id')
return None
- xcos_file_id = int(xcos_file_id)
+ xcos_file_id = task.task_id
(diagrams, __, __, __, __, __, __) = init_session(session)
- if xcos_file_id < 0 or xcos_file_id >= len(diagrams):
+ if xcos_file_id not in diagrams:
logger.warning('id %s not in diagrams', xcos_file_id)
return None
@@ -1089,49 +1423,45 @@ def get_diagram(session, xcos_file_id, remove=False):
return diagram
-def add_diagram(session):
+def add_diagram(session, task):
(diagrams, scripts, __, __, __, sessiondir, diagramlock) = init_session(session)
with diagramlock:
diagram = Diagram()
diagram.diagram_id = str(len(diagrams))
diagram.sessiondir = sessiondir
- diagrams.append(diagram)
+ # diagrams.append(diagram)
+ diagrams[task.task_id] = diagram
return (diagram, scripts, sessiondir)
-def get_script(session, script_id, scripts=None, remove=False):
- if script_id is None:
- return None
- if not script_id:
- logger.warning('no id')
+def get_script(session, task, scripts=None, remove=False):
+ if task is None:
return None
if scripts is None:
(__, scripts, __, __, __, __, __) = init_session(session)
- if script_id not in scripts:
- logger.warning('id %s not in scripts', script_id)
+ if task.task_id not in scripts:
+ logger.warning('id %s not in scripts', task.task_id)
return None
- script = scripts[script_id]
+ script = scripts[task.task_id]
if remove:
- del scripts[script_id]
+ del scripts[task.task_id]
return script
-def add_script(session):
- (__, scripts, getscriptcount, __, __, sessiondir, __) = init_session(session)
-
- script_id = getscriptcount()
+def add_script(session, task):
+ (__, scripts, __, __, __, sessiondir, __) = init_session(session)
script = Script()
- script.script_id = script_id
+ script.script_id = task.task_id
script.sessiondir = sessiondir
- scripts[script_id] = script
+ scripts[task.task_id] = script
return (script, sessiondir)
@@ -1192,24 +1522,6 @@ def get_request_id(request, key='id'):
return ''
-def get_script_id(request, key='script_id', default=''):
- form = request.form
- if form is None:
- logger.warning('No form in request')
- return default
- if key not in form:
- logger.warning('No %s in request.form', key)
- return default
- value = form[key]
- if re.fullmatch(r'[0-9]+', value):
- return value
- displayvalue = value if len(
- value) <= DISPLAY_LIMIT + 3 else value[:DISPLAY_LIMIT] + '...'
- logger.warning('Invalid value %s for %s in request.form',
- displayvalue, key)
- return default
-
-
def internal_fun(session, task, internal_key):
(__, __, __, scifile, __, sessiondir, __) = init_session(session)
@@ -1310,10 +1622,10 @@ def clean_text_2(s, forindex):
return s
-def kill_scilab(diagram=None, session=None):
+def kill_scilab(diagram=None, session=None, task=None):
'''Define function to kill scilab(if still running) and remove files'''
if diagram is None:
- diagram = get_diagram(session, get_request_id(), True)
+ diagram = get_diagram(session, task, True)
if diagram is None:
logger.warning('no diagram')
@@ -1335,10 +1647,10 @@ def kill_scilab(diagram=None, session=None):
stopDetailsThread(diagram)
-def kill_script(script=None, session=None):
+def kill_script(script=None, session=None, task=None):
'''Below route is called for stopping a running script file.'''
if script is None:
- script = get_script(session, get_script_id(), remove=True)
+ script = get_script(session, task, remove=True)
if script is None:
# when called with same script_id again or with incorrect script_id
logger.warning('no script')
diff --git a/blocks/simulationAPI/tasks.py b/blocks/simulationAPI/tasks.py
index e13c73bb..5d18d789 100644
--- a/blocks/simulationAPI/tasks.py
+++ b/blocks/simulationAPI/tasks.py
@@ -8,6 +8,7 @@ import traceback
from blocks.celery_tasks import app
from simulationAPI.helpers.ngspice_helper import ExecXml, update_task_status
from simulationAPI.models import Task
+from simulationAPI.helpers.scilab_manager import uploadscript, getscriptoutput
logger = get_task_logger(__name__)
@@ -27,26 +28,35 @@ def release_lock(lock):
def process_task(self, task_id):
task = Task.objects.get(task_id=task_id)
session_id = task.session.session_id
+ task_type = task.type
current_thread().name = f"{session_id[:6]}:{task_id[:8]}"
lock = acquire_lock(session_id) # Prevent multiple runs per session
try:
- logger.info("Processing %s %s %s",
- task_id, task.file.path, task.session.app_name)
+ logger.info("Processing %s %s %s %s",
+ task_id, task.file.path, task.session.app_name, task.workspace_file)
update_task_status(task_id, 'STARTED',
meta={'current_process': 'Started Processing File'})
- output = ExecXml(task, self.name)
- if output == "Streaming":
- state = 'STREAMING'
- current_process = 'Processed Xml, Streaming Output'
- elif output == "Success":
+ if task_type == 'SCRIPT':
+ output = uploadscript(task.session, task)
+ output = getscriptoutput(task.session, task)
state = 'SUCCESS'
- current_process = 'Processed Xml, Loading Output'
+ update_task_status(task_id, state,
+ meta=output)
+ else:
+ output = ExecXml(task, self.name, task.workspace_file)
+ if output == "Streaming":
+ state = 'STREAMING'
+ current_process = 'Processed Xml, Streaming Output'
+ elif output == "Success":
+ state = 'SUCCESS'
+ current_process = 'Processed Xml, Loading Output'
+
+ update_task_status(task_id, state,
+ meta={'current_process': current_process})
- update_task_status(task_id, state,
- meta={'current_process': current_process})
return output
except Exception as e:
@@ -60,3 +70,4 @@ def process_task(self, task_id):
finally:
release_lock(lock) # Ensure lock is always released
+
diff --git a/blocks/simulationAPI/urls.py b/blocks/simulationAPI/urls.py
index 5e37d066..1714a768 100644
--- a/blocks/simulationAPI/urls.py
+++ b/blocks/simulationAPI/urls.py
@@ -18,4 +18,5 @@ urlpatterns = [
path('cancel/<uuid:task_id>', simulationAPI_views.CancelTaskView.as_view(), name='cancel'),
path('get_session', simulationAPI_views.get_session, name='get_session'),
+
]
diff --git a/blocks/simulationAPI/views.py b/blocks/simulationAPI/views.py
index dd1a7758..625aa774 100644
--- a/blocks/simulationAPI/views.py
+++ b/blocks/simulationAPI/views.py
@@ -17,7 +17,8 @@ from simulationAPI.models import Task, Session
from simulationAPI.negotiation import IgnoreClientContentNegotiation
from simulationAPI.serializers import TaskSerializer
from simulationAPI.tasks import process_task
-from simulationAPI.helpers.ngspice_helper import CreateXcos
+from simulationAPI.helpers.ngspice_helper import CreateXcos, update_task_status
+
SCILAB_INSTANCE_TIMEOUT_INTERVAL = 300
@@ -63,15 +64,35 @@ class XmlUploader(APIView):
serializer = TaskSerializer(data=request.data, context={'request': request})
if serializer.is_valid():
- serializer.save()
+ task = serializer.save()
+
+ task_type = request.data.get('type')
+ script_task_id = request.data.get('script_task_id')
+
+ if task_type == 'XCOS' and script_task_id:
+ try:
+ script_task = Task.objects.get(task_id=script_task_id, type='SCRIPT')
+ if script_task.workspace_file:
+ task.workspace_file = script_task.workspace_file
+ task.save()
+ logger.info(f'Copied workspace file from script task {script_task_id} to xcos task {task.task_id}')
+ else:
+ logger.warning(f'Script task {script_task_id} does not have a workspace file')
+ except Task.DoesNotExist:
+ logger.warning(f'Script task {script_task_id} not found')
+ # serializer.save()
task_id = serializer.data['task_id']
celery_task = process_task.apply_async(
kwargs={'task_id': str(task_id)}, task_id=str(task_id))
- # celery_task = process_task.delay(str(task_id))
- response_data = {
- 'state': celery_task.state,
- 'details': serializer.data,
- }
+ if task_type == 'XCOS':
+ response_data = {
+ 'state': celery_task.state,
+ 'details': serializer.data,
+ }
+ else:
+ rv = celery_task.get(timeout=10)
+ response_data = {**rv, 'task_id':task_id}
+
return Response(response_data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@@ -349,6 +370,7 @@ class StreamView(APIView):
else:
logger.info('lines = %s, log size = %s', lineno, log_size)
+ update_task_status(task_id, 'SUCCESS')
# Notify Client
yield "event: DONE\ndata: None\n\n"