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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
package generic
import (
"fmt"
"net/url"
"github.com/nicholas-fedor/shoutrrr/pkg/format"
"github.com/nicholas-fedor/shoutrrr/pkg/services/standard"
"github.com/nicholas-fedor/shoutrrr/pkg/types"
)
// Scheme identifies this service in configuration URLs.
const (
Scheme = "generic"
DefaultWebhookScheme = "https"
)
// Config holds settings for the generic notification service.
type Config struct {
standard.EnumlessConfig
// The webhook URL to send notifications to
webhookURL *url.URL
// Custom HTTP headers to include in requests
headers map[string]string
// Additional data to include in JSON payloads
extraData map[string]string
ContentType string `default:"application/json" desc:"The value of the Content-Type header" key:"contenttype"`
DisableTLS bool `default:"No" key:"disabletls"`
Template string ` desc:"The template used for creating the request payload" key:"template" optional:""`
Title string `default:"" key:"title"`
TitleKey string `default:"title" desc:"The key that will be used for the title value" key:"titlekey"`
MessageKey string `default:"message" desc:"The key that will be used for the message value" key:"messagekey"`
RequestMethod string `default:"POST" key:"method"`
}
// DefaultConfig creates a new Config with default values and its associated PropKeyResolver.
func DefaultConfig() (*Config, format.PropKeyResolver) {
// Initialize empty config
config := &Config{}
// Create property key resolver
pkr := format.NewPropKeyResolver(config)
// Set default properties from struct tags
_ = pkr.SetDefaultProps(config)
return config, pkr
}
// ConfigFromWebhookURL constructs a Config from a parsed webhook URL.
func ConfigFromWebhookURL(webhookURL url.URL) (*Config, format.PropKeyResolver, error) {
// Get default config and resolver
config, pkr := DefaultConfig()
// Extract query parameters
webhookQuery := webhookURL.Query()
// Extract custom headers and extra data
headers, extraData := stripCustomQueryValues(webhookQuery)
// Set config properties from remaining query params
_, err := format.SetConfigPropsFromQuery(&pkr, webhookQuery)
if err != nil {
return nil, pkr, fmt.Errorf("setting config properties from query: %w", err)
}
// Update URL with modified query
webhookURL.RawQuery = webhookQuery.Encode()
// Assign webhook URL
config.webhookURL = &webhookURL
// Assign extracted headers
config.headers = headers
// Assign extracted extra data
config.extraData = extraData
// Set TLS based on scheme
config.DisableTLS = webhookURL.Scheme == "http"
return config, pkr, nil
}
// WebhookURL returns the configured webhook URL, adjusted for TLS settings.
func (config *Config) WebhookURL() *url.URL {
// Copy the URL to modify
webhookURL := *config.webhookURL
// Set default HTTPS scheme
webhookURL.Scheme = DefaultWebhookScheme
if config.DisableTLS {
// Use HTTP if TLS is disabled
webhookURL.Scheme = "http"
}
return &webhookURL
}
// GetURL generates a URL from the current configuration values.
func (config *Config) GetURL() *url.URL {
// Create resolver for this config
resolver := format.NewPropKeyResolver(config)
// Generate URL using resolver
return config.getURL(&resolver)
}
// SetURL updates the configuration from a service URL.
func (config *Config) SetURL(serviceURL *url.URL) error {
// Create resolver for this config
resolver := format.NewPropKeyResolver(config)
// Parse and set URL
return config.setURL(&resolver, serviceURL)
}
// getURL generates a service URL from the configuration using the provided resolver.
func (config *Config) getURL(resolver types.ConfigQueryResolver) *url.URL {
// Copy webhook URL
serviceURL := *config.webhookURL
// Get existing query params
webhookQuery := config.webhookURL.Query()
// Build query with config fields
serviceQuery := format.BuildQueryWithCustomFields(resolver, webhookQuery)
// Add custom headers and extra data
appendCustomQueryValues(serviceQuery, config.headers, config.extraData)
// Encode the query
serviceURL.RawQuery = serviceQuery.Encode()
// Set service scheme
serviceURL.Scheme = Scheme
return &serviceURL
}
// setURL updates the configuration from a service URL using the provided resolver.
func (config *Config) setURL(resolver types.ConfigQueryResolver, serviceURL *url.URL) error {
// Copy service URL
webhookURL := *serviceURL
// Extract query parameters
serviceQuery := serviceURL.Query()
// Extract custom headers and extra data
headers, extraData := stripCustomQueryValues(serviceQuery)
// Set config properties from query
customQuery, err := format.SetConfigPropsFromQuery(resolver, serviceQuery)
if err != nil {
return fmt.Errorf("setting config properties from service URL query: %w", err)
}
// Update URL with remaining query
webhookURL.RawQuery = customQuery.Encode()
// Assign webhook URL
config.webhookURL = &webhookURL
// Assign extracted headers
config.headers = headers
// Assign extracted extra data
config.extraData = extraData
return nil
}
|