GoBroke/tplCmd/funcs_tpl.go
2025-02-04 12:14:08 -05:00

311 lines
6.3 KiB
Go

package tplCmd
import (
`fmt`
`net`
`strconv`
`strings`
`github.com/vishvananda/netlink`
`go4.org/netipx`
)
/*
This file contains functions strictly for use in templates.
*/
// Host functionality
// TODO: How would I do this on non-Linux?
/*
GetDefaultIface returns the interface name for the default route using netlink.
IPv4 by default, IPv6 if ipv6 is true.
If multiple routes match the default route for the inet family,
the lowest metric route's interface will be returned.
*/
func GetDefaultIface(ipv6 bool) (iface string, err error) {
var inetFamily int
var defNet *net.IPNet
var routes []netlink.Route
var defRt *netlink.Route
var defIface *net.Interface
var curPrio int = -1
// This can even be netlink.FAMILY_ALL, but that's silly.
if !ipv6 {
inetFamily = netlink.FAMILY_V4
defNet = &net.IPNet{
IP: net.ParseIP("0.0.0.0"),
Mask: net.CIDRMask(0, 32),
}
} else {
inetFamily = netlink.FAMILY_V6
defNet = &net.IPNet{
IP: net.ParseIP("::"),
Mask: net.CIDRMask(0, 128),
}
}
if routes, err = netlink.RouteList(nil, inetFamily); err != nil {
return
}
for _, route := range routes {
if !(route.Dst != nil || route.Dst.String() == defNet.String()) {
continue
}
if curPrio == -1 {
curPrio = route.Priority
defRt = &route
} else {
if route.Priority < curPrio {
curPrio = route.Priority
defRt = &route
}
}
}
if defRt != nil {
// There's also defRt.ILinkIndex, which is used for VLANs, tunnels, etc.
if defIface, err = net.InterfaceByIndex(defRt.LinkIndex); err != nil {
return
}
if defIface != nil {
iface = defIface.Name
return
}
}
return
}
func GetSITIface() () {
return
}
// Conversions/assertions/coercions.
/*
TplIsNil returns true if v is nil. This lets you determine if e.g. a map or slice is empty or nil.
It currently only really works for a []interface{}, map[interface{}]interface{}, or map[string]interface{}.
*/
func TplIsNil(v interface{}) (isNil bool) {
switch t := v.(type) {
case []interface{}:
isNil = t == nil
case map[interface{}]interface{}:
isNil = t == nil
case map[string]interface{}:
isNil = t == nil
case nil:
isNil = true
}
return
}
// TplToBool attempts to determine a boolean from v. Note that for numbers, b is true if v is *NOT* 0.
func TplToBool(v interface{}) (b bool, err error) {
switch t := v.(type) {
case bool:
b = t
case string:
switch s := strings.ToLower(t); s {
case "true", "y", "yes", "on", "1":
b = true
}
case []byte:
switch s := strings.ToLower(string(t)); s {
case "true", "y", "yes", "on", "1":
b = true
}
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
b = t != 0
}
return
}
/*
TplToFloat returns a float64 from v.
Strings will be run through strconv.ParseFloat with 64 bitness.
Mind overflows.
*/
func TplToFloat(v interface{}) (i float64, err error) {
switch t := v.(type) {
case uint, uint8, uint16, uint32, uint64:
i = float64(t.(uint64))
case int, int8, int16, int32, int64:
i = float64(t.(int64))
case float64:
i = t
case float32:
i = float64(t)
case string:
if i, err = strconv.ParseFloat(t, 64); err != nil {
return
}
case []byte:
if i, err = strconv.ParseFloat(string(t), 64); err != nil {
return
}
}
return
}
/*
TplToInt returns a signed 64-bit integer from primitives.
Strings will be run through strconv.ParseInt with base 10 and 64 bitness.
Mind overflows.
*/
func TplToInt(v interface{}) (i int64, err error) {
switch t := v.(type) {
case uint, uint8, uint16, uint32, uint64:
i = int64(t.(uint64)) // If an overflow happens anywhere, it's either here or the string/[]bytes.
case int64:
i = t
case int, int8, int16, int32:
i = t.(int64)
case float32, float64:
i = int64(t.(float64))
case string:
if i, err = strconv.ParseInt(t, 10, 64); err != nil {
return
}
case []byte:
if i, err = strconv.ParseInt(string(t), 10, 64); err != nil {
return
}
}
return
}
/*
TplToMap attempts to return a map[string]interface{} from v.
Values can then be used with other TplTo* functions further.
m will be nil if it can't be asserted.
*/
func TplToMap(v interface{}) (m map[string]interface{}, err error) {
switch t := v.(type) {
case map[string]interface{}:
m = t
}
return
}
// TplToString returns a string representation of primitives.
func TplToString(v interface{}) (s string, err error) {
switch t := v.(type) {
case string:
s = t
case []byte:
s = string(t)
default:
s = fmt.Sprintf("%v", v)
}
return
}
/*
TplToUint returns an unsigned 64-bit integer from primitives.
Strings will be run through strconv.ParseUint with base 10 and 64 bitness.
Mind overflows.
*/
func TplToUint(v interface{}) (i uint64, err error) {
switch t := v.(type) {
case uint64:
i = t
case uint, uint8, uint16, uint32:
i = t.(uint64)
case int, int8, int16, int32, int64:
i = uint64(t.(int64))
case float32, float64:
i = uint64(t.(float64))
case string:
if i, err = strconv.ParseUint(t, 10, 64); err != nil {
return
}
case []byte:
if i, err = strconv.ParseUint(string(t), 10, 64); err != nil {
return
}
}
return
}
// Wrappers
// TplGetIPSetBuilder returns a netipx.IPSetBuilder.
func TplGetIPSetBuilder() (ipsb *netipx.IPSetBuilder) {
ipsb = new(netipx.IPSetBuilder)
*ipsb = netipx.IPSetBuilder{}
return
}
// TplGetResolver returns a net.Resolver from the given options.
func TplGetResolver(useGo, strictErr bool) (resolver *net.Resolver) {
resolver = &net.Resolver{
PreferGo: useGo,
StrictErrors: strictErr,
}
return
}
// TplSplitHostPortHost wraps net.SplitHostPort and returns the host.
func TplSplitHostPortHost(s string) (host string, err error) {
if host, _, err = net.SplitHostPort(s); err != nil {
return
}
return
}
// TplSplitHostPortPort wraps net.SplitHostPort and returns the port.
func TplSplitHostPortPort(s string) (port string, err error) {
if _, port, err = net.SplitHostPort(s); err != nil {
return
}
return
}
// TplToCidrHost wraps net.ParseCIDR and returns the host net.IP and any error.
func TplToCidrHost(s string) (host net.IP, err error) {
if host, _, err = net.ParseCIDR(s); err != nil {
return
}
return
}
// TplToCidrNet wraps net.ParseCIDR and returns the network *net.IPNet and any error.
func TplToCidrNet(s string) (netwk *net.IPNet, err error) {
if _, netwk, err = net.ParseCIDR(s); err != nil {
return
}
return
}