Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

201 Zeilen
5.6KB

  1. import json
  2. import sys
  3. from flask import Blueprint, request, send_from_directory
  4. from importlib import import_module
  5. from modules import socketio, cbpi
  6. from git import Repo
  7. import os
  8. import requests
  9. import yaml
  10. import shutil
  11. import imp
  12. blueprint = Blueprint('addon', __name__)
  13. modules = {}
  14. def merge(source, destination):
  15. """
  16. Helper method to merge two dicts
  17. :param source:
  18. :param destination:
  19. :return:
  20. """
  21. for key, value in list(source.items()):
  22. if isinstance(value, dict):
  23. # get node or create one
  24. node = destination.setdefault(key, {})
  25. merge(value, node)
  26. else:
  27. destination[key] = value
  28. return destination
  29. @blueprint.route('/', methods=['GET'])
  30. def getPlugins():
  31. """
  32. Endpoint for all plugins
  33. :return:
  34. """
  35. result = []
  36. for filename in os.listdir("./modules/plugins"):
  37. if filename.endswith(".DS_Store") or filename.endswith(".py") or filename.endswith(".pyc"):
  38. continue
  39. result.append(filename)
  40. return json.dumps(result)
  41. @blueprint.route('/<name>', methods=['GET'])
  42. def getFile(name):
  43. """
  44. Returns plugin code
  45. :param name: plugin name
  46. :return: the plugin code from __init__.py
  47. """
  48. return send_from_directory('./plugins/'+name, "__init__.py")
  49. @blueprint.route('/<name>', methods=['PUT'])
  50. def createPlugin(name):
  51. """
  52. Create a new plugin file
  53. :param name: the plugin name
  54. :return: empty http response 204
  55. """
  56. if not os.path.exists("./modules/plugins/"+name):
  57. os.makedirs("./modules/plugins/"+name)
  58. with open("./modules/plugins/" + name + "/__init__.py", "wb") as fo:
  59. fo.write("")
  60. cbpi.emit_message("PLUGIN %s CREATED" % (name))
  61. return ('', 204)
  62. else:
  63. cbpi.emit_message("Failed to create plugin %s. Name arlready in use" % (name))
  64. return ('', 500)
  65. @blueprint.route('/<name>', methods=['POST'])
  66. def saveFile(name):
  67. """
  68. save plugin code. code is provides via http body
  69. :param name: the plugin name
  70. :return: empty http reponse
  71. """
  72. with open("./modules/plugins/"+name+"/__init__.py", "wb") as fo:
  73. fo.write(request.get_data())
  74. cbpi.emit_message("PLUGIN %s SAVED" % (name))
  75. return ('', 204)
  76. @blueprint.route('/<name>', methods=['DELETE'])
  77. def deletePlugin(name):
  78. """
  79. Delete plugin
  80. :param name: plugin name
  81. :return: HTTP 204 if ok - HTTP 500 if plugin not exists
  82. """
  83. if os.path.isdir("./modules/plugins/"+name) is False:
  84. return ('Dir Not found', 500)
  85. shutil.rmtree("./modules/plugins/"+name)
  86. cbpi.notify("Plugin deleted", "Plugin %s deleted successfully" % name)
  87. return ('', 204)
  88. @blueprint.route('/<name>/reload/', methods=['POST'])
  89. def reload(name):
  90. """
  91. hot reload plugnin
  92. :param name:
  93. :return:
  94. """
  95. try:
  96. if name in cache["modules"]:
  97. imp.reload(cache["modules"][name])
  98. cbpi.emit_message("REALOD OF PLUGIN %s SUCCESSFUL" % (name))
  99. return ('', 204)
  100. else:
  101. cache["modules"][name] = import_module("modules.plugins.%s" % (name))
  102. return ('', 204)
  103. except Exception as e:
  104. cbpi.emit_message("REALOD OF PLUGIN %s FAILED" % (name))
  105. return json.dumps(e.message)
  106. @blueprint.route('/list', methods=['GET'])
  107. def plugins():
  108. """
  109. Read the central plugin yaml to get a list of all official plugins
  110. :return:
  111. """
  112. response = requests.get("https://raw.githubusercontent.com/jpgimenez/craftbeerpi-plugins/master/plugins.yaml")
  113. cbpi.cache["plugins"] = merge(yaml.safe_load(response.text), cbpi.cache["plugins"])
  114. for key, value in cbpi.cache["plugins"].items():
  115. value["installed"] = os.path.isdir("./modules/plugins/%s/" % (key))
  116. return json.dumps(cbpi.cache["plugins"])
  117. @blueprint.route('/<name>/download', methods=['POST'])
  118. def download_addon(name):
  119. plugin = cbpi.cache["plugins"].get(name)
  120. plugin["loading"] = True
  121. if plugin is None:
  122. return ('', 404)
  123. try:
  124. Repo.clone_from(plugin.get("repo_url"), "./modules/plugins/%s/" % (name))
  125. cbpi.notify("Download successful", "Plugin %s downloaded successfully" % name)
  126. finally:
  127. plugin["loading"] = False
  128. return ('', 204)
  129. @blueprint.route('/<name>/update', methods=['POST'])
  130. def update_addon(name):
  131. repo = Repo("./modules/plugins/%s/" % (name))
  132. o = repo.remotes.origin
  133. info = o.pull()
  134. cbpi.notify("Plugin Updated", "Plugin %s updated successfully. Please restart the system" % name)
  135. return ('', 204)
  136. def loadCorePlugins():
  137. for filename in os.listdir("./modules/base_plugins"):
  138. if os.path.isdir("./modules/base_plugins/"+filename) is False:
  139. continue
  140. try:
  141. modules[filename] = import_module("modules.base_plugins.%s" % (filename))
  142. except Exception as e:
  143. cbpi.notify("Failed to load plugin %s " % filename, str(e), type="danger", timeout=None)
  144. cbpi.app.logger.error(e)
  145. def loadPlugins():
  146. for filename in os.listdir("./modules/plugins"):
  147. if os.path.isdir("./modules/plugins/" + filename) is False:
  148. continue
  149. try:
  150. modules[filename] = import_module("modules.plugins.%s" % (filename))
  151. except Exception as e:
  152. cbpi.notify("Failed to load plugin %s " % filename, str(e), type="danger", timeout=None)
  153. cbpi.app.logger.error(e)
  154. #@cbpi.initalizer(order=1)
  155. def initPlugins():
  156. loadCorePlugins()
  157. loadPlugins()
  158. @cbpi.initalizer(order=2)
  159. def init(cbpi):
  160. cbpi.app.register_blueprint(blueprint, url_prefix='/api/editor')