knqyf263 / go-plugin

Go Plugin System over WebAssembly
MIT License
586 stars 30 forks source link

Plugin seems to be closing. Saving plugins in a map and calling on functionality elsewhere #20

Closed amlwwalker closed 1 year ago

amlwwalker commented 1 year ago

Hey, I might have missed something. I am loading plugins like so

        pluginMap := make(map[string]*MyPlugin)
    filepath.Walk(root, func(path string, info os.FileInfo, err error) error  {

        if !info.IsDir() && filepath.Ext(path) == EXT {
            if this, err := p.Load(ctx, path, PluginFunctions{}); err != nil {
                return err
            } else {
                pluginMap[uuid.New().String()] = &this
            }
        }
        return nil
    })
    m.plugins = pluginMap

then from "somewhere else" I am calling

func (p PluginManager) CallContentOnPlugins(ctx context.Context) error {
    for _, v := range p.plugins {
        content, err := (*v).Content(ctx, emptypb.Empty{})
        if err != nil {
            return err
        }
        fmt.Println("render content ", content.GetContent())
    }
    return nil
}

If I were to do this directly, in the first code snippet above where I am adding the plugin to the map, it works fine. However when I try to do this from this function, I get the error

error module "" closed with exit_code(0)

My guess is that I would have to keep calling .Load on the plugin however I would have thought all would be OK as I am storing the plugin in the map as a reference, but for some reason that doesnt' work? Any tips as to why?

(on another note, is there ways to expose functions in the plugin to the 'host' at runtime - i.e functions that are not known about in the proto file. Perhaps with reflection, or perhaps with a map of functions in the plugin that are exposed in the proto file?)

Thanks for your help!

amlwwalker commented 1 year ago

EDIT - it seems that passing a plugin around is causing the crash... is that something that makes any sense?

@codefromthecrypt @knqyf263 - I have put a 'broken' example here demonstrating the issue. Specifically here - I call Content when I first load the plugin, but when I try to call it from somewhere else using a reference to the plugin the plugin seems to crash with not further information.

I'm not sure how to debug this - I am using Goland - wondering if you have any tips on how to debug a plugin (when its called from the host)

P.S: Is the plugin expecting to only be run once and then it closes? Do I have to either keep loading it every time I want to use it, or do I have to somehow keep the main() function in the plugin running constantly with a waitgroup of something?

amlwwalker commented 1 year ago

I got it!

The issue was the plugin loader was defer p.Close(ctx) closing. I had not thought that this needed to be open for a plugin to work, but it makes sense now. I'll add that to my struct and close it later.

Hopefully this helps someone

codefromthecrypt commented 1 year ago

Thanks for putting the comment back about what happens. It helps to share this info, @amlwwalker, even if only to re-enforce the point.