link 3 år sedan
förälder
incheckning
2508a4e07d

+ 2 - 2
go.mod

@@ -48,8 +48,8 @@ require (
 	github.com/smartystreets/goconvey v1.6.4 // indirect
 	github.com/smartystreets/goconvey v1.6.4 // indirect
 	github.com/swaggo/gin-swagger v1.3.0
 	github.com/swaggo/gin-swagger v1.3.0
 	github.com/swaggo/swag v1.7.3
 	github.com/swaggo/swag v1.7.3
-	github.com/tidwall/gjson v1.8.0
-	github.com/tidwall/pretty v1.2.0 // indirect
+	github.com/tidwall/gjson v1.10.2
+	github.com/tidwall/sjson v1.2.3
 	github.com/tklauser/go-sysconf v0.3.6 // indirect
 	github.com/tklauser/go-sysconf v0.3.6 // indirect
 	github.com/ugorji/go v1.2.6 // indirect
 	github.com/ugorji/go v1.2.6 // indirect
 	go.opencensus.io v0.23.0 // indirect
 	go.opencensus.io v0.23.0 // indirect

+ 6 - 5
go.sum

@@ -741,13 +741,14 @@ github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG
 github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
 github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
 github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
 github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
 github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
 github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
-github.com/tidwall/gjson v1.8.0 h1:Qt+orfosKn0rbNTZqHYDqBrmm3UDA4KRkv70fDzG+PQ=
-github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
-github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
-github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
-github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/tidwall/gjson v1.10.2 h1:APbLGOM0rrEkd8WBw9C24nllro4ajFuJu0Sc9hRz8Bo=
+github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
+github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
 github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
 github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
 github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
 github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/tidwall/sjson v1.2.3 h1:5+deguEhHSEjmuICXZ21uSSsXotWMA0orU783+Z7Cp8=
+github.com/tidwall/sjson v1.2.3/go.mod h1:5WdjKx3AQMvCJ4RG6/2UYT7dLrGvJUV1x4jdTAyGvZs=
 github.com/tklauser/go-sysconf v0.3.4/go.mod h1:Cl2c8ZRWfHD5IrfHo9VN+FX9kCFjIOyVklgXycLB6ek=
 github.com/tklauser/go-sysconf v0.3.4/go.mod h1:Cl2c8ZRWfHD5IrfHo9VN+FX9kCFjIOyVklgXycLB6ek=
 github.com/tklauser/go-sysconf v0.3.6 h1:oc1sJWvKkmvIxhDHeKWvZS4f6AW+YcoguSfRF2/Hmo4=
 github.com/tklauser/go-sysconf v0.3.6 h1:oc1sJWvKkmvIxhDHeKWvZS4f6AW+YcoguSfRF2/Hmo4=
 github.com/tklauser/go-sysconf v0.3.6/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
 github.com/tklauser/go-sysconf v0.3.6/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=

+ 2 - 0
pkg/utils/oasis_err/e.go

@@ -16,6 +16,7 @@ const (
 	DIR_ALREADY_EXISTS  = 20001
 	DIR_ALREADY_EXISTS  = 20001
 	FILE_ALREADY_EXISTS = 20002
 	FILE_ALREADY_EXISTS = 20002
 	FILE_OR_DIR_EXISTS  = 20003
 	FILE_OR_DIR_EXISTS  = 20003
+	PORT_IS_OCCUPIED    = 20004
 
 
 	//zerotier
 	//zerotier
 	GET_TOKEN_ERROR = 30001
 	GET_TOKEN_ERROR = 30001
@@ -49,6 +50,7 @@ var MsgFlags = map[int]string{
 	DIR_ALREADY_EXISTS:  "Directory already exists",
 	DIR_ALREADY_EXISTS:  "Directory already exists",
 	FILE_ALREADY_EXISTS: "File already exists",
 	FILE_ALREADY_EXISTS: "File already exists",
 	FILE_OR_DIR_EXISTS:  "File or directory already exists",
 	FILE_OR_DIR_EXISTS:  "File or directory already exists",
+	PORT_IS_OCCUPIED:    "Port is occupied",
 
 
 	//zerotier
 	//zerotier
 	GET_TOKEN_ERROR: "Get token error,Please log in to zerotier's official website to confirm whether the account is available",
 	GET_TOKEN_ERROR: "Get token error,Please log in to zerotier's official website to confirm whether the account is available",

+ 4 - 0
route/route.go

@@ -141,6 +141,8 @@ func InitRouter() *gin.Engine {
 		{
 		{
 			//获取我的已安装的列表
 			//获取我的已安装的列表
 			v1AppGroup.GET("/mylist", v1.MyAppList)
 			v1AppGroup.GET("/mylist", v1.MyAppList)
+			//
+			v1AppGroup.GET("/usage", v1.AppUsageList)
 			//app详情
 			//app详情
 			v1AppGroup.GET("/appinfo/:id", v1.AppInfo)
 			v1AppGroup.GET("/appinfo/:id", v1.AppInfo)
 			//获取未安装的列表
 			//获取未安装的列表
@@ -192,6 +194,8 @@ func InitRouter() *gin.Engine {
 			v1SysGroup.POST("/config", v1.PostSetSystemConfig)
 			v1SysGroup.POST("/config", v1.PostSetSystemConfig)
 			v1SysGroup.GET("/widget/config", v1.GetWidgetConfig)
 			v1SysGroup.GET("/widget/config", v1.GetWidgetConfig)
 			v1SysGroup.POST("/widget/config", v1.PostSetWidgetConfig)
 			v1SysGroup.POST("/widget/config", v1.PostSetWidgetConfig)
+			v1SysGroup.PUT("/port", v1.PutCasaOSPort)
+			v1SysGroup.POST("/kill", v1.PostKillCasaOS)
 		}
 		}
 		v1FileGroup := v1Group.Group("/file")
 		v1FileGroup := v1Group.Group("/file")
 		v1FileGroup.Use()
 		v1FileGroup.Use()

+ 23 - 0
route/v1/app.go

@@ -103,6 +103,18 @@ func MyAppList(c *gin.Context) {
 	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})
 }
 }
 
 
+// @Summary my app hardware usage list
+// @Produce  application/json
+// @Accept application/json
+// @Tags app
+// @Security ApiKeyAuth
+// @Success 200 {string} string "ok"
+// @Router /app/usage [get]
+func AppUsageList(c *gin.Context) {
+	list := service.MyService.App().GetHardwareUsage()
+	c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
+}
+
 // @Summary 应用详情
 // @Summary 应用详情
 // @Produce  application/json
 // @Produce  application/json
 // @Accept application/json
 // @Accept application/json
@@ -212,3 +224,14 @@ func ShareAppFile(c *gin.Context) {
 	content := service.MyService.OAPI().ShareAppFile(str)
 	content := service.MyService.OAPI().ShareAppFile(str)
 	c.JSON(http.StatusOK, json.RawMessage(content))
 	c.JSON(http.StatusOK, json.RawMessage(content))
 }
 }
+
+// @Summary Resource Usage
+// @Produce  application/json
+// @Accept application/json
+// @Tags app
+// @Security ApiKeyAuth
+// @Success 200 {string} string "ok"
+// @Router /app/share [post]
+func AppListResourceUsage() {
+
+}

+ 7 - 6
route/v1/disk.go

@@ -1,13 +1,14 @@
 package v1
 package v1
 
 
 import (
 import (
+	"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"
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 	"github.com/shirou/gopsutil/v3/disk"
 	"github.com/shirou/gopsutil/v3/disk"
-	"net/http"
-	"strconv"
 )
 )
 
 
 // @Summary 获取磁盘列表
 // @Summary 获取磁盘列表
@@ -59,7 +60,7 @@ func GetPlugInDisk(c *gin.Context) {
 	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: lst})
 }
 }
 
 
