Ver Fonte

New App Store

link há 3 anos atrás
pai
commit
1d17d27c96

+ 1 - 1
UI

@@ -1 +1 @@
-Subproject commit 65d4738a607ec28f22bffb1d489dd284c360d2ce
+Subproject commit f3088b635482fd4330c3fce6bbfcd1f70ff8024a

+ 3 - 0
model/app.go

@@ -15,6 +15,7 @@ type ServerAppList struct {
 	Icon           string    `json:"icon"`
 	Icon           string    `json:"icon"`
 	ScreenshotLink Strings   `gorm:"type:json" json:"screenshot_link"`
 	ScreenshotLink Strings   `gorm:"type:json" json:"screenshot_link"`
 	Category       string    `json:"category"`
 	Category       string    `json:"category"`
+	CategoryFont   string    `json:"category_font"`
 	PortMap        string    `json:"port_map"`
 	PortMap        string    `json:"port_map"`
 	ImageVersion   string    `json:"image_version"`
 	ImageVersion   string    `json:"image_version"`
 	Tip            string    `json:"tip"`
 	Tip            string    `json:"tip"`
@@ -36,6 +37,8 @@ type ServerAppList struct {
 	Healthy        string    `json:"healthy"`
 	Healthy        string    `json:"healthy"`
 	Plugins        Strings   `json:"plugins"`
 	Plugins        Strings   `json:"plugins"`
 	Origin         string    `json:"origin"`
 	Origin         string    `json:"origin"`
+	Type           int       `json:"type"`
+	Developer      string    `json:"developer"`
 }
 }
 
 
 type Ports struct {
 type Ports struct {

+ 1 - 0
model/category.go

@@ -5,6 +5,7 @@ type ServerCategoryList struct {
 	//CreatedAt time.Time `json:"created_at"`
 	//CreatedAt time.Time `json:"created_at"`
 	//
 	//
 	//UpdatedAt time.Time `json:"updated_at"`
 	//UpdatedAt time.Time `json:"updated_at"`
+	Font  string `json:"font"`
 	Name  string `json:"name"`
 	Name  string `json:"name"`
 	Count uint   `json:"count"`
 	Count uint   `json:"count"`
 }
 }

+ 3 - 27
pkg/docker/volumes.go

@@ -3,33 +3,9 @@ package docker
 import "strings"
 import "strings"
 
 
 func GetDir(id, envName string) string {
 func GetDir(id, envName string) string {
-	var path string
 
 
-	if len(id) == 0 {
-		id = "$AppID"
+	if strings.Contains(envName, "$AppID") && len(id) > 0 {
+		return strings.ReplaceAll(envName, "$AppID", id)
 	}
 	}
-
-	switch {
-	case strings.Contains(strings.ToLower(envName), "config") || strings.Contains(strings.ToLower(envName), "photoprism/storage") || strings.Contains(strings.ToLower(envName), "config"):
-		path = "/DATA/AppData/" + id + "/"
-	case strings.Contains(strings.ToLower(envName), "media"):
-		path = "/DATA/Media/"
-	case strings.Contains(strings.ToLower(envName), "movie"):
-		path = "/DATA/Media/Movies/"
-	case strings.Contains(strings.ToLower(envName), "music"):
-		path = "/DATA/Media/Music/"
-	case strings.Contains(strings.ToLower(envName), "photoprism/originals"):
-		path = "/DATA/Gallery"
-	case strings.Contains(strings.ToLower(envName), "download"):
-		path = "/DATA/Downloads/"
-	case strings.Contains(strings.ToLower(envName), "photo") || strings.Contains(strings.ToLower(envName), "pictures"):
-		path = "/DATA/Downloads/"
-	case strings.ToLower(envName) == "/srv":
-		path = "/DATA/"
-	case strings.ToLower(envName) == "/tv":
-		path = "/DATA/Media/TV Shows"
-	default:
-		//path = "/media"
-	}
-	return path
+	return envName
 }
 }

+ 3 - 2
pkg/sqlite/db.go

@@ -2,11 +2,12 @@ package sqlite
 
 
 import (
 import (
 	"fmt"
 	"fmt"
+	"time"
+
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
 	model2 "github.com/IceWhaleTech/CasaOS/service/model"
 	model2 "github.com/IceWhaleTech/CasaOS/service/model"
 	"gorm.io/driver/sqlite"
 	"gorm.io/driver/sqlite"
 	"gorm.io/gorm"
 	"gorm.io/gorm"
-	"time"
 )
 )
 
 
 var gdb *gorm.DB
 var gdb *gorm.DB
@@ -30,7 +31,7 @@ func GetDb(projectPath string) *gorm.DB {
 		return nil
 		return nil
 	}
 	}
 	gdb = db
 	gdb = db
-	err = db.AutoMigrate(&model2.TaskDBModel{}, &model2.AppNotify{}, &model2.AppListDBModel{})
+	err = db.AutoMigrate(&model2.TaskDBModel{}, &model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{})
 	if err != nil {
 	if err != nil {
 		fmt.Println("检查和创建数据库出错", err)
 		fmt.Println("检查和创建数据库出错", err)
 	}
 	}

+ 1 - 0
pkg/utils/command/command_helper.go

