report.go 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. //go:build darwin || linux || windows
  2. package libbox
  3. import (
  4. "bytes"
  5. "encoding/json"
  6. "os"
  7. "path/filepath"
  8. "runtime"
  9. "strconv"
  10. "time"
  11. C "github.com/sagernet/sing-box/constant"
  12. E "github.com/sagernet/sing/common/exceptions"
  13. )
  14. type reportMetadata struct {
  15. Source string `json:"source,omitempty"`
  16. BundleIdentifier string `json:"bundleIdentifier,omitempty"`
  17. ProcessName string `json:"processName,omitempty"`
  18. ProcessPath string `json:"processPath,omitempty"`
  19. StartedAt string `json:"startedAt,omitempty"`
  20. AppVersion string `json:"appVersion,omitempty"`
  21. AppMarketingVersion string `json:"appMarketingVersion,omitempty"`
  22. CoreVersion string `json:"coreVersion,omitempty"`
  23. GoVersion string `json:"goVersion,omitempty"`
  24. }
  25. func baseReportMetadata() reportMetadata {
  26. processPath, _ := os.Executable()
  27. processName := filepath.Base(processPath)
  28. if processName == "." {
  29. processName = ""
  30. }
  31. return reportMetadata{
  32. Source: sCrashReportSource,
  33. ProcessName: processName,
  34. ProcessPath: processPath,
  35. CoreVersion: C.Version,
  36. GoVersion: GoVersion(),
  37. }
  38. }
  39. func writeReportFile(destPath string, name string, content []byte) {
  40. filePath := filepath.Join(destPath, name)
  41. os.WriteFile(filePath, content, 0o666)
  42. chownReport(filePath)
  43. }
  44. func writeReportMetadata(destPath string, metadata any) {
  45. data, err := json.Marshal(metadata)
  46. if err != nil {
  47. return
  48. }
  49. writeReportFile(destPath, "metadata.json", data)
  50. }
  51. func copyConfigSnapshot(destPath string) {
  52. snapshotPath := configSnapshotPath()
  53. content, err := os.ReadFile(snapshotPath)
  54. if err != nil {
  55. return
  56. }
  57. if len(bytes.TrimSpace(content)) == 0 {
  58. return
  59. }
  60. writeReportFile(destPath, "configuration.json", content)
  61. }
  62. func initReportDir(path string) {
  63. os.MkdirAll(path, 0o777)
  64. chownReport(path)
  65. }
  66. func chownReport(path string) {
  67. if runtime.GOOS != "android" && runtime.GOOS != "windows" {
  68. os.Chown(path, sUserID, sGroupID)
  69. }
  70. }
  71. func nextAvailableReportPath(reportsDir string, timestamp time.Time) (string, error) {
  72. destName := timestamp.Format("2006-01-02T15-04-05")
  73. destPath := filepath.Join(reportsDir, destName)
  74. _, err := os.Stat(destPath)
  75. if os.IsNotExist(err) {
  76. return destPath, nil
  77. }
  78. for i := 1; i <= 1000; i++ {
  79. suffixedPath := filepath.Join(reportsDir, destName+"-"+strconv.Itoa(i))
  80. _, err = os.Stat(suffixedPath)
  81. if os.IsNotExist(err) {
  82. return suffixedPath, nil
  83. }
  84. }
  85. return "", E.New("no available report path for ", destName)
  86. }