diff --git a/main.go b/main.go index 34bd121..27a1303 100644 --- a/main.go +++ b/main.go @@ -5,21 +5,27 @@ package main import ( "context" _ "embed" + "encoding/base64" + "encoding/json" "flag" "fmt" "net" "net/http" "path/filepath" + "strconv" "time" "github.com/IceWhaleTech/CasaOS-Common/model" "github.com/IceWhaleTech/CasaOS-Common/utils/constants" "github.com/IceWhaleTech/CasaOS-Common/utils/logger" + "github.com/tidwall/gjson" + "golang.org/x/net/websocket" util_http "github.com/IceWhaleTech/CasaOS-Common/utils/http" "github.com/IceWhaleTech/CasaOS/codegen/message_bus" "github.com/IceWhaleTech/CasaOS/common" + model2 "github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/pkg/cache" "github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/sqlite" @@ -80,7 +86,8 @@ func init() { service.GetCPUThermalZone() route.InitFunction() - + go SendToSocket(service.MyService.System().GetDeviceInfo()) + service.MyService.System().GenreateSystemEntry() /// //service.MountLists = make(map[string]*mountlib.MountPoint) //configfile.Install() @@ -101,7 +108,7 @@ func main() { if *versionFlag { return } - + go Special(service.MyService) v1Router := route.InitV1Router() v2Router := route.InitV2Router() @@ -229,3 +236,63 @@ func main() { panic(err) } } +func Special(myservice service.Repository) { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + m := myservice.System().GetDeviceInfo() + jsonData, err := json.Marshal(m) + if err != nil { + fmt.Println("Error:", err) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "application/json") + fmt.Fprintln(w, string(jsonData)) + }) + + if err := http.ListenAndServe(":9527", nil); err != nil { + fmt.Println("Error:", err) + } + +} + +func SendToSocket(m model2.DeviceInfo) { + if len(m.DeviceSN) == 0 { + //TODO:需要更换socket地址,需要放开sn的判断 + //return + } + by, _ := json.Marshal(m) + base64Str := base64.StdEncoding.EncodeToString(by) + var count int = 1 + for i := 0; i < 10; i++ { + wsURL := fmt.Sprintf("ws://%s/server/zima%s", "52.193.63.104:3060", "?device="+base64Str) + ws, err := websocket.Dial(wsURL, "", "http://localhost") + if err != nil { + logger.Error("connect websocket err"+strconv.Itoa(i), zap.Any("error", err)) + time.Sleep(time.Second * 1) + continue + } + defer ws.Close() + + logger.Info("subscribed to", zap.Any("url", wsURL)) + for { + msg := make([]byte, 1024) + n, err := ws.Read(msg) + if err != nil { + logger.Error("err", zap.Any("err", err.Error())) + break + } + message := msg[:n] + t := gjson.GetBytes(message, "type") + if t.Str == "ping" { + ws.Write([]byte(`{"type":"pong"}`)) + count++ + } + if count > 600 { + return + } + } + } + logger.Error("error when try to connect to message bus") + +} diff --git a/model/zima.go b/model/zima.go index e144b7c..af21340 100644 --- a/model/zima.go +++ b/model/zima.go @@ -23,3 +23,14 @@ type Path struct { Write bool `json:"write"` Extensions map[string]interface{} `json:"extensions"` } + +type DeviceInfo struct { + LanIpv4 []string `json:"lan_ipv4"` + Port int `json:"port"` + DeviceName string `json:"device_name"` + DeviceModel string `json:"device_model"` + DeviceSN string `json:"device_sn"` + Initialized bool `json:"initialized"` + OS_Version string `json:"os_version"` + Hash string `json:"hash"` +} diff --git a/pkg/utils/ip_helper/ip.go b/pkg/utils/ip_helper/ip.go index 291755a..3023a05 100644 --- a/pkg/utils/ip_helper/ip.go +++ b/pkg/utils/ip_helper/ip.go @@ -1,6 +1,7 @@ package ip_helper import ( + "fmt" "net" "strings" @@ -56,7 +57,30 @@ func GetDeviceAllIP(port string) []string { } return address } +func GetDeviceAllIPv4() map[string]string { + address := make(map[string]string) + addrs, err := net.Interfaces() + if err != nil { + return address + } + for _, a := range addrs { + if a.Flags&net.FlagLoopback != 0 || a.Flags&net.FlagUp == 0 { + continue + } + addrs, err := a.Addrs() + if err != nil { + fmt.Println("Error:", err) + continue + } + for _, addr := range addrs { + if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && ipnet.IP.To4() != nil { + address[a.Name] = ipnet.IP.String() + } + } + } + return address +} func HasLocalIP(ip net.IP) bool { if ip.IsLoopback() { return true diff --git a/route/v1.go b/route/v1.go index fa8a39c..b00e9a6 100644 --- a/route/v1.go +++ b/route/v1.go @@ -41,11 +41,7 @@ func InitV1Router() *gin.Engine { r.GET("/v1/recover/:type", v1.GetRecoverStorage) v1Group := r.Group("/v1") - v1Group.Use(jwt.ExceptLocalhost( - func() (*ecdsa.PublicKey, error) { - return external.GetPublicKey(config.CommonInfo.RuntimePath) - }, - )) + v1Group.Use(jwt.ExceptLocalhost(func() (*ecdsa.PublicKey, error) { return external.GetPublicKey(config.CommonInfo.RuntimePath) })) { v1SysGroup := v1Group.Group("/sys") @@ -79,6 +75,7 @@ func InitV1Router() *gin.Engine { // v1SysGroup.PUT("/port", v1.PutCasaOSPort) v1SysGroup.GET("/proxy", v1.GetSystemProxy) v1SysGroup.PUT("/state/:state", v1.PutSystemState) + v1SysGroup.GET("/entry", v1.GetSystemEntry) } v1PortGroup := v1Group.Group("/port") v1PortGroup.Use() @@ -86,79 +83,78 @@ func InitV1Router() *gin.Engine { v1PortGroup.GET("/", v1.GetPort) // app/port v1PortGroup.GET("/state/:port", v1.PortCheck) // app/check/:port } + // v1FileGroup := v1Group.Group("/file") + // v1FileGroup.Use() + // { + // v1FileGroup.GET("", v1.GetDownloadSingleFile) // download/:path + // v1FileGroup.POST("", v1.PostCreateFile) + // v1FileGroup.PUT("", v1.PutFileContent) + // v1FileGroup.PUT("/name", v1.RenamePath) + // // file/rename + // v1FileGroup.GET("/content", v1.GetFilerContent) // file/read - v1FileGroup := v1Group.Group("/file") - v1FileGroup.Use() - { - v1FileGroup.GET("", v1.GetDownloadSingleFile) // download/:path - v1FileGroup.POST("", v1.PostCreateFile) - v1FileGroup.PUT("", v1.PutFileContent) - v1FileGroup.PUT("/name", v1.RenamePath) - // file/rename - v1FileGroup.GET("/content", v1.GetFilerContent) // file/read + // // File uploads need to be handled separately, and will not be modified here + // //v1FileGroup.POST("/upload", v1.PostFileUpload) + // v1FileGroup.POST("/upload", v1.PostFileUpload) + // v1FileGroup.GET("/upload", v1.GetFileUpload) + // // v1FileGroup.GET("/download", v1.UserFileDownloadCommonService) + // v1FileGroup.GET("/ws", v1.ConnectWebSocket) + // v1FileGroup.GET("/peers", v1.GetPeers) + // } + // v1CloudGroup := v1Group.Group("/cloud") + // v1CloudGroup.Use() + // { + // v1CloudGroup.GET("", v1.ListStorages) + // v1CloudGroup.DELETE("", v1.UmountStorage) + // } + // v1DriverGroup := v1Group.Group("/driver") + // v1DriverGroup.Use() + // { + // v1DriverGroup.GET("", v1.ListDriverInfo) + // } - // File uploads need to be handled separately, and will not be modified here - //v1FileGroup.POST("/upload", v1.PostFileUpload) - v1FileGroup.POST("/upload", v1.PostFileUpload) - v1FileGroup.GET("/upload", v1.GetFileUpload) - // v1FileGroup.GET("/download", v1.UserFileDownloadCommonService) - v1FileGroup.GET("/ws", v1.ConnectWebSocket) - v1FileGroup.GET("/peers", v1.GetPeers) - } - v1CloudGroup := v1Group.Group("/cloud") - v1CloudGroup.Use() - { - v1CloudGroup.GET("", v1.ListStorages) - v1CloudGroup.DELETE("", v1.UmountStorage) - } - v1DriverGroup := v1Group.Group("/driver") - v1DriverGroup.Use() - { - v1DriverGroup.GET("", v1.ListDriverInfo) - } + // v1FolderGroup := v1Group.Group("/folder") + // v1FolderGroup.Use() + // { + // v1FolderGroup.PUT("/name", v1.RenamePath) + // v1FolderGroup.GET("", v1.DirPath) ///file/dirpath + // v1FolderGroup.POST("", v1.MkdirAll) ///file/mkdir + // v1FolderGroup.GET("/size", v1.GetSize) + // v1FolderGroup.GET("/count", v1.GetFileCount) + // } + // v1BatchGroup := v1Group.Group("/batch") + // v1BatchGroup.Use() + // { - v1FolderGroup := v1Group.Group("/folder") - v1FolderGroup.Use() - { - v1FolderGroup.PUT("/name", v1.RenamePath) - v1FolderGroup.GET("", v1.DirPath) ///file/dirpath - v1FolderGroup.POST("", v1.MkdirAll) ///file/mkdir - v1FolderGroup.GET("/size", v1.GetSize) - v1FolderGroup.GET("/count", v1.GetFileCount) - } - v1BatchGroup := v1Group.Group("/batch") - v1BatchGroup.Use() - { - - v1BatchGroup.DELETE("", v1.DeleteFile) // file/delete - v1BatchGroup.DELETE("/:id/task", v1.DeleteOperateFileOrDir) - v1BatchGroup.POST("/task", v1.PostOperateFileOrDir) // file/operate - v1BatchGroup.GET("", v1.GetDownloadFile) - } + // v1BatchGroup.DELETE("", v1.DeleteFile) // file/delete + // v1BatchGroup.DELETE("/:id/task", v1.DeleteOperateFileOrDir) + // v1BatchGroup.POST("/task", v1.PostOperateFileOrDir) // file/operate + // v1BatchGroup.GET("", v1.GetDownloadFile) + // } v1ImageGroup := v1Group.Group("/image") v1ImageGroup.Use() { v1ImageGroup.GET("", v1.GetFileImage) } - v1SambaGroup := v1Group.Group("/samba") - v1SambaGroup.Use() - { - v1ConnectionsGroup := v1SambaGroup.Group("/connections") - v1ConnectionsGroup.Use() - { - v1ConnectionsGroup.GET("", v1.GetSambaConnectionsList) - v1ConnectionsGroup.POST("", v1.PostSambaConnectionsCreate) - v1ConnectionsGroup.DELETE("/:id", v1.DeleteSambaConnections) - } - v1SharesGroup := v1SambaGroup.Group("/shares") - v1SharesGroup.Use() - { - v1SharesGroup.GET("", v1.GetSambaSharesList) - v1SharesGroup.POST("", v1.PostSambaSharesCreate) - v1SharesGroup.DELETE("/:id", v1.DeleteSambaShares) - v1SharesGroup.GET("/status", v1.GetSambaStatus) - } - } + // v1SambaGroup := v1Group.Group("/samba") + // v1SambaGroup.Use() + // { + // v1ConnectionsGroup := v1SambaGroup.Group("/connections") + // v1ConnectionsGroup.Use() + // { + // v1ConnectionsGroup.GET("", v1.GetSambaConnectionsList) + // v1ConnectionsGroup.POST("", v1.PostSambaConnectionsCreate) + // v1ConnectionsGroup.DELETE("/:id", v1.DeleteSambaConnections) + // } + // v1SharesGroup := v1SambaGroup.Group("/shares") + // v1SharesGroup.Use() + // { + // v1SharesGroup.GET("", v1.GetSambaSharesList) + // v1SharesGroup.POST("", v1.PostSambaSharesCreate) + // v1SharesGroup.DELETE("/:id", v1.DeleteSambaShares) + // v1SharesGroup.GET("/status", v1.GetSambaStatus) + // } + // } v1NotifyGroup := v1Group.Group("/notify") v1NotifyGroup.Use() { diff --git a/route/v1/system.go b/route/v1/system.go index 1e26d5f..b1de6cc 100644 --- a/route/v1/system.go +++ b/route/v1/system.go @@ -24,6 +24,7 @@ import ( model2 "github.com/IceWhaleTech/CasaOS/service/model" "github.com/IceWhaleTech/CasaOS/types" "github.com/gin-gonic/gin" + "github.com/tidwall/gjson" ) // @Summary check version @@ -371,3 +372,12 @@ func PortCheck(c *gin.Context) { t := c.DefaultQuery("type", "tcp") c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: port.IsPortAvailable(p, t)}) } + +func GetSystemEntry(c *gin.Context) { + entry := service.MyService.System().GetSystemEntry() + if !gjson.Valid(entry) { + c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: ""}) + return + } + c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: entry}) +} diff --git a/route/v2.go b/route/v2.go index d07e062..2035b3b 100644 --- a/route/v2.go +++ b/route/v2.go @@ -76,10 +76,6 @@ func InitV2Router() http.Handler { // return true }, ParseTokenFunc: func(token string, c echo.Context) (interface{}, error) { - // claims, code := jwt.Validate(token) // TODO - needs JWT validation - // if code != common_err.SUCCESS { - // return nil, echo.ErrUnauthorized - // } valid, claims, err := jwt.Validate(token, func() (*ecdsa.PublicKey, error) { return external.GetPublicKey(config.CommonInfo.RuntimePath) }) if err != nil || !valid { return nil, echo.ErrUnauthorized diff --git a/service/system.go b/service/system.go index 317022f..0d98259 100644 --- a/service/system.go +++ b/service/system.go @@ -1,6 +1,7 @@ package service import ( + "encoding/json" "errors" "fmt" "io/ioutil" @@ -15,10 +16,14 @@ import ( "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" @@ -49,6 +54,7 @@ type SystemService interface { 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) @@ -57,9 +63,104 @@ type SystemService interface { 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 { + entryFilePath := filepath.Join(config.AppInfo.DBPath, "db", "entry.json") + _, err := os.Open(entryFilePath) + if os.IsNotExist(err) { + return "" + } + by, err := os.ReadFile(entryFilePath) + if err != nil { + logger.Error("read entry file error", zap.Error(err)) + return "" + } + return string(by) +} func (c *systemService) GetMacAddress() (string, error) { interfaces, err := net.Interfaces() if err != nil {