-
Notifications
You must be signed in to change notification settings - Fork 76
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Plugin support #104
base: main
Are you sure you want to change the base?
Plugin support #104
Conversation
@dominikbraun Note: we may have discovered another possiblity: -> upside: much easier to maintain -> for rpc we need to basically create one rpc endpoint for each public method. It would also be possible to use the lib-approach for subcommand-plugins and the rpc approach for datasource-plugins, where then the plugins would contain the rpc server and timetrace would query the data through that from the plugins. |
@aligator this seems to be really cool, I will take a closer look at it this weekend and see if I can adapt the notify command as a plugin via your library :) |
@FelixTheodor But don't build something too serious. @aligator found yet another way to solve the plugin communication, but due to the (over-?) complexity of these approaches we're currently thinking about making timetrace usable as a Go package with plugins being completely isolated standalone binaries using that package. |
@dominikbraun These methods are basically also just callable as lib. So if someone wants to use that approach it works also with the same api-methods. The idea is that the only requirement for API-functions is to be a 'Method' of 'something' and that the 'something' is created at startup so that it can be passed to GoPlug in the beginning. In our case we could even use the timetrace struct. package actions
import (
"fmt"
"math/rand"
"strconv"
"time"
)
type App struct {
isSeeded bool
lastHello int
}
//goplug:generate
func (a *App) GetRandomInt(n int) (int, error) {
if !a.isSeeded {
rand.Seed(time.Now().UnixNano())
a.isSeeded = true
}
return rand.Intn(n), nil
}
//goplug:generate
func (a *App) PrintHello() error {
fmt.Println("Hellooooooo", strconv.Itoa(a.lastHello))
a.lastHello++
return nil
} This results currently in generated code like this: A plugin calls these methods as any other method: func main() {
p := New()
p.SetSubCommand("rand", func(args []string) error {
if len(args) < 2 {
return errors.New("rand: invalid arg count")
}
parsedInt, err := strconv.Atoi(args[1])
if err != nil {
return err
}
rand, err := p.GetRandomInt(parsedInt)
if err != nil {
return err
}
p.Print(fmt.Sprintf("Random result for input %v: \n%v", args[1], strconv.Itoa(rand)))
return nil
})
p.Run()
} |
# Conflicts: # config/config.go # go.sum
@dominikbraun @FelixTheodor Updated goplug to do the code generation. Also updated the example timetrace plugin to use that. Now it is nothing more needed than the annotation to @FelixTheodor feel free to try to implement the notify plugin. Should be easy to do. But don't expect the plugin support to be in the final state :-)
|
What do you guys think of using WebAssembly (WASI, to be specific) for the plugins? |
@obnoxiousnerd also an interesting idea, but I think in this case it is much more overhead than needed. If we support plugins I would prefer any more native way than another execution layer (webassembly). |
As discussed in #91 we may need plugins.
This is a first draft, which uses the GoPlug lib, which I created specifically for timetrace.
Both, this PR and GoPlug are in a very experimental and untested stage.
So feel free to leave suggestions or even other ideas to implement plugins.
Currently it is possible to add custom commands to timetrace and to print text to stdout.
Argument parsing has to be done in the plugin separately. (It should be possible to just use another cobra instance for that??)
(however don't know yet how to pass the help-output (e.g. timetrace help hello) to the plugin. Maybe with SetHelpFunc)
This should be enough to implement #91 as plugin. (except getting the latest record)
Note: not tested on windows yet...
Example
I added a basic example which adds a new timetrace subcommand
timetrace hello
To run it, first build the plugin by running
Then just run
It will print out "Hello World" and the other passed arguments.
The hello command will even be visible in the timetrace help.
As GoPlug works through stdin / stdout, it should be possible to write plugins in any language. (haven't tried that yet)