-// @Summary 获取磁盘列表
+// @Summary get disk list
 // @Produce  application/json
 // @Produce  application/json
 // @Accept application/json
 // @Accept application/json
 // @Tags disk
 // @Tags disk
@@ -76,12 +77,12 @@ func GetPlugInDisks(c *gin.Context) {
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: result})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: result})
 }
 }
 
 
-// @Summary 磁盘详情
+// @Summary disk detail
 // @Produce  application/json
 // @Produce  application/json
 // @Accept application/json
 // @Accept application/json
 // @Tags disk
 // @Tags disk
 // @Security ApiKeyAuth
 // @Security ApiKeyAuth
-// @Param  path query string true "要获取的磁盘详情 例如/dev/sda"
+// @Param  path query string true "for example /dev/sda"
 // @Success 200 {string} string "ok"
 // @Success 200 {string} string "ok"
 // @Router /disk/info [get]
 // @Router /disk/info [get]
 func GetDiskInfo(c *gin.Context) {
 func GetDiskInfo(c *gin.Context) {
@@ -93,7 +94,7 @@ func GetDiskInfo(c *gin.Context) {
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: m})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: m})
 }
 }
 
 
-// @Summary 磁盘详情
+// @Summary format disk
 // @Produce  application/json
 // @Produce  application/json
 // @Accept multipart/form-data
 // @Accept multipart/form-data
 // @Tags disk
 // @Tags disk