@@ -75,6 +75,7 @@ func ExecResultStr(cmdStr string) string {
 func ExecLSBLK() []byte {
 func ExecLSBLK() []byte {
 	output, err := exec.Command("lsblk", "-O", "-J", "-b").Output()
 	output, err := exec.Command("lsblk", "-O", "-J", "-b").Output()
 	if err != nil {
 	if err != nil {
+		fmt.Println("lsblk", err)
 		return nil
 		return nil
 	}
 	}
 	return output
 	return output

+ 9 - 2
pkg/utils/env_helper/env.go

@@ -2,18 +2,25 @@ package env_helper
 
 
 import "strings"
 import "strings"
 
 
-func ReplaceDefaultENV(key string) string {
+func ReplaceDefaultENV(key, tz string) string {
 	temp := ""
 	temp := ""
 	switch key {
 	switch key {
 	case "$DefaultPassword":
 	case "$DefaultPassword":
 		temp = "casaos"
 		temp = "casaos"
 	case "$DefaultUserName":
 	case "$DefaultUserName":
 		temp = "admin"
 		temp = "admin"
+
+	case "$PUID":
+		temp = "1000"
+	case "$PGID":
+		temp = "1000"
+	case "$TZ":
+		temp = tz
 	}
 	}
 	return temp
 	return temp
 }
 }
 
 
 //replace env default setting
 //replace env default setting
 func ReplaceStringDefaultENV(str string) string {
 func ReplaceStringDefaultENV(str string) string {
-	return strings.ReplaceAll(strings.ReplaceAll(str, "$DefaultPassword", ReplaceDefaultENV("$DefaultPassword")), "$DefaultUserName", ReplaceDefaultENV("$DefaultUserName"))
+	return strings.ReplaceAll(strings.ReplaceAll(str, "$DefaultPassword", ReplaceDefaultENV("$DefaultPassword", "")), "$DefaultUserName", ReplaceDefaultENV("$DefaultUserName", ""))
 }
 }

+ 25 - 7
route/init.go

@@ -22,6 +22,8 @@ import (
 func InitFunction() {
 func InitFunction() {
 	go checkSystemApp()
 	go checkSystemApp()
 	Update2_3()
 	Update2_3()
+	CheckSerialDiskMount()
+
 }
 }
 
 
 var syncIsExistence = false
 var syncIsExistence = false
@@ -72,9 +74,6 @@ func installSyncthing(appId string) {
 		appInfo.Tip = env_helper.ReplaceStringDefaultENV(appInfo.Tip)
 		appInfo.Tip = env_helper.ReplaceStringDefaultENV(appInfo.Tip)
 	}
 	}
 
 
-	for i := 0; i < len(appInfo.Volumes); i++ {
-		appInfo.Volumes[i].Path = docker.GetDir("", appInfo.Volumes[i].ContainerPath)
-	}
 	appInfo.MaxMemory = service.MyService.ZiMa().GetMemInfo().Total >> 20
 	appInfo.MaxMemory = service.MyService.ZiMa().GetMemInfo().Total >> 20
 
 
 	id := uuid.NewV4().String()
 	id := uuid.NewV4().String()
@@ -171,7 +170,7 @@ func checkSystemApp() {
 			path := ""
 			path := ""
 			for _, i := range paths {
 			for _, i := range paths {
 				if i.ContainerPath == "/config" {
 				if i.ContainerPath == "/config" {
-					path = docker.GetDir(v.CustomId, i.ContainerPath) + "config.xml"
+					path = docker.GetDir(v.CustomId, i.Path) + "config.xml"
 					for i := 0; i < 10; i++ {
 					for i := 0; i < 10; i++ {
 						if file.CheckNotExist(path) {
 						if file.CheckNotExist(path) {
 							time.Sleep(1 * time.Second)
 							time.Sleep(1 * time.Second)
@@ -189,12 +188,31 @@ func checkSystemApp() {
 		}
 		}
 	}
 	}
 	if !syncIsExistence {
 	if !syncIsExistence {
-		installSyncthing("44")
+		installSyncthing("74")
 	}
 	}
 }
 }
 func CheckSerialDiskMount() {
 func CheckSerialDiskMount() {
-	// 检查挂载点重新挂载
-	// 检查新硬盘是否有多个分区,如有多个分区需提示
+	// check mount point
+	dbList := service.MyService.Disk().GetSerialAll()
+
+	list := service.MyService.Disk().LSBLK()
+	mountPoint := make(map[string]string, len(dbList))
+
+	for _, v := range list {
+		if v.Children != nil {
+			for _, h := range v.Children {
+				mountPoint[h.MountPoint] = "1"
+			}
+		}
+	}
+
+	//remount
+	for _, item := range dbList {
+		if _, ok := mountPoint[item.MountPoint]; !ok {
+			service.MyService.Disk().MountDisk(item.Path, item.MountPoint)
+		}
+	}
+
 }
 }
 func Update2_3() {
 func Update2_3() {
 	command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/assist.sh")
 	command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/assist.sh")

+ 6 - 4
route/route.go

@@ -70,8 +70,7 @@ func InitRouter() *gin.Engine {
 
 
 			//获取网络信息
 			//获取网络信息
 			v1ZiMaGroup.GET("/getnetinfo", v1.NetInfo)
 			v1ZiMaGroup.GET("/getnetinfo", v1.NetInfo)
-			//获取网络信息
-			v1ZiMaGroup.GET("/getinfo", v1.Info)
+
 			//获取系统信息
 			//获取系统信息
 			v1ZiMaGroup.GET("/sysinfo", v1.SysInfo)
 			v1ZiMaGroup.GET("/sysinfo", v1.SysInfo)
 		}
 		}
@@ -197,6 +196,7 @@ func InitRouter() *gin.Engine {
 			v1SysGroup.GET("/port", v1.GetCasaOSPort)
 			v1SysGroup.GET("/port", v1.GetCasaOSPort)
 			v1SysGroup.PUT("/port", v1.PutCasaOSPort)
 			v1SysGroup.PUT("/port", v1.PutCasaOSPort)
 			v1SysGroup.POST("/kill", v1.PostKillCasaOS)
 			v1SysGroup.POST("/kill", v1.PostKillCasaOS)
+			v1SysGroup.GET("/info", v1.Info)
 		}
 		}
 		v1FileGroup := v1Group.Group("/file")
 		v1FileGroup := v1Group.Group("/file")
 		v1FileGroup.Use()
 		v1FileGroup.Use()
@@ -211,11 +211,13 @@ func InitRouter() *gin.Engine {
 			v1FileGroup.POST("/create", v1.PostCreateFile)
 			v1FileGroup.POST("/create", v1.PostCreateFile)
 
 
 			v1FileGroup.GET("/download", v1.GetDownloadFile)
 			v1FileGroup.GET("/download", v1.GetDownloadFile)
+			v1FileGroup.PUT("/move", v1.PutFileMove)
 			//v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
 			//v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
 		}
 		}
 		v1DiskGroup := v1Group.Group("/disk")
 		v1DiskGroup := v1Group.Group("/disk")
 		v1DiskGroup.Use()
 		v1DiskGroup.Use()
 		{
 		{
+			v1DiskGroup.GET("/check", v1.GetDiskCheck)
 			//获取磁盘列表
 			//获取磁盘列表
 			v1DiskGroup.GET("/list", v1.GetPlugInDisk)
 			v1DiskGroup.GET("/list", v1.GetPlugInDisk)
 
 
@@ -238,8 +240,8 @@ func InitRouter() *gin.Engine {
 			v1DiskGroup.POST("/mount", v1.PostMountDisk)
 			v1DiskGroup.POST("/mount", v1.PostMountDisk)
 
 
 			//umount SATA disk
 			//umount SATA disk
-			v1DiskGroup.POST("/umount", v1.DeleteUmountDisk)
-
+			v1DiskGroup.POST("/umount", v1.PostDiskUmount)
+			v1DiskGroup.DELETE("/remove/:id", v1.DeleteDisk)
 		}
 		}
 		v1ShareGroup := v1Group.Group("/share")
 		v1ShareGroup := v1Group.Group("/share")
 		v1ShareGroup.Use()
 		v1ShareGroup.Use()

+ 29 - 14
route/v1/app.go

@@ -7,8 +7,6 @@ import (
 	"strconv"
 	"strconv"
 
 
 	"github.com/IceWhaleTech/CasaOS/model"
 	"github.com/IceWhaleTech/CasaOS/model"
-	"github.com/IceWhaleTech/CasaOS/pkg/docker"
-	"github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
 	oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
 	oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
 	port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
 	port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
@@ -33,20 +31,33 @@ func AppList(c *gin.Context) {
 	//service.MyService.Docker().DockerContainerCommit("test2")
 	//service.MyService.Docker().DockerContainerCommit("test2")
 
 
 	index := c.DefaultQuery("index", "1")
 	index := c.DefaultQuery("index", "1")
-	size := c.DefaultQuery("size", "10")
+	size := c.DefaultQuery("size", "10000")
 	t := c.DefaultQuery("type", "rank")
 	t := c.DefaultQuery("type", "rank")
 	categoryId := c.DefaultQuery("category_id", "0")
 	categoryId := c.DefaultQuery("category_id", "0")
 	key := c.DefaultQuery("key", "")
 	key := c.DefaultQuery("key", "")
-	list, count := service.MyService.OAPI().GetServerList(index, size, t, categoryId, key)
+	recommend, list, community := service.MyService.OAPI().GetServerList(index, size, t, categoryId, key)
+	for i := 0; i < len(recommend); i++ {
+		ct, _ := service.MyService.Docker().DockerListByImage(recommend[i].Image, recommend[i].ImageVersion)
+		if ct != nil {
+			list[i].State = ct.State
+		}
+	}
 	for i := 0; i < len(list); i++ {
 	for i := 0; i < len(list); i++ {
 		ct, _ := service.MyService.Docker().DockerListByImage(list[i].Image, list[i].ImageVersion)
 		ct, _ := service.MyService.Docker().DockerListByImage(list[i].Image, list[i].ImageVersion)
 		if ct != nil {
 		if ct != nil {
 			list[i].State = ct.State
 			list[i].State = ct.State
 		}
 		}
 	}
 	}
-	data := make(map[string]interface{}, 2)
-	data["count"] = count
-	data["items"] = list
+	for i := 0; i < len(community); i++ {
+		ct, _ := service.MyService.Docker().DockerListByImage(community[i].Image, community[i].ImageVersion)
+		if ct != nil {
+			list[i].State = ct.State
+		}
+	}
+	data := make(map[string]interface{}, 3)
+	data["recommend"] = recommend
+	data["list"] = list
+	data["community"] = community
 
 
 	c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
 	c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
 }
 }
@@ -147,6 +158,13 @@ func AppInfo(c *gin.Context) {
 				info.PortMap = info.Ports[i].CommendPort
 				info.PortMap = info.Ports[i].CommendPort
 			}
 			}
 		}
 		}
+	} else {
+		for i := 0; i < len(info.Ports); i++ {
+			if info.Ports[i].Type == 0 {
+				info.PortMap = info.Ports[i].ContainerPort
+				break
+			}
+		}
 	}
 	}
 
 
 	for i := 0; i < len(info.Devices); i++ {
 	for i := 0; i < len(info.Devices); i++ {
@@ -154,13 +172,10 @@ func AppInfo(c *gin.Context) {
 			info.Devices[i].Path = info.Devices[i].ContainerPath
 			info.Devices[i].Path = info.Devices[i].ContainerPath
 		}
 		}
 	}
 	}
-	if len(info.Tip) > 0 {
-		info.Tip = env_helper.ReplaceStringDefaultENV(info.Tip)
-	}
+	// if len(info.Tip) > 0 {
+	// 	info.Tip = env_helper.ReplaceStringDefaultENV(info.Tip)
+	// }
 
 
-	for i := 0; i < len(info.Volumes); i++ {
-		info.Volumes[i].Path = docker.GetDir("", info.Volumes[i].ContainerPath)
-	}
 	// portOrder := func(c1, c2 *model.Ports) bool {
 	// portOrder := func(c1, c2 *model.Ports) bool {
 	// 	return c1.Type < c2.Type
 	// 	return c1.Type < c2.Type
 	// }
 	// }
@@ -207,7 +222,7 @@ func CategoryList(c *gin.Context) {
 	}
 	}
 
 
 	rear := append([]model.ServerCategoryList{}, list[0:]...)
 	rear := append([]model.ServerCategoryList{}, list[0:]...)
