Skip to content

Commit 2e6c45a

Browse files
authored
Merge pull request #1 from eternal-flame-AD/master
v1 API
2 parents a84b0aa + a46fa32 commit 2e6c45a

File tree

13 files changed

+359
-1
lines changed

13 files changed

+359
-1
lines changed

.travis.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
language: go
2+
go:
3+
- "1.11"
4+
5+
notifications:
6+
email: false
7+
8+
env:
9+
- GO111MODULE=on
10+
11+
before_install:
12+
- make download-tools
13+
14+
install:
15+
- go get
16+
17+
script:
18+
- make check

Makefile

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
PKG=./
2+
3+
cap-version:
4+
wget -O /tmp/gotify.go.mod https://github.com/gotify/server/raw/master/go.mod; \
5+
for P in ${PKG}; do \
6+
go run github.com/gotify/plugin-api/cmd/gomod-cap -to `echo $$P` -from /tmp/gotify.go.mod; \
7+
done
8+
9+
check: check-go check-symbol check-mod check-lint
10+
11+
check-go:
12+
for P in ${PKG}; do \
13+
go test `echo $$P`; \
14+
done
15+
16+
check-lint:
17+
for P in ${PKG}; do \
18+
golint -set_exit_status `echo $$P`; \
19+
done
20+
21+
check-mod:
22+
wget -O /tmp/gotify.go.mod https://github.com/gotify/server/raw/master/go.mod; \
23+
for P in ${PKG}; do \
24+
go run github.com/gotify/plugin-api/cmd/gomod-cap -to `echo $$P` -from /tmp/gotify.go.mod -check=true; \
25+
done
26+
27+
check-symbol:
28+
for P in ${PKG}; do \
29+
go-exports -d `echo $$P` -c `echo $$P/export_ref_do_not_edit.json`; \
30+
done
31+
32+
release: generate-symbol
33+
34+
generate-symbol:
35+
for P in ${PKG}; do \
36+
if [ ! -f `echo $$P/export_ref_do_not_edit.json` ]; then \
37+
go-exports -d `echo $$P` > `echo $$P/export_ref_do_not_edit.json`; \
38+
fi; \
39+
done
40+
41+
download-tools:
42+
go get -u golang.org/x/lint/golint
43+
go get -u github.com/eternal-flame-AD/go-exports
44+
45+
.PHONY: check-go check-symbol check-lint check-mod generate-symbol cap-version download-tools

README.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,39 @@
11
# plugin-api
22

