system.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. package service
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. net2 "net"
  6. "os"
  7. "os/exec"
  8. "path/filepath"
  9. "runtime"
  10. "strconv"
  11. "strings"
  12. "time"
  13. "github.com/IceWhaleTech/CasaOS/model"
  14. "github.com/IceWhaleTech/CasaOS/pkg/config"
  15. command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
  16. "github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
  17. "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
  18. "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
  19. "github.com/shirou/gopsutil/v3/cpu"
  20. "github.com/shirou/gopsutil/v3/disk"
  21. "github.com/shirou/gopsutil/v3/host"
  22. "github.com/shirou/gopsutil/v3/mem"
  23. "github.com/shirou/gopsutil/v3/net"
  24. )
  25. type SystemService interface {
  26. UpdateSystemVersion(version string)
  27. GetSystemConfigDebug() []string
  28. GetCasaOSLogs(lineNumber int) string
  29. UpdateAssist()
  30. UpSystemPort(port string)
  31. GetTimeZone() string
  32. UpAppOrderFile(str, id string)
  33. GetAppOrderFile(id string) []byte
  34. GetNet(physics bool) []string
  35. GetNetInfo() []net.IOCountersStat
  36. GetCpuCoreNum() int
  37. GetCpuPercent() float64
  38. GetMemInfo() map[string]interface{}
  39. GetCpuInfo() []cpu.InfoStat
  40. GetDirPath(path string) []model.Path
  41. GetDirPathOne(path string) (m model.Path)
  42. GetNetState(name string) string
  43. GetDiskInfo() *disk.UsageStat
  44. GetSysInfo() host.InfoStat
  45. GetDeviceTree() string
  46. CreateFile(path string) (int, error)
  47. RenameFile(oldF, newF string) (int, error)
  48. MkdirAll(path string) (int, error)
  49. IsServiceRunning(name string) bool
  50. GetCPUTemperature() int
  51. GetCPUPower() map[string]string
  52. GetMacAddress() (string, error)
  53. SystemReboot() error
  54. SystemShutdown() error
  55. }
  56. type systemService struct{}
  57. func (c *systemService) GetMacAddress() (string, error) {
  58. interfaces, err := net.Interfaces()
  59. if err != nil {
  60. return "", err
  61. }
  62. inter := interfaces[0]
  63. return inter.HardwareAddr, nil
  64. }
  65. func (c *systemService) MkdirAll(path string) (int, error) {
  66. _, err := os.Stat(path)
  67. if err == nil {
  68. return common_err.DIR_ALREADY_EXISTS, nil
  69. } else {
  70. if os.IsNotExist(err) {
  71. os.MkdirAll(path, os.ModePerm)
  72. return common_err.SUCCESS, nil
  73. } else if strings.Contains(err.Error(), ": not a directory") {
  74. return common_err.FILE_OR_DIR_EXISTS, err
  75. }
  76. }
  77. return common_err.SERVICE_ERROR, err
  78. }
  79. func (c *systemService) RenameFile(oldF, newF string) (int, error) {
  80. _, err := os.Stat(newF)
  81. if err == nil {
  82. return common_err.DIR_ALREADY_EXISTS, nil
  83. } else {
  84. if os.IsNotExist(err) {
  85. err := os.Rename(oldF, newF)
  86. if err != nil {
  87. return common_err.SERVICE_ERROR, err
  88. }
  89. return common_err.SUCCESS, nil
  90. }
  91. }
  92. return common_err.SERVICE_ERROR, err
  93. }
  94. func (c *systemService) CreateFile(path string) (int, error) {
  95. _, err := os.Stat(path)
  96. if err == nil {
  97. return common_err.FILE_OR_DIR_EXISTS, nil
  98. } else {
  99. if os.IsNotExist(err) {
  100. file.CreateFile(path)
  101. return common_err.SUCCESS, nil
  102. }
  103. }
  104. return common_err.SERVICE_ERROR, err
  105. }
  106. func (c *systemService) GetDeviceTree() string {
  107. return command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;GetDeviceTree")
  108. }
  109. func (c *systemService) GetSysInfo() host.InfoStat {
  110. info, _ := host.Info()
  111. return *info
  112. }
  113. func (c *systemService) GetDiskInfo() *disk.UsageStat {
  114. path := "/"
  115. if runtime.GOOS == "windows" {
  116. path = "C:"
  117. }
  118. diskInfo, _ := disk.Usage(path)
  119. diskInfo.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.UsedPercent), 64)
  120. diskInfo.InodesUsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.InodesUsedPercent), 64)
  121. return diskInfo
  122. }
  123. func (c *systemService) GetNetState(name string) string {
  124. return command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;CatNetCardState " + name)
  125. }
  126. func (c *systemService) GetDirPathOne(path string) (m model.Path) {
  127. f, err := os.Stat(path)
  128. if err != nil {
  129. return
  130. }
  131. m.IsDir = f.IsDir()
  132. m.Name = f.Name()
  133. m.Path = path
  134. m.Size = f.Size()
  135. m.Date = f.ModTime()
  136. return
  137. }
  138. func (c *systemService) GetDirPath(path string) []model.Path {
  139. if path == "/DATA" {
  140. sysType := runtime.GOOS
  141. if sysType == "windows" {
  142. path = "C:\\CasaOS\\DATA"
  143. }
  144. if sysType == "darwin" {
  145. path = "./CasaOS/DATA"
  146. }
  147. }
  148. ls, _ := ioutil.ReadDir(path)
  149. dirs := []model.Path{}
  150. if len(path) > 0 {
  151. for _, l := range ls {
  152. filePath := filepath.Join(path, l.Name())
  153. link, err := filepath.EvalSymlinks(filePath)
  154. if err != nil {
  155. link = filePath
  156. }
  157. temp := model.Path{Name: l.Name(), Path: filePath, IsDir: l.IsDir(), Date: l.ModTime(), Size: l.Size()}
  158. if filePath != link {
  159. file, _ := os.Stat(link)
  160. temp.IsDir = file.IsDir()
  161. }
  162. dirs = append(dirs, temp)
  163. }
  164. } else {
  165. dirs = append(dirs, model.Path{Name: "DATA", Path: "/DATA/", IsDir: true, Date: time.Now()})
  166. }
  167. return dirs
  168. }
  169. func (c *systemService) GetCpuInfo() []cpu.InfoStat {
  170. info, _ := cpu.Info()
  171. return info
  172. }
  173. func (c *systemService) GetMemInfo() map[string]interface{} {
  174. memInfo, _ := mem.VirtualMemory()
  175. memInfo.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", memInfo.UsedPercent), 64)
  176. memData := make(map[string]interface{})
  177. memData["total"] = memInfo.Total
  178. memData["available"] = memInfo.Available
  179. memData["used"] = memInfo.Used
  180. memData["free"] = memInfo.Free
  181. memData["usedPercent"] = memInfo.UsedPercent
  182. return memData
  183. }
  184. func (c *systemService) GetCpuPercent() float64 {
  185. percent, _ := cpu.Percent(0, false)
  186. value, _ := strconv.ParseFloat(fmt.Sprintf("%.1f", percent[0]), 64)
  187. return value
  188. }
  189. func (c *systemService) GetCpuCoreNum() int {
  190. count, _ := cpu.Counts(false)
  191. return count
  192. }
  193. func (c *systemService) GetNetInfo() []net.IOCountersStat {
  194. parts, _ := net.IOCounters(true)
  195. return parts
  196. }
  197. func (c *systemService) GetNet(physics bool) []string {
  198. t := "1"
  199. if physics {
  200. t = "2"
  201. }
  202. return command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetNetCard " + t)
  203. }
  204. func (s *systemService) UpdateSystemVersion(version string) {
  205. if file.Exists(config.AppInfo.LogPath + "/upgrade.log") {
  206. os.Remove(config.AppInfo.LogPath + "/upgrade.log")
  207. }
  208. file.CreateFile(config.AppInfo.LogPath + "/upgrade.log")
  209. //go command2.OnlyExec("curl -fsSL https://raw.githubusercontent.com/LinkLeong/casaos-alpha/main/update.sh | bash")
  210. if len(config.ServerInfo.UpdateUrl) > 0 {
  211. go command2.OnlyExec("curl -fsSL " + config.ServerInfo.UpdateUrl + " | bash")
  212. } else {
  213. go command2.OnlyExec("curl -fsSL https://get.casaos.io/update | bash")
  214. }
  215. //s.log.Error(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version)
  216. //s.log.Error(command2.ExecResultStr(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version))
  217. }
  218. func (s *systemService) UpdateAssist() {
  219. command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/assist.sh")
  220. }
  221. func (s *systemService) GetTimeZone() string {
  222. return command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;GetTimeZone")
  223. }
  224. func (s *systemService) GetSystemConfigDebug() []string {
  225. return command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetSysInfo")
  226. }
  227. func (s *systemService) UpAppOrderFile(str, id string) {
  228. file.WriteToPath([]byte(str), config.AppInfo.DBPath+"/"+id, "app_order.json")
  229. }
  230. func (s *systemService) GetAppOrderFile(id string) []byte {
  231. return file.ReadFullFile(config.AppInfo.UserDataPath + "/" + id + "/app_order.json")
  232. }
  233. func (s *systemService) UpSystemPort(port string) {
  234. if len(port) > 0 && port != config.ServerInfo.HttpPort {
  235. config.Cfg.Section("server").Key("HttpPort").SetValue(port)
  236. config.ServerInfo.HttpPort = port
  237. }
  238. config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
  239. }
  240. func (s *systemService) GetCasaOSLogs(lineNumber int) string {
  241. file, err := os.Open(filepath.Join(config.AppInfo.LogPath, fmt.Sprintf("%s.%s",
  242. config.AppInfo.LogSaveName,
  243. config.AppInfo.LogFileExt,
  244. )))
  245. if err != nil {
  246. return err.Error()
  247. }
  248. defer file.Close()
  249. content, err := ioutil.ReadAll(file)
  250. if err != nil {
  251. return err.Error()
  252. }
  253. return string(content)
  254. }
  255. func GetDeviceAllIP() []string {
  256. var address []string
  257. addrs, err := net2.InterfaceAddrs()
  258. if err != nil {
  259. return address
  260. }
  261. for _, a := range addrs {
  262. if ipNet, ok := a.(*net2.IPNet); ok && !ipNet.IP.IsLoopback() {
  263. if ipNet.IP.To16() != nil {
  264. address = append(address, ipNet.IP.String())
  265. }
  266. }
  267. }
  268. return address
  269. }
  270. func (s *systemService) IsServiceRunning(name string) bool {
  271. status := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;CheckServiceStatus smbd")
  272. return strings.TrimSpace(status) == "running"
  273. }
  274. // find thermal_zone of cpu.
  275. // assertions:
  276. // - thermal_zone "type" and "temp" are required fields
  277. // (https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-thermal)
  278. func GetCPUThermalZone() string {
  279. keyName := "cpu_thermal_zone"
  280. var path string
  281. if result, ok := Cache.Get(keyName); ok {
  282. path, ok = result.(string)
  283. if ok {
  284. return path
  285. }
  286. }
  287. var name string
  288. cpu_types := []string{"x86_pkg_temp", "cpu", "CPU", "soc"}
  289. stub := "/sys/devices/virtual/thermal/thermal_zone"
  290. for i := 0; i < 100; i++ {
  291. path = stub + strconv.Itoa(i)
  292. if _, err := os.Stat(path); !os.IsNotExist(err) {
  293. name = strings.TrimSuffix(string(file.ReadFullFile(path+"/type")), "\n")
  294. for _, s := range cpu_types {
  295. if strings.HasPrefix(name, s) {
  296. loger.Info(fmt.Sprintf("CPU thermal zone found: %s, path: %s.", name, path))
  297. Cache.SetDefault(keyName, path)
  298. return path
  299. }
  300. }
  301. } else {
  302. if len(name) > 0 { //proves at least one zone
  303. path = stub + "0"
  304. } else {
  305. path = ""
  306. }
  307. break
  308. }
  309. }
  310. Cache.SetDefault(keyName, path)
  311. return path
  312. }
  313. func (s *systemService) GetCPUTemperature() int {
  314. outPut := ""
  315. path := GetCPUThermalZone()
  316. if len(path) > 0 {
  317. outPut = string(file.ReadFullFile(path + "/temp"))
  318. } else {
  319. outPut = "0"
  320. }
  321. celsius, _ := strconv.Atoi(strings.TrimSpace(outPut))
  322. if celsius > 1000 {
  323. celsius = celsius / 1000
  324. }
  325. return celsius
  326. }
  327. func (s *systemService) GetCPUPower() map[string]string {
  328. data := make(map[string]string, 2)
  329. data["timestamp"] = strconv.FormatInt(time.Now().Unix(), 10)
  330. if file.Exists("/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj") {
  331. data["value"] = strings.TrimSpace(string(file.ReadFullFile("/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj")))
  332. } else {
  333. data["value"] = "0"
  334. }
  335. return data
  336. }
  337. func (s *systemService) SystemReboot() error {
  338. arg := []string{"6"}
  339. cmd := exec.Command("init", arg...)
  340. _, err := cmd.CombinedOutput()
  341. if err != nil {
  342. return err
  343. }
  344. return nil
  345. }
  346. func (s *systemService) SystemShutdown() error {
  347. arg := []string{"0"}
  348. cmd := exec.Command("init", arg...)
  349. _, err := cmd.CombinedOutput()
  350. if err != nil {
  351. return err
  352. }
  353. return nil
  354. }
  355. func NewSystemService() SystemService {
  356. return &systemService{}
  357. }