-	list = append(list[:0], model.ServerCategoryList{Count: count, Name: "All"})
+	list = append(list[:0], model.ServerCategoryList{Count: count, Name: "All", Font: "apps"})
 	list = append(list, rear...)
 	list = append(list, rear...)
 	c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
 	c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
 }
 }

+ 95 - 45
route/v1/disk.go

@@ -2,10 +2,12 @@ package v1
 
 
 import (
 import (
 	"net/http"
 	"net/http"
+	"strconv"
 
 
 	"github.com/IceWhaleTech/CasaOS/model"
 	"github.com/IceWhaleTech/CasaOS/model"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
 	"github.com/IceWhaleTech/CasaOS/service"
 	"github.com/IceWhaleTech/CasaOS/service"
+	model2 "github.com/IceWhaleTech/CasaOS/service/model"
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 	"github.com/shirou/gopsutil/v3/disk"
 	"github.com/shirou/gopsutil/v3/disk"
 )
 )
@@ -19,44 +21,9 @@ import (
 // @Router /disk/list [get]
 // @Router /disk/list [get]
 func GetPlugInDisk(c *gin.Context) {
 func GetPlugInDisk(c *gin.Context) {
 
 
-	//ls := service.MyService.Disk().GetPlugInDisk()
-	//fmt.Println(ls)
-	//dd, _ := disk.Partitions(true)
-	//fmt.Println(dd)
-	//
-	//dir, err := ioutil.ReadDir("/sys/block")
-	//if err != nil {
-	//	panic(err)
-	//}
-	//
-	//files := make([]string, 0)
-	//
-	////fmt.Println(regexp.MatchString("sd[a-z]*[0-9]", "sda"))
-	//
-	//for _, f := range dir {
-	//	if match, _ := regexp.MatchString("sd[a-z]", f.Name()); match {
-	//		files = append(files, f.Name())
-	//	}
-	//}
-	//fmt.Println(files)
-	//filess := make([]string, 0)
-	//for _, file := range files {
-	//	dirs, _ := ioutil.ReadDir("/sys/block/" + file)
-	//
-	//	for _, f := range dirs {
-	//		if match, _ := regexp.MatchString("sd[a-z]*[0-9]", f.Name()); match {
-	//			filess = append(filess, f.Name())
-	//		}
-	//	}
-	//}
-	//fmt.Println(filess)
-	//
-	//for _, s := range filess {
-	//	fmt.Println(disk.Usage("/dev/" + s))
-	//}
+	list := service.MyService.Disk().LSBLK()
 
 
-	lst := service.MyService.Disk().LSBLK()
-	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: lst})
+	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: list})
 }
 }
 
 
 // @Summary get disk list
 // @Summary get disk list
@@ -98,7 +65,7 @@ func GetDiskInfo(c *gin.Context) {
 // @Accept multipart/form-data
 // @Accept multipart/form-data
 // @Tags disk
 // @Tags disk
 // @Security ApiKeyAuth
 // @Security ApiKeyAuth
-// @Param  path formData string true "磁盘路径 例如/dev/sda1"
+// @Param  path formData string true "for example  /dev/sda1"
 // @Success 200 {string} string "ok"
 // @Success 200 {string} string "ok"
 // @Router /disk/format [post]
 // @Router /disk/format [post]
 func FormatDisk(c *gin.Context) {
 func FormatDisk(c *gin.Context) {
@@ -108,8 +75,8 @@ func FormatDisk(c *gin.Context) {
 
 
 	if len(path) == 0 || len(t) == 0 {
 	if len(path) == 0 || len(t) == 0 {
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
+		return
 	}
 	}
-	//格式化磁盘
 	service.MyService.Disk().FormatDisk(path, t)
 	service.MyService.Disk().FormatDisk(path, t)
 
 
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
@@ -168,23 +135,106 @@ func AddPartition(c *gin.Context) {
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
 }
 }
 
 
+// @Summary add mount point
+// @Produce  application/json
+// @Accept multipart/form-data
+// @Tags disk
+// @Security ApiKeyAuth
+// @Param  path formData string true "for example: /dev/sda1"
+// @Param  serial formData string true "disk id"
+// @Success 200 {string} string "ok"
+// @Router /disk/mount [post]
 func PostMountDisk(c *gin.Context) {
 func PostMountDisk(c *gin.Context) {
 	// for example: path=/dev/sda1
 	// for example: path=/dev/sda1
 	path := c.PostForm("path")
 	path := c.PostForm("path")
-	//执行挂载目录
-	service.MyService.Disk().MountDisk(path, "volume")
-	//添加到数据库
+	serial := c.PostForm("serial")
+
+	mountPath := "/mnt/volume"
+	var list = service.MyService.Disk().GetSerialAll()
+	var pathMapList = make(map[string]string, len(list))
+	for _, v := range list {
+		pathMapList[v.MountPoint] = "1"
+	}
+
+	for i := 0; i < len(list)+1; i++ {
+		if _, ok := pathMapList[mountPath+strconv.Itoa(i)]; !ok {
+			mountPath = mountPath + strconv.Itoa(i)
+			break
+		}
+	}
 
 
+	//mount dir
+	service.MyService.Disk().MountDisk(path, mountPath)
+	//save to data
+	m := model2.SerialDisk{}
+	m.MountPoint = mountPath
+	m.Path = path
+	m.Serial = serial
+	m.State = 0
+	service.MyService.Disk().SaveMountPoint(m)
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
 }
 }
 
 
-func DeleteUmountDisk(c *gin.Context) {
+// @Summary remove mount point
+// @Produce  application/json
+// @Accept multipart/form-data
+// @Tags disk
+// @Security ApiKeyAuth
+// @Param  path formData string true "for example: /dev/sda1"
+// @Param  mount_point formData string true "for example: /mnt/volume1"
+// @Success 200 {string} string "ok"
+// @Router /disk/umount [post]
+func PostDiskUmount(c *gin.Context) {
 
 
-	// for example: path=/dev/sda1
+	//
 	path := c.PostForm("path")
 	path := c.PostForm("path")
+	mountPoint := c.PostForm("mount_point")
 	service.MyService.Disk().UmountPointAndRemoveDir(path)
 	service.MyService.Disk().UmountPointAndRemoveDir(path)
 
 
-	//删除数据库记录
+	//delete data
+	service.MyService.Disk().DeleteMountPoint(path, mountPoint)
+	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
+}
+
+// @Summary confirm delete disk
+// @Produce  application/json
+// @Accept application/json
+// @Tags disk
+// @Security ApiKeyAuth
+// @Param  id path string true "id"
+// @Success 200 {string} string "ok"
+// @Router /disk/remove/{id} [delete]
+func DeleteDisk(c *gin.Context) {
+	id := c.Param("id")
+	service.MyService.Disk().DeleteMount(id)
+	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
+}
+
+// @Summary check mount point
+// @Produce  application/json
+// @Accept application/json
+// @Tags disk
+// @Security ApiKeyAuth
+// @Success 200 {string} string "ok"
+// @Router /disk/init [get]
+func GetDiskCheck(c *gin.Context) {
+
+	dbList := service.MyService.Disk().GetSerialAll()
+	list := service.MyService.Disk().LSBLK()
+
+	mapList := make(map[string]string)
+
+	for _, v := range list {
+		mapList[v.Serial] = "1"
+	}
+
+	for _, v := range dbList {
+		if _, ok := mapList[v.Serial]; !ok {
+			//disk undefind
+			c.JSON(http.StatusOK, model.Result{Success: oasis_err.ERROR, Message: oasis_err.GetMsg(oasis_err.ERROR), Data: "disk undefind"})
+			return
+		}
+	}
 
 
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
 }
 }

+ 20 - 10
route/v1/docker.go

@@ -218,14 +218,24 @@ func InstallApp(c *gin.Context) {
 		}
 		}
 
 
 	}
 	}
