diff options
author | Suchita Lad | 2025-04-02 17:13:23 +0530 |
---|---|---|
committer | Suchita Lad | 2025-04-02 17:13:23 +0530 |
commit | b022d2ffddf5591929f7b902961be33165a17cac (patch) | |
tree | 16dc6e83d08ec21288235e6c9f9bee164e4cae7f | |
parent | a068b1fd9f936675f81e90f83589923f39c6dc10 (diff) | |
download | Common-Interface-Project-b022d2ffddf5591929f7b902961be33165a17cac.tar.gz Common-Interface-Project-b022d2ffddf5591929f7b902961be33165a17cac.tar.bz2 Common-Interface-Project-b022d2ffddf5591929f7b902961be33165a17cac.zip |
Updated files to store workspace file in task model
-rw-r--r-- | blocks/eda-frontend/src/components/SchematicEditor/SimulationProperties.js | 15 | ||||
-rw-r--r-- | blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js | 12 | ||||
-rw-r--r-- | blocks/eda-frontend/src/redux/reducers/simulationReducer.js | 2 | ||||
-rw-r--r-- | blocks/simulationAPI/helpers/config.py | 5 | ||||
-rw-r--r-- | blocks/simulationAPI/helpers/ngspice_helper.py | 105 | ||||
-rw-r--r-- | blocks/simulationAPI/helpers/scilab_manager.py | 336 | ||||
-rw-r--r-- | blocks/simulationAPI/tasks.py | 10 | ||||
-rw-r--r-- | blocks/simulationAPI/views.py | 23 |
8 files changed, 410 insertions, 98 deletions
diff --git a/blocks/eda-frontend/src/components/SchematicEditor/SimulationProperties.js b/blocks/eda-frontend/src/components/SchematicEditor/SimulationProperties.js index 05216811..b79ccd72 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.netlistReducer.title) const isSimRes = useSelector(state => state.simulationReducer.isSimRes) + const scriptTaskId = useSelector(state => state.simulationReducer.scriptTaskId) const dispatch = useDispatch() const classes = useStyles() const [transientAnalysisControlLine, setTransientAnalysisControlLine] = useState({ @@ -86,11 +87,12 @@ export default function SimulationProperties () { 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 - function netlistConfig (file) { + 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 e5f20e54..aa335c35 100644 --- a/blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js +++ b/blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js @@ -346,16 +346,15 @@ export function ScriptScreen ({ isOpen, onClose }) { } const fetchScriptOutput = async (taskId) => { - console.log('Fetching script output for task:', taskId) try { const response = await api.get(`simulation/get_script_output/${taskId}`) const data = response.data setResult(data.output || 'No output available.') if (data.variables && Array.isArray(data.variables)) { - console.log('Variables:', data.variables) setVariables(data.variables) } + return data } catch (error) { console.error('Error fetching script output:', error) setResult('Error fetching script output.') @@ -379,14 +378,10 @@ export function ScriptScreen ({ isOpen, onClose }) { const taskId = res.details.task_id dispatch(setScriptTaskId(taskId)) - setTimeout(() => { fetchScriptOutput(taskId) - .then((response) => { - if (response.status === 200) { - const data = response.data - dispatch(setResult(data.output, data.variables)) - } + .then(() => { + }) }, 3000) }) @@ -417,6 +412,7 @@ export function ScriptScreen ({ isOpen, onClose }) { const resetCode = () => { dispatch(setSchScriptDump('')) + dispatch(setScriptTaskId('')) setResult('No output yet...') setVariables('') diff --git a/blocks/eda-frontend/src/redux/reducers/simulationReducer.js b/blocks/eda-frontend/src/redux/reducers/simulationReducer.js index 08b3c2d2..3a5f2fb7 100644 --- a/blocks/eda-frontend/src/redux/reducers/simulationReducer.js +++ b/blocks/eda-frontend/src/redux/reducers/simulationReducer.js @@ -45,7 +45,7 @@ export default function (state = initialState, action) { case actions.SET_SCRIPT_TASK_ID: { return { ...state, - scriptTaskId: action.payload.taskId + scriptTaskId: action.payload.scriptTaskId } } diff --git a/blocks/simulationAPI/helpers/config.py b/blocks/simulationAPI/helpers/config.py index c1593a68..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 = ( @@ -22,4 +24,7 @@ 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 ad4fd778..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 d0b7d8ec..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 @@ -18,13 +19,17 @@ 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) @@ -224,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 @@ -252,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: @@ -859,11 +864,11 @@ def getscriptoutput(session, task): 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 '' @@ -945,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" @@ -1030,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: @@ -1098,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 @@ -1118,14 +1423,15 @@ 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) @@ -1316,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') diff --git a/blocks/simulationAPI/tasks.py b/blocks/simulationAPI/tasks.py index f41ec7de..7360fcc6 100644 --- a/blocks/simulationAPI/tasks.py +++ b/blocks/simulationAPI/tasks.py @@ -33,8 +33,8 @@ def process_task(self, task_id): 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'}) @@ -44,7 +44,7 @@ def process_task(self, task_id): state = 'STREAMING' current_process = 'Processed Script, Streaming Output' else: - output = ExecXml(task, self.name) + output = ExecXml(task, self.name, task.workspace_file) if output == "Streaming": state = 'STREAMING' current_process = 'Processed Xml, Streaming Output' @@ -73,4 +73,6 @@ def process_task(self, task_id): def process_task_script(task_id): task = Task.objects.get(task_id=task_id) session = task.session - return getscriptoutput(session, task) + result = getscriptoutput(session, task) + update_task_status(task_id, 'SUCCESS', meta=result) + return result diff --git a/blocks/simulationAPI/views.py b/blocks/simulationAPI/views.py index 09541c75..03494c46 100644 --- a/blocks/simulationAPI/views.py +++ b/blocks/simulationAPI/views.py @@ -17,7 +17,7 @@ from simulationAPI.models import Task, Session from simulationAPI.negotiation import IgnoreClientContentNegotiation from simulationAPI.serializers import TaskSerializer from simulationAPI.tasks import process_task, process_task_script -from simulationAPI.helpers.ngspice_helper import CreateXcos +from simulationAPI.helpers.ngspice_helper import CreateXcos, update_task_status @@ -64,11 +64,26 @@ 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, @@ -350,6 +365,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" @@ -364,6 +380,7 @@ class GetScriptOutputView(APIView): try: celery_task = process_task_script.apply_async(kwargs={'task_id': str(task_id)}, task_id=str(uuid.uuid4())) result = celery_task.get(timeout=30) + update_task_status(celery_task.id, 'SUCCESS', meta=result) print("RESULT:", result) return Response(result, status=status.HTTP_200_OK) except Exception as e: |