mirror of
https://github.com/IceWhaleTech/CasaOS.git
synced 2025-06-16 05:55:33 +00:00
feat: Multiple updates
1.Add the function of modifying the WebUI port. 2.Add the function to modify the search engine. 3.Add the multi-language function and add Chinese translation. 4.Add detailed CPU and memory statistics.
This commit is contained in:
parent
997d912f4d
commit
6c235d3f2a
2
UI
2
UI
@ -1 +1 @@
|
|||||||
Subproject commit f7c46d7379ab31bc70a35900ef6a50f7f3c2ef4f
|
Subproject commit a982eb4bddafe0beaa629fcfef9581b8ef1eddf3
|
@ -2,8 +2,9 @@ package middleware
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Cors() gin.HandlerFunc {
|
func Cors() gin.HandlerFunc {
|
||||||
@ -17,7 +18,7 @@ func Cors() gin.HandlerFunc {
|
|||||||
//服务器支持的所有跨域请求的方法
|
//服务器支持的所有跨域请求的方法
|
||||||
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
|
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
|
||||||
//允许跨域设置可以返回其他子段,可以自定义字段
|
//允许跨域设置可以返回其他子段,可以自定义字段
|
||||||
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session")
|
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,Language")
|
||||||
// 允许浏览器(客户端)可以解析的头部 (重要)
|
// 允许浏览器(客户端)可以解析的头部 (重要)
|
||||||
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
|
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
|
||||||
//设置缓存时间
|
//设置缓存时间
|
||||||
|
@ -24,6 +24,7 @@ type LSBLKModel struct {
|
|||||||
Tran string `json:"tran"`
|
Tran string `json:"tran"`
|
||||||
MinIO uint64 `json:"min-io"`
|
MinIO uint64 `json:"min-io"`
|
||||||
UsedPercent float64 `json:"used_percent"`
|
UsedPercent float64 `json:"used_percent"`
|
||||||
|
Serial string `json:"serial"`
|
||||||
Children []LSBLKModel `json:"children"`
|
Children []LSBLKModel `json:"children"`
|
||||||
//详情特有
|
//详情特有
|
||||||
StartSector uint64 `json:"start_sector,omitempty"`
|
StartSector uint64 `json:"start_sector,omitempty"`
|
||||||
|
8
model/docker.go
Normal file
8
model/docker.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type DockerStatsModel struct {
|
||||||
|
Icon string `json:"icon"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
Pre interface{} `json:"pre"`
|
||||||
|
}
|
@ -68,3 +68,7 @@ type SystemConfig struct {
|
|||||||
SyncPort string `json:"sync_port"`
|
SyncPort string `json:"sync_port"`
|
||||||
SyncKey string `json:"sync_key"`
|
SyncKey string `json:"sync_key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CasaOSGlobalVariables struct {
|
||||||
|
AddApp bool
|
||||||
|
}
|
||||||
|
@ -33,6 +33,8 @@ var ServerInfo = &model.ServerModel{}
|
|||||||
|
|
||||||
var SystemConfigInfo = &model.SystemConfig{}
|
var SystemConfigInfo = &model.SystemConfig{}
|
||||||
|
|
||||||
|
var CasaOSGlobalVariables = &model.CasaOSGlobalVariables{}
|
||||||
|
|
||||||
var Cfg *ini.File
|
var Cfg *ini.File
|
||||||
|
|
||||||
//初始化设置,获取系统的部分信息。
|
//初始化设置,获取系统的部分信息。
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/IceWhaleTech/CasaOS/model/system_app"
|
"github.com/IceWhaleTech/CasaOS/model/system_app"
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/docker"
|
"github.com/IceWhaleTech/CasaOS/pkg/docker"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper"
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper"
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/port"
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/port"
|
||||||
@ -20,6 +21,7 @@ import (
|
|||||||
|
|
||||||
func InitFunction() {
|
func InitFunction() {
|
||||||
go checkSystemApp()
|
go checkSystemApp()
|
||||||
|
Update2_3()
|
||||||
}
|
}
|
||||||
|
|
||||||
var syncIsExistence = false
|
var syncIsExistence = false
|
||||||
@ -190,3 +192,10 @@ func checkSystemApp() {
|
|||||||
installSyncthing("44")
|
installSyncthing("44")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func CheckSerialDiskMount() {
|
||||||
|
// 检查挂载点重新挂载
|
||||||
|
// 检查新硬盘是否有多个分区,如有多个分区需提示
|
||||||
|
}
|
||||||
|
func Update2_3() {
|
||||||
|
command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/assist.sh")
|
||||||
|
}
|
||||||
|
@ -194,6 +194,7 @@ 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.GET("/port", v1.GetCasaOSPort)
|
||||||
v1SysGroup.PUT("/port", v1.PutCasaOSPort)
|
v1SysGroup.PUT("/port", v1.PutCasaOSPort)
|
||||||
v1SysGroup.POST("/kill", v1.PostKillCasaOS)
|
v1SysGroup.POST("/kill", v1.PostKillCasaOS)
|
||||||
}
|
}
|
||||||
@ -225,7 +226,7 @@ func InitRouter() *gin.Engine {
|
|||||||
v1DiskGroup.POST("/format", v1.FormatDisk)
|
v1DiskGroup.POST("/format", v1.FormatDisk)
|
||||||
|
|
||||||
//添加分区
|
//添加分区
|
||||||
v1DiskGroup.POST("/addpart", v1.AddPartition)
|
v1DiskGroup.POST("/part", v1.AddPartition)
|
||||||
|
|
||||||
//获取可以格式化的内容
|
//获取可以格式化的内容
|
||||||
v1DiskGroup.GET("/type", v1.FormatDiskType)
|
v1DiskGroup.GET("/type", v1.FormatDiskType)
|
||||||
@ -233,6 +234,12 @@ func InitRouter() *gin.Engine {
|
|||||||
//删除分区
|
//删除分区
|
||||||
v1DiskGroup.DELETE("/delpart", v1.RemovePartition)
|
v1DiskGroup.DELETE("/delpart", v1.RemovePartition)
|
||||||
|
|
||||||
|
//mount SATA disk
|
||||||
|
v1DiskGroup.POST("/mount", v1.PostMountDisk)
|
||||||
|
|
||||||
|
//umount SATA disk
|
||||||
|
v1DiskGroup.POST("/umount", v1.DeleteUmountDisk)
|
||||||
|
|
||||||
}
|
}
|
||||||
v1ShareGroup := v1Group.Group("/share")
|
v1ShareGroup := v1Group.Group("/share")
|
||||||
v1ShareGroup.Use()
|
v1ShareGroup.Use()
|
||||||
|
@ -2,7 +2,6 @@ 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"
|
||||||
@ -110,15 +109,9 @@ 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)})
|
||||||
}
|
}
|
||||||
|
|
||||||
//删除挂载点
|
|
||||||
service.MyService.Disk().UmountPointAndRemoveDir(path)
|
|
||||||
|
|
||||||
//格式化磁盘
|
//格式化磁盘
|
||||||
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)})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,25 +148,43 @@ func RemovePartition(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 添加分区
|
// @Summary serial number
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Accept multipart/form-data
|
// @Accept multipart/form-data
|
||||||
// @Tags disk
|
// @Tags disk
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Param path formData string true "磁盘路径 例如/dev/sda"
|
// @Param path formData string true "磁盘路径 例如/dev/sda"
|
||||||
// @Param size formData string true "需要分区容量大小(MB)"
|
// @Param serial formData string true "serial"
|
||||||
// @Param num formData string true "磁盘符号"
|
|
||||||
// @Success 200 {string} string "ok"
|
// @Success 200 {string} string "ok"
|
||||||
// @Router /disk/addpart [post]
|
// @Router /disk/addpart [post]
|
||||||
func AddPartition(c *gin.Context) {
|
func AddPartition(c *gin.Context) {
|
||||||
path := c.PostForm("path")
|
path := c.PostForm("path")
|
||||||
size, _ := strconv.Atoi(c.DefaultPostForm("size", "0"))
|
serial := c.PostForm("serial")
|
||||||
num := c.DefaultPostForm("num", "9")
|
if len(path) == 0 || len(serial) == 0 {
|
||||||
if len(path) == 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().AddPartition(path)
|
||||||
//size*1024*1024/512
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||||
service.MyService.Disk().AddPartition(path, num, uint64(size*1024*2))
|
}
|
||||||
|
|
||||||
|
func PostMountDisk(c *gin.Context) {
|
||||||
|
// for example: path=/dev/sda1
|
||||||
|
path := c.PostForm("path")
|
||||||
|
//执行挂载目录
|
||||||
|
service.MyService.Disk().MountDisk(path, "volume")
|
||||||
|
//添加到数据库
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteUmountDisk(c *gin.Context) {
|
||||||
|
|
||||||
|
// for example: path=/dev/sda1
|
||||||
|
path := c.PostForm("path")
|
||||||
|
service.MyService.Disk().UmountPointAndRemoveDir(path)
|
||||||
|
|
||||||
|
//删除数据库记录
|
||||||
|
|
||||||
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)})
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/IceWhaleTech/CasaOS/model"
|
"github.com/IceWhaleTech/CasaOS/model"
|
||||||
|
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/docker"
|
"github.com/IceWhaleTech/CasaOS/pkg/docker"
|
||||||
upnp2 "github.com/IceWhaleTech/CasaOS/pkg/upnp"
|
upnp2 "github.com/IceWhaleTech/CasaOS/pkg/upnp"
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||||
@ -420,9 +421,12 @@ func InstallApp(c *gin.Context) {
|
|||||||
rely := model.MapStrings{}
|
rely := model.MapStrings{}
|
||||||
|
|
||||||
copier.Copy(&rely, &relyMap)
|
copier.Copy(&rely, &relyMap)
|
||||||
for i := 0; i < len(m.Volumes); i++ {
|
if m.Origin != "custom" {
|
||||||
m.Volumes[i].Path = docker.GetDir(id, m.Volumes[i].ContainerPath)
|
for i := 0; i < len(m.Volumes); i++ {
|
||||||
|
m.Volumes[i].Path = docker.GetDir(id, m.Volumes[i].ContainerPath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
portsStr, _ := json2.Marshal(m.Ports)
|
portsStr, _ := json2.Marshal(m.Ports)
|
||||||
envsStr, _ := json2.Marshal(m.Envs)
|
envsStr, _ := json2.Marshal(m.Envs)
|
||||||
volumesStr, _ := json2.Marshal(m.Volumes)
|
volumesStr, _ := json2.Marshal(m.Volumes)
|
||||||
@ -462,6 +466,7 @@ func InstallApp(c *gin.Context) {
|
|||||||
// m.PortMap = m.Port
|
// m.PortMap = m.Port
|
||||||
//}
|
//}
|
||||||
service.MyService.App().SaveContainer(md)
|
service.MyService.App().SaveContainer(md)
|
||||||
|
config.CasaOSGlobalVariables.AddApp = true
|
||||||
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -137,14 +137,30 @@ func PostSetWidgetConfig(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Summary get casaos server port
|
||||||
|
// @Produce application/json
|
||||||
|
// @Accept application/json
|
||||||
|
// @Tags sys
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Success 200 {string} string "ok"
|
||||||
|
// @Router /sys/port [get]
|
||||||
|
func GetCasaOSPort(c *gin.Context) {
|
||||||
|
c.JSON(http.StatusOK,
|
||||||
|
model.Result{
|
||||||
|
Success: oasis_err.SUCCESS,
|
||||||
|
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
|
||||||
|
Data: config.ServerInfo.HttpPort,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// @Summary edit casaos server port
|
// @Summary edit casaos server port
|
||||||
// @Produce application/json
|
// @Produce application/json
|
||||||
// @Accept application/json
|
// @Accept application/json
|
||||||
// @Tags sys
|
// @Tags sys
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Param port formData file true "用户头像"
|
// @Param port formData string true "port"
|
||||||
// @Success 200 {string} string "ok"
|
// @Success 200 {string} string "ok"
|
||||||
// @Router /sys/widget/config [post]
|
// @Router /sys/port [put]
|
||||||
func PutCasaOSPort(c *gin.Context) {
|
func PutCasaOSPort(c *gin.Context) {
|
||||||
port, err := strconv.Atoi(c.PostForm("port"))
|
port, err := strconv.Atoi(c.PostForm("port"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
144
service/app.go
144
service/app.go
@ -2,12 +2,15 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/IceWhaleTech/CasaOS/model"
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||||
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||||
@ -16,7 +19,6 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,7 +33,9 @@ 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
|
GetHardwareUsageSteam()
|
||||||
|
GetHardwareUsage() []model.DockerStatsModel
|
||||||
|
GetAppStats(id string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
type appStruct struct {
|
type appStruct struct {
|
||||||
@ -158,7 +162,6 @@ func (a *appStruct) GetSystemAppList() *[]model2.MyAppList {
|
|||||||
//Rely: m.Rely,
|
//Rely: m.Rely,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &list
|
return &list
|
||||||
@ -237,57 +240,108 @@ 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 map[string]model.DockerStatsModel
|
||||||
|
|
||||||
var dataStr []string
|
var isFinish bool = false
|
||||||
|
|
||||||
|
func (a *appStruct) GetAppStats(id string) string {
|
||||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return dataStr
|
return ""
|
||||||
|
}
|
||||||
|
defer cli.Close()
|
||||||
|
con, err := cli.ContainerStats(context.Background(), id, false)
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
defer con.Body.Close()
|
||||||
|
c, _ := ioutil.ReadAll(con.Body)
|
||||||
|
return string(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *appStruct) GetHardwareUsage() []model.DockerStatsModel {
|
||||||
|
|
||||||
|
steam := true
|
||||||
|
for !isFinish {
|
||||||
|
if steam {
|
||||||
|
steam = false
|
||||||
|
go func() {
|
||||||
|
a.GetHardwareUsageSteam()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
// 切一下,再次分配任务
|
||||||
|
runtime.Gosched()
|
||||||
|
}
|
||||||
|
list := []model.DockerStatsModel{}
|
||||||
|
for _, v := range dataStr {
|
||||||
|
list = append(list, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return list
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *appStruct) GetHardwareUsageSteam() {
|
||||||
|
var lock = &sync.Mutex{}
|
||||||
|
if len(dataStr) == 0 {
|
||||||
|
lock.Lock()
|
||||||
|
dataStr = make(map[string]model.DockerStatsModel)
|
||||||
|
lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
lock := &sync.Mutex{}
|
ctx := context.Background()
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
var lm []model2.AppListDBModel
|
var lm []model2.AppListDBModel
|
||||||
var count = 0
|
a.db.Table(model2.CONTAINERTABLENAME).Select("label,icon,container_id").Where("origin != ?", "system").Find(&lm)
|
||||||
a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,container_id").Find(&lm)
|
var list []types.ContainerStats
|
||||||
for _, v := range lm {
|
for i := 0; i < 100; i++ {
|
||||||
go func(lock *sync.Mutex, id, title, icon string) {
|
if config.CasaOSGlobalVariables.AddApp {
|
||||||
stats, err := cli.ContainerStats(context.Background(), id, false)
|
a.db.Table(model2.CONTAINERTABLENAME).Select("label,icon,container_id").Where("origin != ?", "system").Find(&lm)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
var wg sync.WaitGroup
|
||||||
return dataStr
|
for _, v := range lm {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(v model2.AppListDBModel, lock *sync.Mutex) {
|
||||||
|
defer wg.Done()
|
||||||
|
stats, err := cli.ContainerStats(ctx, v.ContainerId, true)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
decode := json.NewDecoder(stats.Body)
|
||||||
|
var data interface{}
|
||||||
|
if err := decode.Decode(&data); err == io.EOF {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lock.Lock()
|
||||||
|
dockerStats := model.DockerStatsModel{}
|
||||||
|
dockerStats.Pre = dataStr[v.ContainerId].Data
|
||||||
|
|
||||||
|
dockerStats.Data = data
|
||||||
|
dockerStats.Icon = v.Icon
|
||||||
|
dockerStats.Title = v.Label
|
||||||
|
dataStr[v.ContainerId] = dockerStats
|
||||||
|
lock.Unlock()
|
||||||
|
}(v, lock)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
isFinish = true
|
||||||
|
if i == 99 {
|
||||||
|
for _, v := range list {
|
||||||
|
v.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
|
}
|
||||||
|
isFinish = false
|
||||||
|
cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
// init install
|
// init install
|
||||||
|
@ -10,8 +10,10 @@ import (
|
|||||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||||
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||||
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||||
|
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||||
"github.com/shirou/gopsutil/v3/disk"
|
"github.com/shirou/gopsutil/v3/disk"
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DiskService interface {
|
type DiskService interface {
|
||||||
@ -21,11 +23,14 @@ type DiskService interface {
|
|||||||
UmountPointAndRemoveDir(path string) string
|
UmountPointAndRemoveDir(path string) string
|
||||||
GetDiskInfo(path string) model.LSBLKModel
|
GetDiskInfo(path string) model.LSBLKModel
|
||||||
DelPartition(path, num string) string
|
DelPartition(path, num string) string
|
||||||
AddPartition(path, num string, size uint64) string
|
AddPartition(path string) string
|
||||||
GetDiskInfoByPath(path string) *disk.UsageStat
|
GetDiskInfoByPath(path string) *disk.UsageStat
|
||||||
|
MountDisk(path, volume string)
|
||||||
|
SerialAll(mountPoint string) *[]model2.SerialDisk
|
||||||
}
|
}
|
||||||
type diskService struct {
|
type diskService struct {
|
||||||
log loger2.OLog
|
log loger2.OLog
|
||||||
|
db *gorm.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
//通过脚本获取外挂磁盘
|
//通过脚本获取外挂磁盘
|
||||||
@ -55,28 +60,17 @@ func (d *diskService) DelPartition(path, num string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
//添加分区
|
//part
|
||||||
func (d *diskService) AddPartition(path, num string, size uint64) string {
|
func (d *diskService) AddPartition(path string) string {
|
||||||
|
r := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;AddPartition " + path)
|
||||||
var maxSector uint64 = 0
|
|
||||||
|
|
||||||
chiList := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetPartitionSectors " + path)
|
|
||||||
if len(chiList) == 0 {
|
|
||||||
d.log.Error("chiList length error")
|
|
||||||
}
|
|
||||||
for i := 0; i < len(chiList); i++ {
|
|
||||||
tempArr := strings.Split(chiList[i], ",")
|
|
||||||
tempSector, _ := strconv.ParseUint(tempArr[2], 10, 64)
|
|
||||||
if tempSector > maxSector {
|
|
||||||
maxSector = tempSector
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
r := command2.ExecResultStrArray("source ./shell/helper.sh ;AddPartition " + path + " " + num + " " + strconv.FormatUint(maxSector+1, 10) + " " + strconv.FormatUint(size+maxSector+1, 10))
|
|
||||||
fmt.Println(r)
|
fmt.Println(r)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *diskService) AddAllPartition(path string) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//获取硬盘详情
|
//获取硬盘详情
|
||||||
func (d *diskService) GetDiskInfoByPath(path string) *disk.UsageStat {
|
func (d *diskService) GetDiskInfoByPath(path string) *disk.UsageStat {
|
||||||
diskInfo, err := disk.Usage(path + "1")
|
diskInfo, err := disk.Usage(path + "1")
|
||||||
@ -111,7 +105,7 @@ func (d *diskService) LSBLK() []model.LSBLKModel {
|
|||||||
|
|
||||||
var health = true
|
var health = true
|
||||||
for _, i := range m {
|
for _, i := range m {
|
||||||
if i.Type != "loop" {
|
if i.Type != "loop" && !i.RO {
|
||||||
fsused = 0
|
fsused = 0
|
||||||
for _, child := range i.Children {
|
for _, child := range i.Children {
|
||||||
if child.RM {
|
if child.RM {
|
||||||
@ -197,17 +191,21 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
//func GetDiskInfo(path string) *disk.UsageStat {
|
func (d *diskService) MountDisk(path, volume string) {
|
||||||
// diskInfo, _ := disk.Usage(path)
|
r := command2.ExecResultStr("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;do_mount " + path + " " + volume)
|
||||||
// diskInfo.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.UsedPercent), 64)
|
fmt.Print(r)
|
||||||
// diskInfo.InodesUsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.InodesUsedPercent), 64)
|
}
|
||||||
// return diskInfo
|
|
||||||
//}
|
func (d *diskService) SaveMountPoint(m model2.SerialDisk) {
|
||||||
|
d.db.Save(&m)
|
||||||
//func (d *diskService) GetPlugInDisk() []string {
|
}
|
||||||
// return disk.Partitions(false)
|
|
||||||
//}
|
func (d *diskService) SerialAll(mountPoint string) *[]model2.SerialDisk {
|
||||||
|
var m []model2.SerialDisk
|
||||||
func NewDiskService(log loger2.OLog) DiskService {
|
d.db.Find(&m)
|
||||||
return &diskService{log: log}
|
return &m
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDiskService(log loger2.OLog, db *gorm.DB) DiskService {
|
||||||
|
return &diskService{log: log, db: db}
|
||||||
}
|
}
|
||||||
|
@ -26,14 +26,10 @@ type AppListDBModel struct {
|
|||||||
PortMap string `json:"port_map"`
|
PortMap string `json:"port_map"`
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
EnableUPNP bool `json:"enable_upnp"`
|
EnableUPNP bool `json:"enable_upnp"`
|
||||||
//Envs model.EnvArrey `json:"envs" bson:"envs"`
|
Envs string `json:"envs"`
|
||||||
//Ports model.PortArrey `json:"ports" bson:"ports"`
|
Ports string `json:"ports"`
|
||||||
//Volumes model.PathArrey `json:"volumes" bson:"volumes"`
|
Volumes string `json:"volumes"`
|
||||||
//Devices model.PathArrey `json:"devices" bson:"devices"`
|
Devices string `json:"devices"`
|
||||||
Envs string `json:"envs"`
|
|
||||||
Ports string `json:"ports"`
|
|
||||||
Volumes string `json:"volumes"`
|
|
||||||
Devices string `json:"devices"`
|
|
||||||
//Envs []model.Env `json:"envs"`
|
//Envs []model.Env `json:"envs"`
|
||||||
//Ports []model.PortMap `gorm:"type:json" json:"ports"`
|
//Ports []model.PortMap `gorm:"type:json" json:"ports"`
|
||||||
//Volumes []model.PathMap `gorm:"type:json" json:"volumes"`
|
//Volumes []model.PathMap `gorm:"type:json" json:"volumes"`
|
||||||
|
14
service/model/o_disk.go
Normal file
14
service/model/o_disk.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
//SerialAdvanced Technology Attachment (STAT)
|
||||||
|
type SerialDisk struct {
|
||||||
|
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||||
|
DiskId string `json:"disk_id"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
State int `json:"state"`
|
||||||
|
MountPoint string `json:"mount_point"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SerialDisk) TableName() string {
|
||||||
|
return "o_disk"
|
||||||
|
}
|
@ -40,7 +40,7 @@ func NewService(db *gorm.DB, log loger2.OLog) Repository {
|
|||||||
zerotier: NewZeroTierService(),
|
zerotier: NewZeroTierService(),
|
||||||
zima: NewZiMaService(),
|
zima: NewZiMaService(),
|
||||||
oapi: NewOasisService(),
|
oapi: NewOasisService(),
|
||||||
disk: NewDiskService(log),
|
disk: NewDiskService(log, db),
|
||||||
notify: NewNotifyService(db),
|
notify: NewNotifyService(db),
|
||||||
shareDirectory: NewShareDirService(db, log),
|
shareDirectory: NewShareDirService(db, log),
|
||||||
task: NewTaskService(db, log),
|
task: NewTaskService(db, log),
|
||||||
|
@ -1,25 +1,12 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
#update to v0.2.3
|
#add in v0.2.3
|
||||||
version_0_2_3(){
|
version_0_2_3() {
|
||||||
((EUID)) && sudo_cmd="sudo"
|
((EUID)) && sudo_cmd="sudo"
|
||||||
|
$sudo_cmd cp -rf /casaOS/server/shell/11-usb-mount.rules /etc/udev/rules.d/
|
||||||
#copy file to path
|
$sudo_cmd chmod +x /casaOS/server/shell/usb-mount.sh
|
||||||
if [ ! -s "/etc/udev/rules.d/11-usb-mount.rules" ]; then
|
$sudo_cmd cp -rf /casaOS/server/shell/usb-mount@.service /etc/systemd/system/
|
||||||
$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
|
version_0_2_3
|
||||||
|
100
shell/helper.sh
100
shell/helper.sh
@ -103,20 +103,22 @@ DelPartition() {
|
|||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
#添加分区
|
#添加分区只有一个分区
|
||||||
#param 路径 /dev/sdb
|
#param 路径 /dev/sdb
|
||||||
#param 磁盘号 最大128
|
#param 要挂载的目录
|
||||||
#param 磁盘大小 字节 512*2048=1024kb=1M
|
|
||||||
AddPartition() {
|
AddPartition() {
|
||||||
# fdisk $1 <<EOF
|
|
||||||
# n
|
|
||||||
# $2
|
|
||||||
# $3
|
|
||||||
# $4
|
|
||||||
# wq
|
|
||||||
#EOF
|
|
||||||
|
|
||||||
parted $1 mkpart primary ext4 s3 s4
|
DelPartition $1
|
||||||
|
parted -s $1 mklabel gpt
|
||||||
|
|
||||||
|
parted -s $1 mkpart primary ext4 0 100%
|
||||||
|
|
||||||
|
mkfs.ext4 $11
|
||||||
|
|
||||||
|
partprobe $1
|
||||||
|
|
||||||
|
# mount $11 $2
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#磁盘类型
|
#磁盘类型
|
||||||
@ -151,7 +153,83 @@ GetPartitionSectors() {
|
|||||||
fdisk $1 -l | grep "/dev/sda[1-9]" | awk 'BEGIN{OFS=","}{print $1,$2,$3,$4}'
|
fdisk $1 -l | grep "/dev/sda[1-9]" | awk 'BEGIN{OFS=","}{print $1,$2,$3,$4}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#检查没有使用的挂载点删除文件夹
|
||||||
|
AutoRemoveUnuseDir() {
|
||||||
|
DIRECTORY="/mnt/"
|
||||||
|
dir=$(ls -l $DIRECTORY | awk '/^d/ {print $NF}')
|
||||||
|
for i in $dir; do
|
||||||
|
|
||||||
|
path="$DIRECTORY$i"
|
||||||
|
mountStr=$(mountpoint $path)
|
||||||
|
notMountpoint="is not a mountpoint"
|
||||||
|
if [[ $mountStr =~ $notMountpoint ]]; then
|
||||||
|
if [ "$(ls -A $path)" = "" ]; then
|
||||||
|
rm -fr $path
|
||||||
|
else
|
||||||
|
echo "$path is not empty"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
#重载samba服务
|
#重载samba服务
|
||||||
ReloadSamba() {
|
ReloadSamba() {
|
||||||
/etc/init.d/smbd reload
|
/etc/init.d/smbd reload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# $1=sda1
|
||||||
|
# $2=volume{1}
|
||||||
|
do_mount() {
|
||||||
|
DEVBASE=$1
|
||||||
|
DEVICE="${DEVBASE}"
|
||||||
|
# See if this drive is already mounted, and if so where
|
||||||
|
MOUNT_POINT=$(mount | grep ${DEVICE} | awk '{ print $3 }')
|
||||||
|
|
||||||
|
if [ -n "${MOUNT_POINT}" ]; then
|
||||||
|
${log} "Warning: ${DEVICE} is already mounted at ${MOUNT_POINT}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 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")
|
||||||
|
|
||||||
|
LABEL=$2
|
||||||
|
if grep -q " /media/${LABEL} " /etc/mtab; then
|
||||||
|
# Already in use, make a unique one
|
||||||
|
LABEL+="-${DEVBASE}"
|
||||||
|
fi
|
||||||
|
DEV_LABEL="${LABEL}"
|
||||||
|
|
||||||
|
# Use the device name in case the drive doesn't have label
|
||||||
|
if [ -z ${DEV_LABEL} ]; then
|
||||||
|
DEV_LABEL="${DEVBASE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
MOUNT_POINT="/media/${DEV_LABEL}"
|
||||||
|
|
||||||
|
${log} "Mount point: ${MOUNT_POINT}"
|
||||||
|
|
||||||
|
mkdir -p ${MOUNT_POINT}
|
||||||
|
|
||||||
|
case ${ID_FS_TYPE} in
|
||||||
|
vfat)
|
||||||
|
mount -t vfat -o rw,relatime,users,gid=100,umask=000,shortname=mixed,utf8=1,flush ${DEVICE} ${MOUNT_POINT}
|
||||||
|
;;
|
||||||
|
ext[2-4])
|
||||||
|
mount -o noatime ${DEVICE} ${MOUNT_POINT} >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
exfat)
|
||||||
|
mount -t exfat ${DEVICE} ${MOUNT_POINT} >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
ntfs)
|
||||||
|
ntfs-3g ${DEVICE} ${MOUNT_POINT}
|
||||||
|
;;
|
||||||
|
iso9660)
|
||||||
|
mount -t iso9660 ${DEVICE} ${MOUNT_POINT}
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
/bin/rmdir "${MOUNT_POINT}"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
@ -99,13 +99,13 @@ update() {
|
|||||||
target_arch="386"
|
target_arch="386"
|
||||||
;;
|
;;
|
||||||
*armv5*)
|
*armv5*)
|
||||||
target_arch="armv5"
|
target_arch="arm-5"
|
||||||
;;
|
;;
|
||||||
*armv6*)
|
*armv6*)
|
||||||
target_arch="armv6"
|
target_arch="arm-6"
|
||||||
;;
|
;;
|
||||||
*armv7*)
|
*armv7*)
|
||||||
target_arch="armv7"
|
target_arch="arm-7"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
show 1 "Aborted, unsupported or unknown architecture: $unamem"
|
show 1 "Aborted, unsupported or unknown architecture: $unamem"
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
log="logger -t usb-mount.sh -s "
|
log="logger -t usb-mount.sh -s "
|
||||||
|
|
||||||
${log} "变量:$1 $2"
|
|
||||||
|
|
||||||
ACTION=$1
|
ACTION=$1
|
||||||
|
|
||||||
DEVBASE=$2
|
DEVBASE=$2
|
||||||
@ -33,7 +31,7 @@ do_mount() {
|
|||||||
# Figure out a mount point to use
|
# Figure out a mount point to use
|
||||||
# LABEL=${ID_FS_LABEL}
|
# LABEL=${ID_FS_LABEL}
|
||||||
LABEL=${DEVBASE}
|
LABEL=${DEVBASE}
|
||||||
if grep -q " /media/${LABEL} " /etc/mtab; then
|
if grep -q " /mnt/casa_${LABEL} " /etc/mtab; then
|
||||||
# Already in use, make a unique one
|
# Already in use, make a unique one
|
||||||
LABEL+="-${DEVBASE}"
|
LABEL+="-${DEVBASE}"
|
||||||
fi
|
fi
|
||||||
@ -44,7 +42,7 @@ do_mount() {
|
|||||||
DEV_LABEL="${DEVBASE}"
|
DEV_LABEL="${DEVBASE}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
MOUNT_POINT="/media/${DEV_LABEL}"
|
MOUNT_POINT="/mnt/casa_${DEV_LABEL}"
|
||||||
|
|
||||||
${log} "Mount point: ${MOUNT_POINT}"
|
${log} "Mount point: ${MOUNT_POINT}"
|
||||||
|
|
||||||
|
@ -4,5 +4,5 @@ Description=Mount USB Drive on %i
|
|||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
RemainAfterExit=true
|
RemainAfterExit=true
|
||||||
ExecStart=/casaOS/util/shell/usb-mount.sh add %i
|
ExecStart=/casaOS/server/shell/usb-mount.sh add %i
|
||||||
ExecStop=/casaOS/util/shell/usb-mount.sh remove %i
|
ExecStop=/casaOS/server/shell/usb-mount.sh remove %i
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
const CURRENTVERSION = "0.2.2"
|
const CURRENTVERSION = "0.2.3"
|
||||||
const BODY = "<li>ui adjustment</li><li>fixed bugs</li>"
|
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>"
|
||||||
|
11
web/img/add_button.76237e85.svg
Normal file
11
web/img/add_button.76237e85.svg
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect opacity="0.32" x="0.435625" y="0.435625" width="71.1288" height="71.1288" rx="7.56437" fill="white" stroke="url(#paint0_linear_812_2050)" stroke-width="0.87125"/>
|
||||||
|
<path d="M36.0606 22L36.0239 50" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M22 36H50" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="paint0_linear_812_2050" x1="77.6757" y1="64.5405" x2="35.9839" y2="53.5747" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#CBEFFF" stop-opacity="0.16"/>
|
||||||
|
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 752 B |
325
web/js/2.js
325
web/js/2.js
File diff suppressed because one or more lines are too long
10
web/js/3.js
10
web/js/3.js
File diff suppressed because one or more lines are too long
10
web/js/4.js
10
web/js/4.js
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user