Files
connpy/connpy/api.py

189 lines
5.2 KiB
Python
Raw Normal View History

2023-04-06 18:47:29 -03:00
from flask import Flask, request, jsonify
2024-07-02 16:53:07 -03:00
from flask_cors import CORS
from connpy import configfile, node, nodes, hooks, printer
from connpy.ai import ai as myai
2023-04-06 18:47:29 -03:00
from waitress import serve
import os
import signal
app = Flask(__name__)
2024-07-02 16:53:07 -03:00
CORS(app)
2023-04-06 18:47:29 -03:00
conf = configfile()
2023-04-14 11:44:56 -03:00
PID_FILE1 = "/run/connpy.pid"
PID_FILE2 = "/tmp/connpy.pid"
2023-04-06 18:47:29 -03:00
@app.route("/")
2023-04-14 11:44:56 -03:00
def root():
return jsonify({
'message': 'Welcome to Connpy api',
'version': '1.0',
'documentation': 'https://fluzzi.github.io/connpy/'
})
@app.route("/list_nodes", methods=["POST"])
def list_nodes():
conf = app.custom_config
case = conf.config["case"]
try:
data = request.get_json()
filter = data["filter"]
if not case:
if isinstance(filter, list):
filter = [item.lower() for item in filter]
else:
filter = filter.lower()
output = conf._getallnodes(filter)
2023-04-14 11:44:56 -03:00
except:
output = conf._getallnodes()
return jsonify(output)
@app.route("/get_nodes", methods=["POST"])
def get_nodes():
conf = app.custom_config
case = conf.config["case"]
try:
data = request.get_json()
filter = data["filter"]
if not case:
if isinstance(filter, list):
filter = [item.lower() for item in filter]
else:
filter = filter.lower()
output = conf._getallnodesfull(filter)
except:
output = conf._getallnodesfull()
2023-04-14 11:44:56 -03:00
return jsonify(output)
2023-04-06 18:47:29 -03:00
@app.route("/ask_ai", methods=["POST"])
def ask_ai():
conf = app.custom_config
data = request.get_json()
input = data["input"]
if "dryrun" in data:
dryrun = data["dryrun"]
else:
dryrun = False
2023-05-10 12:34:19 -03:00
if "chat_history" in data:
chat_history = data["chat_history"]
else:
chat_history = None
ai = myai(conf)
2023-05-10 12:34:19 -03:00
return ai.ask(input, dryrun, chat_history)
2023-05-12 12:05:25 -03:00
@app.route("/confirm", methods=["POST"])
def confirm():
conf = app.custom_config
data = request.get_json()
input = data["input"]
ai = myai(conf)
return str(ai.confirm(input))
2023-04-06 18:47:29 -03:00
@app.route("/run_commands", methods=["POST"])
def run_commands():
conf = app.custom_config
data = request.get_json()
2023-04-14 11:44:56 -03:00
case = conf.config["case"]
mynodes = {}
args = {}
try:
action = data["action"]
nodelist = data["nodes"]
args["commands"] = data["commands"]
if action == "test":
args["expected"] = data["expected"]
except KeyError as e:
error = "'{}' is mandatory".format(e.args[0])
return({"DataError": error})
if isinstance(nodelist, list):
mynodes = conf.getitems(nodelist)
2023-04-14 11:44:56 -03:00
else:
if not case:
nodelist = nodelist.lower()
if nodelist.startswith("@"):
mynodes = conf.getitem(nodelist)
else:
mynodes[nodelist] = conf.getitem(nodelist)
mynodes = nodes(mynodes, config=conf)
try:
2023-05-12 12:05:25 -03:00
args["vars"] = data["vars"]
2023-04-14 11:44:56 -03:00
except:
pass
try:
options = data["options"]
thisoptions = {k: v for k, v in options.items() if k in ["prompt", "parallel", "timeout"]}
args.update(thisoptions)
except:
options = None
if action == "run":
output = mynodes.run(**args)
elif action == "test":
2023-05-12 12:05:25 -03:00
output = {}
output["result"] = mynodes.test(**args)
output["output"] = mynodes.output
2023-04-14 11:44:56 -03:00
else:
error = "Wrong action '{}'".format(action)
return({"DataError": error})
2023-04-06 18:47:29 -03:00
return output
2024-04-22 18:17:11 -03:00
@hooks.MethodHook
2023-04-06 18:47:29 -03:00
def stop_api():
# Read the process ID (pid) from the file
2023-04-14 11:44:56 -03:00
try:
with open(PID_FILE1, "r") as f:
2023-04-15 22:38:52 -03:00
pid = int(f.readline().strip())
port = int(f.readline().strip())
2023-04-14 11:44:56 -03:00
PID_FILE=PID_FILE1
except:
try:
with open(PID_FILE2, "r") as f:
2023-04-15 22:38:52 -03:00
pid = int(f.readline().strip())
port = int(f.readline().strip())
2023-04-14 11:44:56 -03:00
PID_FILE=PID_FILE2
except:
printer.warning("Connpy API server is not running.")
2023-04-14 11:44:56 -03:00
return
2023-04-06 18:47:29 -03:00
# Send a SIGTERM signal to the process
2023-04-18 18:00:43 -03:00
try:
os.kill(pid, signal.SIGTERM)
except:
pass
2023-04-06 18:47:29 -03:00
# Delete the PID file
os.remove(PID_FILE)
printer.info(f"Server with process ID {pid} stopped.")
2023-04-15 22:38:52 -03:00
return port
2024-04-22 18:17:11 -03:00
@hooks.MethodHook
2023-04-15 22:38:52 -03:00
def debug_api(port=8048):
app.custom_config = configfile()
app.run(debug=True, port=port)
2023-04-06 18:47:29 -03:00
2024-04-22 18:17:11 -03:00
@hooks.MethodHook
2023-04-15 22:38:52 -03:00
def start_server(port=8048):
2023-04-14 11:44:56 -03:00
app.custom_config = configfile()
2023-04-15 22:38:52 -03:00
serve(app, host='0.0.0.0', port=port)
2023-04-06 18:47:29 -03:00
2024-04-22 18:17:11 -03:00
@hooks.MethodHook
2023-04-15 22:38:52 -03:00
def start_api(port=8048):
2023-04-14 11:44:56 -03:00
if os.path.exists(PID_FILE1) or os.path.exists(PID_FILE2):
printer.warning("Connpy server is already running.")
2023-04-14 11:44:56 -03:00
return
2023-04-06 18:47:29 -03:00
pid = os.fork()
if pid == 0:
2023-04-15 22:38:52 -03:00
start_server(port)
2023-04-06 18:47:29 -03:00
else:
2023-04-14 11:44:56 -03:00
try:
with open(PID_FILE1, "w") as f:
2023-04-15 22:38:52 -03:00
f.write(str(pid) + "\n" + str(port))
2023-04-14 11:44:56 -03:00
except:
try:
with open(PID_FILE2, "w") as f:
2023-04-15 22:38:52 -03:00
f.write(str(pid) + "\n" + str(port))
2023-04-14 11:44:56 -03:00
except:
printer.error("Couldn't create PID file.")
exit(1)
printer.start(f"Server is running with process ID {pid} on port {port}")
2023-04-06 18:47:29 -03:00