mirror of https://github.com/jlelse/GoBlog
Document plugins and how to implement them
This commit is contained in:
parent
567eeb1116
commit
ba085e7403
|
@ -1,6 +1,6 @@
|
|||
# GoBlog Plugins
|
||||
|
||||
GoBlog has a (still experimental) plugin system, that allows adding new functionality to GoBlog without adding anything to the GoBlog source and recompiling GoBlog. Plugins work using the [Yaegi](https://github.com/traefik/yaegi) package by Traefik and are interpreted at run time.
|
||||
GoBlog has a (still experimental) plugin system, that allows adding new functionality to GoBlog without adding anything to the GoBlog source and recompiling GoBlog. Plugins work using the [Yaegi](https://github.com/traefik/yaegi) package by Traefik, are written in Go and are interpreted at run time.
|
||||
|
||||
## Configuration
|
||||
|
||||
|
@ -8,34 +8,93 @@ Plugins can be added to GoBlog by adding a "plugins" section to the configuratio
|
|||
|
||||
```yaml
|
||||
plugins:
|
||||
- path: ./plugins/syndication
|
||||
type: ui
|
||||
- path: embedded:syndication # Use a Plugin provided by GoBlog using the "embedded:" prefix
|
||||
import: syndication
|
||||
config:
|
||||
config: # Provide configuration for the plugin
|
||||
parameter: syndication
|
||||
- path: ./plugins/demo
|
||||
type: ui
|
||||
import: demoui
|
||||
- path: ./plugins/demo
|
||||
type: middleware
|
||||
import: demomiddleware
|
||||
- path: embedded:demo
|
||||
import: demo
|
||||
- path: ./plugins/mycustomplugin
|
||||
import: mycustompluginpackage
|
||||
config:
|
||||
prio: 99
|
||||
abc:
|
||||
def:
|
||||
one: 1
|
||||
two: 2
|
||||
```
|
||||
|
||||
You need to specify the path to the plugin (remember to mount the path to your GoBlog container when using Docker), the type of the plugin, the import (the Go packakge) and you can additionally provide configuration for the plugin.
|
||||
You need to specify the path to the plugin (remember to mount the path to your GoBlog container when using Docker) and the Go packakge and you can additionally provide configuration for the plugin.
|
||||
|
||||
## Types of plugins
|
||||
|
||||
- `exec` (Command that is executed in a Go routine when starting GoBlog) - see https://pkg.go.dev/go.goblog.app/app/pkgs/plugintypes#Exec
|
||||
- `middleware` (HTTP middleware to intercept or modify HTTP requests) - see https://pkg.go.dev/go.goblog.app/app/pkgs/plugintypes#Middleware
|
||||
- `ui` (Render additional HTML) - see https://pkg.go.dev/go.goblog.app/app/pkgs/plugintypes#UI
|
||||
- `SetApp` (Access more GoBlog functionalities like the database) - see https://pkg.go.dev/go.goblog.app/app/pkgs/plugintypes#SetApp
|
||||
- `SetConfig` (Access the configuration provided for the plugin) - see https://pkg.go.dev/go.goblog.app/app/pkgs/plugintypes#SetConfig
|
||||
|
||||
- `Exec` (Command that is executed in a Go routine when starting GoBlog) - see https://pkg.go.dev/go.goblog.app/app/pkgs/plugintypes#Exec
|
||||
- `Middleware` (HTTP middleware to intercept or modify HTTP requests) - see https://pkg.go.dev/go.goblog.app/app/pkgs/plugintypes#Middleware
|
||||
- `UI` (Modify rendered HTML) - see https://pkg.go.dev/go.goblog.app/app/pkgs/plugintypes#UI
|
||||
|
||||
More types will be added later. Any plugin can implement multiple types, see the demo plugin as example.
|
||||
|
||||
## Plugin implementation
|
||||
|
||||
All you need to do is creating a Go-file that has a `GetPlugin` function that returns the interface implementation of the desired GoBlog plugin types.
|
||||
|
||||
So if you want to create a plugin that implements the `Exec` and `UI` plugin types, you need this:
|
||||
|
||||
```go
|
||||
package yourpluginpackage
|
||||
|
||||
import "go.goblog.app/app/pkgs/plugintypes"
|
||||
|
||||
type plugin struct {}
|
||||
|
||||
func GetPlugin() (plugintypes.Exec, plugintypes.UI) {
|
||||
p := &plugin{}
|
||||
return p, p
|
||||
}
|
||||
```
|
||||
|
||||
Of course, the plugin Go type also needs to have the required functions and methods:
|
||||
|
||||
```go
|
||||
// Exec
|
||||
func (p *plugin) Exec() {
|
||||
// Do something
|
||||
}
|
||||
|
||||
// UI
|
||||
func (p *plugin) Render(rc plugintypes.RenderContext, rendered io.Reader, modified io.Writer) {
|
||||
// Do something, but at least write something to modified, otherwise, the page will stay blank
|
||||
}
|
||||
```
|
||||
|
||||
If you want to access the configuration that is provided for your plugin, you need to implement the `SetConfig` plugin type. To access some more functions of GoBlog, implement the `SetApp` plugin type that allows you, for example, to access the database or get posts and their parameters.
|
||||
|
||||
|
||||
### Packages provided
|
||||
|
||||
Several go modules are already provided by GoBlog, so you don't have to vendor them.
|
||||
|
||||
GoBlog modules:
|
||||
|
||||
- `go.goblog.app/app/pkgs/plugintypes` (Needed for every plugin)
|
||||
- `go.goblog.app/app/pkgs/htmlbuilder` (Can be used to generate HTML)
|
||||
- `go.goblog.app/app/pkgs/bufferpool` (Can be used to manage `bytes.Buffer`s more efficiently)
|
||||
|
||||
Third-party modules
|
||||
|
||||
- `github.com/PuerkitoBio/goquery` (Can be used to *manipulate* HTML in a jquery-like way)
|
||||
|
||||
## Plugins
|
||||
|
||||
Some simple plugins are included in the main GoBlog repository. Some can be found elsewhere.
|
||||
|
||||
### Syndication links (plugins/syndication)
|
||||
### Demo (Path `embedded:demo`, Import `demo`)
|
||||
|
||||
A simple demo plugin showcasing some of the features plugins can implement. Take a look at the source code, if you want to implement your own plugin.
|
||||
|
||||
### Syndication links (Path `embedded:syndication`, Import `syndication`)
|
||||
|
||||
Adds hidden `u-syndication` `data` elements to post page when the configured post parameter (default: "syndication") is available.
|
||||
|
||||
|
@ -43,7 +102,7 @@ Adds hidden `u-syndication` `data` elements to post page when the configured pos
|
|||
|
||||
`parameter` (string): Name for the post parameter containing the syndication links.
|
||||
|
||||
### Webrings (plugins/webrings)
|
||||
### Webrings (Path `embedded:webrings`, Import `webrings`)
|
||||
|
||||
Adds webring links to the bottom of the blog footer to easily participate in webrings.
|
||||
|
||||
|
|
3
go.mod
3
go.mod
|
@ -56,7 +56,8 @@ require (
|
|||
// master
|
||||
github.com/tkrajina/gpxgo v1.2.2-0.20220217201249-321f19554eec
|
||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
|
||||
github.com/traefik/yaegi v0.14.3
|
||||
// master
|
||||
github.com/traefik/yaegi v0.14.4-0.20230117132604-1679870ea3c8
|
||||
github.com/vcraescu/go-paginator v1.0.1-0.20201114172518-2cfc59fe05c2
|
||||
github.com/xhit/go-simple-mail/v2 v2.13.0
|
||||
github.com/yuin/goldmark v1.5.3
|
||||
|
|
4
go.sum
4
go.sum
|
@ -407,8 +407,8 @@ github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJ
|
|||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
|
||||
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 h1:PM5hJF7HVfNWmCjMdEfbuOBNXSVF2cMFGgQTPdKCbwM=
|
||||
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208/go.mod h1:BzWtXXrXzZUvMacR0oF/fbDDgUPO8L36tDMmRAf14ns=
|
||||
github.com/traefik/yaegi v0.14.3 h1:LqA0k8DKwvRMc+msfQjNusphHJc+r6WC5tZU5TmUFOM=
|
||||
github.com/traefik/yaegi v0.14.3/go.mod h1:AVRxhaI2G+nUsaM1zyktzwXn69G3t/AuTDrCiTds9p0=
|
||||
github.com/traefik/yaegi v0.14.4-0.20230117132604-1679870ea3c8 h1:/7StGZkjdW/GtwISKUGl2hz6TM+0eYYjTCxppbSAgnk=
|
||||
github.com/traefik/yaegi v0.14.4-0.20230117132604-1679870ea3c8/go.mod h1:AVRxhaI2G+nUsaM1zyktzwXn69G3t/AuTDrCiTds9p0=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
|
|
|
@ -7,7 +7,9 @@ import (
|
|||
|
||||
// App is used to access GoBlog's app instance.
|
||||
type App interface {
|
||||
// Get access to GoBlog's database
|
||||
GetDatabase() Database
|
||||
// Get a post from the database or an error when there is no post for the given path
|
||||
GetPost(path string) (Post, error)
|
||||
}
|
||||
|
||||
|
@ -23,11 +25,14 @@ type Database interface {
|
|||
|
||||
// Post
|
||||
type Post interface {
|
||||
// Get a string array map with all the post's parameters
|
||||
GetParameters() map[string][]string
|
||||
}
|
||||
|
||||
// RenderContext
|
||||
type RenderContext interface {
|
||||
// Get the path of the request
|
||||
GetPath() string
|
||||
// Get the blog name
|
||||
GetBlog() string
|
||||
}
|
||||
|
|
|
@ -15,15 +15,22 @@ type SetConfig interface {
|
|||
SetConfig(config map[string]any)
|
||||
}
|
||||
|
||||
// Exec plugins are executed after all plugins where initialized.
|
||||
type Exec interface {
|
||||
// Exec gets called from a Goroutine, so it runs asynchronously.
|
||||
Exec()
|
||||
}
|
||||
|
||||
// Middleware plugins can intercept and modify HTTP requests or responses.
|
||||
type Middleware interface {
|
||||
Handler(next http.Handler) http.Handler
|
||||
// Return a priority, the higher prio middlewares get called first.
|
||||
Prio() int
|
||||
}
|
||||
|
||||
// UI plugins get called when rendering HTML.
|
||||
type UI interface {
|
||||
// rendered is a reader with all the rendered HTML, modify it and write it to modified. This is then returned to the client.
|
||||
// The renderContext provides information such as the path of the request or the blog name.
|
||||
Render(renderContext RenderContext, rendered io.Reader, modified io.Writer)
|
||||
}
|
||||
|
|
|
@ -62,6 +62,9 @@ func (a *goBlog) initPlugins() error {
|
|||
}
|
||||
|
||||
func (a *goBlog) getPlugins(typ string) []any {
|
||||
if a.pluginHost == nil {
|
||||
return []any{}
|
||||
}
|
||||
return a.pluginHost.GetPlugins(typ)
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ func (p *plugin) SetConfig(config map[string]any) {
|
|||
}
|
||||
|
||||
// UI
|
||||
func (p *plugin) Render(_ plugintypes.RenderContext, rendered io.Reader, modified io.Writer) {
|
||||
func (*plugin) Render(_ plugintypes.RenderContext, rendered io.Reader, modified io.Writer) {
|
||||
doc, err := goquery.NewDocumentFromReader(rendered)
|
||||
if err != nil {
|
||||
fmt.Println("demoui plugin: " + err.Error())
|
||||
|
|
|
@ -7,6 +7,7 @@ github.com/cretz/bine@master
|
|||
github.com/tkrajina/gpxgo@master
|
||||
github.com/yuin/goldmark-emoji@master
|
||||
willnorris.com/go/microformats@main
|
||||
github.com/traefik/yaegi@master
|
||||
"
|
||||
|
||||
checkSkip() {
|
||||
|
|
Loading…
Reference in New Issue