chireiden / shanghai

Shanghai
GNU General Public License v3.0
4 stars 2 forks source link

Plugin system #9

Open FichteFoll opened 8 years ago

FichteFoll commented 8 years ago

this is a changing post with our todo list

Plugins should:

For the future:

Questions:

nitori commented 8 years ago

Some things you might want to add:

Plugins should also be able to add ircv3 capabilities (CAP), and the treatment of those plugins might be different. There is no reason to load a plugin with a specific CAP, if the server doesn't support it.

Also as a question: what would happen if a plugin provides more than one CAP? Should that be allowed? And If it is, how to separate the capabilities that are supported by the server from those that aren't?

The easiest might be to just not allow it, or maybe to bind hooks or similar to a specific CAP, e.g. "only register this hook to the network if it supports the CAP".

Pseudo: register_hook('connect', on_connect, cap='sasl')

nitori commented 8 years ago

A few tools I found:

pluginbase @ pocoo

pluginloader

pluginmanager

None of these seem to have any dependency loading or unloading/reloading mechanics. So we either need to look more or see if one of them is easily extensible and fit for our purpose. Note: I don't particularly like any of them.

nitori commented 8 years ago

In order to understand what our plugin engine should be able to do, we have to consider what typical (or non-typical) bot functions you usually see on IRC.

A list of the things I came up with from the top of my head. I use the ! prefix here even though the "Shanghai" bot officially uses the plus sign (+):

FichteFoll commented 8 years ago

re CAPs: I'm thinking of having a "request_capabilities" hook where plugins get handed a set of the provided capabilities by the network and can return a set of those they want to request. The plugin manager joins the sets and sends them off as a request to the server. Supporting multiple CAPs wouldn't be an issue that way.

There should probably be an attribute for the available and active capabilities for each connection so that plugins can access that. Filtering a hook to only apply if a certain CAP is active should be trivial then. We could provide some of these more advanced hooks as a plugin or add everything to core, idk.

Also note that there is a CAP that allows updating the network's available CAPs (mostly useful for bouncers I suppose).

FichteFoll commented 8 years ago

I wrote down my general idea of plugins in our wiki: https://github.com/chireiden/shanghai/wiki/Plugins

Please review and comment or ask questions.

I put hot-reloading and depending on pypi packages on-hold as they are not required for the basic concept.

nitori commented 8 years ago

Regarding Hook priority: I'd think that a plugin that depends on another plugin might want to ensure that certain hooks are always executed after (or maybe even before) the same hooks of the other plugin, without knowing the specific hook priority of the plugin it depends on.

E.g. plugin A depends on plugin B, and plugin B hooks into, let's say, privmsg events. However, plugin A wants to either modify B's output (ensuring the hook in A is called after B) or prepare it (ensuring the hook in A is called before B).

Simply using priorities might not be sufficient. If the developer of plugin B decides to change the priorities, plugin A has to be changed as well.

I have no idea how to do that though, maybe every registered hook can be accessed via a name? Plugin B plugin key might be "pluginb" and it registered the hook "privmsg". So plugin A might be able to say "please register my privmsg hook after pluginb.privmsg" or something like that.

Pseudo: plugin_system.register('privmsg', after=['pluginb.privmsg']) or the like (a list because it might be more than one).

FichteFoll commented 8 years ago

That would make things complex for a couple reasons.

  1. We would need to manage a two-sided (?) dependency resolution for executing hooks before or after certain other hooks and we have no idea what to do if the provided dependencies collide (i.e. A before B, B before A)
  2. Plugin authors most likley do not (and usually should not) know which other plugins are currently loaded and what they do outside of their dependencies. And these dependencies are module-level. Depending on the exact action that A and B want to do, it might b better/easier to just monkey-patch the A plugin from B's code or for A to provide an API for these situations. The priority level system is specifically designed to prevent plugins from the requirement of knowing what other hooks are currently active.
FichteFoll commented 8 years ago

33 and #34 implemented most of this.

What remains is unload- and reloadability of plugins, auto-reloading when changed on disk (low priority) and all the config stuff.