mirror of https://github.com/synctv-org/synctv
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
3.8 KiB
Go
233 lines
3.8 KiB
Go
package utils
|
|
|
|
import (
|
|
"math/rand"
|
|
"net"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"sync/atomic"
|
|
|
|
yamlcomment "github.com/zijiren233/yaml-comment"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
|
|
|
func RandString(n int) string {
|
|
b := make([]rune, n)
|
|
for i := range b {
|
|
b[i] = letters[rand.Intn(len(letters))]
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
func RandBytes(n int) []byte {
|
|
b := make([]byte, n)
|
|
for i := range b {
|
|
b[i] = byte(rand.Intn(256))
|
|
}
|
|
return b
|
|
}
|
|
|
|
func GetPageItems[T any](items []T, max, page int64) []T {
|
|
if max <= 0 || page <= 0 {
|
|
return nil
|
|
}
|
|
start := (page - 1) * max
|
|
l := int64(len(items))
|
|
if start > l {
|
|
start = l
|
|
}
|
|
end := page * max
|
|
if end > l {
|
|
end = l
|
|
}
|
|
return items[start:end]
|
|
}
|
|
|
|
func Index[T comparable](items []T, item T) int {
|
|
for i, v := range items {
|
|
if v == item {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func In[T comparable](items []T, item T) bool {
|
|
return Index(items, item) != -1
|
|
}
|
|
|
|
func Exists(name string) bool {
|
|
if _, err := os.Stat(name); err != nil {
|
|
if os.IsNotExist(err) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func WriteYaml(file string, module any) error {
|
|
err := os.MkdirAll(filepath.Dir(file), os.ModePerm)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
f, err := os.Create(file)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
return yamlcomment.NewEncoder(yaml.NewEncoder(f)).Encode(module)
|
|
}
|
|
|
|
func ReadYaml(file string, module any) error {
|
|
f, err := os.Open(file)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
return yaml.NewDecoder(f).Decode(module)
|
|
}
|
|
|
|
const (
|
|
VersionEqual = iota
|
|
VersionGreater
|
|
VersionLess
|
|
)
|
|
|
|
func CompVersion(v1, v2 string) (int, error) {
|
|
if v1 == v2 {
|
|
return VersionEqual, nil
|
|
}
|
|
v1s, err := SplitVersion(strings.TrimLeft(v1, "v"))
|
|
if err != nil {
|
|
return VersionEqual, err
|
|
}
|
|
v2s, err := SplitVersion(strings.TrimLeft(v2, "v"))
|
|
if err != nil {
|
|
return VersionEqual, err
|
|
}
|
|
for i := 0; i < len(v1s) && i < len(v2s); i++ {
|
|
if v1s[i] > v2s[i] {
|
|
return VersionGreater, nil
|
|
} else if v1s[i] < v2s[i] {
|
|
return VersionLess, nil
|
|
}
|
|
}
|
|
if len(v1s) > len(v2s) {
|
|
return VersionGreater, nil
|
|
} else if len(v1s) < len(v2s) {
|
|
return VersionLess, nil
|
|
}
|
|
return VersionGreater, nil
|
|
}
|
|
|
|
func SplitVersion(v string) ([]int, error) {
|
|
var vs []int
|
|
for _, s := range strings.Split(v, ".") {
|
|
i, err := strconv.Atoi(s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
vs = append(vs, i)
|
|
}
|
|
return vs, nil
|
|
}
|
|
|
|
type Once struct {
|
|
done uint32
|
|
m sync.Mutex
|
|
}
|
|
|
|
func (o *Once) Done() (doned bool) {
|
|
done := atomic.LoadUint32(&o.done)
|
|
if done == 1 {
|
|
return true
|
|
} else if done == 2 {
|
|
return false
|
|
}
|
|
|
|
o.m.Lock()
|
|
defer o.m.Unlock()
|
|
if o.done == 0 {
|
|
doned = false
|
|
atomic.StoreUint32(&o.done, 2)
|
|
} else if o.done == 1 {
|
|
doned = true
|
|
} else {
|
|
doned = false
|
|
}
|
|
return
|
|
}
|
|
|
|
func (o *Once) Do(f func()) {
|
|
if atomic.LoadUint32(&o.done) == 0 {
|
|
o.doSlow(f)
|
|
}
|
|
}
|
|
|
|
func (o *Once) doSlow(f func()) {
|
|
o.m.Lock()
|
|
defer o.m.Unlock()
|
|
if o.done == 0 {
|
|
defer atomic.StoreUint32(&o.done, 1)
|
|
f()
|
|
}
|
|
}
|
|
|
|
func (o *Once) Reset() {
|
|
atomic.StoreUint32(&o.done, 0)
|
|
}
|
|
|
|
func ParseURLIsLocalIP(u string) (bool, error) {
|
|
url, err := url.Parse(u)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return IsLocalIP(url.Host), nil
|
|
}
|
|
|
|
func IsLocalIP(address string) bool {
|
|
host, _, err := net.SplitHostPort(address)
|
|
if err != nil {
|
|
host = address
|
|
}
|
|
|
|
ipAddr, err := net.ResolveIPAddr("ip", host)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
localIPs := getLocalIPs()
|
|
|
|
for _, localIP := range localIPs {
|
|
if ipAddr.IP.Equal(localIP) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func getLocalIPs() []net.IP {
|
|
var localIPs []net.IP
|
|
|
|
addrs, err := net.InterfaceAddrs()
|
|
if err != nil {
|
|
return localIPs
|
|
|
|
}
|
|
|
|
for _, addr := range addrs {
|
|
if ipNet, ok := addr.(*net.IPNet); ok && ipNet.IP.To4() != nil {
|
|
localIPs = append(localIPs, ipNet.IP)
|
|
}
|
|
}
|
|
|
|
return localIPs
|
|
}
|