mirror of
https://github.com/Manuel83/craftbeerpi3
synced 2026-09-19 15:59:07 +02:00
initializer which are defined in the plugin will be called. Before these initializer where ignored.
200 lines
5.5 KiB
Python
200 lines
5.5 KiB
Python
import json
|
|
|
|
import sys
|
|
from flask import Blueprint, request, send_from_directory
|
|
from importlib import import_module
|
|
from modules import socketio, cbpi
|
|
|
|
|
|
from git import Repo
|
|
import os
|
|
import requests
|
|
import yaml
|
|
import shutil
|
|
|
|
blueprint = Blueprint('addon', __name__)
|
|
|
|
|
|
modules = {}
|
|
|
|
def merge(source, destination):
|
|
"""
|
|
Helper method to merge two dicts
|
|
:param source:
|
|
:param destination:
|
|
:return:
|
|
"""
|
|
for key, value in source.items():
|
|
if isinstance(value, dict):
|
|
# get node or create one
|
|
node = destination.setdefault(key, {})
|
|
merge(value, node)
|
|
else:
|
|
destination[key] = value
|
|
|
|
return destination
|
|
|
|
@blueprint.route('/', methods=['GET'])
|
|
def getPlugins():
|
|
"""
|
|
Endpoint for all plugins
|
|
:return:
|
|
"""
|
|
result = []
|
|
for filename in os.listdir("./modules/plugins"):
|
|
if filename.endswith(".DS_Store") or filename.endswith(".py") or filename.endswith(".pyc"):
|
|
continue
|
|
result.append(filename)
|
|
|
|
return json.dumps(result)
|
|
|
|
@blueprint.route('/<name>', methods=['GET'])
|
|
def getFile(name):
|
|
"""
|
|
Returns plugin code
|
|
:param name: plugin name
|
|
:return: the plugin code from __init__.py
|
|
"""
|
|
return send_from_directory('./plugins/'+name, "__init__.py")
|
|
|
|
@blueprint.route('/<name>', methods=['PUT'])
|
|
def createPlugin(name):
|
|
|
|
"""
|
|
Create a new plugin file
|
|
:param name: the plugin name
|
|
:return: empty http response 204
|
|
"""
|
|
if not os.path.exists("./modules/plugins/"+name):
|
|
os.makedirs("./modules/plugins/"+name)
|
|
with open("./modules/plugins/" + name + "/__init__.py", "wb") as fo:
|
|
fo.write("")
|
|
cbpi.emit_message("PLUGIN %s CREATED" % (name))
|
|
return ('', 204)
|
|
else:
|
|
cbpi.emit_message("Failed to create plugin %s. Name arlready in use" % (name))
|
|
return ('', 500)
|
|
|
|
|
|
|
|
|
|
@blueprint.route('/<name>', methods=['POST'])
|
|
def saveFile(name):
|
|
|
|
"""
|
|
save plugin code. code is provides via http body
|
|
:param name: the plugin name
|
|
:return: empty http reponse
|
|
"""
|
|
with open("./modules/plugins/"+name+"/__init__.py", "wb") as fo:
|
|
fo.write(request.get_data())
|
|
cbpi.emit_message("PLUGIN %s SAVED" % (name))
|
|
|
|
return ('', 204)
|
|
|
|
@blueprint.route('/<name>', methods=['DELETE'])
|
|
def deletePlugin(name):
|
|
|
|
"""
|
|
Delete plugin
|
|
:param name: plugin name
|
|
:return: HTTP 204 if ok - HTTP 500 if plugin not exists
|
|
"""
|
|
if os.path.isdir("./modules/plugins/"+name) is False:
|
|
return ('Dir Not found', 500)
|
|
shutil.rmtree("./modules/plugins/"+name)
|
|
cbpi.notify("Plugin deleted", "Plugin %s deleted successfully" % name)
|
|
return ('', 204)
|
|
|
|
@blueprint.route('/<name>/reload/', methods=['POST'])
|
|
def reload(name):
|
|
"""
|
|
hot reload plugnin
|
|
:param name:
|
|
:return:
|
|
"""
|
|
try:
|
|
if name in cache["modules"]:
|
|
reload(cache["modules"][name])
|
|
cbpi.emit_message("REALOD OF PLUGIN %s SUCCESSFUL" % (name))
|
|
return ('', 204)
|
|
else:
|
|
cache["modules"][name] = import_module("modules.plugins.%s" % (name))
|
|
return ('', 204)
|
|
except Exception as e:
|
|
cbpi.emit_message("REALOD OF PLUGIN %s FAILED" % (name))
|
|
return json.dumps(e.message)
|
|
|
|
|
|
@blueprint.route('/list', methods=['GET'])
|
|
def plugins():
|
|
"""
|
|
Read the central plugin yaml to get a list of all official plugins
|
|
:return:
|
|
"""
|
|
response = requests.get("https://raw.githubusercontent.com/Manuel83/craftbeerpi-plugins/master/plugins.yaml")
|
|
cbpi.cache["plugins"] = merge(yaml.load(response.text), cbpi.cache["plugins"])
|
|
for key, value in cbpi.cache["plugins"].iteritems():
|
|
value["installed"] = os.path.isdir("./modules/plugins/%s/" % (key))
|
|
|
|
return json.dumps(cbpi.cache["plugins"])
|
|
|
|
|
|
@blueprint.route('/<name>/download', methods=['POST'])
|
|
def download_addon(name):
|
|
|
|
plugin = cbpi.cache["plugins"].get(name)
|
|
plugin["loading"] = True
|
|
if plugin is None:
|
|
return ('', 404)
|
|
try:
|
|
Repo.clone_from(plugin.get("repo_url"), "./modules/plugins/%s/" % (name))
|
|
cbpi.notify("Download successful", "Plugin %s downloaded successfully" % name)
|
|
finally:
|
|
plugin["loading"] = False
|
|
|
|
return ('', 204)
|
|
|
|
@blueprint.route('/<name>/update', methods=['POST'])
|
|
def update_addon(name):
|
|
repo = Repo("./modules/plugins/%s/" % (name))
|
|
o = repo.remotes.origin
|
|
info = o.pull()
|
|
cbpi.notify("Plugin Updated", "Plugin %s updated successfully. Please restart the system" % name)
|
|
return ('', 204)
|
|
|
|
|
|
def loadCorePlugins():
|
|
for filename in os.listdir("./modules/base_plugins"):
|
|
|
|
|
|
if os.path.isdir("./modules/base_plugins/"+filename) is False:
|
|
continue
|
|
try:
|
|
modules[filename] = import_module("modules.base_plugins.%s" % (filename))
|
|
except Exception as e:
|
|
|
|
|
|
cbpi.notify("Failed to load plugin %s " % filename, str(e), type="danger", timeout=None)
|
|
cbpi.app.logger.error(e)
|
|
|
|
def loadPlugins():
|
|
for filename in os.listdir("./modules/plugins"):
|
|
if os.path.isdir("./modules/plugins/" + filename) is False:
|
|
continue
|
|
try:
|
|
modules[filename] = import_module("modules.plugins.%s" % (filename))
|
|
except Exception as e:
|
|
cbpi.notify("Failed to load plugin %s " % filename, str(e), type="danger", timeout=None)
|
|
cbpi.app.logger.error(e)
|
|
|
|
#@cbpi.initalizer(order=1)
|
|
def initPlugins():
|
|
loadCorePlugins()
|
|
loadPlugins()
|
|
|
|
@cbpi.initalizer(order=2)
|
|
def init(cbpi):
|
|
|
|
cbpi.app.register_blueprint(blueprint, url_prefix='/api/editor')
|