Skip to content

Commit 1a69730

Browse files
example tests
Signed-off-by: eternal-flame-AD <yume@yumechi.jp>
1 parent 4e13724 commit 1a69730

18 files changed

Lines changed: 842 additions & 82 deletions

.github/workflows/test.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Test
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
test:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
- name: Set up Go
14+
uses: actions/setup-go@v4
15+
with:
16+
go-version: 1.24.6
17+
- name: Install dependencies
18+
run: go mod download
19+
- name: Test
20+
run: cd v2 && go test -v ./...
21+
22+
test-windows:
23+
runs-on: windows-latest
24+
steps:
25+
- uses: actions/checkout@v4
26+
- name: Set up Go
27+
uses: actions/setup-go@v4
28+
with:
29+
go-version: 1.24.6
30+
- name: Install dependencies
31+
run: go mod download
32+
- name: Test
33+
run: cd v2 && go test -v ./...

v2/anon_unix.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//go:build unix
2+
3+
package plugin
4+
5+
import (
6+
"golang.org/x/sys/unix"
7+
)
8+
9+
func NewAnonPipe(rx *uintptr, tx *uintptr, cloexec bool) error {
10+
var tmp [2]int
11+
var flags int
12+
if cloexec {
13+
flags = unix.O_CLOEXEC
14+
}
15+
if err := unix.Pipe2(tmp[:], flags); err != nil {
16+
return err
17+
}
18+
*rx = uintptr(tmp[0])
19+
*tx = uintptr(tmp[1])
20+
return nil
21+
}

v2/anon_windows.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//go:build windows
2+
3+
package plugin
4+
5+
import (
6+
"unsafe"
7+
8+
"golang.org/x/sys/windows"
9+
)
10+
11+
func NewAnonPipe(rx *uintptr, tx *uintptr, cloexec bool) error {
12+
var tmp [2]windows.Handle
13+
var sa windows.SecurityAttributes
14+
sa.Length = uint32(unsafe.Sizeof(sa))
15+
if !cloexec {
16+
sa.InheritHandle = 1
17+
}
18+
err := windows.CreatePipe(&tmp[0], &tmp[1], &sa, 0)
19+
if err != nil {
20+
return err
21+
}
22+
*rx = uintptr(tmp[0])
23+
*tx = uintptr(tmp[1])
24+
return nil
25+
}

v2/cli_flags.go

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,44 @@ import (
66
)
77

88
type PluginCliFlags struct {
9-
flagSet *flag.FlagSet
10-
CAData []byte
11-
CertData []byte
12-
KeyData []byte
9+
flagSet *flag.FlagSet
10+
KexReqFile *os.File
11+
KexRespFile *os.File
12+
Debug bool
1313
}
1414

1515
func ParsePluginCLIFlags(args []string) (*PluginCliFlags, error) {
1616
flagSet := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
17-
var caFile string
18-
var certFile string
19-
var keyFile string
20-
flagSet.StringVar(&certFile, "cert-file", "", "Path to the certificate file for Transport Auth.")
21-
flagSet.StringVar(&keyFile, "key-file", "", "Path to the key file for Transport Auth.")
22-
flagSet.StringVar(&caFile, "ca-file", "", "Path to the CA file for Transport Auth.")
17+
var kexReqFileName string
18+
var kexRespFileName string
19+
var debug bool
20+
flagSet.StringVar(&kexReqFileName, "kex-req-file", "", "File name for the key exchange for Transport Auth.")
21+
flagSet.StringVar(&kexRespFileName, "kex-resp-file", "", "File name for the key exchange for Transport Auth.")
22+
flagSet.BoolVar(&debug, "debug", false, "Enable debug mode.")
2323
flagSet.Parse(args)
24-
certData, err := os.ReadFile(certFile)
25-
if err != nil {
26-
return nil, err
27-
}
28-
keyData, err := os.ReadFile(keyFile)
24+
25+
kexReqFile, err := os.OpenFile(kexReqFileName, os.O_WRONLY, 0)
2926
if err != nil {
3027
return nil, err
3128
}
32-
caData, err := os.ReadFile(caFile)
29+
kexRespFile, err := os.OpenFile(kexRespFileName, os.O_RDONLY, 0)
3330
if err != nil {
3431
return nil, err
3532
}
3633
return &PluginCliFlags{
37-
flagSet: flagSet,
38-
CAData: caData,
39-
CertData: certData,
40-
KeyData: keyData,
34+
flagSet: flagSet,
35+
KexReqFile: kexReqFile,
36+
KexRespFile: kexRespFile,
37+
Debug: debug,
4138
}, nil
4239
}
40+
41+
func (f *PluginCliFlags) Close() error {
42+
if err := f.KexReqFile.Close(); err != nil {
43+
return err
44+
}
45+
if err := f.KexRespFile.Close(); err != nil {
46+
return err
47+
}
48+
return nil
49+
}

