返回 DeepSeek-Reasonix
devinfo.go
根目录 / desktop / devinfo.go
1 package main
2
3 import (
4 "runtime"
5 "strconv"
6 "strings"
7 )
8
9 // devinfo.go collects coarse machine facts attached to crash reports: OS version,
10 // CPU model, core count, RAM. Nothing here identifies a user or machine.
11
12 type deviceInfo struct {
13 OSVersion string `json:"osVersion,omitempty"`
14 OSBuild int `json:"osBuild,omitempty"`
15 OSRevision int `json:"osRevision,omitempty"`
16 DistroID string `json:"distroId,omitempty"`
17 DistroVersion string `json:"distroVersion,omitempty"`
18 KernelVersion string `json:"kernelVersion,omitempty"`
19 SessionType string `json:"sessionType,omitempty"`
20 CPU string `json:"cpu,omitempty"`
21 Cores int `json:"cores"`
22 RAMGB int `json:"ramGb,omitempty"`
23 }
24
25 type platformEnvironment struct {
26 DistroID string
27 DistroVersion string
28 KernelVersion string
29 SessionType string
30 }
31
32 const gib = 1 << 30
33
34 func collectDeviceInfo() deviceInfo {
35 osBuild, osRevision := platformOSBuild()
36 environment := platformEnvironmentInfo()
37 return deviceInfo{
38 OSVersion: boundedPlatformField(platformOSVersion(), 128),
39 OSBuild: osBuild,
40 OSRevision: osRevision,
41 DistroID: environment.DistroID,
42 DistroVersion: environment.DistroVersion,
43 KernelVersion: environment.KernelVersion,
44 SessionType: environment.SessionType,
45 CPU: boundedPlatformField(platformCPU(), 128),
46 Cores: runtime.NumCPU(),
47 RAMGB: int((platformRAMBytes() + gib/2) / gib),
48 }
49 }
50
51 func boundedPlatformField(value string, limit int) string {
52 value = strings.TrimSpace(value)
53 value = strings.Map(func(r rune) rune {
54 if r < 0x20 || r == 0x7f {
55 return -1
56 }
57 return r
58 }, value)
59 if len(value) > limit {
60 value = value[:limit]
61 }
62 return value
63 }
64
65 func parseOSRelease(osRelease string) map[string]string {
66 result := make(map[string]string)
67 for line := range strings.SplitSeq(osRelease, "\n") {
68 line = strings.TrimSpace(line)
69 if line == "" || strings.HasPrefix(line, "#") {
70 continue
71 }
72 key, value, ok := strings.Cut(line, "=")
73 if !ok {
74 continue
75 }
76 key = strings.TrimSpace(key)
77 value = strings.TrimSpace(value)
78 if len(value) >= 2 && ((value[0] == '"' && value[len(value)-1] == '"') || (value[0] == '\'' && value[len(value)-1] == '\'')) {
79 value = value[1 : len(value)-1]
80 value = strings.ReplaceAll(value, `\"`, `"`)
81 value = strings.ReplaceAll(value, `\\`, `\`)
82 }
83 result[key] = value
84 }
85 return result
86 }
87
88 func parseCPUModel(cpuinfo string) string {
89 for line := range strings.SplitSeq(cpuinfo, "\n") {
90 if name, ok := strings.CutPrefix(line, "model name"); ok {
91 if _, v, ok := strings.Cut(name, ":"); ok {
92 return strings.TrimSpace(v)
93 }
94 }
95 }
96 return ""
97 }
98
99 func parseMemTotalBytes(meminfo string) uint64 {
100 for line := range strings.SplitSeq(meminfo, "\n") {
101 if rest, ok := strings.CutPrefix(line, "MemTotal:"); ok {
102 kb, err := strconv.ParseUint(strings.TrimSuffix(strings.TrimSpace(rest), " kB"), 10, 64)
103 if err != nil {
104 return 0
105 }
106 return kb * 1024
107 }
108 }
109 return 0
110 }
111
112 func parseOSReleasePrettyName(osRelease string) string {
113 return parseOSRelease(osRelease)["PRETTY_NAME"]
114 }
115
116 func linuxSessionType(getenv func(string) string) string {
117 if getenv("SSH_CONNECTION") != "" || getenv("XRDP_SESSION") != "" {
118 return "remote"
119 }
120 switch strings.ToLower(strings.TrimSpace(getenv("XDG_SESSION_TYPE"))) {
121 case "wayland":
122 return "wayland"
123 case "x11":
124 return "x11"
125 }
126 if getenv("WAYLAND_DISPLAY") != "" {
127 return "wayland"
128 }
129 if getenv("DISPLAY") != "" {
130 return "x11"
131 }
132 return "unknown"
133 }
134
134 lines GO