mirror of
https://github.com/thiagoralves/OpenPLC_v3.git
synced 2026-08-18 02:37:40 +08:00
Fix REST API errors and make it conform with v4 API
This commit is contained in:
+21
-16
@@ -3,7 +3,7 @@ import subprocess
|
||||
import socket
|
||||
import errno
|
||||
import time
|
||||
from threading import Thread
|
||||
from threading import Thread, Lock
|
||||
from queue import Queue, Empty
|
||||
import os.path
|
||||
|
||||
@@ -70,15 +70,16 @@ class NonBlockingStreamReader:
|
||||
class UnexpectedEndOfStream(Exception): pass
|
||||
|
||||
class runtime:
|
||||
project_file = ""
|
||||
project_name = ""
|
||||
project_description = ""
|
||||
compilation_status_str = ""
|
||||
compilation_error_str = ""
|
||||
compilation_object = None
|
||||
compilation_error = None
|
||||
runtime_status = "Stopped"
|
||||
|
||||
def __init__(self):
|
||||
self.project_file = ""
|
||||
self.project_name = ""
|
||||
self.project_description = ""
|
||||
self.compilation_status_str = ""
|
||||
self.compilation_error_str = ""
|
||||
self.compilation_object = None
|
||||
self.compilation_error = None
|
||||
self.runtime_status = "Stopped"
|
||||
|
||||
def start_runtime(self):
|
||||
if (self.status() == "Stopped"):
|
||||
self.theprocess = subprocess.Popen(['./core/openplc']) # XXX: iPAS
|
||||
@@ -148,9 +149,12 @@ class runtime:
|
||||
f.write(c_debug)
|
||||
|
||||
# Start compilation
|
||||
a = subprocess.Popen(['./scripts/compile_program.sh', str(st_file)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
self.compilation_object = NonBlockingStreamReader(a.stdout)
|
||||
self.compilation_error = NonBlockingStreamReader(a.stderr)
|
||||
try:
|
||||
a = subprocess.Popen(['./scripts/compile_program.sh', str(st_file)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
self.compilation_object = NonBlockingStreamReader(a.stdout)
|
||||
# self.compilation_error = NonBlockingStreamReader(a.stderr)
|
||||
except Exception as e:
|
||||
print(f"Error starting compilation: {e}")
|
||||
else:
|
||||
# Debug info was extracted from program
|
||||
program = '\n'.join(program_lines)
|
||||
@@ -170,7 +174,7 @@ class runtime:
|
||||
# Start compilation
|
||||
a = subprocess.Popen(['./scripts/compile_program.sh', str(st_file)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
self.compilation_object = NonBlockingStreamReader(a.stdout)
|
||||
self.compilation_error = NonBlockingStreamReader(a.stderr)
|
||||
# self.compilation_error = NonBlockingStreamReader(a.stderr)
|
||||
|
||||
def compilation_status(self):
|
||||
while self.compilation_object != None:
|
||||
@@ -188,8 +192,9 @@ class runtime:
|
||||
|
||||
def status(self):
|
||||
try:
|
||||
if (self.compilation_object.end_of_stream == False):
|
||||
return "Compiling"
|
||||
if (self.compilation_object != None):
|
||||
if (self.compilation_object.end_of_stream == False):
|
||||
return "Compiling"
|
||||
except Exception as e:
|
||||
print(f"Error checking compilation status: {e}")
|
||||
|
||||
|
||||
+75
-58
@@ -23,6 +23,9 @@ import flask_login
|
||||
|
||||
from credentials import CertGen
|
||||
from restapi import app_restapi, restapi_bp, db, register_callback_get, register_callback_post
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum, auto
|
||||
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
app.secret_key = str(os.urandom(16))
|
||||
@@ -49,97 +52,111 @@ def restapi_callback_get(argument: str, data: dict) -> dict:
|
||||
This is the central callback function that handles the logic
|
||||
based on the 'argument' from the URL and 'data' from the request.
|
||||
"""
|
||||
global openplc_runtime
|
||||
logger.debug(f"GET | Received argument: {argument}, data: {data}")
|
||||
|
||||
if argument == "start-plc":
|
||||
monitor.stop_monitor()
|
||||
openplc_runtime.start_runtime()
|
||||
time.sleep(1)
|
||||
configure_runtime()
|
||||
return {"status": "runtime started"}
|
||||
monitor.cleanup()
|
||||
monitor.parse_st(openplc_runtime.project_file)
|
||||
return {"status": "START:OK"}
|
||||
|
||||
elif argument == "stop-plc":
|
||||
openplc_runtime.stop_runtime()
|
||||
return {"status": "runtime stop"}
|
||||
time.sleep(1)
|
||||
monitor.stop_monitor()
|
||||
return {"status": "STOP:OK"}
|
||||
|
||||
elif argument == "runtime-logs":
|
||||
logs = openplc_runtime.logs()
|
||||
return {"runtime-logs": logs}
|
||||
|
||||
elif argument == "compilation-status":
|
||||
try:
|
||||
logs = openplc_runtime.compilation_status()
|
||||
_logs = logs
|
||||
except Exception as e:
|
||||
logger.error(f"Error retrieving compilation logs: {e}")
|
||||
_logs = str(e)
|
||||
status = 'IDLE'
|
||||
logs = openplc_runtime.compilation_status()
|
||||
exit_code = 0
|
||||
|
||||
status = _logs
|
||||
if status is not str:
|
||||
_status = "No compilation in progress"
|
||||
if "Compilation finished successfully!" in status:
|
||||
_status = "Success"
|
||||
_error = "No error"
|
||||
elif "Compilation finished with errors!" in status:
|
||||
_status = "Error"
|
||||
_error = openplc_runtime.get_compilation_error()
|
||||
logs = str(logs)
|
||||
|
||||
if "Compilation finished successfully!" in logs:
|
||||
status = 'SUCCESS'
|
||||
exit_code = 0
|
||||
elif "Compilation finished with errors!" in logs:
|
||||
status = 'FAILED'
|
||||
exit_code = 1
|
||||
else:
|
||||
_status = "Compiling"
|
||||
_error = openplc_runtime.get_compilation_error()
|
||||
logger.debug(f"Compilation status: {_status}, logs: {_logs}", extra={"error": _error})
|
||||
status = 'COMPILING'
|
||||
exit_code = 0
|
||||
|
||||
return {"status": _status, "logs": _logs, "error": _error}
|
||||
return {
|
||||
"status": status,
|
||||
"logs": logs.splitlines(),
|
||||
"exit_code": exit_code
|
||||
}
|
||||
|
||||
elif argument == "status":
|
||||
return {"current_status": "operational", "details": data}
|
||||
if openplc_runtime.status() == "Running":
|
||||
return {"status" : "STATUS:RUNNING"}
|
||||
elif openplc_runtime.status() == "Compiling":
|
||||
return {"status" : "STATUS:EMPTY"}
|
||||
elif openplc_runtime.status() == "Stopped":
|
||||
return {"status" : "STATUS:STOPPED"}
|
||||
else:
|
||||
return {"status" : "STATUS:UNKNOWN"}
|
||||
|
||||
elif argument == "ping":
|
||||
return {"status": "pong"}
|
||||
return {"status": "PING:OK"}
|
||||
else:
|
||||
return {"error": "Unknown argument"}
|
||||
|
||||
# file upload POST handler
|
||||
def restapi_callback_post(argument: str, data: dict) -> dict:
|
||||
global openplc_runtime
|
||||
logger.debug(f"POST | Received argument: {argument}, data: {data}")
|
||||
|
||||
if argument == "upload-file":
|
||||
try:
|
||||
# validate filename
|
||||
if 'file' not in flask.request.files:
|
||||
return {"UploadFileFail": "No file part in the request"}
|
||||
st_file = flask.request.files['file']
|
||||
# validate file size
|
||||
if st_file.content_length > 32 * 1024 * 1024: # 32 MB limit
|
||||
return {"UploadFileFail": "File is too large"}
|
||||
if openplc_runtime.status() == "Compiling":
|
||||
return {"UploadFileFail": "Runtime is compiling another program, please wait", "CompilationStatus": "COMPILING"}
|
||||
|
||||
# replace program file on database
|
||||
# validate filename
|
||||
if 'file' not in flask.request.files:
|
||||
return {"UploadFileFail": "No file part in the request", "CompilationStatus": "FAILED"}
|
||||
st_file = flask.request.files['file']
|
||||
|
||||
# validate file size
|
||||
if st_file.content_length > 32 * 1024 * 1024: # 32 MB limit
|
||||
return {"UploadFileFail": "File is too large", "CompilationStatus": "FAILED"}
|
||||
|
||||
# replace program file on database
|
||||
database = "openplc.db"
|
||||
conn = create_connection(database)
|
||||
if (conn != None):
|
||||
try:
|
||||
database = "openplc.db"
|
||||
conn = create_connection(database)
|
||||
logger.info(f"{database} connected")
|
||||
if (conn != None):
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT * FROM Programs WHERE Name = 'webserver_program'")
|
||||
row = cur.fetchone()
|
||||
cur.close()
|
||||
except Exception as e:
|
||||
return {"UploadFileFail": e}
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT * FROM Programs WHERE Name = 'webserver_program'")
|
||||
row = cur.fetchone()
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
filename = str(row[3])
|
||||
st_file.save(os.path.join('st_files', filename))
|
||||
|
||||
openplc_runtime.project_name = str(row[1])
|
||||
openplc_runtime.project_description = str(row[2])
|
||||
openplc_runtime.project_file = str(row[3])
|
||||
|
||||
except Exception as e:
|
||||
return {"UploadFileFail": f"Error connecting to the database: {e}"}
|
||||
return {"UploadFileFail": e, "CompilationStatus": "FAILED"}
|
||||
else:
|
||||
return {"UploadFileFail": f"Error connecting to the database", "CompilationStatus": "FAILED"}
|
||||
|
||||
filename = str(row[3])
|
||||
st_file.save(f"st_files/{filename}")
|
||||
|
||||
except Exception as e:
|
||||
return {"UploadFileFail": e}
|
||||
|
||||
if (openplc_runtime.status() == "Compiling"):
|
||||
return {"RuntimeStatus": "Compiling"}
|
||||
|
||||
try:
|
||||
openplc_runtime.compile_program(f"{filename}")
|
||||
return {"CompilationStatus": "Starting program compilation"}
|
||||
except Exception as e:
|
||||
return {"CompilationStatusFail": e}
|
||||
# Compile new program
|
||||
delete_persistent_file()
|
||||
openplc_runtime.compile_program(filename)
|
||||
return {"UploadFileFail": "", "CompilationStatus": "COMPILING"}
|
||||
|
||||
else:
|
||||
return {"PostRequestError": "Unknown argument"}
|
||||
|
||||
Reference in New Issue
Block a user