init
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mattermost/mattermost/server/public/plugin"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type httpResponse struct {
|
||||
Status string `json:"status"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func (p *Plugin) sendError(w http.ResponseWriter, err string) {
|
||||
errEnc := json.NewEncoder(w).Encode(httpResponse{
|
||||
Status: "error",
|
||||
Error: err,
|
||||
})
|
||||
if errEnc != nil {
|
||||
p.API.LogError("cant encode error response", "error", errEnc)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Plugin) sendRes(w http.ResponseWriter, resp httpResponse) {
|
||||
errEnc := json.NewEncoder(w).Encode(resp)
|
||||
if errEnc != nil {
|
||||
p.API.LogError("cant encode error response", "error", errEnc)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Plugin) InitApi() {
|
||||
p.router = mux.NewRouter()
|
||||
|
||||
p.router.Use(func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if userID := r.Header.Get("Mattermost-User-Id"); userID != "" {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
http.Error(w, "Not authorized", http.StatusUnauthorized)
|
||||
})
|
||||
})
|
||||
|
||||
// Add your API routes here
|
||||
p.router.HandleFunc("/example", p.handleExample).Methods("GET")
|
||||
p.router.HandleFunc("/assets/{fileName}", p.handleAssetFile).Methods("GET")
|
||||
}
|
||||
|
||||
func (p *Plugin) ServeHTTP(_ *plugin.Context, w http.ResponseWriter, r *http.Request) {
|
||||
p.router.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func (p *Plugin) handleAssetFile(w http.ResponseWriter, r *http.Request) {
|
||||
fileName := mux.Vars(r)["fileName"]
|
||||
http.ServeFile(w, r, filepath.Join(p.bundlePath, "assets", fileName))
|
||||
}
|
||||
|
||||
func (p *Plugin) handleExample(w http.ResponseWriter, r *http.Request) {
|
||||
p.sendRes(w, httpResponse{
|
||||
Status: "OK",
|
||||
Data: map[string]interface{}{
|
||||
"message": "Hello from template plugin",
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Configuration struct {
|
||||
// Add your configuration fields here
|
||||
}
|
||||
|
||||
// Clone shallow copies the Configuration. Your implementation may require a deep copy if
|
||||
// your Configuration has reference types.
|
||||
func (c *Configuration) Clone() *Configuration {
|
||||
var clone = *c
|
||||
return &clone
|
||||
}
|
||||
|
||||
// GetConfiguration retrieves the active Configuration under lock, making it safe to use
|
||||
// concurrently. The active Configuration may change underneath the client of this method, but
|
||||
// the struct returned by this API call is considered immutable.
|
||||
func (p *Plugin) GetConfiguration() *Configuration {
|
||||
p.configurationLock.RLock()
|
||||
defer p.configurationLock.RUnlock()
|
||||
|
||||
if p.configuration == nil {
|
||||
return &Configuration{}
|
||||
}
|
||||
|
||||
return p.configuration
|
||||
}
|
||||
|
||||
// SetConfiguration replaces the active Configuration under lock.
|
||||
//
|
||||
// Do not call SetConfiguration while holding the configurationLock, as sync.Mutex is not
|
||||
// reentrant. In particular, avoid using the plugin API entirely, as this may in turn trigger a
|
||||
// hook back into the plugin. If that hook attempts to acquire this lock, a deadlock may occur.
|
||||
//
|
||||
// This method panics if SetConfiguration is called with the existing Configuration. This almost
|
||||
// certainly means that the Configuration was modified without being cloned and may result in
|
||||
// an unsafe access.
|
||||
func (p *Plugin) SetConfiguration(configuration *Configuration) {
|
||||
p.configurationLock.Lock()
|
||||
defer p.configurationLock.Unlock()
|
||||
p.API.LogInfo("Setting configuration")
|
||||
|
||||
if configuration != nil && p.configuration == configuration {
|
||||
// Ignore assignment if the Configuration struct is empty. Go will optimize the
|
||||
// allocation for same to point at the same memory address, breaking the check
|
||||
// above.
|
||||
if reflect.ValueOf(*configuration).NumField() == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
p.API.LogInfo("Panic in SetConfiguration")
|
||||
panic("SetConfiguration called with the existing Configuration")
|
||||
}
|
||||
|
||||
p.configuration = configuration
|
||||
}
|
||||
|
||||
// OnConfigurationChange is invoked when Configuration changes may have been made.
|
||||
func (p *Plugin) OnConfigurationChange() error {
|
||||
p.API.LogInfo("OnConfigurationChange")
|
||||
var configuration = new(Configuration)
|
||||
// Load the public Configuration fields from the Mattermost server Configuration.
|
||||
err := p.API.LoadPluginConfiguration(configuration)
|
||||
if err == nil {
|
||||
p.SetConfiguration(configuration)
|
||||
return nil
|
||||
} else {
|
||||
return errors.Wrap(err, "failed to load plugin Configuration")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"git.wilix.dev/loop/loop-plugin-starter-template/server/telemetry"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mattermost/mattermost/server/public/plugin"
|
||||
"github.com/mattermost/mattermost/server/public/pluginapi"
|
||||
)
|
||||
|
||||
var buildHash string
|
||||
var rudderWriteKey string
|
||||
var rudderDataplaneURL string
|
||||
|
||||
// Plugin implements the interface expected by the Mattermost server to communicate between the server and plugin processes.
|
||||
type Plugin struct {
|
||||
plugin.MattermostPlugin
|
||||
IsReady bool
|
||||
bundlePath string
|
||||
configurationLock sync.RWMutex
|
||||
configuration *Configuration
|
||||
sdk *pluginapi.Client
|
||||
router *mux.Router
|
||||
mut sync.RWMutex
|
||||
telemetry *telemetry.Client
|
||||
}
|
||||
|
||||
func (p *Plugin) OnActivate() error {
|
||||
p.API.LogInfo("Activating template plugin...")
|
||||
p.sdk = pluginapi.NewClient(p.API, p.Driver)
|
||||
|
||||
if p.router == nil {
|
||||
p.InitApi()
|
||||
}
|
||||
|
||||
configuration := p.GetConfiguration()
|
||||
p.configuration = configuration
|
||||
|
||||
bundlePath, err := p.API.GetBundlePath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.bundlePath = bundlePath
|
||||
|
||||
p.IsReady = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Plugin) OnDeactivate() error {
|
||||
p.API.LogInfo("Deactivating template plugin...")
|
||||
if err := p.uninitTelemetry(); err != nil {
|
||||
p.API.LogError(err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package plugin
|
||||
|
||||
// Add your store utility functions here
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2020-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"git.wilix.dev/loop/loop-plugin-starter-template/server/telemetry"
|
||||
)
|
||||
|
||||
func (p *Plugin) uninitTelemetry() error {
|
||||
p.mut.Lock()
|
||||
defer p.mut.Unlock()
|
||||
if p.telemetry == nil {
|
||||
return nil
|
||||
}
|
||||
return p.telemetry.Close()
|
||||
}
|
||||
|
||||
func (p *Plugin) initTelemetry(enableDiagnostics *bool) error {
|
||||
p.mut.Lock()
|
||||
defer p.mut.Unlock()
|
||||
if p.telemetry == nil && enableDiagnostics != nil && *enableDiagnostics {
|
||||
p.API.LogDebug("Initializing telemetry")
|
||||
// setup telemetry
|
||||
client, err := telemetry.NewClient(telemetry.ClientConfig{
|
||||
WriteKey: rudderWriteKey,
|
||||
DataplaneURL: rudderDataplaneURL,
|
||||
DiagnosticID: p.API.GetDiagnosticId(),
|
||||
DefaultProps: map[string]any{
|
||||
"ServerVersion": p.API.GetServerVersion(),
|
||||
"PluginBuild": buildHash,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.telemetry = client
|
||||
} else if p.telemetry != nil && (enableDiagnostics == nil || !*enableDiagnostics) {
|
||||
p.API.LogDebug("Deinitializing telemetry")
|
||||
// destroy telemetry
|
||||
if err := p.telemetry.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
p.telemetry = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user