├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── cmd └── gomod-cap │ └── merge.go ├── config.go ├── displayer.go ├── export_ref_do_not_edit.json ├── go.mod ├── go.sum ├── messenger.go ├── plugin.go ├── storage.go └── webhook.go /.travis.yml: -------------------------------------------------------------------------------- 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 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Gotify 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 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: -------------------------------------------------------------------------------- 1 | # plugin-api 2 | 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 | ``` 40 | -------------------------------------------------------------------------------- /cmd/gomod-cap/merge.go: -------------------------------------------------------------------------------- 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 | } 105 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 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 to set the default config. 7 | // DefaultConfig will also be used if the provided config cannot be validate during initialization. 8 | // The default configuration will be provided to the user for future editing. Used for generating schemas and unmarshaling. 9 | DefaultConfig() 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 DefaultConfig() 13 | ValidateAndSetConfig(c interface{}) error 14 | } 15 | -------------------------------------------------------------------------------- /displayer.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import "net/url" 4 | 5 | // Displayer is the interface plugins should implement to show a text to the user. 6 | // The text will appear on the plugin details page and can be multi-line. 7 | // Markdown syntax is allowed. Good for providing dynamically generated instructions to the user. 8 | // Location is the current location the user is accessing the API from, nil if not recoverable. 9 | // Location contains the path to the display api endpoint, you may only need the base url. 10 | // Example: https://gotify.net/plugin/5/display 11 | type Displayer interface { 12 | Plugin 13 | GetDisplay(location *url.URL) string 14 | } 15 | -------------------------------------------------------------------------------- /export_ref_do_not_edit.json: -------------------------------------------------------------------------------- 1 | [{"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"}]}}]},{"label":"Displayer","type":"interface","fileName":"displayer.go","pos":390,"members":[{"label":"Plugin","type":"embed"},{"label":"GetDisplay","type":"method","funcSpec":{"params":[{"label":"*url.URL","type":"star"}],"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":"Extras","type":"member"}]},{"label":"MessageHandler","type":"interface","fileName":"messenger.go","pos":270,"members":[{"label":"SendMessage","type":"method","funcSpec":{"params":[{"type":"type","underlyingType":"Message"}],"returns":[{"type":"type","underlyingType":"error"}]}}]},{"label":"Messenger","type":"interface","fileName":"messenger.go","pos":485,"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":"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":[{"type":"type","underlyingType":"string"},{"label":"*gin.RouterGroup","type":"star"}]}}]}] 2 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 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 | ) 20 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 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= 38 | -------------------------------------------------------------------------------- /messenger.go: -------------------------------------------------------------------------------- 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 | Extras map[string]interface{} 9 | } 10 | 11 | // MessageHandler consists of message callbacks to be used by plugins. 12 | type MessageHandler interface { 13 | // SendMessage sends a message with the given information in the request. 14 | SendMessage(msg Message) error 15 | } 16 | 17 | // Messenger is the interface plugins should implement to send messages. 18 | type Messenger interface { 19 | Plugin 20 | // SetMessageHandler is called every time the plugin is initialized. 21 | // Plugins should record the handler and use the callbacks provided in the handler to send messages. 22 | SetMessageHandler(h MessageHandler) 23 | } 24 | -------------------------------------------------------------------------------- /plugin.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | // Plugin is the interface every plugin need to implement 4 | type Plugin interface { 5 | // Enable is called every time a plugin is started. Spawn custom goroutines here for polling, etc. 6 | // It is always called after ^Set.*Handler$ 7 | Enable() error 8 | // Disable is called every time a plugin is disabled. Plugins should stop all custom goroutines here. 9 | Disable() error 10 | } 11 | 12 | // UserContext is provided when calling New to create a plugin instance for each user 13 | type UserContext struct { 14 | ID uint 15 | Name string 16 | Admin bool 17 | } 18 | 19 | // Info is returned by the exported plugin function GetPluginInfo() for identification 20 | // plugins are identified by their ModulePath, gotify will refuse to load plugins with empty ModulePath 21 | type Info struct { 22 | Version string 23 | Author string 24 | Name string 25 | Website string 26 | Description string 27 | License string 28 | ModulePath string 29 | } 30 | -------------------------------------------------------------------------------- /storage.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | // StorageHandler consists callbacks used to perform read/writes to the persistent storage for plugins. 4 | type StorageHandler interface { 5 | Save(b []byte) error 6 | Load() ([]byte, error) 7 | } 8 | 9 | // Storager is the interface plugins should implement to use persistent storage. 10 | type Storager interface { 11 | Plugin 12 | SetStorageHandler(handler StorageHandler) 13 | } 14 | -------------------------------------------------------------------------------- /webhook.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | // Webhooker is the interface plugin should implement to register custom handlers. 6 | type Webhooker interface { 7 | Plugin 8 | // RegisterWebhook is called for plugins to create their own handler. 9 | RegisterWebhook(basePath string, mux *gin.RouterGroup) 10 | } 11 | --------------------------------------------------------------------------------