system.go 11 KB

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