| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 |
- package utils
- import (
- "crypto/md5"
- "encoding/hex"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "sync"
- "net"
- "net/http"
- "os"
- "os/exec"
- "path/filepath"
- "regexp"
- "runtime"
- "strconv"
- "strings"
- "time"
- // "github.com/cdle/sillyplus/core/logs"
- "github.com/cdle/sillyplus/core/logs"
- "github.com/google/uuid"
- )
- var SlaveMode bool
- func GenUUID() string {
- u2, _ := uuid.NewUUID()
- return u2.String()
- }
- func Float64(str interface{}) float64 {
- f, _ := strconv.ParseFloat(fmt.Sprint(str), 64)
- return f
- }
- func TrimHiddenCharacter(originStr string) string {
- srcRunes := []rune(originStr)
- dstRunes := make([]rune, 0, len(srcRunes))
- for _, c := range srcRunes {
- if c >= 0 && c <= 31 && c != 10 {
- continue
- }
- if c == 127 {
- continue
- }
- dstRunes = append(dstRunes, c)
- }
- return strings.ReplaceAll(string(dstRunes), "", "")
- }
- func Md5(str string) string {
- h := md5.New()
- h.Write([]byte(str))
- return hex.EncodeToString(h.Sum(nil))
- }
- func Itob(i uint64) []byte {
- return []byte(fmt.Sprint(i))
- }
- var Int = func(s interface{}) int {
- i, _ := strconv.Atoi(fmt.Sprint(s))
- return i
- }
- var Int64 = func(s interface{}) int64 {
- i, _ := strconv.Atoi(fmt.Sprint(s))
- return int64(i)
- }
- func init() {
- err := KillPeer()
- if err != nil {
- logs.Warn("结束进程失败:", err)
- }
- err = os.WriteFile(GetPidFile(), []byte(fmt.Sprintf("%d", os.Getpid())), 0o644)
- if err != nil {
- logs.Warn("写入进程ID失败:", err)
- }
- for _, arg := range os.Args {
- if arg == "-d" {
- Daemon()
- }
- }
- }
- var once = new(sync.Once)
- var GetDataHome = func() string {
- home := os.Getenv("SILLYGIRL_DATA_PATH")
- if home == "" {
- if runtime.GOOS == "windows" {
- home = `C:\ProgramData\sillyplus\`
- } else if runtime.GOOS == "darwin" {
- home = ExecPath + "/.sillyplus/"
- } else {
- home = `/etc/sillyplus/`
- }
- }
- once.Do(func() {
- if err := os.MkdirAll(home, os.ModePerm); err != nil {
- fmt.Println(err)
- }
- })
- return home
- }
- func KillProcess(pid int) error {
- var cmd *exec.Cmd
- switch runtime.GOOS {
- case "linux", "darwin":
- cmd = exec.Command("kill", "-TERM", strconv.Itoa(pid))
- case "windows":
- cmd = exec.Command("taskkill", "/F", "/PID", strconv.Itoa(pid))
- default:
- return fmt.Errorf("unsupported operating system: %v", runtime.GOOS)
- }
- // cmd.Stdout = os.Stdout
- // cmd.Stderr = os.Stderr
- err := cmd.Run()
- if _, ok := err.(*exec.ExitError); ok {
- return nil
- }
- if err != nil {
- return fmt.Errorf("failed to kill process %d: %v", pid, err)
- }
- return nil
- }
- func KillPeer() error {
- id, err := GetPidFromFile(GetPidFile())
- if err != nil {
- return err
- }
- if id != 0 {
- return KillProcess(id)
- }
- return nil
- }
- var ProcessName = getProcessName()
- var ExecPath, _ = filepath.Abs(filepath.Dir(os.Args[0]))
- var getProcessName = func() string {
- if runtime.GOOS == "windows" {
- return regexp.MustCompile(`([\w\.-]*)\.exe$`).FindStringSubmatch(os.Args[0])[0]
- }
- return regexp.MustCompile(`/([^/\s]+)$`).FindStringSubmatch(os.Args[0])[1]
- }
- var GetPidFile = func() string {
- return filepath.Join(GetDataHome(), "sillyGirl.pid")
- }
- func GetPidFromFile(pidFile string) (int, error) {
- if _, err := os.Stat(pidFile); err != nil {
- return 0, nil
- }
- data, err := ioutil.ReadFile(pidFile)
- if err != nil {
- return 0, err
- }
- pidStr := strings.TrimSpace(string(data))
- pid, err := strconv.Atoi(pidStr)
- if err != nil {
- return 0, err
- }
- return pid, nil
- }
- func CopyFile(src string, dst string) error {
- // 打开源文件
- srcFile, err := os.Open(src)
- if err != nil {
- return err
- }
- defer srcFile.Close()
- // 创建目标文件,如果目标文件已存在则覆盖
- dstFile, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
- if err != nil {
- return err
- }
- defer dstFile.Close()
- // 将源文件内容复制到目标文件
- _, err = io.Copy(dstFile, srcFile)
- if err != nil {
- return err
- }
- return nil
- }
- func Daemon(str ...string) {
- first := ""
- if len(str) > 0 {
- first = str[0]
- }
- args := os.Args[1:]
- if first == "ready" { //原->准备
- os.Args[0] = strings.Replace(os.Args[0], ".exe", ".ready.exe", -1)
- args = append(args, "-r")
- }
- if first == "reset" { //准备->原
- os.Args[0] = strings.Replace(os.Args[0], ".ready.exe", ".exe", -1)
- }
- execArgs := make([]string, 0)
- l := len(args)
- for i := 0; i < l; i++ {
- if strings.Contains(args[i], "-d") {
- continue
- }
- if strings.Contains(args[i], "-t") {
- continue
- }
- execArgs = append(execArgs, args[i])
- }
- proc := exec.Command(os.Args[0], execArgs...)
- err := proc.Start()
- if err != nil {
- panic(err)
- }
- logs.Info("程序以静默形式运行")
- // err = os.WriteFile(GetPidFile(), []byte(fmt.Sprintf("%d", proc.Process.Pid)), 0o644)
- if err != nil {
- logs.Info(err)
- }
- os.Exit(0)
- }
- func FetchCookieValue(ps ...string) string {
- var key, cookies string
- if len(ps) == 2 {
- if len(ps[0]) > len(ps[1]) {
- key, cookies = ps[1], ps[0]
- } else {
- key, cookies = ps[0], ps[1]
- }
- }
- match := regexp.MustCompile(key + `=([^;]*);{0,1}`).FindStringSubmatch(cookies)
- if len(match) == 2 {
- return strings.Trim(match[1], " ")
- } else {
- return ""
- }
- }
- func Contains(strs []string, str ...string) bool {
- for _, o := range strs {
- for _, str_ := range strs {
- if str_ == o {
- return true
- }
- }
- }
- return false
- }
- func Remove(strs []string, str string) []string {
- for i, o := range strs {
- if str == o {
- return append(strs[:i], strs[i+1:]...)
- }
- }
- return strs
- }
- func SafeError(err error) error {
- s := err.Error()
- s = regexp.MustCompile(`(http|https)://[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?`).ReplaceAllString(s, "http://138.2.2.75:5700")
- return errors.New(s)
- }
- func MonitorGoroutine() {
- if runtime.GOOS == "windows" {
- return
- }
- ticker := time.NewTicker(time.Millisecond * 100)
- lastGNum := 0
- for {
- <-ticker.C
- if newGNum := runtime.NumGoroutine(); lastGNum != newGNum {
- lastGNum = newGNum
- if newGNum > 800 {
- Daemon()
- }
- }
- }
- }
- func JsonMarshal(v interface{}) (d []byte) {
- d, _ = json.Marshal(v)
- return
- }
- func Str2Ints(str string) []int {
- is := []int{}
- for _, v := range Str2IntStr(str) {
- is = append(is, Int(v))
- }
- return is
- }
- func Str2IntStr(str string) []string {
- return regexp.MustCompile(`-?[\d]+`).FindAllString(str, -1)
- }
- func ToVideoQrcode(url string) string {
- return `[CQ:video,file=` + url + `]`
- }
- func ToImageQrcode(url string) string {
- return `[CQ:image,file=` + url + `]`
- }
- func FormatLog(f interface{}, v ...interface{}) string {
- var msg string
- switch f := f.(type) {
- case string:
- msg = f
- if len(v) == 0 {
- return msg
- }
- if strings.Contains(msg, "%") && !strings.Contains(msg, "%%") {
- //format string
- } else {
- //do not contain format char
- msg += strings.Repeat(" %v", len(v))
- }
- default:
- msg = fmt.Sprint(f)
- if len(v) == 0 {
- return msg
- }
- msg += strings.Repeat(" %v", len(v))
- }
- return fmt.Sprintf(msg, v...)
- }
- func IsZeroOrEmpty(str string) bool {
- return str == "0" || str == "" || str == "nil"
- }
- // func Unique(strs ...interface{}) []string {
- // m := make(map[string]bool)
- // var result []string
- // for _, arg := range strs {
- // switch arg := arg.(type) {
- // case []string:
- // for _, v := range arg {
- // if _, ok := m[v]; !ok {
- // m[v] = true
- // result = append(result, v)
- // }
- // }
- // case string:
- // if _, ok := m[arg]; !ok {
- // m[arg] = true
- // result = append(result, arg)
- // }
- // }
- // }
- // return result
- // }
- func Unique(strs ...interface{}) []string {
- var result []string
- for _, arg := range strs {
- var toAppend []string
- switch arg := arg.(type) {
- case []string:
- for _, v := range arg {
- if !contains(result, v) && !contains(toAppend, v) {
- toAppend = append(toAppend, v)
- }
- }
- case []interface{}:
- for _, v := range arg {
- if !contains(result, v.(string)) && !contains(toAppend, v.(string)) {
- toAppend = append(toAppend, v.(string))
- }
- }
- case string:
- if !contains(result, arg) {
- toAppend = append(toAppend, arg)
- }
- case [][]string:
- subResult := Unique(flatten(arg)...)
- for _, v := range subResult {
- if !contains(result, v) && !contains(toAppend, v) {
- toAppend = append(toAppend, v)
- }
- }
- default:
- // Unsupported type
- continue
- }
- result = append(result, toAppend...)
- }
- return result
- }
- func contains(strs []string, s string) bool {
- for _, v := range strs {
- if v == s {
- return true
- }
- }
- return false
- }
- func flatten(arr [][]string) []interface{} {
- var result []interface{}
- for _, subarr := range arr {
- var subresult []interface{}
- for _, v := range subarr {
- subresult = append(subresult, v)
- }
- result = append(result, subresult)
- }
- return result
- }
- func Itoa(i interface{}) string {
- switch i := i.(type) {
- case int:
- return strconv.Itoa(i)
- case int32:
- return strconv.Itoa(int(i))
- case int64:
- return strconv.Itoa(int(i))
- case int16:
- return strconv.Itoa(int(i))
- case string:
- return i
- case float32:
- return strconv.Itoa(int(i))
- case float64:
- return strconv.Itoa(int(i))
- default:
- return fmt.Sprint(i)
- }
- }
- func GetPublicIP() (string, error) {
- var ip string
- // 使用 ipapi.co 获取公网IP地址
- resp, err := http.Get("https://ipapi.co/ip/")
- if err == nil {
- defer resp.Body.Close()
- ipBytes, err := ioutil.ReadAll(resp.Body)
- if err == nil {
- ip = string(ipBytes)
- }
- }
- if !IsIPv4(ip) {
- ip = ""
- }
- // 使用 ifconfig.co 获取公网IP地址
- if ip == "" {
- resp, err = http.Get("https://ifconfig.co/ip")
- if err == nil {
- defer resp.Body.Close()
- ipBytes, err := ioutil.ReadAll(resp.Body)
- if err == nil {
- ip = string(ipBytes)
- }
- }
- }
- if ip == "" {
- return "", fmt.Errorf("获取IP地址失败")
- }
- if !IsIPv4(ip) {
- return "", fmt.Errorf("获取IP地址失败")
- }
- return ip, nil
- }
- func IsIPv4(ip string) bool {
- parsedIP := net.ParseIP(ip)
- return parsedIP != nil && parsedIP.To4() != nil
- }
|