v2/examples_v1/echo/echo.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"log"
7+
"net/url"
8+
9+
"github.com/gin-gonic/gin"
10+
"github.com/gotify/plugin-api"
11+
)
12+
13+
// GetGotifyPluginInfo returns gotify plugin info.
14+
func GetGotifyPluginInfo() plugin.Info {
15+
return plugin.Info{
16+
ModulePath: "github.com/gotify/server/v2/plugin/example/echo",
17+
Name: "test plugin",
18+
}
19+
}
20+
21+
// EchoPlugin is the gotify plugin instance.
22+
type EchoPlugin struct {
23+
msgHandler plugin.MessageHandler
24+
storageHandler plugin.StorageHandler
25+
config *Config
26+
basePath string
27+
}
28+
29+
// SetStorageHandler implements plugin.Storager
30+
func (c *EchoPlugin) SetStorageHandler(h plugin.StorageHandler) {
31+
c.storageHandler = h
32+
}
33+
34+
// SetMessageHandler implements plugin.Messenger.
35+
func (c *EchoPlugin) SetMessageHandler(h plugin.MessageHandler) {
36+
c.msgHandler = h
37+
}
38+
39+
// Storage defines the plugin storage scheme
40+
type Storage struct {
41+
CalledTimes int `json:"called_times"`
42+
}
43+
44+
// Config defines the plugin config scheme
45+
type Config struct {
46+
MagicString string `yaml:"magic_string"`
47+
}
48+
49+
// DefaultConfig implements plugin.Configurer
50+
func (c *EchoPlugin) DefaultConfig() interface{} {
51+
return &Config{
52+
MagicString: "hello world",
53+
}
54+
}
55+
56+
// ValidateAndSetConfig implements plugin.Configurer
57+
func (c *EchoPlugin) ValidateAndSetConfig(config interface{}) error {
58+
c.config = config.(*Config)
59+
return nil
60+
}
61+
62+
// Enable enables the plugin.
63+
func (c *EchoPlugin) Enable() error {
64+
log.Println("echo plugin enabled")
65+
return nil
66+
}
67+
68+
// Disable disables the plugin.
69+
func (c *EchoPlugin) Disable() error {
70+
log.Println("echo plugin disbled")
71+
return nil
72+
}
73+
74+
// RegisterWebhook implements plugin.Webhooker.
75+
func (c *EchoPlugin) RegisterWebhook(baseURL string, g *gin.RouterGroup) {
76+
c.basePath = baseURL
77+
g.GET("/echo", func(ctx *gin.Context) {
78+
79+
storage, _ := c.storageHandler.Load()
80+
conf := new(Storage)
81+
json.Unmarshal(storage, conf)
82+
conf.CalledTimes++
83+
newStorage, _ := json.Marshal(conf)
84+
c.storageHandler.Save(newStorage)
85+
86+
c.msgHandler.SendMessage(plugin.Message{
87+
Title: "Hello received",
88+
Message: fmt.Sprintf("echo server received a hello message %d times", conf.CalledTimes),
89+
Priority: 2,
90+
Extras: map[string]any{
91+
"plugin::name": "echo",
92+
},
93+
})
94+
ctx.Writer.WriteString(fmt.Sprintf("Magic string is: %s\r\nEcho server running at %secho", c.config.MagicString, c.basePath))
95+
})
96+
}
97+
98+
// GetDisplay implements plugin.Displayer.
99+
func (c *EchoPlugin) GetDisplay(location *url.URL) string {
100+
loc := &url.URL{
101+
Path: c.basePath,
102+
}
103+
if location != nil {
104+
loc.Scheme = location.Scheme
105+
loc.Host = location.Host
106+
}
107+
loc = loc.ResolveReference(&url.URL{
108+
Path: "echo",
109+
})
110+
return "Echo plugin running at: " + loc.String()
111+
}
112+
113+
// NewGotifyPluginInstance creates a plugin instance for a user context.
114+
func NewGotifyPluginInstance(ctx plugin.UserContext) plugin.Plugin {
115+
return &EchoPlugin{}
116+
}
117+
118+
func main() {
119+
panic("this should be built as go plugin")
120+
}

0 commit comments

Comments
 (0)