+ 3 - 10
route/v1/docker.go

@@ -2,7 +2,6 @@ package v1
 
 
 import (
 import (
 	"bytes"
 	"bytes"
-	"encoding/json"
 	json2 "encoding/json"
 	json2 "encoding/json"
 	"net/http"
 	"net/http"
 	"reflect"
 	"reflect"
@@ -677,7 +676,7 @@ func UnInstallApp(c *gin.Context) {
 	}
 	}
 
 
 	//step:删除容器
 	//step:删除容器
-	err = service.MyService.Docker().DockerContainerRemove(appId)
+	err = service.MyService.Docker().DockerContainerRemove(appId, false)
 	if err != nil {
 	if err != nil {
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.UNINSTALL_APP_ERROR, Message: oasis_err2.GetMsg(oasis_err2.UNINSTALL_APP_ERROR), Data: err.Error()})
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.UNINSTALL_APP_ERROR, Message: oasis_err2.GetMsg(oasis_err2.UNINSTALL_APP_ERROR), Data: err.Error()})
 		return
 		return
@@ -908,16 +907,10 @@ func UpdateSetting(c *gin.Context) {
 	//如果容器端口均未修改,这不进行处理
 	//如果容器端口均未修改,这不进行处理
 	portsStr, _ := json2.Marshal(m.Ports)
 	portsStr, _ := json2.Marshal(m.Ports)
 
 
-	list := []model.PathMap{}
-	json.Unmarshal([]byte(appInfo.Volumes), &list)
-	for i := 0; i < len(list); i++ {
-		list[i].Path = docker.GetDir(id, list[i].ContainerPath)
-	}
 	envsStr, _ := json2.Marshal(m.Envs)
 	envsStr, _ := json2.Marshal(m.Envs)
 	volumesStr, _ := json2.Marshal(m.Volumes)
 	volumesStr, _ := json2.Marshal(m.Volumes)
 	devicesStr, _ := json2.Marshal(m.Devices)
 	devicesStr, _ := json2.Marshal(m.Devices)
-	listStr, _ := json2.Marshal(list)
-	if !reflect.DeepEqual(string(portsStr), appInfo.Ports) || !reflect.DeepEqual(string(envsStr), appInfo.Envs) || !reflect.DeepEqual(volumesStr, listStr) || m.PortMap != appInfo.PortMap || m.NetworkModel != appInfo.NetModel {
+	if !reflect.DeepEqual(string(portsStr), appInfo.Ports) || !reflect.DeepEqual(string(envsStr), appInfo.Envs) || !reflect.DeepEqual(string(volumesStr), appInfo.Volumes) || m.PortMap != appInfo.PortMap || m.NetworkModel != appInfo.NetModel {
 
 
 		var newUUid = uuid.NewV4().String()
 		var newUUid = uuid.NewV4().String()
 		var err error
 		var err error
@@ -934,7 +927,7 @@ func UpdateSetting(c *gin.Context) {
 			return
 			return
 		}
 		}
 
 
-		err = service.MyService.Docker().DockerContainerRemove(id)
+		err = service.MyService.Docker().DockerContainerRemove(id, true)
 		if err != nil {
 		if err != nil {
 			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
 			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
 			return
 			return

+ 50 - 1
route/v1/system.go

@@ -4,12 +4,14 @@ import (
 	"encoding/json"
 	"encoding/json"
 	"fmt"
 	"fmt"
 	"net/http"
 	"net/http"
+	"os"
 	"strconv"
 	"strconv"
 	"time"
 	"time"
 
 
 	"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"
+	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"
 	model2 "github.com/IceWhaleTech/CasaOS/service/model"
 	model2 "github.com/IceWhaleTech/CasaOS/service/model"
@@ -80,7 +82,7 @@ func GetCasaOSErrorLogs(c *gin.Context) {
 // @Produce  application/json
 // @Produce  application/json
 // @Accept multipart/form-data
 // @Accept multipart/form-data
 // @Tags sys
 // @Tags sys
-// @Param file formData file true "用户头像"
+// @Param config formData string true "config json string"
 // @Security ApiKeyAuth
 // @Security ApiKeyAuth
 // @Success 200 {string} string "ok"
 // @Success 200 {string} string "ok"
 // @Router /sys/changhead [post]
 // @Router /sys/changhead [post]
@@ -135,6 +137,42 @@ func PostSetWidgetConfig(c *gin.Context) {
 		})
 		})
 }
 }
 
 
+// @Summary edit casaos server port
+// @Produce  application/json
+// @Accept application/json
+// @Tags sys
+// @Security ApiKeyAuth
+// @Param port formData file true "用户头像"
+// @Success 200 {string} string "ok"
+// @Router /sys/widget/config [post]
+func PutCasaOSPort(c *gin.Context) {
+	port, err := strconv.Atoi(c.PostForm("port"))
+	if err != nil {
+		c.JSON(http.StatusOK,
+			model.Result{
+				Success: oasis_err.ERROR,
+				Message: err.Error(),
+			})
+		return
+	}
+
+	isAvailable := port2.IsPortAvailable(port, "tcp")
+	if !isAvailable {
+		c.JSON(http.StatusOK,
+			model.Result{
+				Success: oasis_err.PORT_IS_OCCUPIED,
+				Message: oasis_err.GetMsg(oasis_err.PORT_IS_OCCUPIED),
+			})
+		return
+	}
+	service.MyService.System().UpSystemPort(strconv.Itoa(port))
+	c.JSON(http.StatusOK,
+		model.Result{
+			Success: oasis_err.SUCCESS,
+			Message: oasis_err.GetMsg(oasis_err.SUCCESS),
+		})
+}
+
 // @Summary 检查是否进入引导状态
 // @Summary 检查是否进入引导状态
 // @Produce  application/json
 // @Produce  application/json
 // @Accept application/json
 // @Accept application/json
@@ -156,3 +194,14 @@ func GetGuideCheck(c *gin.Context) {
 			Data:    data,
 			Data:    data,
 		})
 		})
 }
 }
