mirror of
https://codeberg.org/june64/mrvc.git
synced 2026-01-10 08:02:53 +01:00
193 lines
7.7 KiB
Go
193 lines
7.7 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
type rooms []string
|
|
|
|
type configOption[T any] struct {
|
|
flagName string
|
|
flagDefaultValue T
|
|
flagHelpBase string
|
|
envVarName string
|
|
}
|
|
|
|
type configOptions struct {
|
|
userID configOption[string]
|
|
token configOption[string]
|
|
rooms configOption[rooms]
|
|
recursive configOption[bool]
|
|
recursionMaxDepth configOption[int]
|
|
recursionSuggestedOnly configOption[bool]
|
|
json configOption[bool]
|
|
outputHomeserverMemberCount configOption[bool]
|
|
homeserverVersionInfoTimeout configOption[time.Duration]
|
|
}
|
|
|
|
type Config struct {
|
|
UserID string
|
|
Token string
|
|
Rooms rooms
|
|
Recursive bool
|
|
RecursionMaxDepth *int
|
|
RecursionSuggestedOnly bool
|
|
JSON bool
|
|
OutputHomeserverMemberCount bool
|
|
HomeserverVersionInfoTimeout time.Duration
|
|
}
|
|
|
|
var configOpts = configOptions{
|
|
userID: configOption[string]{"user-id", "", "The Matrix user ID to use.", "MRVC_USER_ID"},
|
|
token: configOption[string]{"token", "", "The Matrix access token to use.", "MRVC_TOKEN"},
|
|
rooms: configOption[rooms]{"room", []string{}, "The Matrix room to check. The flag can be set multiple times to check multiple rooms.", "MRVC_ROOM"},
|
|
recursive: configOption[bool]{"recursive", false, "Recursively check the child rooms for the given rooms (spaces) as well.", "MRVC_RECURSIVE"},
|
|
recursionMaxDepth: configOption[int]{"recursion-max-depth", 0, "The maximum depth when recursively getting child rooms. Defaults to 0, which gets interpreted as the servers default.", "MRVC_RECURSION_MAX_DEPTH"},
|
|
recursionSuggestedOnly: configOption[bool]{"recursion-suggested-only", false, "Only include the suggested children, when recursively getting child rooms.", "MRVC_RECURSION_SUGGESTED_ONLY"},
|
|
json: configOption[bool]{"json", false, "Output result as JSON.", "MRVC_JSON"},
|
|
outputHomeserverMemberCount: configOption[bool]{"output-homeserver-member-count", false, "Output the member count for each homeserver.", "MRVC_OUTPUT_HOMESERVER_MEMBER_COUNT"},
|
|
homeserverVersionInfoTimeout: configOption[time.Duration]{"homeserver-version-info-timeout", time.Second * 5, "Timeout for getting the homeservers version information per homeserver.", "MRVC_HOMESERVER_VERSION_INFO_TIMEOUT"},
|
|
}
|
|
|
|
func (r *rooms) String() string {
|
|
return fmt.Sprint(*r)
|
|
}
|
|
|
|
func (r *rooms) Set(value string) error {
|
|
*r = append(*r, value)
|
|
return nil
|
|
}
|
|
|
|
func (configOpt configOption[T]) getFlagHelp() string {
|
|
return fmt.Sprintf("%s (EnvVar: %s)", configOpt.flagHelpBase, configOpt.envVarName)
|
|
}
|
|
|
|
func (configOpt configOption[T]) getFlagArgs() (string, T, string) {
|
|
return configOpt.flagName, configOpt.flagDefaultValue, configOpt.getFlagHelp()
|
|
}
|
|
|
|
// Functions for getting config values from flags and environment variables.
|
|
// Flags take precedence over environment variables.
|
|
func (configOpt configOption[T]) getConfigValueWithDefault(configFlag *T, visitedFlags map[string]bool, envVarParser func(string) T) T {
|
|
if visitedFlags[configOpt.flagName] {
|
|
return *configFlag
|
|
} else if envVar, ok := os.LookupEnv(configOpt.envVarName); ok {
|
|
return envVarParser(envVar)
|
|
} else {
|
|
return configOpt.flagDefaultValue
|
|
}
|
|
}
|
|
|
|
// This function can be used to ensure some configuration options got explicitly set.
|
|
func (configOpt configOption[T]) getConfigValueWithError(configFlag *T, visitedFlags map[string]bool, envVarParser func(string) T) (T, error) {
|
|
if visitedFlags[configOpt.flagName] {
|
|
return *configFlag, nil
|
|
} else if envVar, ok := os.LookupEnv(configOpt.envVarName); ok {
|
|
return envVarParser(envVar), nil
|
|
} else {
|
|
return configOpt.flagDefaultValue, errors.New("no command-line flag or environment variable set")
|
|
}
|
|
}
|
|
|
|
var userIdFlag = flag.String(configOpts.userID.getFlagArgs())
|
|
var tokenFlag = flag.String(configOpts.token.getFlagArgs())
|
|
var recursiveFlag = flag.Bool(configOpts.recursive.getFlagArgs())
|
|
var recursionMaxDepthFlag = flag.Int(configOpts.recursionMaxDepth.getFlagArgs())
|
|
var recursionSuggestedOnlyFlag = flag.Bool(configOpts.recursionSuggestedOnly.getFlagArgs())
|
|
var jsonFlag = flag.Bool(configOpts.json.getFlagArgs())
|
|
var outputHomeserverMemberCountFlag = flag.Bool(configOpts.outputHomeserverMemberCount.getFlagArgs())
|
|
var homeserverVersionInfoTimeoutFlag = flag.Duration(configOpts.homeserverVersionInfoTimeout.getFlagArgs())
|
|
|
|
var roomsFlag rooms
|
|
|
|
func init() {
|
|
flag.Var(&roomsFlag, configOpts.rooms.flagName, configOpts.rooms.getFlagHelp())
|
|
}
|
|
|
|
func Get() Config {
|
|
flag.Parse()
|
|
|
|
var config Config
|
|
|
|
visitedFlags := make(map[string]bool)
|
|
flag.Visit(func(flag *flag.Flag) {
|
|
visitedFlags[flag.Name] = true
|
|
})
|
|
|
|
var err error
|
|
|
|
config.UserID, err = configOpts.userID.getConfigValueWithError(userIdFlag, visitedFlags, func(envVar string) string { return envVar })
|
|
if err != nil {
|
|
log.Fatal("A Matrix user ID must be provided.")
|
|
}
|
|
config.Token, err = configOpts.token.getConfigValueWithError(tokenFlag, visitedFlags, func(envVar string) string { return envVar })
|
|
if err != nil {
|
|
log.Fatal("A Matrix access token must be provided.")
|
|
}
|
|
config.Rooms, err = configOpts.rooms.getConfigValueWithError(&roomsFlag, visitedFlags, func(envVar string) rooms { return []string{envVar} })
|
|
if err != nil {
|
|
log.Fatal("A Matrix room must be provided.")
|
|
}
|
|
config.Recursive = configOpts.recursive.getConfigValueWithDefault(recursiveFlag, visitedFlags, func(envVar string) bool {
|
|
parsedEnvVar, err := strconv.ParseBool(envVar)
|
|
if err != nil {
|
|
log.Printf("Error parsing %s:\n", configOpts.recursive.envVarName)
|
|
log.Fatal(err)
|
|
}
|
|
return parsedEnvVar
|
|
})
|
|
givenRecursionMaxDepth := configOpts.recursionMaxDepth.getConfigValueWithDefault(recursionMaxDepthFlag, visitedFlags, func(envVar string) int {
|
|
parsedEnvVar, err := strconv.Atoi(envVar)
|
|
if err != nil {
|
|
log.Printf("Error parsing %s:\n", configOpts.recursionMaxDepth.envVarName)
|
|
log.Fatal(err)
|
|
}
|
|
return parsedEnvVar
|
|
})
|
|
// Since we actually want an *int, interpret 0 as nil as described in the help text.
|
|
if givenRecursionMaxDepth != 0 {
|
|
config.RecursionMaxDepth = &givenRecursionMaxDepth
|
|
} else {
|
|
config.RecursionMaxDepth = nil
|
|
}
|
|
config.RecursionSuggestedOnly = configOpts.recursionSuggestedOnly.getConfigValueWithDefault(recursionSuggestedOnlyFlag, visitedFlags, func(envVar string) bool {
|
|
parsedEnvVar, err := strconv.ParseBool(envVar)
|
|
if err != nil {
|
|
log.Printf("Error parsing %s:\n", configOpts.recursionSuggestedOnly.envVarName)
|
|
log.Fatal(err)
|
|
}
|
|
return parsedEnvVar
|
|
})
|
|
config.JSON = configOpts.json.getConfigValueWithDefault(jsonFlag, visitedFlags, func(envVar string) bool {
|
|
parsedEnvVar, err := strconv.ParseBool(envVar)
|
|
if err != nil {
|
|
log.Printf("Error parsing %s:\n", configOpts.json.envVarName)
|
|
log.Fatal(err)
|
|
}
|
|
return parsedEnvVar
|
|
})
|
|
config.OutputHomeserverMemberCount = configOpts.outputHomeserverMemberCount.getConfigValueWithDefault(outputHomeserverMemberCountFlag, visitedFlags, func(envVar string) bool {
|
|
parsedEnvVar, err := strconv.ParseBool(envVar)
|
|
if err != nil {
|
|
log.Printf("Error parsing %s:\n", configOpts.outputHomeserverMemberCount.envVarName)
|
|
log.Fatal(err)
|
|
}
|
|
return parsedEnvVar
|
|
})
|
|
config.HomeserverVersionInfoTimeout = configOpts.homeserverVersionInfoTimeout.getConfigValueWithDefault(homeserverVersionInfoTimeoutFlag, visitedFlags, func(envVar string) time.Duration {
|
|
parsedEnvVar, err := time.ParseDuration(envVar)
|
|
if err != nil {
|
|
log.Printf("Error parsing %s:\n", configOpts.homeserverVersionInfoTimeout.envVarName)
|
|
log.Fatal(err)
|
|
}
|
|
return parsedEnvVar
|
|
})
|
|
|
|
return config
|
|
}
|