package plugin import ( "reflect" "github.com/pkg/errors" ) type Configuration struct { SentryUrl string SentryOrganisationName string SentryAuthToken string // 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") } }