Skip to content

Commit 121ee51

Browse files
wip for v2 plugin docs
Signed-off-by: eternal-flame-AD <yume@yumechi.jp>
1 parent 66d48e2 commit 121ee51

File tree

2 files changed

+118
-39
lines changed

2 files changed

+118
-39
lines changed

docs/plugin-v1.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
id: plugin-v1
3+
title: Intro to Gotify Plugins (v1)
4+
---
5+
6+
> Plugins are currently only supported on Linux and MacOS due to a current limitation of golang.
7+
8+
## Description
9+
10+
_This documentation is generally designed for plugin developers. If you just wanted to use an existing plugin, you would need to refer to the documentation from the plugin maintainer._
11+
12+
Gotify provides built-in plugin functionality built on top of the [go plugin system](https://godoc.org/plugin). It is built for extending Gotify functionality.
13+
14+
## Get Started
15+
16+
First let's see a minimal example of gotify plugin, you can copy this boilerplate code to bootstrap your own plugin:
17+
18+
```golang
19+
package main
20+
21+
import (
22+
"github.com/gotify/plugin-api"
23+
)
24+
25+
// GetGotifyPluginInfo returns gotify plugin info
26+
func GetGotifyPluginInfo() plugin.Info {
27+
return plugin.Info{
28+
Name: "minimal plugin",
29+
ModulePath: "github.com/gotify/server/example/minimal",
30+
}
31+
}
32+
33+
// Plugin is plugin instance
34+
type Plugin struct{}
35+
36+
// Enable implements plugin.Plugin
37+
func (c *Plugin) Enable() error {
38+
return nil
39+
}
40+
41+
// Disable implements plugin.Plugin
42+
func (c *Plugin) Disable() error {
43+
return nil
44+
}
45+
46+
// NewGotifyPluginInstance creates a plugin instance for a user context.
47+
func NewGotifyPluginInstance(ctx plugin.UserContext) plugin.Plugin {
48+
return &Plugin{}
49+
}
50+
51+
func main() {
52+
panic("this should be built as go plugin")
53+
}
54+
```
55+
56+
This program exports two functions: `GetGotifyPluginInfo` and `NewGotifyPluginInstance`, gotify will use these to obtain the plugin metadata and create plugin instances for each user.
57+
58+
The `GetGotifyPluginInfo` must return a [`plugin.Info`](https://godoc.org/github.com/gotify/plugin-api#Info) containing descriptive info of the current plugin, all fields are optional except `ModulePath`(the module path of this plugin), which is used to distinguish different plugins.
59+
60+
The `NewGotifyPluginInstance` is called with a [`plugin.UserContext`](https://godoc.org/github.com/gotify/plugin-api#UserContext) for each user at startup and every time a new user is added, the plugin must return a plugin instance that satisfies [`plugin.Plugin`](https://godoc.org/github.com/gotify/plugin-api#Plugin) interface.
61+
More functionalities can be implemented by implementing more interfaces in the [`plugin-api`](https://godoc.org/github.com/gotify/plugin-api#Info) package.

docs/plugin.md

Lines changed: 57 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ id: plugin
33
title: Intro to Gotify Plugins
44
---
55

6-
> Plugins are currently only supported on Linux and MacOS due to a current limitation of golang.
7-
86
## Description
97

108
_This documentation is generally designed for plugin developers. If you just wanted to use an existing plugin, you would need to refer to the documentation from the plugin maintainer._
119

12-
Gotify provides built-in plugin functionality built on top of the [go plugin system](https://godoc.org/plugin). It is built for extending Gotify functionality.
10+
Gotify plugins are platform executables that use the gRPC architecture and contains two core behaviors:
11+
12+
- Establishing a secure socket connection to the server through a certificate exchange (abbreviated as `kex` in API and protocol documentation).
13+
- Act as a gRPC server that responds to requests from the server and provides updates to the user's state.
1314

1415
## Features
1516

@@ -27,51 +28,68 @@ Gotify provides built-in plugin functionality built on top of the [go plugin sys
2728
- Extending the WebUI functionality.
2829
- Delivering alarm notifications.
2930

30-
## Get Started
31+
## Architecture
3132

32-
First let's see a minimal example of gotify plugin, you can copy this boilerplate code to bootstrap your own plugin:
33+
- gRPC based, plugin is the "server" and gotify/server is the "client".
34+
- each user gets a long-running server-streaming RPC.
35+
- Backwards compatibility is provided by:
36+
- Using optional fields in the `RunUserInstanceServer` initialization request.
37+
- Using separate RPCs for functionally disjoint features. So the call interface can be extended without pushing breaking changes to the whole RPC schema.
3338

34-
```golang
35-
package main
39+
## Development Workflow
3640

37-
import (
38-
"github.com/gotify/plugin-api"
39-
)
41+
### Using the official Go Plugin Template
4042

41-
// GetGotifyPluginInfo returns gotify plugin info
42-
func GetGotifyPluginInfo() plugin.Info {
43-
return plugin.Info{
44-
Name: "minimal plugin",
45-
ModulePath: "github.com/gotify/server/example/minimal",
46-
}
47-
}
43+
Use the template [`gotify/plugin-template`](https://github.com/gotify/plugin-template) to scaffold your plugin.
4844

49-
// Plugin is plugin instance
50-
type Plugin struct{}
45+
The core logic happens in `PluginServer#RunUserInstance`, which creates a context that is valid (not cancelled) for the duration of the session.
5146

52-
// Enable implements plugin.Plugin
53-
func (c *Plugin) Enable() error {
54-
return nil
55-
}
56-
57-
// Disable implements plugin.Plugin
58-
func (c *Plugin) Disable() error {
59-
return nil
60-
}
61-
62-
// NewGotifyPluginInstance creates a plugin instance for a user context.
63-
func NewGotifyPluginInstance(ctx plugin.UserContext) plugin.Plugin {
64-
return &Plugin{}
65-
}
47+
```
6648
67-
func main() {
68-
panic("this should be built as go plugin")
49+
func (s *PluginServer) RunUserInstance(req *protobuf.UserInstanceRequest, stream protobuf.Plugin_RunUserInstanceServer) error {
50+
for i := range myplugin.Capabilities {
51+
if err := stream.Send(&protobuf.InstanceUpdate{
52+
Update: &protobuf.InstanceUpdate_Capable{
53+
Capable: myplugin.Capabilities[i],
54+
},
55+
}); err != nil {
56+
return err
57+
}
58+
}
59+
ticker := time.NewTicker(10 * time.Second)
60+
61+
ctx, cancel := context.WithCancel(context.Background())
62+
defer cancel()
63+
64+
go func() {
65+
// your logic here
66+
//
67+
_ = ctx
68+
}()
69+
70+
defer ticker.Stop()
71+
for {
72+
select {
73+
case <-ticker.C:
74+
if err := stream.Send(&protobuf.InstanceUpdate{
75+
Update: &protobuf.InstanceUpdate_Ping{
76+
Ping: new(emptypb.Empty),
77+
},
78+
}); err != nil {
79+
return err
80+
}
81+
case <-s.shutdown:
82+
return nil
83+
}
84+
}
6985
}
7086
```
7187

72-
This program exports two functions: `GetGotifyPluginInfo` and `NewGotifyPluginInstance`, gotify will use these to obtain the plugin metadata and create plugin instances for each user.
7388

74-
The `GetGotifyPluginInfo` must return a [`plugin.Info`](https://godoc.org/github.com/gotify/plugin-api#Info) containing descriptive info of the current plugin, all fields are optional except `ModulePath`(the module path of this plugin), which is used to distinguish different plugins.
89+
### Manual Implementation in your favorite Language/Scaffold
90+
91+
We support "duck-typed" plugins (i.e. plugins that loosely behave like one built using the Go template), namely it has to provide two functions:
92+
- A TLS key exchange using secure file descriptors at startup.
93+
- A long running gRPC server that instantiates a server-side stream for each user session.
7594

76-
The `NewGotifyPluginInstance` is called with a [`plugin.UserContext`](https://godoc.org/github.com/gotify/plugin-api#UserContext) for each user at startup and every time a new user is added, the plugin must return a plugin instance that satisfies [`plugin.Plugin`](https://godoc.org/github.com/gotify/plugin-api#Plugin) interface.
77-
More functionalities can be implemented by implementing more interfaces in the [`plugin-api`](https://godoc.org/github.com/gotify/plugin-api#Info) package.
95+
The protobuf files are located in [gotify/plugin-api](https://github.com/gotify/plugin-api) repository.

0 commit comments

Comments
 (0)