+
+// @Summary active killing casaos
+// @Produce  application/json
+// @Accept application/json
+// @Tags sys
+// @Security ApiKeyAuth
+// @Success 200 {string} string "ok"
+// @Router /sys/kill [post]
+func PostKillCasaOS(c *gin.Context) {
+	os.Exit(0)
+}

+ 58 - 1
service/app.go

@@ -2,7 +2,10 @@ package service
 
 
 import (
 import (
 	"context"
 	"context"
+	"io/ioutil"
+	"runtime"
 	"strings"
 	"strings"
+	"sync"
 	"time"
 	"time"
 
 
 	"github.com/IceWhaleTech/CasaOS/pkg/config"
 	"github.com/IceWhaleTech/CasaOS/pkg/config"
@@ -13,6 +16,7 @@ import (
 	"github.com/docker/docker/api/types/filters"
 	"github.com/docker/docker/api/types/filters"
 	client2 "github.com/docker/docker/client"
 	client2 "github.com/docker/docker/client"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
+	"github.com/tidwall/sjson"
 	"gorm.io/gorm"
 	"gorm.io/gorm"
 )
 )
 
 
@@ -27,6 +31,7 @@ type AppService interface {
 	GetSimpleContainerInfo(name string) (types.Container, error)
 	GetSimpleContainerInfo(name string) (types.Container, error)
 	DelAppConfigDir(path string)
 	DelAppConfigDir(path string)
 	GetSystemAppList() *[]model2.MyAppList
 	GetSystemAppList() *[]model2.MyAppList
+	GetHardwareUsage() []string
 }
 }
 
 
 type appStruct struct {
 type appStruct struct {
@@ -48,7 +53,6 @@ func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppLis
 	if err != nil {
 	if err != nil {
 		a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
 		a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
 	}
 	}
-
 	//获取本地数据库应用
 	//获取本地数据库应用
 
 
 	var lm []model2.AppListDBModel
 	var lm []model2.AppListDBModel
@@ -231,6 +235,59 @@ func (a *appStruct) RemoveContainerById(id string) {
 	a.db.Table(model2.CONTAINERTABLENAME).Where("custom_id = ?", id).Delete(&model2.AppListDBModel{})
 	a.db.Table(model2.CONTAINERTABLENAME).Where("custom_id = ?", id).Delete(&model2.AppListDBModel{})
 }
 }
 
 
+func (a *appStruct) GetHardwareUsage() []string {
+
+	var dataStr []string
+	cli, err := client2.NewClientWithOpts(client2.FromEnv)
+	if err != nil {
+		return dataStr
+	}
+	defer cli.Close()
+
+	lock := &sync.Mutex{}
+	var lm []model2.AppListDBModel
+	var count = 0
+	a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,container_id").Find(&lm)
+	for _, v := range lm {
+		go func(lock *sync.Mutex, id, title, icon string) {
+			stats, err := cli.ContainerStats(context.Background(), id, false)
+			if err != nil {
+				lock.Lock()
+				count++
+				lock.Unlock()
+				return
+			}
+			defer stats.Body.Close()
+			statsByte, err := ioutil.ReadAll(stats.Body)
+			if err != nil {
+				lock.Lock()
+				count++
+				lock.Unlock()
+				return
+			}
+			lock.Lock()
+			statsByte, _ = sjson.SetBytes(statsByte, "icon", icon)
+			statsByte, _ = sjson.SetBytes(statsByte, "title", title)
+			dataStr = append(dataStr, string(statsByte))
+			count++
+			lock.Unlock()
+		}(lock, v.ContainerId, v.Title, v.Icon)
+	}
+
+	for {
+		lock.Lock()
+		c := count
+		lock.Unlock()
+
+		runtime.Gosched()
+		if c == len(lm) {
+			break
+		}
+	}
+	return dataStr
+
+}
+
 // init install
 // init install
 func Init() {
 func Init() {
 
 

+ 3 - 3
service/disk.go

@@ -90,7 +90,7 @@ func (d *diskService) GetDiskInfoByPath(path string) *disk.UsageStat {
 	return diskInfo
 	return diskInfo
 }
 }
 
 
-//获取磁盘信息
+//get disk details
 func (d *diskService) LSBLK() []model.LSBLKModel {
 func (d *diskService) LSBLK() []model.LSBLKModel {
 	str := command2.ExecLSBLK()
 	str := command2.ExecLSBLK()
 	if str == nil {
 	if str == nil {
@@ -111,7 +111,7 @@ func (d *diskService) LSBLK() []model.LSBLKModel {
 
 
 	var health = true
 	var health = true
 	for _, i := range m {
 	for _, i := range m {
-		if i.Children != nil {
+		if i.Type != "loop" {
 			fsused = 0
 			fsused = 0
 			for _, child := range i.Children {
 			for _, child := range i.Children {
 				if child.RM {
 				if child.RM {
@@ -134,7 +134,7 @@ func (d *diskService) LSBLK() []model.LSBLKModel {
 			i.Children = c
 			i.Children = c
 			if fsused > 0 {
 			if fsused > 0 {
 				i.UsedPercent, err = strconv.ParseFloat(fmt.Sprintf("%.4f", float64(fsused)/float64(i.Size)), 64)
 				i.UsedPercent, err = strconv.ParseFloat(fmt.Sprintf("%.4f", float64(fsused)/float64(i.Size)), 64)
-				fmt.Println(err)
+				d.log.Fatal("diskservice_lsblk_fsused", err)
 			}
 			}
 			n = append(n, i)
 			n = append(n, i)
 			health = true
 			health = true

+ 8 - 6
service/docker.go

@@ -53,7 +53,7 @@ type DockerService interface {
 	DockerListByImage(image, version string) (*types.Container, error)
 	DockerListByImage(image, version string) (*types.Container, error)
 	DockerContainerInfo(name string) (*types.ContainerJSON, error)
 	DockerContainerInfo(name string) (*types.ContainerJSON, error)
 	DockerImageRemove(name string) error
 	DockerImageRemove(name string) error
-	DockerContainerRemove(name string) error
+	DockerContainerRemove(name string, update bool) error
 	DockerContainerStop(id string) error
 	DockerContainerStop(id string) error
 	DockerContainerUpdateName(name, id string) (err error)
 	DockerContainerUpdateName(name, id string) (err error)
 	DockerContainerUpdate(m model.CustomizationPostData, id string) (err error)
 	DockerContainerUpdate(m model.CustomizationPostData, id string) (err error)
@@ -352,7 +352,7 @@ func (ds *dockerService) DockerPullImage(imageName string, m model2.AppNotify) e
 //param udp 容器其他udp端口
 //param udp 容器其他udp端口
 func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId string, m model.CustomizationPostData, net string) (containerId string, err error) {
 func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId string, m model.CustomizationPostData, net string) (containerId string, err error) {
 	if len(net) == 0 {
 	if len(net) == 0 {
-		net = "oasis"
+		net = "bridge"
 	}
 	}
 
 
 	cli, err := client2.NewClientWithOpts(client2.FromEnv)
 	cli, err := client2.NewClientWithOpts(client2.FromEnv)
@@ -515,7 +515,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
 }
 }
 
 
 //删除容器
 //删除容器
-func (ds *dockerService) DockerContainerRemove(name string) error {
+func (ds *dockerService) DockerContainerRemove(name string, update bool) error {
 	cli, err := client2.NewClientWithOpts(client2.FromEnv)
 	cli, err := client2.NewClientWithOpts(client2.FromEnv)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -524,9 +524,11 @@ func (ds *dockerService) DockerContainerRemove(name string) error {
 	err = cli.ContainerRemove(context.Background(), name, types.ContainerRemoveOptions{})
 	err = cli.ContainerRemove(context.Background(), name, types.ContainerRemoveOptions{})
 
 
 	//路径处理
 	//路径处理
-	path := docker.GetDir(name, "/config")
-	if !file.CheckNotExist(path) {
-		file.RMDir(path)
+	if !update {
+		path := docker.GetDir(name, "/config")
+		if !file.CheckNotExist(path) {
+			file.RMDir(path)
+		}
 	}
 	}
 
 
 	if err != nil {
 	if err != nil {

+ 12 - 0
service/system.go

@@ -14,6 +14,8 @@ type SystemService interface {
 	UpdateSystemVersion(version string)
 	UpdateSystemVersion(version string)
 	GetSystemConfigDebug() []string
 	GetSystemConfigDebug() []string
 	GetCasaOSLogs(lineNumber int) string
 	GetCasaOSLogs(lineNumber int) string
+	UpdateAssist()
+	UpSystemPort(port string)
 }
 }
 type systemService struct {
 type systemService struct {
 	log loger.OLog
 	log loger.OLog
@@ -25,6 +27,9 @@ func (s *systemService) UpdateSystemVersion(version string) {
 	s.log.Error(command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/tools.sh ;update " + version))
 	s.log.Error(command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/tools.sh ;update " + version))
 	//s.log.Error(command2.ExecResultStr(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() {
+	s.log.Error(command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/assist.sh"))
+}
 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")
 }
 }
@@ -39,6 +44,13 @@ func (s *systemService) UpSystemConfig(str string, widget string) {
 	}
 	}
 	config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
 	config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
 }
 }
+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 {
 func (s *systemService) GetCasaOSLogs(lineNumber int) string {
 	file, err := os.Open(s.log.Path())
 	file, err := os.Open(s.log.Path())
 	if err != nil {
 	if err != nil {

+ 0 - 1
service/zima_info.go

@@ -116,7 +116,6 @@ func (c *zima) GetNetState(name string) string {
 
 
 //网络信息
 //网络信息
 func (c *zima) GetNetInfo() []net.IOCountersStat {
 func (c *zima) GetNetInfo() []net.IOCountersStat {
-	//loger.Error("输出个内容试试")
 	parts, _ := net.IOCounters(true)
 	parts, _ := net.IOCounters(true)
 	//fmt.Println(net.ConntrackStatsWithContext(true))
 	//fmt.Println(net.ConntrackStatsWithContext(true))
 	return parts
 	return parts

+ 25 - 0
shell/assist.sh

@@ -0,0 +1,25 @@
+#!/bin/bash
+
+#update to v0.2.3
+version_0_2_3(){
+  ((EUID)) && sudo_cmd="sudo"
+
+#copy file to path
+  if [ ! -s "/etc/udev/rules.d/11-usb-mount.rules" ]; then
+    $sudo_cmd cp /casaOS/server/shell/11-usb-mount.rules /etc/udev/rules.d/
+  fi
+
+  if [ ! -s "/casaOS/util/shell/usb-mount.sh" ]; then
+    $sudo_cmd cp /casaOS/server/shell/usb-mount.sh /casaOS/util/shell/
+    $sudo_cmd chmod +x /casaOS/util/shell/usb-mount.sh
+  fi
+  if [ ! -s "/etc/systemd/system/cp /casaOS/server/shell/usb-mount@.service" ]; then
+     $sudo_cmd cp /casaOS/server/shell/usb-mount@.service /etc/systemd/system/
+  fi
+
+
+
+
+}
+
+version_0_2_3

+ 1 - 1
shell/tools.sh

@@ -60,7 +60,7 @@ show() {
 }
 }
 
 
 run_external_script() {
 run_external_script() {
-  show 0 "run_external_script"
+  assist.sh
 }
 }
 
 
 update() {
 update() {

+ 3 - 3
shell/usb-mount.sh

@@ -1,6 +1,6 @@
 #!/bin/sh
 #!/bin/sh
 
 
-# copy to /oasis/util/shell path
+# copy to /casaOS/util/shell path
 # chmod 755
 # chmod 755
 
 
 log="logger -t usb-mount.sh -s "
 log="logger -t usb-mount.sh -s "
@@ -18,10 +18,10 @@ MOUNT_POINT=$(mount | grep ${DEVICE} | awk '{ print $3 }')
 
 
 do_mount() {
 do_mount() {
 
 
-  if [[ -n ${MOUNT_POINT} ]]; then
+  if [ -n "${MOUNT_POINT}" ]; then
     ${log} "Warning: ${DEVICE} is already mounted at ${MOUNT_POINT}"
     ${log} "Warning: ${DEVICE} is already mounted at ${MOUNT_POINT}"
     exit 1
     exit 1
-  fib
+  fi
 
 
   # Get info for this drive: $ID_FS_LABEL and $ID_FS_TYPE
   # Get info for this drive: $ID_FS_LABEL and $ID_FS_TYPE
   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")

+ 2 - 2
shell/usb-mount@.service

@@ -4,5 +4,5 @@ Description=Mount USB Drive on %i
 [Service]
 [Service]
 Type=oneshot
 Type=oneshot
 RemainAfterExit=true
 RemainAfterExit=true
-ExecStart=/oasis/util/shell/usb-mount.sh add %i
-ExecStop=/oasis/util/shell/usb-mount.sh remove %i
+ExecStart=/casaOS/util/shell/usb-mount.sh add %i
+ExecStop=/casaOS/util/shell/usb-mount.sh remove %i