/
configuration.go
101 lines (84 loc) 路 3.53 KB
/
configuration.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package main
import (
"reflect"
"github.com/pkg/errors"
)
// configuration captures the plugin's external configuration as exposed in the Mattermost server
// configuration, as well as values computed from the configuration. Any public fields will be
// deserialized from the Mattermost server configuration in OnConfigurationChange.
//
// As plugins are inherently concurrent (hooks being called asynchronously), and the plugin
// configuration can change at any time, access to the configuration must be synchronized. The
// strategy used in this plugin is to guard a pointer to the configuration, and clone the entire
// struct whenever it changes. You may replace this with whatever strategy you choose.
//
// If you add non-reference types to your configuration struct, be sure to rewrite Clone as a deep
// copy appropriate for your types.
type configuration struct {
DOTeamID string
DOAdmins string
CronConfig string
IMAPServer string
IMAPUsername string
IMAPPassword string
}
const adminKVKey = "com.mattermost.digitalocean_admin"
// 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()
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
}
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 {
var configuration = new(configuration)
// Load the public configuration fields from the Mattermost server configuration.
if err := p.API.LoadPluginConfiguration(configuration); err != nil {
p.API.LogError("Failed to load configuration", "Err", err.Error())
return errors.Wrap(err, "failed to load plugin configuration")
}
p.setConfiguration(configuration)
// stop old crons and start a new one with updated config
// Might require a more detailed check within the config to only run the code below
// cron config changes
if p.cron != nil {
p.StopCronJobs()
p.cron = newCron()
p.StartCronJobs()
}
return nil
}