Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

220 řádky
6.0KB

  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. if plugin is None:
  121. return ('', 404)
  122. plugin["loading"] = True
  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. """
  132. Updates a addon
  133. :param name: plugin name
  134. :return: HTTP 204 if ok - HTTP 500 if plugin not exists
  135. """
  136. plugin = cbpi.cache["plugins"].get(name)
  137. if plugin is None:
  138. return ('', 404)
  139. plugin["loading"] = True
  140. repo = Repo("./modules/plugins/%s/" % (name))
  141. if repo.remotes.origin.url == plugin.get('repo_url'):
  142. o = repo.remotes.origin
  143. _info = o.pull()
  144. else:
  145. # url has changed the plugin needs to be re-downloaded
  146. deletePlugin(name)
  147. return download_addon(name)
  148. reload(name)
  149. plugin["loading"] = False
  150. cbpi.notify("Plugin Updated", "Plugin %s updated successfully. Please restart the system" % name)
  151. return ('', 204)
  152. def loadCorePlugins():
  153. for filename in os.listdir("./modules/base_plugins"):
  154. if os.path.isdir("./modules/base_plugins/"+filename) is False:
  155. continue
  156. try:
  157. modules[filename] = import_module("modules.base_plugins.%s" % (filename))
  158. except Exception as e:
  159. cbpi.notify("Failed to load plugin %s " % filename, str(e), type="danger", timeout=None)
  160. cbpi.app.logger.error(e)
  161. def loadPlugins():
  162. for filename in os.listdir("./modules/plugins"):
  163. if os.path.isdir("./modules/plugins/" + filename) is False:
  164. continue
  165. try:
  166. modules[filename] = import_module("modules.plugins.%s" % (filename))
  167. except Exception as e:
  168. cbpi.notify("Failed to load plugin %s " % filename, str(e), type="danger", timeout=None)
  169. cbpi.app.logger.error(e)
  170. #@cbpi.initalizer(order=1)
  171. def initPlugins():
  172. loadCorePlugins()
  173. loadPlugins()
  174. @cbpi.initalizer(order=2)
  175. def init(cbpi):
  176. cbpi.app.register_blueprint(blueprint, url_prefix='/api/editor')