mirror of
https://github.com/h44z/wg-portal.git
synced 2025-04-17 07:55:13 +00:00
171 lines
3.6 KiB
Go
171 lines
3.6 KiB
Go
package internal
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"log/slog"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
"syscall"
|
|
)
|
|
|
|
// LogClose closes the given Closer and logs any error that occurs
|
|
func LogClose(c io.Closer) {
|
|
if err := c.Close(); err != nil {
|
|
slog.Error("error during Close()", "error", err)
|
|
}
|
|
}
|
|
|
|
// LogError logs the given error if it is not nil.
|
|
// If a message is given, it is prepended to the error message.
|
|
// Only the first message is used.
|
|
func LogError(err error, msg ...string) {
|
|
if err == nil {
|
|
return
|
|
}
|
|
|
|
if len(msg) > 0 {
|
|
slog.Error(msg[0], "error", err)
|
|
} else {
|
|
slog.Error(err.Error())
|
|
}
|
|
}
|
|
|
|
// SignalAwareContext returns a context that gets closed once a given signal is retrieved.
|
|
// By default, the following signals are handled: syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP
|
|
func SignalAwareContext(ctx context.Context, sig ...os.Signal) context.Context {
|
|
c := make(chan os.Signal, 1)
|
|
if len(sig) == 0 {
|
|
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
|
|
} else {
|
|
|
|
signal.Notify(c, sig...)
|
|
}
|
|
signalCtx, cancel := context.WithCancel(ctx)
|
|
|
|
// Attach signal handlers to context
|
|
go func() {
|
|
select {
|
|
case <-ctx.Done():
|
|
// normal shutdown, quit go routine
|
|
case <-c:
|
|
cancel() // cancel the context
|
|
}
|
|
|
|
// cleanup
|
|
signal.Stop(c)
|
|
close(c)
|
|
}()
|
|
|
|
return signalCtx
|
|
}
|
|
|
|
// AssertNoError panics if the given error is not nil.
|
|
func AssertNoError(err error) {
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
// MapDefaultString returns the string value for the given key or a default value
|
|
func MapDefaultString(m map[string]any, key string, dflt string) string {
|
|
if m == nil {
|
|
return dflt
|
|
}
|
|
if tmp, ok := m[key]; !ok {
|
|
return dflt
|
|
} else {
|
|
switch v := tmp.(type) {
|
|
case string:
|
|
return v
|
|
case nil:
|
|
return dflt
|
|
default:
|
|
return fmt.Sprintf("%v", v)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MapDefaultStringSlice returns the string slice value for the given key or a default value
|
|
func MapDefaultStringSlice(m map[string]any, key string, dflt []string) []string {
|
|
if m == nil {
|
|
return dflt
|
|
}
|
|
if tmp, ok := m[key]; !ok {
|
|
return dflt
|
|
} else {
|
|
switch v := tmp.(type) {
|
|
case []any:
|
|
result := make([]string, 0, len(v))
|
|
for _, elem := range v {
|
|
switch vElem := elem.(type) {
|
|
case string:
|
|
result = append(result, vElem)
|
|
default:
|
|
result = append(result, fmt.Sprintf("%v", vElem))
|
|
}
|
|
}
|
|
return result
|
|
case []string:
|
|
return v
|
|
case string:
|
|
return []string{v}
|
|
case nil:
|
|
return dflt
|
|
default:
|
|
return []string{fmt.Sprintf("%v", v)}
|
|
}
|
|
}
|
|
}
|
|
|
|
// UniqueStringSlice removes duplicates in the given string slice
|
|
func UniqueStringSlice(slice []string) []string {
|
|
keys := make(map[string]struct{})
|
|
uniqueSlice := make([]string, 0, len(slice))
|
|
for _, entry := range slice {
|
|
if _, exists := keys[entry]; !exists {
|
|
keys[entry] = struct{}{}
|
|
uniqueSlice = append(uniqueSlice, entry)
|
|
}
|
|
}
|
|
return uniqueSlice
|
|
}
|
|
|
|
// SliceString returns a string slice from a comma-separated string
|
|
func SliceString(str string) []string {
|
|
strParts := strings.Split(str, ",")
|
|
stringSlice := make([]string, 0, len(strParts))
|
|
|
|
for _, s := range strParts {
|
|
trimmed := strings.TrimSpace(s)
|
|
if trimmed != "" {
|
|
stringSlice = append(stringSlice, trimmed)
|
|
}
|
|
}
|
|
|
|
return stringSlice
|
|
}
|
|
|
|
// SliceToString returns a comma-separated string from a string slice
|
|
func SliceToString(slice []string) string {
|
|
return strings.Join(slice, ",")
|
|
}
|
|
|
|
// TruncateString returns a string truncated to the given length
|
|
func TruncateString(s string, max int) string {
|
|
if max > len(s) {
|
|
return s
|
|
}
|
|
return s[:max]
|
|
}
|
|
|
|
// BoolToFloat64 converts a boolean to a float64. True is 1.0, false is 0.0
|
|
func BoolToFloat64(b bool) float64 {
|
|
if b {
|
|
return 1.0
|
|
}
|
|
return 0.0
|
|
}
|