+	if m.Origin == "custom" {
+		for _, device := range m.Devices {
+			if file.CheckNotExist(device.Path) {
+				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DEVICE_NOT_EXIST, Message: device.Path + "," + oasis_err2.GetMsg(oasis_err2.DEVICE_NOT_EXIST)})
+				return
+			}
 
 
-	for _, device := range m.Devices {
-		if file.CheckNotExist(device.Path) {
-			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DEVICE_NOT_EXIST, Message: device.Path + "," + oasis_err2.GetMsg(oasis_err2.DEVICE_NOT_EXIST)})
-			return
 		}
 		}
-
+	} else {
+		dev := []model.PathMap{}
+		for _, device := range dev {
+			if !file.CheckNotExist(device.Path) {
+				dev = append(dev, device)
+			}
+		}
+		m.Devices = dev
 	}
 	}
+
 	//restart := c.PostForm("restart") //always 总是重启,   unless-stopped 除非用户手动停止容器,否则总是重新启动,    on-failure:仅当容器退出代码非零时重新启动
 	//restart := c.PostForm("restart") //always 总是重启,   unless-stopped 除非用户手动停止容器,否则总是重新启动,    on-failure:仅当容器退出代码非零时重新启动
 	//if len(restart) > 0 {
 	//if len(restart) > 0 {
 	//
 	//
