DEV Community

Cover image for Plugin in Golang
JackTT
JackTT

Posted on • Edited on

Plugin in Golang

#go

Golang plugin implementation

This repository explores the plugin feature introduced in Go 1.8, providing a example to help you understand and utilize this powerful functionality.

About plugin feature in Golang

Starting from Go 1.8, developers have the ability to write plugins and load them dynamically at runtime. This feature adds a new level of flexibility to Go programs, allowing for modular and extensible designs. With plugins, you can extend your application's functionality without the need to recompile or redeploy the entire codebase.

Key benefit

  • Dynamic Loading: Plugins can be loaded and unloaded dynamically at runtime, enabling the addition or removal of functionality without disrupting the main program.
  • Flexibility: Unlike traditional library imports, which are resolved at build time, plugins offer a more flexible approach. They can be swapped or updated independently, giving you the freedom to iterate and experiment with different implementations.
  • Modularity: The plugin feature promotes a modular design pattern by encapsulating specific functionalities in separate components. This enhances code organization, reusability, and maintainability.
  • Encapsulation: Plugins run in their own isolated namespaces, preventing conflicts between different plugins or the main program. This allows for secure and reliable extensibility.

How to run this example:

  1. Build plugins
 go build -buildmode=plugin -o ./plugins/eng/eng.so ./plugins/eng/speaker.go
Enter fullscreen mode Exit fullscreen mode

You can use the Makefile to quickly build all plugins:

make build-plugins
Enter fullscreen mode Exit fullscreen mode
  1. Run
go run main.go english

# Alice says "hello" in English

go run main.go vietnamese

# Anh Thư says "xin chào" in Vietnamese
Enter fullscreen mode Exit fullscreen mode

How to implement a plugin

  • A plugin package must be identified as main.
  • Exported package functions and variables become shared library symbols. In the above, variable Speaker will be exported as a symbol in the compiled shared library.

Example implementation:

package main

type speaker struct {
}

func (s *speaker) Speak() string {
    return "hello"
}

// Exported
var Speaker speaker
var SpeakerName = "Alice"
Enter fullscreen mode Exit fullscreen mode

In this example, we are exporting both the Speaker type and the SpeakerName variable, which are referred to as symbols in the context of plugins. By exporting these symbols, we enable their accessibility and visibility to other packages and modules that import them.

How to open plugin

plugin, err := plugin.Open("path/to/plugin.so")
if err != nil {
    return err
}
Enter fullscreen mode Exit fullscreen mode

How to look up symbol

You can look up the symbol that has been exported in plugin implementation by the following syntax:

symSpeaker, err := plugin.Lookup("Speaker")
if err != nil {
  return err
}

var speaker Speaker
speaker, ok := symSpeaker.(Speaker)
if !ok {
    return errors.New("unexpected type from module symbol")
}
speaker.Speak()
Enter fullscreen mode Exit fullscreen mode

Example implementation

https://github.com/huantt/golang-plugin-examle

Top comments (2)

Collapse
 
andreitelteu profile image
Andrei Telteu

I made a plugin system using this tutorial that allows any custom gofiber http handler to be attached from the plugin, if anyone is interested on a real-world example.
The conversion of types received from the plugin is the tricky part, but i got it working.
You can also see in this repo a local docker-compose setup with separate dockerfiles for the main program and the plugin, with air for rebuilding on save.
github.com/AndreiTelteu/hestia-go/...

Collapse
 
andreitelteu profile image
Andrei Telteu

That's amazing ! So useful.
If adopted by k6 for example will be super easy to install plugins like github.com/szkiba/xk6-dashboard or k6-browser without having to rebuild k6 every time you want to add a plugin. Just download the plugin and place it in the plugins folder :D
Also they can make it even simpler by having a command like k6 plugin add k6-browser