3-
tbd
3+
[![Build Status](https://travis-ci.org/gotify/plugin-api.svg?branch=master)](https://travis-ci.org/gotify/plugin-api)
4+
[![GoDoc](https://godoc.org/github.com/gotify/plugin-api?status.svg)](https://godoc.org/github.com/gotify/plugin-api)
5+
6+
This repository consisted of APIs used in gotify plugins.
7+
8+
## Usage
9+
10+
### Plugin API
11+
12+
https://gotify.net/docs/plugin
13+
14+
### CLI tools
15+
16+
#### `github.com/gotify/cmd/gomod-cap`
17+
18+
Since `go.mod` follows a [minimal version selection](https://github.com/golang/proposal/blob/master/design/24301-versioned-go.md), packages are built with the lowest common version requirement defined in `go.mod`. This poses a problem when developing plugins:
19+
20+
If the gotify server is built with the following go.mod:
21+
```
22+
require some/package v0.1.0
23+
```
24+
But when the plugin is built, it used a newer version of this package:
25+
```
26+
require some/package v0.1.1
27+
```
28+
Since the server is built with `v0.1.0` and the plugin is built with `v0.1.1` of `some/package`, the built plugin could not be loaded due to different import package versions.
29+
30+
`gomod-cap` is a simple util to ensure that plugin `go.mod` files does not have higher version requirements than the main gotify `go.mod` file.
31+
32+
To resolve all incompatible requirements:
33+
```bash
34+
$ go run github.com/gotify/plugin-api/cmd/gomod-cap -from /path/to/gotify/server/go.mod -to /path/to/plugin/go.mod
35+
```
36+
To only check for incompatible requirements(useful in CI):
37+
```bash
38+
$ go run github.com/gotify/plugin-api/cmd/gomod-cap -from /path/to/gotify/server/go.mod -to /path/to/plugin/go.mod -check=true
39+
```

cmd/gomod-cap/merge.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*gomod-cap
2+
3+
This command line util is used to help plugins keep their go.mod file requirements lower than the gotify-server itself in order to make sure that plugins are built with the same version of dependencies as the main gotify program does.
4+
5+
Since go.mod follow a minimal version selection(https://github.com/golang/proposal/blob/master/design/24301-versioned-go.md). Common import paths described in the plugin go.mod must have a lower or equal version than the main program itself.
6+
7+
Sample usage:
8+
9+
$ go run github.com/gotify/plugin-api/cmd/gomod-cap -from /path/to/gotify/server/go.mod -to /path/to/your/plugin/go.mod
10+
*/
11+
package main
12+
13+
import (
14+
"bytes"
15+
"encoding/json"
16+
"flag"
17+
"log"
18+
"os"
19+
"os/exec"
20+
"path"
21+
)
22+
23+
// Copied from go help mod edit
24+
25+
type Module struct {
26+
Path string
27+
Version string
28+
}
29+
30+
type GoMod struct {
31+
Module Module
32+
Require []Require
33+
Exclude []Module
34+
Replace []Replace
35+
}
36+
37+
type Require struct {
38+
Path string
39+
Version string
40+
Indirect bool
41+
}
42+
43+
type Replace struct {
44+
Old Module
45+
New Module
46+
}
47+
48+
func goCmd(args ...string) ([]byte, error) {
49+
cmd := exec.Command("go", args...)
50+
out := bytes.NewBuffer([]byte{})
51+
cmd.Stdout = out
52+
cmd.Stderr = os.Stderr
53+
err := cmd.Run()
54+
return out.Bytes(), err
55+
}
56+
57+
func getModuleRequireFromGoModFile(path string) []Require {
58+
var res GoMod
59+
goModJSON, err := goCmd("mod", "edit", "-json", path)
60+
if err != nil {
61+
panic(err)
62+
}
63+
if err := json.Unmarshal(goModJSON, &res); err != nil {
64+
panic(err)
65+
}
66+
return res.Require
67+
}
68+
69+
func main() {
70+
fromFlag := flag.String("from", "./go.mod", "go.mod file or dir to cap go.mod version from")
71+
toFlag := flag.String("to", "./go.mod", "go.mod file or dir to cap go.mod version to")
72+
checkFlag := flag.Bool("check", false, "check for incompatibility only")
73+
flag.Parse()
74+
75+
from := *fromFlag
76+
if info, err := os.Stat(from); err == nil && info.IsDir() {
77+
from = path.Join(from, "./", "go.mod")
78+
}
79+
cur := *toFlag
80+
if info, err := os.Stat(cur); err == nil && info.IsDir() {
81+
cur = path.Join(cur, "./", "go.mod")
82+
}
83+
curMods := getModuleRequireFromGoModFile(cur)
84+
fromMods := getModuleRequireFromGoModFile(from)
85+
86+
modConstraint := make(map[string]string)
87+
for _, req := range fromMods {
88+
modConstraint[req.Path] = req.Version
89+
}
90+
91+
for _, req := range curMods {
92+
if constraintVersion, ok := modConstraint[req.Path]; ok {
93+
log.Printf("Found common import path %s", req.Path)
94+
if req.Version != constraintVersion {
95+
if *checkFlag {
96+
log.Printf("Found incompatible go.mod constraint: path %s has version %s, higher than %s", req.Path, req.Version, constraintVersion)
97+
os.Exit(1)
98+
}
99+
log.Printf("Changing require version to %s", constraintVersion)
100+
goCmd("mod", "edit", "-require="+req.Path+"@"+constraintVersion, cur)
101+
}
102+
}
103+
}
104+
}

config.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package plugin
2+
3+
// Configurer is the interface plugins should implement in order to provide configuration interface to the user
4+
type Configurer interface {
5+
Plugin
6+
// DefaultConfig will be called on plugin first run. The default configuration will be provided to the user for future editing.
7+
DefaultConfig() interface{}
8+
// EmptyConfig returns an instance of an empty configuration. Used for generating schemes.
9+
EmptyConfig() interface{}
10+
// ValidateAndSetConfig will be called every time the plugin is initialized or the configuration has been changed by the user.
11+
// Plugins should check whether the configuration is valid and optionally return an error.
12+
// Parameter is guaranteed to be the same type as the return type of EmptyConfig()
13+
ValidateAndSetConfig(c interface{}) error
14+
}

displayer.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package plugin
2+
3+
// Displayer is the interface plugins should implement to show a text to the user.
4+
// The text will appear on the plugin details page and can be multi-line.
5+
// Markdown syntax is allowed. Good for providing dynamically generated instructions to the user.
6+
type Displayer interface {
7+
Plugin
8+
GetDisplay() string
9+
}

export_ref_do_not_edit.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[{"label":"Displayer","type":"interface","fileName":"displayer.go","pos":276,"members":[{"label":"Plugin","type":"embed"},{"label":"GetDisplay","type":"method","funcSpec":{"returns":[{"type":"type","underlyingType":"string"}]}}]},{"label":"Message","type":"struct","fileName":"messenger.go","pos":93,"members":[{"label":"Message","type":"member"},{"label":"Title","type":"member"},{"label":"Priority","type":"member"}]},{"label":"MessageHandler","type":"interface","fileName":"messenger.go","pos":237,"members":[{"label":"SendMessage","type":"method","funcSpec":{"params":[{"type":"type","underlyingType":"Message"}],"returns":[{"type":"type","underlyingType":"error"}]}}]},{"label":"Messenger","type":"interface","fileName":"messenger.go","pos":452,"members":[{"label":"Plugin","type":"embed"},{"label":"SetMessageHandler","type":"method","funcSpec":{"params":[{"type":"type","underlyingType":"MessageHandler"}]}}]},{"label":"Plugin","type":"interface","fileName":"plugin.go","pos":79,"members":[{"label":"Enable","type":"method","funcSpec":{"returns":[{"type":"type","underlyingType":"error"}]}},{"label":"Disable","type":"method","funcSpec":{"returns":[{"type":"type","underlyingType":"error"}]}}]},{"label":"UserContext","type":"struct","fileName":"plugin.go","pos":473,"members":[{"label":"ID","type":"member"},{"label":"Name","type":"member"},{"label":"Admin","type":"member"}]},{"label":"Info","type":"struct","fileName":"plugin.go","pos":731,"members":[{"label":"Version","type":"member"},{"label":"Author","type":"member"},{"label":"Name","type":"member"},{"label":"Website","type":"member"},{"label":"Description","type":"member"},{"label":"License","type":"member"},{"label":"ModulePath","type":"member"}]},{"label":"Configurer","type":"interface","fileName":"config.go","pos":133,"members":[{"label":"Plugin","type":"embed"},{"label":"DefaultConfig","type":"method","funcSpec":{"returns":[{"type":"interface"}]}},{"label":"EmptyConfig","type":"method","funcSpec":{"returns":[{"type":"interface"}]}},{"label":"ValidateAndSetConfig","type":"method","funcSpec":{"params":[{"type":"interface"}],"returns":[{"type":"type","underlyingType":"error"}]}}]},{"label":"Webhooker","type":"interface","fileName":"webhook.go","pos":139,"members":[{"label":"Plugin","type":"embed"},{"label":"RegisterWebhook","type":"method","funcSpec":{"params":[{"label":"gin.RouterGroup","type":"selector"}]}}]},{"label":"StorageHandler","type":"interface","fileName":"storage.go","pos":125,"members":[{"label":"Save","type":"method","funcSpec":{"params":[{"label":"[]byte","type":"array"}],"returns":[{"type":"type","underlyingType":"error"}]}},{"label":"Load","type":"method","funcSpec":{"returns":[{"label":"[]byte","type":"array"},{"type":"type","underlyingType":"error"}]}}]},{"label":"Storager","type":"interface","fileName":"storage.go","pos":287,"members":[{"label":"Plugin","type":"embed"},{"label":"SetStorageHandler","type":"method","funcSpec":{"params":[{"type":"type","underlyingType":"StorageHandler"}]}}]}]

go.mod

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module github.com/gotify/plugin-api
2+
3+
require (
4+
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect
5+
github.com/gin-gonic/gin v1.3.0
6+
github.com/golang/protobuf v1.2.0 // indirect
7+
github.com/json-iterator/go v1.1.5 // indirect
8+
github.com/mattn/go-isatty v0.0.4 // indirect
9+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
10+
github.com/modern-go/reflect2 v1.0.1 // indirect
11+
github.com/stretchr/testify v1.3.0 // indirect
12+
github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2 // indirect
13+
golang.org/x/net v0.0.0-20190110200230-915654e7eabc // indirect
14+
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect
15+
golang.org/x/sys v0.0.0-20190109145017-48ac38b7c8cb // indirect
16+
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
17+
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
18+
gopkg.in/yaml.v2 v2.2.2 // indirect
19+
)

go.sum

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
2+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cougNAV9szl6CVoj2RYwzS3DpUQNtlY=
4+
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
5+
github.com/gin-gonic/gin v1.3.0 h1:kCmZyPklC0gVdL728E6Aj20uYBJV93nj/TkwBTKhFbs=
6+
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
7+
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
8+
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
9+
github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE=
10+
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
11+
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
12+
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
13+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
14+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
15+
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
16+
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
17+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
18+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
19+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
20+
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
21+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
22+
github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2 h1:EICbibRW4JNKMcY+LsWmuwob+CRS1BmdRdjphAm9mH4=
23+
github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
24+
golang.org/x/net v0.0.0-20190110200230-915654e7eabc h1:Yx9JGxI1SBhVLFjpAkWMaO1TF+xyqtHLjZpvQboJGiM=
25+
golang.org/x/net v0.0.0-20190110200230-915654e7eabc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
26+
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
27+
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
28+
golang.org/x/sys v0.0.0-20190109145017-48ac38b7c8cb h1:1w588/yEchbPNpa9sEvOcMZYbWHedwJjg4VOAdDHWHk=
29+
golang.org/x/sys v0.0.0-20190109145017-48ac38b7c8cb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
30+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
31+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
32+
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
33+
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
34+
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
35+
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
36+
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
37+
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

messenger.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package plugin
2+
3+
// Message describes a message to be send by MessageHandler#SendMessage
4+
type Message struct {
5+
Message string
6+
Title string
7+
Priority int
8+
}
9+
10+
// MessageHandler consists of message callbacks to be used by plugins.
11+
type MessageHandler interface {
12+
// SendMessage sends a message with the given information in the request.
13+
SendMessage(msg Message) error
14+
}
15+
16+
// Messenger is the interface plugins should implement to send messages.
17+
type Messenger interface {
18+
Plugin
19+
// SetMessageHandler is called every time the plugin is initialized.
20+
// Plugins should record the handler and use the callbacks provided in the handler to send messages.
21+
SetMessageHandler(h MessageHandler)
22+
}

0 commit comments

Comments
 (0)