@@ -421,11 +431,11 @@ func InstallApp(c *gin.Context) {
 		rely := model.MapStrings{}
 		rely := model.MapStrings{}
 
 
 		copier.Copy(&rely, &relyMap)
 		copier.Copy(&rely, &relyMap)
-		if m.Origin != "custom" {
-			for i := 0; i < len(m.Volumes); i++ {
-				m.Volumes[i].Path = docker.GetDir(id, m.Volumes[i].ContainerPath)
-			}
-		}
+		// if m.Origin != "custom" {
+		// 	for i := 0; i < len(m.Volumes); i++ {
+		// 		m.Volumes[i].Path = docker.GetDir(id, m.Volumes[i].Path)
+		// 	}
+		// }
 
 
 		portsStr, _ := json2.Marshal(m.Ports)
 		portsStr, _ := json2.Marshal(m.Ports)
 		envsStr, _ := json2.Marshal(m.Envs)
 		envsStr, _ := json2.Marshal(m.Envs)

+ 63 - 0
route/v1/file.go

@@ -9,6 +9,8 @@ import (
 	"net/http"
 	"net/http"
 	"os"
 	"os"
 	"path"
 	"path"
+	"path/filepath"
+	"time"
 
 
 	"github.com/IceWhaleTech/CasaOS/model"
 	"github.com/IceWhaleTech/CasaOS/model"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
@@ -256,3 +258,64 @@ func PostFileUpload(c *gin.Context) {
 	io.Copy(out, file)
 	io.Copy(out, file)
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
 }
 }
+
+func PutFileMove(c *gin.Context) {
+	from := "/Users/liangjianli/go/CasaOS"
+	to := "/Users/liangjianli/go/CasaOS/test"
+	//t := 1 //是否覆盖
+
+	//方法体
+	stopCh := make(chan int)
+	f, err := os.Stat(from)
+	if err != nil {
+		//未拿到文件信息
+		fmt.Println("stat", err)
+	}
+	//未创建新的文件夹
+	if f.IsDir() {
+		//from 是文件夹,定义to也是文件夹
+		if list, err := ioutil.ReadDir(from); err == nil {
+			for _, v := range list {
+				time.Sleep(time.Second)
+				if err = Copy(stopCh, filepath.Join(from, v.Name()), filepath.Join(to, v.Name())); err != nil {
+					fmt.Printf("copy %s ,err %d", v.Name(), err)
+				}
+			}
+		}
+	} else {
+		p := filepath.Dir(to)
+		if _, err = os.Stat(p); err != nil {
+			if err = os.MkdirAll(p, 0777); err != nil {
+				fmt.Println("mkdir", err)
+			}
+		}
+	}
+
+	file, err := os.Open(from)
+
+	if err != nil {
+		fmt.Println("open file error ", err)
+	}
+	defer file.Close()
+	out, err := os.Create(to)
+	if err != nil {
+		fmt.Println("create to file err", err)
+	}
+	defer out.Close()
+	io.Copy(out, file)
+	time.Sleep(time.Second * 4)
+	close(stopCh)
+}
+func Copy(stop chan int, from, to string) error {
+
+	for {
+		select {
+		case <-stop:
+			return nil
+		default:
+			fmt.Println(from)
+
+		}
+	}
+	return nil
+}

+ 46 - 1
route/v1/system.go

@@ -6,11 +6,14 @@ import (
 	"net/http"
 	"net/http"
 	"os"
 	"os"
 	"strconv"
 	"strconv"
+	"strings"
 	"time"
 	"time"
+	"unsafe"
 
 
 	"github.com/IceWhaleTech/CasaOS/model"
 	"github.com/IceWhaleTech/CasaOS/model"
 	"github.com/IceWhaleTech/CasaOS/pkg/config"
 	"github.com/IceWhaleTech/CasaOS/pkg/config"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
+	oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
 	port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
 	port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/version"
 	"github.com/IceWhaleTech/CasaOS/pkg/utils/version"
 	"github.com/IceWhaleTech/CasaOS/service"
 	"github.com/IceWhaleTech/CasaOS/service"
@@ -127,8 +130,9 @@ func GetWidgetConfig(c *gin.Context) {
 func PostSetWidgetConfig(c *gin.Context) {
 func PostSetWidgetConfig(c *gin.Context) {
 	buf := make([]byte, 1024)
 	buf := make([]byte, 1024)
 	n, _ := c.Request.Body.Read(buf)
 	n, _ := c.Request.Body.Read(buf)
-
+	fmt.Println("错误", strconv.Itoa(n))
 	service.MyService.System().UpSystemConfig("", string(buf[0:n]))
 	service.MyService.System().UpSystemConfig("", string(buf[0:n]))
+	fmt.Println("错误1", string(buf[0:n]))
 	c.JSON(http.StatusOK,
 	c.JSON(http.StatusOK,
 		model.Result{
 		model.Result{
 			Success: oasis_err.SUCCESS,
 			Success: oasis_err.SUCCESS,
@@ -221,3 +225,44 @@ func GetGuideCheck(c *gin.Context) {
 func PostKillCasaOS(c *gin.Context) {
 func PostKillCasaOS(c *gin.Context) {
 	os.Exit(0)
 	os.Exit(0)
 }
 }
+
+// @Summary system info
+// @Produce  application/json
+// @Accept application/json
+// @Tags sys
+// @Security ApiKeyAuth
+// @Success 200 {string} string "ok"
+// @Router /sys/info [get]
+func Info(c *gin.Context) {
+	var data = make(map[string]interface{}, 5)
+
+	list := service.MyService.Disk().LSBLK()
+	data["disk"] = list
+	cpu := service.MyService.ZiMa().GetCpuPercent()
+	num := service.MyService.ZiMa().GetCpuCoreNum()
+	cpuData := make(map[string]interface{})
+	cpuData["percent"] = cpu
+	cpuData["num"] = num
+	data["cpu"] = cpuData
+	data["mem"] = service.MyService.ZiMa().GetMemInfo()
+
+	//拼装网络信息
+	netList := service.MyService.ZiMa().GetNetInfo()
+	newNet := []model.IOCountersStat{}
+	nets := service.MyService.ZiMa().GetNet(true)
+	for _, n := range netList {
+		for _, netCardName := range nets {
+			if n.Name == netCardName {
+				item := *(*model.IOCountersStat)(unsafe.Pointer(&n))
+				item.State = strings.TrimSpace(service.MyService.ZiMa().GetNetState(n.Name))
+				item.DateTime = time.Now()
+				newNet = append(newNet, item)
+				break
+			}
+		}
+	}
+
+	data["net"] = newNet
+
+	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
+}

+ 5 - 47
route/v1/zima_info.go

@@ -1,15 +1,15 @@
 package v1
 package v1
 
 
 import (
 import (
-	"github.com/IceWhaleTech/CasaOS/model"
-	oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
-	"github.com/IceWhaleTech/CasaOS/service"
-	"github.com/gin-gonic/gin"
-	"github.com/shirou/gopsutil/v3/disk"
 	"net/http"
 	"net/http"
 	"strings"
 	"strings"
 	"time"
 	"time"
 	"unsafe"
 	"unsafe"
+
+	"github.com/IceWhaleTech/CasaOS/model"
+	oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
+	"github.com/IceWhaleTech/CasaOS/service"
+	"github.com/gin-gonic/gin"
 )
 )
 
 
 // @Summary 获取cpu信息
 // @Summary 获取cpu信息
@@ -83,48 +83,6 @@ func NetInfo(c *gin.Context) {
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: newNet})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: newNet})
 }
 }
 
 
-// @Summary 获取信息
-// @Produce  application/json
-// @Accept application/json
-// @Tags zima
-// @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /zima/getinfo [get]
-func Info(c *gin.Context) {
-	var data = make(map[string]interface{}, 4)
-
-	var diskArr []*disk.UsageStat
-	diskArr = append(diskArr, service.MyService.ZiMa().GetDiskInfo())
-	data["disk"] = diskArr
-	cpu := service.MyService.ZiMa().GetCpuPercent()
-	num := service.MyService.ZiMa().GetCpuCoreNum()
-	cpuData := make(map[string]interface{})
-	cpuData["percent"] = cpu
-	cpuData["num"] = num
-	data["cpu"] = cpuData
-	data["mem"] = service.MyService.ZiMa().GetMemInfo()
-
-	//拼装网络信息
-	netList := service.MyService.ZiMa().GetNetInfo()
-	newNet := []model.IOCountersStat{}
-	nets := service.MyService.ZiMa().GetNet(true)
-	for _, n := range netList {
-		for _, netCardName := range nets {
-			if n.Name == netCardName {
-				item := *(*model.IOCountersStat)(unsafe.Pointer(&n))
-				item.State = strings.TrimSpace(service.MyService.ZiMa().GetNetState(n.Name))
-				item.DateTime = time.Now()
-				newNet = append(newNet, item)
-				break
-			}
-		}
-	}
-
-	data["net"] = newNet
-
-	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
-}
-
 // @Summary 获取信息系统信息
 // @Summary 获取信息系统信息
 // @Produce  application/json
 // @Produce  application/json
 // @Accept application/json
 // @Accept application/json

+ 13 - 13
service/app.go

@@ -46,7 +46,7 @@ type appStruct struct {
 //获取我的应用列表
 //获取我的应用列表
 func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppList {
 func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppList {
 	//获取docker应用
 	//获取docker应用
-	cli, err := client2.NewClientWithOpts(client2.FromEnv)
+	cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5))
 	if err != nil {
 	if err != nil {
 		a.log.Error("初始化client失败", "app.getmylist", "line:36", err)
 		a.log.Error("初始化client失败", "app.getmylist", "line:36", err)
 	}
 	}
@@ -81,13 +81,13 @@ func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppLis
 				m.Label = m.Title
 				m.Label = m.Title
 			}
 			}
 
 
-			info, err := cli.ContainerInspect(context.Background(), container.ID)
-			var tm string
-			if err != nil {
-				tm = time.Now().String()
-			} else {
-				tm = info.State.StartedAt
-			}
+			// info, err := cli.ContainerInspect(context.Background(), container.ID)
+			// var tm string
+			// if err != nil {
+			// 	tm = time.Now().String()
+			// } else {
+			// 	tm = info.State.StartedAt
+			//}
 			list = append(list, model2.MyAppList{
 			list = append(list, model2.MyAppList{
 				Name:     m.Label,
 				Name:     m.Label,
 				Icon:     m.Icon,
 				Icon:     m.Icon,
@@ -95,9 +95,9 @@ func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppLis
 				CustomId: strings.ReplaceAll(container.Names[0], "/", ""),
 				CustomId: strings.ReplaceAll(container.Names[0], "/", ""),
 				Port:     m.PortMap,
 				Port:     m.PortMap,
 				Index:    m.Index,
 				Index:    m.Index,
-				UpTime:   tm,
-				Image:    m.Image,
-				Slogan:   m.Slogan,
+				//UpTime:   tm,
+				Image:  m.Image,
+				Slogan: m.Slogan,
 				//Rely:     m.Rely,
 				//Rely:     m.Rely,
 			})
 			})
 		}
 		}
@@ -120,7 +120,7 @@ func (a *appStruct) GetSystemAppList() *[]model2.MyAppList {
 	fts.Add("label", "origin=system")
 	fts.Add("label", "origin=system")
 	containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts})
 	containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts})
 	if err != nil {
 	if err != nil {
-		a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
+		a.log.Error("获取docker容器失败", "app.sys", "line:123", err)
 	}
 	}
 
 
 	//获取本地数据库应用
 	//获取本地数据库应用
