Compare commits

...

14 Commits

Author SHA1 Message Date
link
8df63c6c5c Merge pull request #60 from IceWhaleTech/dev
New App Store
2021-12-29 16:42:56 +08:00
link
1d17d27c96 New App Store 2021-12-29 16:42:20 +08:00
John Guan
bdcbae69a5 Update README.md 2021-12-14 11:41:42 +08:00
John Guan
cdbc3437be Update README.md 2021-12-14 10:40:17 +08:00
link
8940b520e0 Merge pull request #53 from IceWhaleTech/dev
update ui
2021-12-11 15:44:55 +08:00
link
1d62fbd670 update ui 2021-12-11 15:44:17 +08:00
link
a0b56d809e Merge pull request #52 from IceWhaleTech/dev
update cpu changes when the application is removed
2021-12-10 18:08:49 +08:00
link
f1f6d33e26 update cpu changes when the application is removed 2021-12-10 18:08:02 +08:00
link
f292edd2ba Merge pull request #51 from IceWhaleTech/dev
update app.go
2021-12-10 17:14:46 +08:00
link
caa9b50b65 update app.go 2021-12-10 17:14:01 +08:00
link
61b824065b Merge pull request #50 from IceWhaleTech/dev
update stats steam
2021-12-10 16:34:29 +08:00
link
9a900b2ca0 update stats steam 2021-12-10 16:33:39 +08:00
link
4c1cbc98a4 Merge pull request #49 from IceWhaleTech/dev
fixed bug
2021-12-10 14:18:01 +08:00
link
8660b95756 fixed bug 2021-12-10 14:17:36 +08:00
27 changed files with 733 additions and 270 deletions

View File

@@ -6,7 +6,7 @@
[![Pull Requests](https://img.shields.io/github/issues-pr/IceWhaleTech/CasaOS?color=162453&style=flat-square)](https://github.com/IceWhaleTech/CasaOS/pulls) [![Pull Requests](https://img.shields.io/github/issues-pr/IceWhaleTech/CasaOS?color=162453&style=flat-square)](https://github.com/IceWhaleTech/CasaOS/pulls)
[![Issues](https://img.shields.io/github/issues/IceWhaleTech/CasaOS?color=162453&style=flat-square)](https://github.com/IceWhaleTech/CasaOS/issues) [![Issues](https://img.shields.io/github/issues/IceWhaleTech/CasaOS?color=162453&style=flat-square)](https://github.com/IceWhaleTech/CasaOS/issues)
[![GitHub Stars](https://img.shields.io/github/stars/IceWhaleTech/CasaOS?color=162453&logo=github&style=flat-square)](https://github.com/IceWhaleTech/CasaOS/stargazers) [![GitHub Stars](https://img.shields.io/github/stars/IceWhaleTech/CasaOS?color=162453&logo=github&style=flat-square)](https://github.com/IceWhaleTech/CasaOS/stargazers)
[![Discord](https://img.shields.io/discord/884667213326463016?color=162453&label=Chat&logo=discord&logoColor=fff&style=flat-square)](https://discord.gg/Gx4BCEtHjx) [![Discord](https://img.shields.io/discord/884667213326463016?color=162453&label=Chat&logo=discord&logoColor=fff&style=flat-square)](https://discord.gg/knqAbbBbeX)
CasaOS is an open-source Home Cloud system based on the Docker ecosystem and designed for home scenarios. It is committed to building the world's most simple, easy-to-use, and elegant Home Cloud system. CasaOS is an open-source Home Cloud system based on the Docker ecosystem and designed for home scenarios. It is committed to building the world's most simple, easy-to-use, and elegant Home Cloud system.
@@ -19,7 +19,7 @@ IceWhale team believes that through community-driven collaborative innovation an
> ⚠️ Note: > ⚠️ Note:
> >
> CasaOS is still in the early development stage and may vary significantly with the final release. Feel free to test run and share your feedback in the [Discord server](https://discord.gg/Gx4BCEtHjx)! > CasaOS is still in the early development stage and may vary significantly with the final release. Feel free to test run and share your feedback in the [Discord server](https://discord.gg/knqAbbBbeX)!
### Quick Setup CasaOS ### Quick Setup CasaOS
@@ -71,9 +71,9 @@ After looking at many systems and software on the market, the team found no serv
So, we set out to build this open source project to develop CasaOS with our own hands, everyone in the community, and you. So, we set out to build this open source project to develop CasaOS with our own hands, everyone in the community, and you.
> A warm welcome for you to share and discuss your great ideas in the [Discord server](https://discord.gg/Gx4BCEtHjx)! > A warm welcome for you to share and discuss your great ideas in the [Discord server](https://discord.gg/knqAbbBbeX)!
[![Discord Card](https://discordapp.com/api/guilds/884667213326463016/widget.png?style=banner2)](https://discord.gg/Gx4BCEtHjx) [![Discord Card](https://discordapp.com/api/guilds/884667213326463016/widget.png?style=banner2)](https://discord.gg/knqAbbBbeX)

2
UI

Submodule UI updated: a982eb4bdd...f3088b6354

View File

@@ -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 {

View File

@@ -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"`
} }

View File

@@ -70,5 +70,5 @@ type SystemConfig struct {
} }
type CasaOSGlobalVariables struct { type CasaOSGlobalVariables struct {
AddApp bool AppChange bool
} }

View File

@@ -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 { if strings.Contains(envName, "$AppID") && len(id) > 0 {
id = "$AppID" return strings.ReplaceAll(envName, "$AppID", id)
} }
return envName
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
} }

View File

@@ -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)
} }

View File

@@ -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

View File

@@ -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", ""))
} }

View File

@@ -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")

View File

@@ -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()

View File

@@ -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) for i := 0; i < len(community); i++ {
data["count"] = count ct, _ := service.MyService.Docker().DockerListByImage(community[i].Image, community[i].ImageVersion)
data["items"] = list 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 { // if len(info.Tip) > 0 {
info.Tip = env_helper.ReplaceStringDefaultENV(info.Tip) // 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})
} }

View File

@@ -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() list := service.MyService.Disk().LSBLK()
//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))
//}
lst := service.MyService.Disk().LSBLK() c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: list})
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: lst})
} }
// @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")
//执行挂载目录 serial := c.PostForm("serial")
service.MyService.Disk().MountDisk(path, "volume")
//添加到数据库
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)})
} }

