Is it possible to make extension plugins, for example, WordPress actions in Rust?

I'm going to rewrite the high-modulus CMS in Rust, so my question is, is it even possible for the “main” application to set extension points (actions / interceptors) that other plugins / boxes can “tab” into.

Something like this would be enough, but how would you do it in Rust? The above architecture uses the plugin registry and initiates each core plugin method from the kernel by iterating over each one. However, in Rust, since you cannot have a global variable called "modules", for example. plugin_registry lib box, I think this is not the right way of thinking in Rust.

Is there a better and more flexible way for plugins to integrate seamlessly with the main application? For example, something like an event dispatcher like WordPress?

+4
source share
1 answer

As Shepanster said, this is a very general question; therefore there are many ways to do what you want. And, as already mentioned, irona great example of a modular structure.

However, I will try to give a useful example of how to implement such a plug-in system. As an example, I assume that there is some kind of main box that can load plugins and "configure" CMS. This means that plugins do not load dynamically!


Structure

First, let's say we have four drawers:

  • rustpress: , WordPress.
  • rustpress-plugin: ( , , rustpress )
  • rustpress-signature: ,
  • my-blog: , -

1. /

Rust - trait s. . trait , rustpress-plugin:

pub trait Plugin {
    /// Returns the name of the plugin
    fn name(&self) -> &str;
    /// Hook to change the title of a post
    fn filter_title(&self, title: &mut String) {}
    /// Hook to change the body of a post
    fn filter_body(&self, body: &mut String) {}
}

, filter_* , ({}). , , .

2.

, , . impl ( rustpress-signature):

extern crate rustpress_plugin;
use rustpress_plugin::Plugin;

pub struct Signature {
    pub text: String,
}

impl Plugin for Signature {
    fn name(&self) -> &str {
        "Signature Plugin v0.1 by ferris"
    }

    fn filter_body(&self, body: &mut String) {
        body.push_str("\n-------\n");   // add visual seperator 
        body.push_str(&self.text);
    }
}

Signature, Plugin. name(), filter_body(). . filter_title(), .

3.

CMS . , CMS rustpress, . ( rustpress):

extern crate rustpress_plugin;
use rustpress_plugin::Plugin;

pub struct RustPress {
    // ...
    plugins: Vec<Box<Plugin>>,
}

impl RustPress {
    pub fn new() -> RustPress {
        RustPress {
            // ...
            plugins: Vec::new(),
        }
    }

    /// Adds a plugin to the stack
    pub fn add_plugin<P: Plugin + 'static>(&mut self, plugin: P) {
        self.plugins.push(Box::new(plugin));
    }

    /// Internal function that prepares a post
    fn serve_post(&self) {
        let mut title = "dummy".to_string();
        let mut body = "dummy body".to_string();

        for p in &self.plugins {
            p.filter_title(&mut title);
            p.filter_body(&mut body);
        }

        // use the finalized title and body now ...
    }

    /// Starts the CMS ...
    pub fn start(&self) {}
}

, Vec ( , , ). CMS -, .

4. CMS

- CMS ( ). my-blog:

extern crate rustpress;
extern crate rustpress_plugin;
extern crate rustpress_signature;

use rustpress::RustPress;
use rustpress_plugin::Plugin;
use rustpress_signature::Signature;

fn main() {
    let mut rustpress = RustPress::new();

    // add plugin
    let sig = Signature { text: "Ferris loves you <3".into() };
    rustpress.add_plugin(sig);

    rustpress.start();
}

Cargo.toml. , .

, . , . .

+6

Source: https://habr.com/ru/post/1625668/


All Articles