123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531 |
- package service
- import (
- "encoding/json"
- "errors"
- "fmt"
- "io/ioutil"
- net2 "net"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "strconv"
- "strings"
- "time"
- "github.com/IceWhaleTech/CasaOS-Common/utils/file"
- "github.com/IceWhaleTech/CasaOS-Common/utils/logger"
- "github.com/IceWhaleTech/CasaOS/common"
- "github.com/IceWhaleTech/CasaOS/model"
- "github.com/IceWhaleTech/CasaOS/pkg/config"
- command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
- "github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
- "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
- "github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
- "github.com/tidwall/gjson"
- "go.uber.org/zap"
- "github.com/shirou/gopsutil/v3/cpu"
- "github.com/shirou/gopsutil/v3/disk"
- "github.com/shirou/gopsutil/v3/host"
- "github.com/shirou/gopsutil/v3/mem"
- "github.com/shirou/gopsutil/v3/net"
- )
- type SystemService interface {
- UpdateSystemVersion(version string)
- GetSystemConfigDebug() []string
- GetCasaOSLogs(lineNumber int) string
- UpdateAssist()
- UpSystemPort(port string)
- GetTimeZone() string
- UpAppOrderFile(str, id string)
- GetAppOrderFile(id string) []byte
- GetNet(physics bool) []string
- GetNetInfo() []net.IOCountersStat
- GetCpuCoreNum() int
- GetCpuPercent() float64
- GetMemInfo() map[string]interface{}
- GetCpuInfo() []cpu.InfoStat
- GetDirPath(path string) ([]model.Path, error)
- GetDirPathOne(path string) (m model.Path)
- GetNetState(name string) string
- GetDiskInfo() *disk.UsageStat
- GetSysInfo() host.InfoStat
- GetDeviceTree() string
- GetDeviceInfo() model.DeviceInfo
- CreateFile(path string) (int, error)
- RenameFile(oldF, newF string) (int, error)
- MkdirAll(path string) (int, error)
- GetCPUTemperature() int
- GetCPUPower() map[string]string
- GetMacAddress() (string, error)
- SystemReboot() error
- SystemShutdown() error
- GetSystemEntry() string
- GenreateSystemEntry()
- }
- type systemService struct{}
- func (c *systemService) GetDeviceInfo() model.DeviceInfo {
- m := model.DeviceInfo{}
- m.OS_Version = common.VERSION
- err, portStr := MyService.Gateway().GetPort()
- if err != nil {
- m.Port = 80
- } else {
- port := gjson.Get(portStr, "data")
- if len(port.Raw) == 0 {
- m.Port = 80
- } else {
- p, err := strconv.Atoi(port.Raw)
- if err != nil {
- m.Port = 80
- } else {
- m.Port = p
- }
- }
- }
- allIpv4 := ip_helper.GetDeviceAllIPv4()
- ip := []string{}
- nets := MyService.System().GetNet(true)
- for _, n := range nets {
- if v, ok := allIpv4[n]; ok {
- {
- ip = append(ip, v)
- }
- }
- }
- m.LanIpv4 = ip
- h, err := host.Info() /* */
- if err == nil {
- m.DeviceName = h.Hostname
- }
- mb := model.BaseInfo{}
- err = json.Unmarshal(file.ReadFullFile(config.AppInfo.DBPath+"/baseinfo.conf"), &mb)
- if err == nil {
- m.Hash = mb.Hash
- }
- osRelease, _ := file.ReadOSRelease()
- m.DeviceModel = osRelease["MODEL"]
- m.DeviceSN = osRelease["SN"]
- res := httper.Get("http://127.0.0.1:"+strconv.Itoa(m.Port)+"/v1/users/status", nil)
- init := gjson.Get(res, "data.initialized")
- m.Initialized, _ = strconv.ParseBool(init.Raw)
- return m
- }
- func (c *systemService) GenreateSystemEntry() {
- modelsPath := "/var/lib/casaos/www/modules"
- entryFileName := "entry.json"
- entryFilePath := filepath.Join(config.AppInfo.DBPath, "db", entryFileName)
- file.IsNotExistCreateFile(entryFilePath)
- dir, err := os.ReadDir(modelsPath)
- if err != nil {
- logger.Error("read dir error", zap.Error(err))
- return
- }
- json := "["
- for _, v := range dir {
- data, err := os.ReadFile(filepath.Join(modelsPath, v.Name(), entryFileName))
- if err != nil {
- logger.Error("read entry file error", zap.Error(err))
- continue
- }
- json += string(data) + ","
- }
- json = strings.TrimRight(json, ",")
- json += "]"
- err = os.WriteFile(entryFilePath, []byte(json), 0666)
- if err != nil {
- logger.Error("write entry file error", zap.Error(err))
- return
- }
- }
- func (c *systemService) GetSystemEntry() string {
- modelsPath := "/var/lib/casaos/www/modules"
- entryFileName := "entry.json"
- dir, err := os.ReadDir(modelsPath)
- if err != nil {
- logger.Error("read dir error", zap.Error(err))
- return ""
- }
- json := "["
- for _, v := range dir {
- data, err := os.ReadFile(filepath.Join(modelsPath, v.Name(), entryFileName))
- if err != nil {
- logger.Error("read entry file error", zap.Error(err))
- continue
- }
- json += string(data) + ","
- }
- json = strings.TrimRight(json, ",")
- json += "]"
- if err != nil {
- logger.Error("write entry file error", zap.Error(err))
- return ""
- }
- return json
- }
- func (c *systemService) GetMacAddress() (string, error) {
- interfaces, err := net.Interfaces()
- if err != nil {
- return "", err
- }
- nets := MyService.System().GetNet(true)
- for _, v := range interfaces {
- for _, n := range nets {
- if v.Name == n {
- return v.HardwareAddr, nil
- }
- }
- }
- return "", errors.New("not found")
- }
- func (c *systemService) MkdirAll(path string) (int, error) {
- _, err := os.Stat(path)
- if err == nil {
- return common_err.DIR_ALREADY_EXISTS, nil
- } else {
- if os.IsNotExist(err) {
- os.MkdirAll(path, os.ModePerm)
- return common_err.SUCCESS, nil
- } else if strings.Contains(err.Error(), ": not a directory") {
- return common_err.FILE_OR_DIR_EXISTS, err
- }
- }
- return common_err.SERVICE_ERROR, err
- }
- func (c *systemService) RenameFile(oldF, newF string) (int, error) {
- _, err := os.Stat(newF)
- if err == nil {
- return common_err.DIR_ALREADY_EXISTS, nil
- } else {
- if os.IsNotExist(err) {
- err := os.Rename(oldF, newF)
- if err != nil {
- return common_err.SERVICE_ERROR, err
- }
- return common_err.SUCCESS, nil
- }
- }
- return common_err.SERVICE_ERROR, err
- }
- func (c *systemService) CreateFile(path string) (int, error) {
- _, err := os.Stat(path)
- if err == nil {
- return common_err.FILE_OR_DIR_EXISTS, nil
- } else {
- if os.IsNotExist(err) {
- file.CreateFile(path)
- return common_err.SUCCESS, nil
- }
- }
- return common_err.SERVICE_ERROR, err
- }
- func (c *systemService) GetDeviceTree() string {
- return command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;GetDeviceTree")
- }
- func (c *systemService) GetSysInfo() host.InfoStat {
- info, _ := host.Info()
- return *info
- }
- func (c *systemService) GetDiskInfo() *disk.UsageStat {
- path := "/"
- if runtime.GOOS == "windows" {
- path = "C:"
- }
- diskInfo, _ := disk.Usage(path)
- diskInfo.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.UsedPercent), 64)
- diskInfo.InodesUsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.InodesUsedPercent), 64)
- return diskInfo
- }
- func (c *systemService) GetNetState(name string) string {
- return command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;CatNetCardState " + name)
- }
- func (c *systemService) GetDirPathOne(path string) (m model.Path) {
- f, err := os.Stat(path)
- if err != nil {
- return
- }
- m.IsDir = f.IsDir()
- m.Name = f.Name()
- m.Path = path
- m.Size = f.Size()
- m.Date = f.ModTime()
- return
- }
- func (c *systemService) GetDirPath(path string) ([]model.Path, error) {
- if path == "/DATA" {
- sysType := runtime.GOOS
- if sysType == "windows" {
- path = "C:\\CasaOS\\DATA"
- }
- if sysType == "darwin" {
- path = "./CasaOS/DATA"
- }
- }
- ls, err := os.ReadDir(path)
- if err != nil {
- logger.Error("when read dir", zap.Error(err))
- return []model.Path{}, err
- }
- dirs := []model.Path{}
- if len(path) > 0 {
- for _, l := range ls {
- filePath := filepath.Join(path, l.Name())
- link, err := filepath.EvalSymlinks(filePath)
- if err != nil {
- link = filePath
- }
- tempFile, err := l.Info()
- if err != nil {
- logger.Error("when read dir", zap.Error(err))
- return []model.Path{}, err
- }
- temp := model.Path{Name: l.Name(), Path: filePath, IsDir: l.IsDir(), Date: tempFile.ModTime(), Size: tempFile.Size()}
- if filePath != link {
- file, _ := os.Stat(link)
- temp.IsDir = file.IsDir()
- }
- dirs = append(dirs, temp)
- }
- } else {
- dirs = append(dirs, model.Path{Name: "DATA", Path: "/DATA/", IsDir: true, Date: time.Now()})
- }
- return dirs, nil
- }
- func (c *systemService) GetCpuInfo() []cpu.InfoStat {
- info, _ := cpu.Info()
- return info
- }
- func (c *systemService) GetMemInfo() map[string]interface{} {
- memInfo, _ := mem.VirtualMemory()
- memInfo.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", memInfo.UsedPercent), 64)
- memData := make(map[string]interface{})
- memData["total"] = memInfo.Total
- memData["available"] = memInfo.Available
- memData["used"] = memInfo.Used
- memData["free"] = memInfo.Free
- memData["usedPercent"] = memInfo.UsedPercent
- return memData
- }
- func (c *systemService) GetCpuPercent() float64 {
- percent, _ := cpu.Percent(0, false)
- value, _ := strconv.ParseFloat(fmt.Sprintf("%.1f", percent[0]), 64)
- return value
- }
- func (c *systemService) GetCpuCoreNum() int {
- count, _ := cpu.Counts(false)
- return count
- }
- func (c *systemService) GetNetInfo() []net.IOCountersStat {
- parts, _ := net.IOCounters(true)
- return parts
- }
- func (c *systemService) GetNet(physics bool) []string {
- t := "1"
- if physics {
- t = "2"
- }
- return command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetNetCard " + t)
- }
- func (s *systemService) UpdateSystemVersion(version string) {
- keyName := "casa_version"
- Cache.Delete(keyName)
- if file.Exists(config.AppInfo.LogPath + "/upgrade.log") {
- os.Remove(config.AppInfo.LogPath + "/upgrade.log")
- }
- file.CreateFile(config.AppInfo.LogPath + "/upgrade.log")
- // go command2.OnlyExec("curl -fsSL https://raw.githubusercontent.com/LinkLeong/casaos-alpha/main/update.sh | bash")
- if len(config.ServerInfo.UpdateUrl) > 0 {
- go command2.OnlyExec("curl -fsSL " + config.ServerInfo.UpdateUrl + " | bash")
- } else {
- osRelease, _ := file.ReadOSRelease()
- go command2.OnlyExec("curl -fsSL https://get.casaos.io/update?t=" + osRelease["MANUFACTURER"] + " | bash")
- }
- // s.log.Error(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version)
- // s.log.Error(command2.ExecResultStr(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version))
- }
- func (s *systemService) UpdateAssist() {
- command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/assist.sh")
- }
- func (s *systemService) GetTimeZone() string {
- return command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;GetTimeZone")
- }
- func (s *systemService) GetSystemConfigDebug() []string {
- return command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetSysInfo")
- }
- func (s *systemService) UpAppOrderFile(str, id string) {
- file.WriteToPath([]byte(str), config.AppInfo.DBPath+"/"+id, "app_order.json")
- }
- func (s *systemService) GetAppOrderFile(id string) []byte {
- return file.ReadFullFile(config.AppInfo.UserDataPath + "/" + id + "/app_order.json")
- }
- func (s *systemService) UpSystemPort(port string) {
- if len(port) > 0 && port != config.ServerInfo.HttpPort {
- config.Cfg.Section("server").Key("HttpPort").SetValue(port)
- config.ServerInfo.HttpPort = port
- }
- config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
- }
- func (s *systemService) GetCasaOSLogs(lineNumber int) string {
- file, err := os.Open(filepath.Join(config.AppInfo.LogPath, fmt.Sprintf("%s.%s",
- config.AppInfo.LogSaveName,
- config.AppInfo.LogFileExt,
- )))
- if err != nil {
- return err.Error()
- }
- defer file.Close()
- content, err := ioutil.ReadAll(file)
- if err != nil {
- return err.Error()
- }
- return string(content)
- }
- func GetDeviceAllIP() []string {
- var address []string
- addrs, err := net2.InterfaceAddrs()
- if err != nil {
- return address
- }
- for _, a := range addrs {
- if ipNet, ok := a.(*net2.IPNet); ok && !ipNet.IP.IsLoopback() {
- if ipNet.IP.To16() != nil {
- address = append(address, ipNet.IP.String())
- }
- }
- }
- return address
- }
- // find thermal_zone of cpu.
- // assertions:
- // - thermal_zone "type" and "temp" are required fields
- // (https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-thermal)
- func GetCPUThermalZone() string {
- keyName := "cpu_thermal_zone"
- var path string
- if result, ok := Cache.Get(keyName); ok {
- path, ok = result.(string)
- if ok {
- return path
- }
- }
- var name string
- cpu_types := []string{"x86_pkg_temp", "cpu", "CPU", "soc"}
- stub := "/sys/devices/virtual/thermal/thermal_zone"
- for i := 0; i < 100; i++ {
- path = stub + strconv.Itoa(i)
- if _, err := os.Stat(path); !os.IsNotExist(err) {
- name = strings.TrimSuffix(string(file.ReadFullFile(path+"/type")), "\n")
- for _, s := range cpu_types {
- if strings.HasPrefix(name, s) {
- logger.Info(fmt.Sprintf("CPU thermal zone found: %s, path: %s.", name, path))
- Cache.SetDefault(keyName, path)
- return path
- }
- }
- } else {
- if len(name) > 0 { // proves at least one zone
- path = stub + "0"
- } else {
- path = ""
- }
- break
- }
- }
- Cache.SetDefault(keyName, path)
- return path
- }
- func (s *systemService) GetCPUTemperature() int {
- outPut := ""
- path := GetCPUThermalZone()
- if len(path) > 0 {
- outPut = string(file.ReadFullFile(path + "/temp"))
- } else {
- outPut = "0"
- }
- celsius, _ := strconv.Atoi(strings.TrimSpace(outPut))
- if celsius > 1000 {
- celsius = celsius / 1000
- }
- return celsius
- }
- func (s *systemService) GetCPUPower() map[string]string {
- data := make(map[string]string, 2)
- data["timestamp"] = strconv.FormatInt(time.Now().Unix(), 10)
- if file.Exists("/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj") {
- data["value"] = strings.TrimSpace(string(file.ReadFullFile("/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj")))
- } else {
- data["value"] = "0"
- }
- return data
- }
- func (s *systemService) SystemReboot() error {
- // cmd := exec.Command("/bin/bash", "-c", "reboot")
- arg := []string{"6"}
- cmd := exec.Command("init", arg...)
- _, err := cmd.CombinedOutput()
- if err != nil {
- return err
- }
- return nil
- }
- func (s *systemService) SystemShutdown() error {
- arg := []string{"0"}
- cmd := exec.Command("init", arg...)
- _, err := cmd.CombinedOutput()
- if err != nil {
- return err
- }
- return nil
- }
- func NewSystemService() SystemService {
- return &systemService{}
- }
|