View File

@@ -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" { // if m.Origin != "custom" {
for i := 0; i < len(m.Volumes); i++ { // for i := 0; i < len(m.Volumes); i++ {
m.Volumes[i].Path = docker.GetDir(id, m.Volumes[i].ContainerPath) // 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)
@@ -466,7 +476,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 config.CasaOSGlobalVariables.AppChange = true
}() }()
@@ -743,7 +753,7 @@ func UnInstallApp(c *gin.Context) {
// } // }
//} //}
} }
config.CasaOSGlobalVariables.AppChange = true
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)})
} }

View File

@@ -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
}

View File

@@ -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})
}

View File

@@ -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

View File

@@ -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) // info, err := cli.ContainerInspect(context.Background(), container.ID)
var tm string // var tm string
if err != nil { // if err != nil {
tm = time.Now().String() // tm = time.Now().String()
} else { // } else {
tm = info.State.StartedAt // 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, //UpTime: tm,
Image: m.Image, Image: m.Image,
Slogan: m.Slogan, 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 {
@@ -240,7 +240,7 @@ 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{})
} }
var dataStr map[string]model.DockerStatsModel var dataStats sync.Map
var isFinish bool = false var isFinish bool = false
@@ -269,25 +269,19 @@ func (a *appStruct) GetHardwareUsage() []model.DockerStatsModel {
a.GetHardwareUsageSteam() a.GetHardwareUsageSteam()
}() }()
} }
// 切一下,再次分配任务
runtime.Gosched() runtime.Gosched()
} }
list := []model.DockerStatsModel{} list := []model.DockerStatsModel{}
for _, v := range dataStr {
list = append(list, v)
}
dataStats.Range(func(key, value interface{}) bool {
list = append(list, value.(model.DockerStatsModel))
return true
})
return list return list
} }
func (a *appStruct) GetHardwareUsageSteam() { 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) cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil { if err != nil {
@@ -299,16 +293,28 @@ func (a *appStruct) GetHardwareUsageSteam() {
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
var lm []model2.AppListDBModel var lm []model2.AppListDBModel
a.db.Table(model2.CONTAINERTABLENAME).Select("label,icon,container_id").Where("origin != ?", "system").Find(&lm) a.db.Table(model2.CONTAINERTABLENAME).Select("label,title,icon,container_id").Where("origin != ?", "system").Find(&lm)
var list []types.ContainerStats
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
if config.CasaOSGlobalVariables.AddApp { if config.CasaOSGlobalVariables.AppChange {
a.db.Table(model2.CONTAINERTABLENAME).Select("label,icon,container_id").Where("origin != ?", "system").Find(&lm) lm = []model2.AppListDBModel{}
config.CasaOSGlobalVariables.AppChange = false
a.db.Table(model2.CONTAINERTABLENAME).Select("label,title,icon,container_id").Where("origin != ?", "system").Find(&lm)
dataApps := dataStats
dataStats.Range(func(key, value interface{}) bool {
dataStats.Delete(key)
return true
})
for _, v := range lm {
m, _ := dataApps.Load(v.ContainerId)
if m != nil {
dataStats.Store(v.ContainerId, m)
}
}
} }
var wg sync.WaitGroup var wg sync.WaitGroup
for _, v := range lm { for _, v := range lm {
wg.Add(1) wg.Add(1)
go func(v model2.AppListDBModel, lock *sync.Mutex) { go func(v model2.AppListDBModel, i int) {
defer wg.Done() defer wg.Done()
stats, err := cli.ContainerStats(ctx, v.ContainerId, true) stats, err := cli.ContainerStats(ctx, v.ContainerId, true)
if err != nil { if err != nil {
@@ -319,37 +325,32 @@ func (a *appStruct) GetHardwareUsageSteam() {
if err := decode.Decode(&data); err == io.EOF { if err := decode.Decode(&data); err == io.EOF {
return return
} }
lock.Lock() m, _ := dataStats.Load(v.ContainerId)
dockerStats := model.DockerStatsModel{} dockerStats := model.DockerStatsModel{}
dockerStats.Pre = dataStr[v.ContainerId].Data if m != nil {
dockerStats.Pre = m.(model.DockerStatsModel).Data
}
dockerStats.Data = data dockerStats.Data = data
dockerStats.Icon = v.Icon dockerStats.Icon = v.Icon
dockerStats.Title = v.Label if len(v.Label) > 0 {
dataStr[v.ContainerId] = dockerStats dockerStats.Title = v.Label
lock.Unlock() } else {
}(v, lock) dockerStats.Title = v.Title
}
dataStats.Store(v.ContainerId, dockerStats)
if i == 99 {
stats.Body.Close()
}
}(v, i)
} }
wg.Wait() wg.Wait()
isFinish = true isFinish = true
if i == 99 { time.Sleep(time.Second * 3)
for _, v := range list {
v.Body.Close()
}
}
time.Sleep(time.Second * 2)
} }
isFinish = false isFinish = false
cancel() cancel()
} }
// init install
func Init() {
}
func NewAppService(db *gorm.DB, logger loger2.OLog) AppService { func NewAppService(db *gorm.DB, logger loger2.OLog) AppService {
Init()
return &appStruct{db: db, log: logger} return &appStruct{db: db, log: logger}
} }

View File

@@ -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() if len(list) > 0 {
json2.Unmarshal([]byte(gjson.Get(listS, "data.items").String()), &list) Cache.SetDefault(keyName, listS)
}
return list, count 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)

View File

@@ -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 {

View File

@@ -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" { // if portMap.CommendPort == m.PortMap && portMap.Protocol == "tcp" || portMap.Protocol == "both" {
port = portMap.ContainerPort // 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+$)`) //reg1 := regexp.MustCompile(`([^<>/\\\|:""\*\?]+\.\w+$)`)
result1 := reg1.FindAllStringSubmatch(path, -1) //result1 := reg1.FindAllStringSubmatch(path, -1)
if len(result1) == 0 { //if len(result1) == 0 {
err = file.IsNotExistMkDir(path) err = file.IsNotExistMkDir(path)
if err != nil { if err != nil {
ds.log.Error("mkdir error", err) ds.log.Error("mkdir error", err)
continue continue
}
} else {
err = file.IsNotExistCreateFile(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{} // healthTest := []string{}
if len(port) > 0 { // if len(port) > 0 {
healthTest = []string{"CMD-SHELL", "curl -f http://localhost:" + port + m.Index + " || exit 1"} // healthTest = []string{"CMD-SHELL", "curl -f http://localhost:" + port + m.Index + " || exit 1"}
} // }
health := &container.HealthConfig{ // health := &container.HealthConfig{
Test: healthTest, // Test: healthTest,
StartPeriod: 0, // StartPeriod: 0,
Retries: 1000, // Retries: 1000,
} // }
fmt.Print(health) // 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
service/file.go Normal file
View File

@@ -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
service/file_test.go Normal file
View File

@@ -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()
}

View File

@@ -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"`

View File

@@ -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")
} }

View File

@@ -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
}

View File

@@ -1,4 +1,4 @@
package types package types
const CURRENTVERSION = "0.2.3" const CURRENTVERSION = "0.2.4"
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 BODY = "<li>New App Store</li><li>Fix minor bugs</li>"