@@ -179,7 +179,7 @@ func (a *appStruct) GetContainerInfo(name string) (types.Container, error) {
 	filters.Add("name", name)
 	filters.Add("name", name)
 	containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters})
 	containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters})
 	if err != nil {
 	if err != nil {
-		a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
+		a.log.Error("获取docker容器失败", "app.getcontainerinfo", "line:182", err)
 	}
 	}
 
 
 	if len(containers) > 0 {
 	if len(containers) > 0 {

+ 25 - 10
service/casa.go

@@ -2,6 +2,7 @@ package service
 
 
 import (
 import (
 	json2 "encoding/json"
 	json2 "encoding/json"
+	"fmt"
 	"strconv"
 	"strconv"
 
 
 	"github.com/IceWhaleTech/CasaOS/model"
 	"github.com/IceWhaleTech/CasaOS/model"
@@ -12,7 +13,7 @@ import (
 )
 )
 
 
 type CasaService interface {
 type CasaService interface {
-	GetServerList(index, size, tp, categoryId, key string) ([]model.ServerAppList, int64)
+	GetServerList(index, size, tp, categoryId, key string) (recommend, list, community []model.ServerAppList)
 	GetServerCategoryList() []model.ServerCategoryList
 	GetServerCategoryList() []model.ServerCategoryList
 	GetTaskList(size int) []model2.TaskDBModel
 	GetTaskList(size int) []model2.TaskDBModel
 	GetServerAppInfo(id string) model.ServerAppList
 	GetServerAppInfo(id string) model.ServerAppList
@@ -44,20 +45,34 @@ func (o *casaService) GetTaskList(size int) []model2.TaskDBModel {
 	return list
 	return list
 }
 }
 
 
-func (o *casaService) GetServerList(index, size, tp, categoryId, key string) ([]model.ServerAppList, int64) {
+func (o *casaService) GetServerList(index, size, tp, categoryId, key string) (recommend, list, community []model.ServerAppList) {
+
+	keyName := fmt.Sprintf("list_%s_%s_%s_%s", index, size, tp, categoryId)
+
+	if result, ok := Cache.Get(keyName); ok {
+		res, ok := result.(string)
+		if ok {
+			json2.Unmarshal([]byte(gjson.Get(res, "data.list").String()), &list)
+			json2.Unmarshal([]byte(gjson.Get(res, "data.recommend").String()), &recommend)
+			json2.Unmarshal([]byte(gjson.Get(res, "data.community").String()), &community)
+			return
+		}
+	}
 
 
 	head := make(map[string]string)
 	head := make(map[string]string)
 
 
 	head["Authorization"] = GetToken()
 	head["Authorization"] = GetToken()
 
 
-	listS := httper2.Get(config.ServerInfo.ServerApi+"/v1/app/list?index="+index+"&size="+size+"&type="+tp+"&category_id="+categoryId+"&key="+key, head)
+	listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/newlist?index="+index+"&size="+size+"&rank="+tp+"&category_id="+categoryId+"&key="+key, head)
 
 
-	list := []model.ServerAppList{}
+	json2.Unmarshal([]byte(gjson.Get(listS, "data.list").String()), &list)
+	json2.Unmarshal([]byte(gjson.Get(listS, "data.recommend").String()), &recommend)
+	json2.Unmarshal([]byte(gjson.Get(listS, "data.community").String()), &community)
 
 
-	count := gjson.Get(listS, "data.count").Int()
-	json2.Unmarshal([]byte(gjson.Get(listS, "data.items").String()), &list)
-
-	return list, count
+	if len(list) > 0 {
+		Cache.SetDefault(keyName, listS)
+	}
+	return
 }
 }
 
 
 func (o *casaService) GetServerCategoryList() []model.ServerCategoryList {
 func (o *casaService) GetServerCategoryList() []model.ServerCategoryList {
@@ -65,7 +80,7 @@ func (o *casaService) GetServerCategoryList() []model.ServerCategoryList {
 	head := make(map[string]string)
 	head := make(map[string]string)
 	head["Authorization"] = GetToken()
 	head["Authorization"] = GetToken()
 
 
-	listS := httper2.Get(config.ServerInfo.ServerApi+"/v1/app/category", head)
+	listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/category", head)
 
 
 	list := []model.ServerCategoryList{}
 	list := []model.ServerCategoryList{}
 
 
@@ -79,7 +94,7 @@ func (o *casaService) GetServerAppInfo(id string) model.ServerAppList {
 
 
 	head["Authorization"] = GetToken()
 	head["Authorization"] = GetToken()
 
 
-	infoS := httper2.Get(config.ServerInfo.ServerApi+"/v1/app/info/"+id, head)
+	infoS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/info/"+id, head)
 
 
 	info := model.ServerAppList{}
 	info := model.ServerAppList{}
 	json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
 	json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)

+ 37 - 8
service/disk.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"fmt"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
+	"time"
 
 
 	"github.com/IceWhaleTech/CasaOS/model"
 	"github.com/IceWhaleTech/CasaOS/model"
 	"github.com/IceWhaleTech/CasaOS/pkg/config"
 	"github.com/IceWhaleTech/CasaOS/pkg/config"
@@ -26,7 +27,10 @@ type DiskService interface {
 	AddPartition(path string) string
 	AddPartition(path string) string
 	GetDiskInfoByPath(path string) *disk.UsageStat
 	GetDiskInfoByPath(path string) *disk.UsageStat
 	MountDisk(path, volume string)
 	MountDisk(path, volume string)
-	SerialAll(mountPoint string) *[]model2.SerialDisk
+	GetSerialAll() []model2.SerialDisk
+	SaveMountPoint(m model2.SerialDisk)
+	DeleteMountPoint(path, mountPoint string)
+	DeleteMount(id string)
 }
 }
 type diskService struct {
 type diskService struct {
 	log loger2.OLog
 	log loger2.OLog
@@ -86,9 +90,21 @@ func (d *diskService) GetDiskInfoByPath(path string) *disk.UsageStat {
 
 
 //get disk details
 //get disk details
 func (d *diskService) LSBLK() []model.LSBLKModel {
 func (d *diskService) LSBLK() []model.LSBLKModel {
+	key := "system_lsblk"
+
+	var n []model.LSBLKModel
+
+	if result, ok := Cache.Get(key); ok {
+
+		res, ok := result.([]model.LSBLKModel)
+		if ok {
+			return res
+		}
+	}
+
 	str := command2.ExecLSBLK()
 	str := command2.ExecLSBLK()
 	if str == nil {
 	if str == nil {
-		d.log.Error("lsblk exec error")
+		d.log.Error("lsblk exec error,lsblk")
 		return nil
 		return nil
 	}
 	}
 	var m []model.LSBLKModel
 	var m []model.LSBLKModel
@@ -97,8 +113,6 @@ func (d *diskService) LSBLK() []model.LSBLKModel {
 		d.log.Error("json ummarshal error", err)
 		d.log.Error("json ummarshal error", err)
 	}
 	}
 
 
-	var n []model.LSBLKModel
-
 	var c []model.LSBLKModel
 	var c []model.LSBLKModel
 
 
 	var fsused uint64
 	var fsused uint64
@@ -136,13 +150,16 @@ func (d *diskService) LSBLK() []model.LSBLKModel {
 			fsused = 0
 			fsused = 0
 		}
 		}
 	}
 	}
+	if len(n) > 0 {
+		Cache.Add(key, n, time.Second*10)
+	}
 	return n
 	return n
 }
 }
 
 
 func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
 func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
 	str := command2.ExecLSBLKByPath(path)
 	str := command2.ExecLSBLKByPath(path)
 	if str == nil {
 	if str == nil {
-		d.log.Error("lsblk exec error")
+		d.log.Error("lsblk exec error,str")
 		return model.LSBLKModel{}
 		return model.LSBLKModel{}
 	}
 	}
 	var ml []model.LSBLKModel
 	var ml []model.LSBLKModel
@@ -197,13 +214,25 @@ func (d *diskService) MountDisk(path, volume string) {
 }
 }
 
 
 func (d *diskService) SaveMountPoint(m model2.SerialDisk) {
 func (d *diskService) SaveMountPoint(m model2.SerialDisk) {
-	d.db.Save(&m)
+	d.db.Create(&m)
 }
 }
 
 
-func (d *diskService) SerialAll(mountPoint string) *[]model2.SerialDisk {
+func (d *diskService) DeleteMount(id string) {
+
+	d.db.Delete(&model2.SerialDisk{}).Where("id = ?", id)
+}
+
+func (d *diskService) DeleteMountPoint(path, mountPoint string) {
+
+	d.db.Delete(&model2.SerialDisk{}).Where("path= ?  && mount_point = ?", path, mountPoint)
+
+	command2.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;do_umount " + path)
+}
+
+func (d *diskService) GetSerialAll() []model2.SerialDisk {
 	var m []model2.SerialDisk
 	var m []model2.SerialDisk
 	d.db.Find(&m)
 	d.db.Find(&m)
-	return &m
+	return m
 }
 }
 
 
 func NewDiskService(log loger2.OLog, db *gorm.DB) DiskService {
 func NewDiskService(log loger2.OLog, db *gorm.DB) DiskService {

+ 32 - 32
service/docker.go

@@ -8,7 +8,6 @@ import (
 	json2 "encoding/json"
 	json2 "encoding/json"
 	"fmt"
 	"fmt"
 	"reflect"
 	"reflect"
-	"regexp"
 	"syscall"
 	"syscall"
 
 
 	model2 "github.com/IceWhaleTech/CasaOS/service/model"
 	model2 "github.com/IceWhaleTech/CasaOS/service/model"
@@ -366,11 +365,11 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
 	//	if net != "host" {
 	//	if net != "host" {
 	//		portMaps[nat.Port(fmt.Sprint(m.Port)+"/tcp")] = []nat.PortBinding{{HostIP: "", HostPort: m.PortMap}}
 	//		portMaps[nat.Port(fmt.Sprint(m.Port)+"/tcp")] = []nat.PortBinding{{HostIP: "", HostPort: m.PortMap}}
 	//	}
 	//	}
-	port := ""
+	//port := ""
 	for _, portMap := range m.Ports {
 	for _, portMap := range m.Ports {
-		if portMap.CommendPort == m.PortMap && portMap.Protocol == "tcp" || portMap.Protocol == "both" {
-			port = portMap.ContainerPort
-		}
+		// if portMap.CommendPort == m.PortMap && portMap.Protocol == "tcp" || portMap.Protocol == "both" {
+		// 	port = portMap.ContainerPort
+		// }
 		if portMap.Protocol == "tcp" {
 		if portMap.Protocol == "tcp" {
 
 
 			tContainer, _ := strconv.Atoi(portMap.ContainerPort)
 			tContainer, _ := strconv.Atoi(portMap.ContainerPort)
@@ -413,7 +412,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
 	var envArr []string
 	var envArr []string
 	for _, e := range m.Envs {
 	for _, e := range m.Envs {
 		if strings.HasPrefix(e.Value, "$") {
 		if strings.HasPrefix(e.Value, "$") {
-			envArr = append(envArr, e.Name+"="+env_helper.ReplaceDefaultENV(e.Value))
+			envArr = append(envArr, e.Name+"="+env_helper.ReplaceDefaultENV(e.Value, MyService.System().GetTimeZone()))
 			continue
 			continue
 		}
 		}
 		if len(e.Value) > 0 {
 		if len(e.Value) > 0 {
@@ -443,27 +442,28 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
 	for _, v := range m.Volumes {
 	for _, v := range m.Volumes {
 		path := v.Path
 		path := v.Path
 		if len(path) == 0 {
 		if len(path) == 0 {
-			path = docker.GetDir(containerDbId, v.ContainerPath)
+			path = docker.GetDir(containerDbId, v.Path)
 			if len(path) == 0 {
 			if len(path) == 0 {
 				continue
 				continue
 			}
 			}
 		}
 		}
 		path = strings.ReplaceAll(path, "$AppID", containerDbId)
 		path = strings.ReplaceAll(path, "$AppID", containerDbId)
-		reg1 := regexp.MustCompile(`([^<>/\\\|:""\*\?]+\.\w+$)`)
-		result1 := reg1.FindAllStringSubmatch(path, -1)
-		if len(result1) == 0 {
-			err = file.IsNotExistMkDir(path)
-			if err != nil {
-				ds.log.Error("mkdir error", err)
-				continue
-			}
-		} else {
-			err = file.IsNotExistCreateFile(path)
-			if err != nil {
-				ds.log.Error("mkdir error", err)
-				continue
-			}
+		//reg1 := regexp.MustCompile(`([^<>/\\\|:""\*\?]+\.\w+$)`)
+		//result1 := reg1.FindAllStringSubmatch(path, -1)
+		//if len(result1) == 0 {
+		err = file.IsNotExistMkDir(path)
+		if err != nil {
+			ds.log.Error("mkdir error", err)
+			continue
 		}
 		}
+		//}
+		//  else {
+		// 	err = file.IsNotExistCreateFile(path)
+		// 	if err != nil {
+		// 		ds.log.Error("mkdir error", err)
+		// 		continue
+		// 	}
+		// }
 
 
 		volumes = append(volumes, mount.Mount{
 		volumes = append(volumes, mount.Mount{
 			Type:   mount.TypeBind,
 			Type:   mount.TypeBind,
@@ -479,17 +479,17 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
 	if len(m.Restart) > 0 {
 	if len(m.Restart) > 0 {
 		rp.Name = m.Restart
 		rp.Name = m.Restart
 	}
 	}
-	healthTest := []string{}
-	if len(port) > 0 {
-		healthTest = []string{"CMD-SHELL", "curl -f http://localhost:" + port + m.Index + " || exit 1"}
-	}
-
-	health := &container.HealthConfig{
-		Test:        healthTest,
-		StartPeriod: 0,
-		Retries:     1000,
-	}
-	fmt.Print(health)
+	// healthTest := []string{}
+	// if len(port) > 0 {
+	// 	healthTest = []string{"CMD-SHELL", "curl -f http://localhost:" + port + m.Index + " || exit 1"}
+	// }
+
+	// health := &container.HealthConfig{
+	// 	Test:        healthTest,
+	// 	StartPeriod: 0,
+	// 	Retries:     1000,
+	// }
+	// fmt.Print(health)
 	config := &container.Config{
 	config := &container.Config{
 		Image:  imageName,
 		Image:  imageName,
 		Labels: map[string]string{"origin": m.Origin, m.Origin: m.Origin},
 		Labels: map[string]string{"origin": m.Origin, m.Origin: m.Origin},

+ 85 - 0
service/file.go

@@ -0,0 +1,85 @@
+package service
+
+import (
+	"context"
+	"io"
+)
+
+// type InteruptReader struct {
+// 	r        io.Reader
+// 	interupt chan int
+// }
+
+// func NewInteruptReader(r io.Reader) InteruptReader {
+// 	return InteruptReader{
+// 		r,
+// 		make(chan int),
+// 	}
+// }
+
+// func (r InteruptReader) Read(p []byte) (n int, err error) {
+// 	if r.r == nil {
+// 		return 0, io.EOF
+// 	}
+// 	select {
+// 	case <-r.interupt:
+// 		return r.r.Read(p)
+// 	default:
+// 		r.r = nil
+// 		return 0, io.EOF
+// 	}
+// }
+
+// func (r InteruptReader) Cancel() {
+// 	r.interupt <- 0
+// }
+
+type reader struct {
+	ctx context.Context
+	r   io.Reader
+}
+
+// NewReader wraps an io.Reader to handle context cancellation.
+//
+// Context state is checked BEFORE every Read.
+func NewReader(ctx context.Context, r io.Reader) io.Reader {
+	if r, ok := r.(*reader); ok && ctx == r.ctx {
+		return r
+	}
+	return &reader{ctx: ctx, r: r}
+}
+
+func (r *reader) Read(p []byte) (n int, err error) {
+	select {
+	case <-r.ctx.Done():
+		return 0, r.ctx.Err()
+	default:
+		return r.r.Read(p)
+	}
+}
+
+type writer struct {
+	ctx context.Context
+	w   io.Writer
+}
+
+type copier struct {
+	writer
+}
+
+func NewWriter(ctx context.Context, w io.Writer) io.Writer {
+	if w, ok := w.(*copier); ok && ctx == w.ctx {
+		return w
+	}
+	return &copier{writer{ctx: ctx, w: w}}
+}
+
+// Write implements io.Writer, but with context awareness.
+func (w *writer) Write(p []byte) (n int, err error) {
+	select {
+	case <-w.ctx.Done():
+		return 0, w.ctx.Err()
+	default:
+		return w.w.Write(p)
+	}
+}

+ 81 - 0
service/file_test.go

@@ -0,0 +1,81 @@
+package service
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"testing"
+	"time"
+)
+
+var ctx context.Context
+var cancel context.CancelFunc
+
+func TestNewInteruptReader(t *testing.T) {
+	ctx, cancel = context.WithCancel(context.Background())
+
+	go func() {
+		// 在初始上下文的基础上创建一个有取消功能的上下文
+		//	ctx, cancel := context.WithCancel(ctx)
+		fmt.Println("开始")
+		fIn, err := os.Open("/Users/liangjianli/Downloads/demo_data.tar.gz")
+		if err != nil {
+
+		}
+		defer fIn.Close()
+		fmt.Println("创建新文件")
+		fOut, err := os.Create("/Users/liangjianli/Downloads/demo_data1.tar.gz")
+		if err != nil {
+			fmt.Println(err)
+		}
+
+		defer fOut.Close()
+
+		fmt.Println("准备复制")
+		//	_, err = io.Copy(out, NewReader(ctx, f))
+		//	time.Sleep(time.Second * 2)
+		//ctx.Done()
+		//	cancel()
+
+		// interrupt context after 500ms
+
+		// interrupt context with SIGTERM (CTRL+C)
+		//sigs := make(chan os.Signal, 1)
+		//signal.Notify(sigs, os.Interrupt)
+
+		if err != nil {
+			log.Fatal(err)
+		}
+
+		// Reader that fails when context is canceled
+		in := NewReader(ctx, fIn)
+		// Writer that fails when context is canceled
+		out := NewWriter(ctx, fOut)
+
+		//time.Sleep(2 * time.Second)
+
+		//cancel()
+
+		n, err := io.Copy(out, in)
+		log.Println(n, "bytes copied.")
+		if err != nil {
+			fmt.Println("Err:", err)
+		}
+
+		fmt.Println("Closing.")
+	}()
+
+	go func() {
+		//<-sigs
+		time.Sleep(time.Second)
+		fmt.Println("退出")
+		ddd()
+	}()
+	time.Sleep(time.Second * 10)
+}
+
+func ddd() {
+	cancel()
+}

+ 1 - 1
service/model/o_disk.go

@@ -3,7 +3,7 @@ package model
 //SerialAdvanced Technology Attachment (STAT)
 //SerialAdvanced Technology Attachment (STAT)
 type SerialDisk struct {
 type SerialDisk struct {
 	Id         uint   `gorm:"column:id;primary_key" json:"id"`
 	Id         uint   `gorm:"column:id;primary_key" json:"id"`
-	DiskId     string `json:"disk_id"`
+	Serial     string `json:"serial"`
 	Path       string `json:"path"`
 	Path       string `json:"path"`
 	State      int    `json:"state"`
 	State      int    `json:"state"`
 	MountPoint string `json:"mount_point"`
 	MountPoint string `json:"mount_point"`

+ 6 - 0
service/system.go

@@ -16,6 +16,7 @@ type SystemService interface {
 	GetCasaOSLogs(lineNumber int) string
 	GetCasaOSLogs(lineNumber int) string
 	UpdateAssist()
 	UpdateAssist()
 	UpSystemPort(port string)
 	UpSystemPort(port string)
+	GetTimeZone() string
 }
 }
 type systemService struct {
 type systemService struct {
 	log loger.OLog
 	log loger.OLog
@@ -30,6 +31,11 @@ func (s *systemService) UpdateSystemVersion(version string) {
 func (s *systemService) UpdateAssist() {
 func (s *systemService) UpdateAssist() {
 	s.log.Error(command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/assist.sh"))
 	s.log.Error(command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/assist.sh"))
 }
 }
+
+func (s *systemService) GetTimeZone() string {
+	return command2.ExecResultStr("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetTimeZone")
+}
+
 func (s *systemService) GetSystemConfigDebug() []string {
 func (s *systemService) GetSystemConfigDebug() []string {
 	return command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetSysInfo")
 	return command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetSysInfo")
 }
 }

+ 98 - 2
shell/helper.sh

@@ -30,6 +30,11 @@ GetNetCard() {
   fi
   fi
 }
 }
 
 
+
+GetTimeZone(){
+  timedatectl | grep "Time zone" | awk '{print $3}'
+}
+
 #查看网卡状态
 #查看网卡状态
 #param 网卡名称
 #param 网卡名称
 CatNetCardState() {
 CatNetCardState() {
@@ -194,7 +199,7 @@ do_mount() {
   eval $(blkid -o udev ${DEVICE} | grep -i -e "ID_FS_LABEL" -e "ID_FS_TYPE")
   eval $(blkid -o udev ${DEVICE} | grep -i -e "ID_FS_LABEL" -e "ID_FS_TYPE")
 
 
   LABEL=$2
   LABEL=$2
-  if grep -q " /media/${LABEL} " /etc/mtab; then
+  if grep -q " ${LABEL} " /etc/mtab; then
     # Already in use, make a unique one
     # Already in use, make a unique one
     LABEL+="-${DEVBASE}"
     LABEL+="-${DEVBASE}"
   fi
   fi
@@ -205,7 +210,7 @@ do_mount() {
     DEV_LABEL="${DEVBASE}"
     DEV_LABEL="${DEVBASE}"
   fi
   fi
 
 
-  MOUNT_POINT="/media/${DEV_LABEL}"
+  MOUNT_POINT="${DEV_LABEL}"
 
 
   ${log} "Mount point: ${MOUNT_POINT}"
   ${log} "Mount point: ${MOUNT_POINT}"
 
 
@@ -233,3 +238,94 @@ do_mount() {
     ;;
     ;;
   esac
   esac
 }
 }
+
+# $1=sda1
+do_umount() {
+  log="logger -t usb-mount.sh -s "
+  DEVBASE=$1
+  DEVICE="${DEVBASE}"
+  MOUNT_POINT=$(mount | grep ${DEVICE} | awk '{ print $3 }')
+
+  if [[ -z ${MOUNT_POINT} ]]; then
+    ${log} "Warning: ${DEVICE} is not mounted"
+  else
+    umount -l ${DEVICE}
+    ${log} "Unmounted ${DEVICE} from ${MOUNT_POINT}"
+    /bin/rmdir "${MOUNT_POINT}"
+    sed -i.bak "\@${MOUNT_POINT}@d" /var/log/usb-mount.track
+  fi
+
+}
+# $1=/mnt/volume1/data.img
+# $2=100G
+PackageDocker() {
+  image=$1
+  docker="/mnt/casa_docker"
+  #判断目录docker存在不存在则创建,存在检查是否为空
+
+  if [ ! -d "$docker" ]; then
+    mkdir ${docker}
+  fi
+
+  if [ "$(ls -A $docker)" = "" ]; then
+    echo "$docker count is 0"
+  else
+    mkdir ${docker}_bak
+    mv -r ${docker} ${docker}_bak
+  fi
+
+  daemon="/etc/docker/daemon.json"
+  #1创建img文件在挂载的目录
+  fallocate -l $2 $image
+  #2初始化img文件
+  mkfs -t ext4 $image
+  #3挂载img文件
+  sudo mount -o loop $image $docker
+  #4给移动/var/lib/docker数据到img挂载的目录
+  systemctl stop docker.socket
+  systemctl stop docker
+  cp -r /var/lib/docker/* ${docker}/
+  #5在/etc/docker写入daemon.json(需要检查)
+  if [ -d "$daemon" ]; then
+    mv -r $daemon ${daemon}.bak
+  fi
+  echo "{\"data-root\": \"$docker\"}" >$daemon
+  #删除老数据腾出空间
+  #rm -fr /var/lib/docker
+  systemctl start docker.socket
+  systemctl start docker
+}
+
+DockerImgMove() {
+  image=$1
+  systemctl stop docker.socket
+  systemctl stop docker
+  sudo umount -f $image
+}
+
+GetDockerDataRoot() {
+  docker info | grep "Docker Root Dir:"
+}
+
+SetLink() {
+  ln -s /mnt/casa_sda1/AppData /DATA/AppData
+  #删除所有软链
+  find /DATA -type l -delete
+}
+
+#压缩文件夹
+
+TarFolder() {
+  #压缩
+  tar -zcvf data.tar.gz -C/DATA/ AppDataBak/
+
+  #解压
+  tar zxvf data.tar.gz 
+
+  #查看某文件夹下的所有包括子文件夹文件
+  ls /DATA/Media -lR | grep "^-" | wc -l
+  # ls -lR|grep "^d"| wc -l 查看某个文件夹下文件夹的个数,包括子文件夹下的文件夹个数。
+
+  #查看固定文件夹大小
+  du -sh /DATA
+}

+ 2 - 2
types/system.go

@@ -1,4 +1,4 @@
 package types
 package types
 
 
-const CURRENTVERSION = "0.2.3"
-const BODY = "<li>Add detailed CPU and memory statistics.</li><li>Add the multi-language function and add Chinese translation.</li><li>Add the function to modify the search engine.</li><li>Add the function of modifying the WebUI port</li><li>fixed some bugs</li><li>Preprocessing usb automounting</li><li>Update update script</li>"
+const CURRENTVERSION = "0.2.4"
+const BODY = "<li>New App Store</li><li>Fix minor bugs</li>"