Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

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