init.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. package utils
  2. import (
  3. "crypto/md5"
  4. "encoding/hex"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "io"
  9. "io/ioutil"
  10. "sync"
  11. "net"
  12. "net/http"
  13. "os"
  14. "os/exec"
  15. "path/filepath"
  16. "regexp"
  17. "runtime"
  18. "strconv"
  19. "strings"
  20. "time"
  21. // "github.com/cdle/sillyplus/core/logs"
  22. "github.com/cdle/sillyplus/core/logs"
  23. "github.com/google/uuid"
  24. )
  25. var SlaveMode bool
  26. func GenUUID() string {
  27. u2, _ := uuid.NewUUID()
  28. return u2.String()
  29. }
  30. func Float64(str interface{}) float64 {
  31. f, _ := strconv.ParseFloat(fmt.Sprint(str), 64)
  32. return f
  33. }
  34. func TrimHiddenCharacter(originStr string) string {
  35. srcRunes := []rune(originStr)
  36. dstRunes := make([]rune, 0, len(srcRunes))
  37. for _, c := range srcRunes {
  38. if c >= 0 && c <= 31 && c != 10 {
  39. continue
  40. }
  41. if c == 127 {
  42. continue
  43. }
  44. dstRunes = append(dstRunes, c)
  45. }
  46. return strings.ReplaceAll(string(dstRunes), "", "")
  47. }
  48. func Md5(str string) string {
  49. h := md5.New()
  50. h.Write([]byte(str))
  51. return hex.EncodeToString(h.Sum(nil))
  52. }
  53. func Itob(i uint64) []byte {
  54. return []byte(fmt.Sprint(i))
  55. }
  56. var Int = func(s interface{}) int {
  57. i, _ := strconv.Atoi(fmt.Sprint(s))
  58. return i
  59. }
  60. var Int64 = func(s interface{}) int64 {
  61. i, _ := strconv.Atoi(fmt.Sprint(s))
  62. return int64(i)
  63. }
  64. func init() {
  65. err := KillPeer()
  66. if err != nil {
  67. logs.Warn("结束进程失败:", err)
  68. }
  69. err = os.WriteFile(GetPidFile(), []byte(fmt.Sprintf("%d", os.Getpid())), 0o644)
  70. if err != nil {
  71. logs.Warn("写入进程ID失败:", err)
  72. }
  73. for _, arg := range os.Args {
  74. if arg == "-d" {
  75. Daemon()
  76. }
  77. }
  78. }
  79. var once = new(sync.Once)
  80. var GetDataHome = func() string {
  81. home := os.Getenv("SILLYGIRL_DATA_PATH")
  82. if home == "" {
  83. if runtime.GOOS == "windows" {
  84. home = `C:\ProgramData\sillyplus\`
  85. } else if runtime.GOOS == "darwin" {
  86. home = ExecPath + "/.sillyplus/"
  87. } else {
  88. home = `/etc/sillyplus/`
  89. }
  90. }
  91. once.Do(func() {
  92. if err := os.MkdirAll(home, os.ModePerm); err != nil {
  93. fmt.Println(err)
  94. }
  95. })
  96. return home
  97. }
  98. func KillProcess(pid int) error {
  99. var cmd *exec.Cmd
  100. switch runtime.GOOS {
  101. case "linux", "darwin":
  102. cmd = exec.Command("kill", "-TERM", strconv.Itoa(pid))
  103. case "windows":
  104. cmd = exec.Command("taskkill", "/F", "/PID", strconv.Itoa(pid))
  105. default:
  106. return fmt.Errorf("unsupported operating system: %v", runtime.GOOS)
  107. }
  108. // cmd.Stdout = os.Stdout
  109. // cmd.Stderr = os.Stderr
  110. err := cmd.Run()
  111. if _, ok := err.(*exec.ExitError); ok {
  112. return nil
  113. }
  114. if err != nil {
  115. return fmt.Errorf("failed to kill process %d: %v", pid, err)
  116. }
  117. return nil
  118. }
  119. func KillPeer() error {
  120. id, err := GetPidFromFile(GetPidFile())
  121. if err != nil {
  122. return err
  123. }
  124. if id != 0 {
  125. return KillProcess(id)
  126. }
  127. return nil
  128. }
  129. var ProcessName = getProcessName()
  130. var ExecPath, _ = filepath.Abs(filepath.Dir(os.Args[0]))
  131. var getProcessName = func() string {
  132. if runtime.GOOS == "windows" {
  133. return regexp.MustCompile(`([\w\.-]*)\.exe$`).FindStringSubmatch(os.Args[0])[0]
  134. }
  135. return regexp.MustCompile(`/([^/\s]+)$`).FindStringSubmatch(os.Args[0])[1]
  136. }
  137. var GetPidFile = func() string {
  138. return filepath.Join(GetDataHome(), "sillyGirl.pid")
  139. }
  140. func GetPidFromFile(pidFile string) (int, error) {
  141. if _, err := os.Stat(pidFile); err != nil {
  142. return 0, nil
  143. }
  144. data, err := ioutil.ReadFile(pidFile)
  145. if err != nil {
  146. return 0, err
  147. }
  148. pidStr := strings.TrimSpace(string(data))
  149. pid, err := strconv.Atoi(pidStr)
  150. if err != nil {
  151. return 0, err
  152. }
  153. return pid, nil
  154. }
  155. func CopyFile(src string, dst string) error {
  156. // 打开源文件
  157. srcFile, err := os.Open(src)
  158. if err != nil {
  159. return err
  160. }
  161. defer srcFile.Close()
  162. // 创建目标文件,如果目标文件已存在则覆盖
  163. dstFile, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
  164. if err != nil {
  165. return err
  166. }
  167. defer dstFile.Close()
  168. // 将源文件内容复制到目标文件
  169. _, err = io.Copy(dstFile, srcFile)
  170. if err != nil {
  171. return err
  172. }
  173. return nil
  174. }
  175. func Daemon(str ...string) {
  176. first := ""
  177. if len(str) > 0 {
  178. first = str[0]
  179. }
  180. args := os.Args[1:]
  181. if first == "ready" { //原->准备
  182. os.Args[0] = strings.Replace(os.Args[0], ".exe", ".ready.exe", -1)
  183. args = append(args, "-r")
  184. }
  185. if first == "reset" { //准备->原
  186. os.Args[0] = strings.Replace(os.Args[0], ".ready.exe", ".exe", -1)
  187. }
  188. execArgs := make([]string, 0)
  189. l := len(args)
  190. for i := 0; i < l; i++ {
  191. if strings.Contains(args[i], "-d") {
  192. continue
  193. }
  194. if strings.Contains(args[i], "-t") {
  195. continue
  196. }
  197. execArgs = append(execArgs, args[i])
  198. }
  199. proc := exec.Command(os.Args[0], execArgs...)
  200. err := proc.Start()
  201. if err != nil {
  202. panic(err)
  203. }
  204. logs.Info("程序以静默形式运行")
  205. // err = os.WriteFile(GetPidFile(), []byte(fmt.Sprintf("%d", proc.Process.Pid)), 0o644)
  206. if err != nil {
  207. logs.Info(err)
  208. }
  209. os.Exit(0)
  210. }
  211. func FetchCookieValue(ps ...string) string {
  212. var key, cookies string
  213. if len(ps) == 2 {
  214. if len(ps[0]) > len(ps[1]) {
  215. key, cookies = ps[1], ps[0]
  216. } else {
  217. key, cookies = ps[0], ps[1]
  218. }
  219. }
  220. match := regexp.MustCompile(key + `=([^;]*);{0,1}`).FindStringSubmatch(cookies)
  221. if len(match) == 2 {
  222. return strings.Trim(match[1], " ")
  223. } else {
  224. return ""
  225. }
  226. }
  227. func Contains(strs []string, str ...string) bool {
  228. for _, o := range strs {
  229. for _, str_ := range strs {
  230. if str_ == o {
  231. return true
  232. }
  233. }
  234. }
  235. return false
  236. }
  237. func Remove(strs []string, str string) []string {
  238. for i, o := range strs {
  239. if str == o {
  240. return append(strs[:i], strs[i+1:]...)
  241. }
  242. }
  243. return strs
  244. }
  245. func SafeError(err error) error {
  246. s := err.Error()
  247. s = regexp.MustCompile(`(http|https)://[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?`).ReplaceAllString(s, "http://138.2.2.75:5700")
  248. return errors.New(s)
  249. }
  250. func MonitorGoroutine() {
  251. if runtime.GOOS == "windows" {
  252. return
  253. }
  254. ticker := time.NewTicker(time.Millisecond * 100)
  255. lastGNum := 0
  256. for {
  257. <-ticker.C
  258. if newGNum := runtime.NumGoroutine(); lastGNum != newGNum {
  259. lastGNum = newGNum
  260. if newGNum > 800 {
  261. Daemon()
  262. }
  263. }
  264. }
  265. }
  266. func JsonMarshal(v interface{}) (d []byte) {
  267. d, _ = json.Marshal(v)
  268. return
  269. }
  270. func Str2Ints(str string) []int {
  271. is := []int{}
  272. for _, v := range Str2IntStr(str) {
  273. is = append(is, Int(v))
  274. }
  275. return is
  276. }
  277. func Str2IntStr(str string) []string {
  278. return regexp.MustCompile(`-?[\d]+`).FindAllString(str, -1)
  279. }
  280. func ToVideoQrcode(url string) string {
  281. return `[CQ:video,file=` + url + `]`
  282. }
  283. func ToImageQrcode(url string) string {
  284. return `[CQ:image,file=` + url + `]`
  285. }
  286. func FormatLog(f interface{}, v ...interface{}) string {
  287. var msg string
  288. switch f := f.(type) {
  289. case string:
  290. msg = f
  291. if len(v) == 0 {
  292. return msg
  293. }
  294. if strings.Contains(msg, "%") && !strings.Contains(msg, "%%") {
  295. //format string
  296. } else {
  297. //do not contain format char
  298. msg += strings.Repeat(" %v", len(v))
  299. }
  300. default:
  301. msg = fmt.Sprint(f)
  302. if len(v) == 0 {
  303. return msg
  304. }
  305. msg += strings.Repeat(" %v", len(v))
  306. }
  307. return fmt.Sprintf(msg, v...)
  308. }
  309. func IsZeroOrEmpty(str string) bool {
  310. return str == "0" || str == "" || str == "nil"
  311. }
  312. // func Unique(strs ...interface{}) []string {
  313. // m := make(map[string]bool)
  314. // var result []string
  315. // for _, arg := range strs {
  316. // switch arg := arg.(type) {
  317. // case []string:
  318. // for _, v := range arg {
  319. // if _, ok := m[v]; !ok {
  320. // m[v] = true
  321. // result = append(result, v)
  322. // }
  323. // }
  324. // case string:
  325. // if _, ok := m[arg]; !ok {
  326. // m[arg] = true
  327. // result = append(result, arg)
  328. // }
  329. // }
  330. // }
  331. // return result
  332. // }
  333. func Unique(strs ...interface{}) []string {
  334. var result []string
  335. for _, arg := range strs {
  336. var toAppend []string
  337. switch arg := arg.(type) {
  338. case []string:
  339. for _, v := range arg {
  340. if !contains(result, v) && !contains(toAppend, v) {
  341. toAppend = append(toAppend, v)
  342. }
  343. }
  344. case []interface{}:
  345. for _, v := range arg {
  346. if !contains(result, v.(string)) && !contains(toAppend, v.(string)) {
  347. toAppend = append(toAppend, v.(string))
  348. }
  349. }
  350. case string:
  351. if !contains(result, arg) {
  352. toAppend = append(toAppend, arg)
  353. }
  354. case [][]string:
  355. subResult := Unique(flatten(arg)...)
  356. for _, v := range subResult {
  357. if !contains(result, v) && !contains(toAppend, v) {
  358. toAppend = append(toAppend, v)
  359. }
  360. }
  361. default:
  362. // Unsupported type
  363. continue
  364. }
  365. result = append(result, toAppend...)
  366. }
  367. return result
  368. }
  369. func contains(strs []string, s string) bool {
  370. for _, v := range strs {
  371. if v == s {
  372. return true
  373. }
  374. }
  375. return false
  376. }
  377. func flatten(arr [][]string) []interface{} {
  378. var result []interface{}
  379. for _, subarr := range arr {
  380. var subresult []interface{}
  381. for _, v := range subarr {
  382. subresult = append(subresult, v)
  383. }
  384. result = append(result, subresult)
  385. }
  386. return result
  387. }
  388. func Itoa(i interface{}) string {
  389. switch i := i.(type) {
  390. case int:
  391. return strconv.Itoa(i)
  392. case int32:
  393. return strconv.Itoa(int(i))
  394. case int64:
  395. return strconv.Itoa(int(i))
  396. case int16:
  397. return strconv.Itoa(int(i))
  398. case string:
  399. return i
  400. case float32:
  401. return strconv.Itoa(int(i))
  402. case float64:
  403. return strconv.Itoa(int(i))
  404. default:
  405. return fmt.Sprint(i)
  406. }
  407. }
  408. func GetPublicIP() (string, error) {
  409. var ip string
  410. // 使用 ipapi.co 获取公网IP地址
  411. resp, err := http.Get("https://ipapi.co/ip/")
  412. if err == nil {
  413. defer resp.Body.Close()
  414. ipBytes, err := ioutil.ReadAll(resp.Body)
  415. if err == nil {
  416. ip = string(ipBytes)
  417. }
  418. }
  419. if !IsIPv4(ip) {
  420. ip = ""
  421. }
  422. // 使用 ifconfig.co 获取公网IP地址
  423. if ip == "" {
  424. resp, err = http.Get("https://ifconfig.co/ip")
  425. if err == nil {
  426. defer resp.Body.Close()
  427. ipBytes, err := ioutil.ReadAll(resp.Body)
  428. if err == nil {
  429. ip = string(ipBytes)
  430. }
  431. }
  432. }
  433. if ip == "" {
  434. return "", fmt.Errorf("获取IP地址失败")
  435. }
  436. if !IsIPv4(ip) {
  437. return "", fmt.Errorf("获取IP地址失败")
  438. }
  439. return ip, nil
  440. }
  441. func IsIPv4(ip string) bool {
  442. parsedIP := net.ParseIP(ip)
  443. return parsedIP != nil && parsedIP.To4() != nil
  444. }