# coding: utf8 import os import subprocess import time import datetime import shutil from luaModule import loadLuaPrg from json import loads as loadJson import traceback import Activity import fsio import FilePaths import re import syslog from glob import glob import logConfig import notify_activity import status_mod import channel_mod import m7z_mod import FileIface SRBPRG_DIR = '/home/tool/config/srbprg/' # Fake globals for syntax check if False: response = None request = None session = None db = None status_mod.sessionUserMgr.setLastVisit(session, request) if logConfig.prgSessFrgt: session.forget(response) @auth.requires(request.ajax==True, requires_login=True) def getLastEditprg(): prgIds = [99] + range(99) + range(100, 256) lastmodif = 0.0 lastSlot = 0 try: for i, slot in enumerate(prgIds): filename = os.path.join(FilePaths.PRG_PATH, 'prg%d.lua' % slot) if os.path.isfile(filename): modif = os.path.getmtime(filename) if lastmodif < modif: lastmodif = modif lastSlot = slot except: pass return response.json({'lastModif': lastSlot}) @auth.requires(request.ajax==True, requires_login=True) def prg(): if request.env.request_method == "GET": torque_unit_factors = channel_mod.get_torque_unit_factors() einheit = torque_unit_factors.get('Aktiv') prgs = [] prgIds = [99] + range(99) + range(100, 256) for i, slot in enumerate(prgIds): filename = os.path.join(FilePaths.PRG_PATH, 'prg%d.lua' % slot) appended = False if os.access(filename, os.R_OK): try: prg = loadLuaPrg(filename) prg['id'] = i + 1 prg['Slot'] = slot prg['Date'] = secsinceepoch2localisodatetimestr(prg['Date']) for step in prg['steps']: if step['Type'] == 0: if 'Speed' not in step: step['StartupTest'] = False step['Speed'] = 5 step['TF_Angle'] = 30 step['MF_TorqueMax_Switching'] = 5 step['MF_Time_Switching'] = 10 step['StartSuppression'] = 0 else: step['StartupTest'] = True if 'MF_AngleMin_Switching' in step: del step['MF_AngleMin_Switching'] prgs.append(prg) appended = True except: pass if not appended: # chancfg = fsio.jsonload(FilePaths.CHAN_CONF_FILENAME) # einheit = chancfg.get('EinheitDrehmoment').get('Aktiv') prg = {'id': i + 1, 'Name': 'n.a', 'Slot': slot, 'Comment': '', 'Date': secsinceepoch2localisodatetimestr(978303600), 'Version': '', 'TorqueUnit': einheit, 'steps': [{'id': 1, 'Type': 0, 'Column': 0, 'Row': 0, 'IO_Next': 2, 'TF_Angle': 0, 'MF_TorqueMax_Switching': 0}, {'id': 2, 'Type': 2, 'Column': 0, 'Row': 1}] } prgs.append(prg) return response.json(prgs) else: data = loadJson(request.body.read()) if not isinstance(data, list): data = [data] my_response = {} torque_unit_map = channel_mod.load_torque_unit_map() for prg in data: filename = os.path.join(FilePaths.PRG_PATH, 'prg%d.lua' % prg['Slot']) fileExists = os.access(filename, os.R_OK) chancfg = fsio.jsonload(FilePaths.CHAN_CONF_FILENAME) torque_unit = chancfg.get('Einheit') if fileExists: try: fprg = loadLuaPrg(filename) torque_unit = fprg.get('TorqueUnit') except: pass if torque_unit is None: torque_unit = 0 # Add this if quotes must be valid input: # prg['Name'] = prg['Name'].replace(r'"', r'\"') if prg['Name'] == 'n.a': if fileExists: os.remove(filename) syslog.syslog(syslog.LOG_INFO, "Program with filename: " + filename + " removed.") notify_activity.configChanged(filename, Activity.PRG_REMOVED, [prg['Slot']], session=session) continue crnl = re.compile("\n|\r") def writePrg(f): # with open(filename, 'wb') as f: # Header f.write('--Tight program generated by NEXO-OS\n--DO NOT EDIT THIS FILE MANUALLY!!\n\n') # General info f.write('--General information\nprg={}\n') new_torque_unit = prg.get('TorqueUnit') if new_torque_unit != torque_unit: Activity.LOG(session, Activity.TORQUE_UNIT_CHANGED, prg['Slot'], torque_unit_map.get(torque_unit), torque_unit_map.get(new_torque_unit)) for k in ['Name', 'Version', 'Comment']: if k in prg: encoded_value = prg[k].encode('utf8') encoded_value = re.sub(crnl, "", encoded_value) f.write('prg.%s = "%s"\n' % (k, encoded_value)) date = int(time.time()) my_response[prg['id']] = secsinceepoch2localisodatetimestr(date) f.write('prg.Date = %s\n' % date) if session.auth: f.write('prg.User = "%s"\n' % session.auth.user.username) else: f.write('prg.User = ""\n') if prg.get("TorqueUnit") is None: prg["TorqueUnit"] = 0 f.write("prg.TorqueUnit = {0}\n".format(prg.get("TorqueUnit"))) # Steps f.write('\n--Steps\nsteps={}\n') for step in prg['steps']: i = step['id'] f.write('\n--steps %d\n' % i) f.write('steps[%d] = {}\n' % i) # Common properties f.write('steps[%d].Name = "%s"\n' % (i, step['Name'].encode('utf8'))) for k in ['Type', 'Column', 'Row']: if k in step: f.write('steps[%d].%s = %s\n' % (i, k, step[k])) # Special properties if step['Type'] == 0: # Start f.write('steps[%d].NIO_Next = nil\n' % i) for k in ['IO_Next', 'GraphResolution', 'MeasuringPoints', 'Category', 'TorqueThreshold', 'PlayStartSwitch', 'CorrectionAngle', 'CorrectionTorqueCt', 'ResultOutputSuppression']: v = step[k] if isinstance(v, bool): v = 'true' if v else 'false' f.write('steps[%d].%s = %s\n' % (i, k, v)) if step['StartupTest']: f.write('steps[%d].StartupTest = {\n' % i) for k in ['Speed', 'TF_Angle', 'StartSuppression', 'MF_TorqueMax_Switching', 'MF_Time_Switching']: f.write(' %s = %s,\n' % (k, step[k])) f.write('}') elif step['Type'] == 1: # Tight for k in ['IO_Next', 'NIO_Next', 'GraphResolution', 'Category', 'Speed', 'StartSuppression', 'TorqueThreshold']: # if k in step: f.write('steps[%d].%s = %s\n' % (i, k, step[k])) for k in ['TF1_UpperTorque', 'TF1_Angle', 'TF1_Time', 'TF2_UpperTorque', 'TF2_Angle', 'TF2_Time']: if k in step and step[k] != None: f.write('steps[%d].%s = %s\n' % (i, k, step[k])) for k in ['MF_TorqueMin', 'MF_TorqueMin_Switching', 'MF_TorqueMax', 'MF_TorqueMax_Switching', 'MF_AngleMin', 'MF_AngleMin_Switching', 'MF_AngleMax', 'MF_AngleMax_Switching', 'MF_Time_Switching', 'MF_GradientMin', 'MF_GradientMin_Switching', 'MF_GradientMax', 'MF_GradientMax_Switching']: if k in step and step[k] != None: f.write('steps[%d].%s = %s\n' % (i, k, step[k])) else: # End f.write('steps[%d].IO_Next = nil\n' % i) f.write('steps[%d].NIO_Next = nil\n' % i) fsio.writebfn(filename, writePrg) if fileExists: changedOrCreated = Activity.PRG_CHANGED else: changedOrCreated = Activity.PRG_CREATED notify_activity.configChanged(filename, changedOrCreated, [prg['Slot']], session=session) return response.json(my_response) def secsinceepoch2localisodatetimestr(timestamp): datestr = "TIMESTAMP not PARSABLE" try: date = datetime.datetime.fromtimestamp(float(timestamp)) datestr = "{0} {1}".format(date.date().isoformat(), date.time().isoformat()) except: pass return datestr def extract_prg_id_name_pair(prgname): prg_no = int(prgname.split("/")[-1][3:].replace(".lua", "")) if os.path.exists(prgname) and os.path.isfile(prgname): with open(prgname, 'r') as f: for line in f.readlines(): if "prg.Name = " in str(line): return {'number': prg_no, 'name': "{0}: {1}".format(prg_no, line[12:-1].replace("\"", ""))} else: return {'number': prg_no, 'name': "{0}: n.a".format(prg_no)} def get_prg_id_name_pair_from_number(prgnumber): return extract_prg_id_name_pair("/home/tool/config/srbprg/prg{0}.lua".format(prgnumber)) from operator import itemgetter def cmp_prgs(left, right): if left == 99 and right == 99: return 0 if left == 99: return -1 elif right == 99: return 1 return cmp(left, right) @auth.requires(request.ajax==True, requires_login=True) def get_prgs(): myPrgs = [] for i in [99] + range(0, 99) + range(100, 256): myPrgs.append("/home/tool/config/srbprg/prg{0}.lua".format(i)) myPrgsNos = map(extract_prg_id_name_pair, myPrgs) myPrgsNos = sorted(myPrgsNos, cmp=cmp_prgs, key=itemgetter('number')) return response.json(myPrgsNos) @auth.requires(request.ajax==True, requires_login=True) def resetToFactory(): shutil.rmtree(FilePaths.PRG_PATH) shutil.copytree('/home/tool/config/default/srbprg', FilePaths.PRG_PATH) return '' @auth.requires(request.ajax==True, requires_login=True) def export(): prg = request.vars.p filename = 'prg{0}.lua'.format(prg) fullpath = '/home/tool/config/srbprg/{0}'.format(filename) try: data = fsio.readb(fullpath) response.headers['Content-Disposition'] = 'attachment; filename="%s"' % filename response.headers['Content-Type'] = 'application/octet-stream; name="%s"' % filename except: raise HTTP(400, 'file not found') return data @auth.requires(request.ajax==True, requires_login=True) def prgimport(): try: prg = request.vars.prg filename = request.vars.fileupload.filename.split("\\")[-1] except: return response.json({'success': False, 'msg': 'Invalid parameters'}) targetpath = '{1}prg{0}.lua'.format(prg, SRBPRG_DIR) resultError = None def writeUploadedPrg(f): try: f.write(request.vars.fileupload.value) except: resultError = response.json({'success': False, 'msg': 'Cannot write file'}) try: fsio.writebfn(targetpath, writeUploadedPrg) except: resultError = response.json({'success': False, 'msg': 'Cannot open file'}) if resultError: return resultError Activity.LOG(session, Activity.PRG_CHANGED, prg) return response.json({'success': True, 'msg': ':-)'}) def __genPrgFileName(number): while len(str(number)) < 3: number = "0" + str(number) name = 'prg{0}'.format(number) ts = time.time() dateStamp = datetime.datetime.fromtimestamp(ts).strftime('%Y_%m_%d') return dateStamp + '_' + name.strip() + '.nxprg' @auth.requires(request.ajax==True, requires_login=True) def existingPrograms(): file_list = glob(SRBPRG_DIR + "prg*.lua", ) prg_re = re.compile(r"^(" + SRBPRG_DIR + "prg)([0-9]{1,3})(\.lua)$") def prg_number(prg_filename): if prg_re.match(prg_filename): return prg_re.match(prg_filename).groups()[1] else: return None prg_numbers = filter(lambda x: x != None, map(prg_number, file_list)) prg_numbers = map(lambda x: int(x), prg_numbers) return response.json(prg_numbers) @auth.requires(request.ajax==True, requires_login=True) def exportPrgFile(): res = {'success': False, 'msg': 'Unknown error'} fsio.fsLock.acquire() try: expfname = __genPrgFileName(request.vars.num) filename = 'prg{0}.lua'.format(request.vars.num) targetPrg = '{0}/{1}'.format(FilePaths.PRG_PATH, filename) res = {'success': True, 'msg': '/tmp/' + expfname} pwd = FilePaths.gen_rev_pwd(FileIface.CFG_LIST_PRG_0) syslog.syslog(syslog.LOG_INFO, "START prg.exportPrgFile.subprocess to " + expfname + " at " + time.asctime()) p = subprocess.Popen(['{0}/prg_exporter.sh'.format(FilePaths.SH_TOOL_PATH), pwd, expfname, targetPrg, '/tmp'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = p.communicate() syslog.syslog(syslog.LOG_INFO, "DONE prg.exportPrgFile.subprocess to " + expfname + " at " + time.asctime()) syslog.syslog(syslog.LOG_INFO, "RESULT prg.exportPrgFile.subprocess to stdout: " + str(stdout)) syslog.syslog(syslog.LOG_INFO, "RESULT prg.exportPrgFile.subprocess to stderr: " + str(stderr)) if p.returncode != 0: # Failure res['success'] = False res['msg'] = str(stderr) except Exception, e: res['success'] = False res['msg'] = str(e) finally: fsio.fsLock.release() return response.json(res) @auth.requires_login() def importPrgFile(): try: prg = request.vars.prg filename = request.vars.fileupload.filename.split("\\")[-1] except: return response.json({'success': False, 'msg': 'Invalid parameters'}) targetpath = '{0}/prg{1}.lua'.format(FilePaths.PRG_PATH, prg) targetfilename = 'prg{0}.lua'.format(prg) res = {'success': False, 'msg': 'Unknown error'} destRootDir = '/tmp/' destDir = 'luaprg' filename = 'luaprg.zip' destPath = destRootDir + destDir + '/' fsio.fsXngLock.acquire() try: filepath = destRootDir + filename with open(filepath, 'w') as f: f.write(request.vars.fileupload.value) pwd = FilePaths.gen_rev_pwd(FileIface.CFG_LIST_PRG_0) returncode = m7z_mod.test_pwd(filepath, pwd) if returncode != 0: return response.json(m7z_mod.get_import_impossible_msg()) p = subprocess.Popen( ['{0}/prg_importer.sh'.format(FilePaths.SH_TOOL_PATH), pwd, filename, destRootDir, destDir], stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = p.communicate() if p.returncode != 0: # Failure res['success'] = False res['msg'] = str(stderr) else: # must be one file and lua extension else error if os.path.exists(destPath): p, d, f = os.walk(destPath).next() if len(f) == 1: if f[0].endswith('.lua'): # read the file fname = destPath + f[0] with open(fname, 'rb') as f1: try: data = f1.read() fsio.write(filename=targetpath, data=data) notify_activity.configChanged(FilePaths.CONFIG_PRG_IMPORTER, Activity.PRG_CHANGED, activityArgs=[prg], session=session) except: syslog.syslog(syslog.LOG_ERR, traceback.format_exc()) syslog.syslog(syslog.LOG_ERR, traceback.format_stack()) return response.json({'success': True, 'msg': ':-)'}) else: res = {'success': False, 'msg': 'No lua file inside source file'} else: res = {'success': False, 'msg': 'More than one lua file inside source file'} else: res = {'success': False, 'msg': 'Expansion process failed'} except Exception, e: res['success'] = False res['msg'] = str(e) finally: fsio.fsXngLock.release() return response.json(res) @auth.requires(request.ajax==True, requires_login=True) def exportAll(): res = {'success': False, 'msg': 'Unknown error'} try: filenames = glob(SRBPRG_DIR + "/prg*.lua") filenames = ' '.join(filenames) expfname = datetime.datetime.fromtimestamp(time.time()).strftime('%Y_%m_%d') + '_' + 'allPrgs.zip' pwd = FilePaths.gen_rev_pwd(FileIface.CFG_LIST_PRG_0) res = {'success': True, 'msg': '/tmp/' + expfname} syslog.syslog(syslog.LOG_INFO, "START prg.exportAll.subprocess to " + expfname + " at " + time.asctime()) p = subprocess.Popen(['{0}/exportAll.sh'.format(FilePaths.SH_TOOL_PATH), pwd, expfname, filenames, '', '/tmp'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = p.communicate() syslog.syslog(syslog.LOG_INFO, "DONE prg.exportAll.subprocess to " + expfname + " at " + time.asctime()) syslog.syslog(syslog.LOG_INFO, "RESULT prg.exportAll.subprocess to stdout: " + str(stdout)) syslog.syslog(syslog.LOG_INFO, "RESULT prg.exportAll.subprocess to stderr: " + str(stderr)) if p.returncode != 0: # Failure res['success'] = False res['msg'] = str(stderr) except Exception as e: res['success'] = False res['msg'] = str(e) return response.json(res) @auth.requires(request.ajax==True, requires_login=True) def importAll(): try: filename = request.vars.fileupload.filename.split("\\")[-1] except: return response.json({'success': False, 'msg': 'Invalid parameters'}) res = {'success': False, 'msg': 'Unknown error'} destRootDir = '/tmp/' destDir = 'luaprg' filename = 'luaprg.zip' destPath = destRootDir + destDir + '/' fsio.fsXngLock.acquire() try: with open(destRootDir + filename, 'w') as f: f.write(request.vars.fileupload.value) pwd = FilePaths.generatePwd() p = subprocess.Popen( ['{0}/prg_importer.sh'.format(FilePaths.SH_TOOL_PATH), pwd, filename, destRootDir, destDir], stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = p.communicate() if p.returncode != 0: # Failure res['success'] = False res['msg'] = str(stderr) else: for root, subFolders, files in os.walk(SRBPRG_DIR): for incFile in files: if incFile.startswith("prg") and incFile.endswith(".lua"): os.remove(os.path.join(SRBPRG_DIR, incFile)) if os.path.exists(destPath): p, d, f = os.walk(destPath).next() if len(f) > 0: for tempFile in f: if tempFile.endswith('.lua'): fsio.shcopy(destPath + tempFile, os.path.join(SRBPRG_DIR, tempFile)) else: res = {'success': False, 'msg': 'No file inside source file'} return response.json({'success': True, 'msg': ':-)'}) else: res = {'success': False, 'msg': 'No file inside source file'} else: res = {'success': False, 'msg': 'Expansion process failed'} except Exception, e: res['success'] = False res['msg'] = str(e) finally: fsio.fsXngLock.release() return response.json(res) @auth.requires(request.ajax==True, requires_login=True) def extractSlot(incFile): match = re.match("prg(.*).lua", incFile) slot = match.groups()[0] return slot @auth.requires(request.ajax==True, requires_login=True) def remove_all_prgs(): for root, subFolders, files in os.walk(SRBPRG_DIR): activities = [] for incFile in files: if incFile.startswith("prg") and incFile.endswith(".lua"): slot = extractSlot(incFile) os.remove(os.path.join(SRBPRG_DIR, incFile)) activities.append(notify_activity.ActivityLogParams( activityArgs=[slot], activityType=Activity.PRG_REMOVED )) notify_activity.configChangedBatch(activities, filename=FilePaths.CONFIG_PRG_IMPORTER, session=session) @auth.requires(request.ajax==True, requires_login=True) def importSelected(): res = {'success': False, 'msg': 'Unknown error'} destRootDir = '/tmp/' flistName = 'prgnamelist.txt' destDir = 'luaprg' filename = 'luaprg.zip' destPath = destRootDir + destDir + '/' fsio.fsXngLock.acquire() try: import base64 filedata = base64.b64decode(request.vars.filedata) filepath = destRootDir + filename with open(filepath, 'w') as f: f.write(filedata) excludeList = request.vars.excludeList namesdata = "" if excludeList != None: if type(excludeList) == type([]): namesdata = '\n'.join(excludeList) else: namesdata = excludeList with open(destRootDir + flistName, 'w') as f: f.write(namesdata) pwd = FilePaths.gen_rev_pwd(FileIface.CFG_LIST_PRG_0) returncode = m7z_mod.test_pwd(filepath, pwd) if returncode != 0: return response.json(m7z_mod.get_import_impossible_msg()) if os.path.exists(destPath): prgs = glob(destPath + '*') for f in prgs: os.remove(f) else: os.makedirs(destPath) p = subprocess.Popen( ['/home/tool/bin/7za', 'x', filepath, '-p' + pwd, '-o' + destPath, '-x@' + destRootDir + flistName, '-y'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = p.communicate() if p.returncode != 0: # Failure res['success'] = False res['msg'] = str(stderr) if res['msg'] == "": res['msg'] = 'System Error' else: # CR12502 we do _not_ want to remove the programs before importing selected: # remove_all_prgs() if os.path.exists(destPath): p, d, f = os.walk(destPath).next() if len(f) > 0: activities = [] for tempFile in f: if tempFile.endswith('.lua'): slot = extractSlot(tempFile) fsio.shcopy(destPath + tempFile, os.path.join(SRBPRG_DIR, tempFile)) activities.append(notify_activity.ActivityLogParams( activityArgs=[slot], activityType=Activity.PRG_CREATED )) else: res = {'success': False, 'msg': 'No file inside source file'} notify_activity.configChangedBatch( activities=activities, filename=FilePaths.CONFIG_PRG_IMPORTER, session=session ) return response.json({'success': True, 'msg': ':-)'}) else: res = {'success': False, 'msg': 'No file inside source file'} else: res = {'success': False, 'msg': 'Expansion process failed'} except Exception, e: res['success'] = False res['msg'] = str(e) finally: fsio.fsXngLock.release() return response.json(res) @auth.requires(request.ajax==True, requires_login=True) def exportSelected(): res = {'success': False, 'msg': 'Unknown error'} try: allfilenames = glob(SRBPRG_DIR + "/prg*.lua") excludeList = request.vars.excludeList filenames = [] if excludeList != None: for name in allfilenames: if type(excludeList) == type([]): if name not in excludeList: filenames.append(name) else: if name != excludeList: filenames.append(name) else: filenames = allfilenames filenames = ' '.join(filenames) if filenames == "": # Failure res['success'] = False res['msg'] = "Error no files included in export" return response.json(res) expfname = datetime.datetime.fromtimestamp(time.time()).strftime('%Y_%m_%d') + '_' + 'selectedPrgs.nxprx' pwd = FilePaths.gen_rev_pwd(FileIface.CFG_LIST_PRG_0) res = {'success': True, 'msg': '/tmp/' + expfname} syslog.syslog(syslog.LOG_INFO, "START prg.exportAll.subprocess to " + expfname + " at " + time.asctime()) p = subprocess.Popen(['{0}/exportAll.sh'.format(FilePaths.SH_TOOL_PATH), pwd, expfname, filenames, '', '/tmp'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = p.communicate() syslog.syslog(syslog.LOG_INFO, "DONE prg.exportAll.subprocess to " + expfname + " at " + time.asctime()) syslog.syslog(syslog.LOG_INFO, "RESULT prg.exportAll.subprocess to stdout: " + str(stdout)) syslog.syslog(syslog.LOG_INFO, "RESULT prg.exportAll.subprocess to stderr: " + str(stderr)) if p.returncode != 0: # Failure res['success'] = False res['msg'] = str(stderr) except Exception as e: res['success'] = False res['msg'] = str(e) return response.json(res)