Files
mattermore/server/configuration.go
T

113 lines
3.2 KiB
Go

package main
import (
"fmt"
"net/url"
"strings"
)
// configuration holds the plugin settings from the System Console.
type configuration struct {
OllamaURL string
DefaultModel string
SystemPrompt string
MaxTokens int
RateLimitPerMinute int
AllowedUserIDs string
StopWords string
}
// getConfiguration returns the current configuration, safe for concurrent use.
func (p *Plugin) getConfiguration() *configuration {
p.configLock.RLock()
defer p.configLock.RUnlock()
return p.configuration
}
// setConfiguration updates the configuration and validates it.
func (p *Plugin) setConfiguration(c *configuration) error {
p.configLock.Lock()
defer p.configLock.Unlock()
if c == nil {
return fmt.Errorf("nil configuration")
}
if err := c.validate(); err != nil {
return fmt.Errorf("invalid configuration: %w", err)
}
p.configuration = c
return nil
}
// validate checks that the configuration values are usable.
func (c *configuration) validate() error {
if c.OllamaURL == "" {
return fmt.Errorf("OllamaURL must not be empty")
}
u, err := url.Parse(c.OllamaURL)
if err != nil {
return fmt.Errorf("OllamaURL is not a valid URL: %w", err)
}
if u.Scheme != "http" && u.Scheme != "https" {
return fmt.Errorf("OllamaURL must use http or https scheme, got %q", u.Scheme)
}
if c.DefaultModel == "" {
return fmt.Errorf("DefaultModel must not be empty")
}
if c.MaxTokens < 0 {
return fmt.Errorf("MaxTokens must not be negative")
}
if c.RateLimitPerMinute < 0 {
return fmt.Errorf("RateLimitPerMinute must not be negative")
}
return nil
}
// OnConfigurationChange is called by the Mattermost server when the plugin
// configuration is changed in the System Console.
func (p *Plugin) OnConfigurationChange() error {
var c configuration
// Load from the System Console settings.
if err := p.API.LoadPluginConfiguration(&c); err != nil {
return fmt.Errorf("failed to load plugin configuration: %w", err)
}
if err := p.setConfiguration(&c); err != nil {
return fmt.Errorf("failed to set configuration: %w", err)
}
return nil
}
// allowedUsers returns the set of user IDs allowed to use the plugin.
// An empty set means all users are allowed.
func (c *configuration) allowedUsers() map[string]bool {
if strings.TrimSpace(c.AllowedUserIDs) == "" {
return nil
}
users := make(map[string]bool)
for _, id := range strings.Split(c.AllowedUserIDs, ",") {
users[strings.TrimSpace(id)] = true
}
return users
}
// stopWordSet returns the set of stop words for the engagement engine.
func (c *configuration) stopWordSet() map[string]bool {
if strings.TrimSpace(c.StopWords) == "" {
return map[string]bool{
"thanks": true, "thank you": true, "bye": true,
"goodbye": true, "that's all": true, "done": true,
"stop": true, "quit": true, "end": true,
}
}
words := make(map[string]bool)
for _, w := range strings.Split(c.StopWords, ",") {
words[strings.TrimSpace(strings.ToLower(w))] = true
}
return words
}